# articles

feed_id: http://sametmax.com/?p=9994
title: Ca va se prolonger
uri: Ca-va-se-prolonger
url: http://sametmax.com/ca-va-se-prolonger/
content:
<p>Situation imprévue et prolongation de l&#8217;absence. Retour sur le blog lundi ou mardi.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=9994&amp;md5=9cb674ceaed6132bc644b788f17379d3" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10007
title: Heartbleed, une semaine plus tard
uri: Heartbleed-une-semaine-plus-tard
url: http://sametmax.com/heartbleed-une-semaine-plus-tard/
content:
<p>Il y a eu pas mal d&#8217;infos sur le sujet, généralement assez technique et en anglais, aussi je vous fais un petit résumé de la crise.</p>
<p>Le 8 avril dernier, une faille dans le logiciel OpenSSL, surnommée <a href="http://heartbleed.com/">Heartbleed</a>, a été <a href="http://www.washingtonpost.com/business/technology/heartbleed-bug-puts-the-chaotic-nature-of-the-internet-under-the-magnifying-glass/2014/04/09/00f7064c-c00b-11e3-bcec-b71ee10e9bc3_story.html">rendue publique</a>. OpenSSL est le logiciel le plus utilisé au monde pour chiffrer les communications entre le navigateur et le site Web. Les banques, les e-commerce, les emails, les réseaux sociaux, tous utilisent SSL, pour éviter que l&#8217;on puisse intercepter vos communications. Et la plupart utilisent OpenSSL sur leurs serveurs pour permettre une connexion SSL.</p>
<p>Ce n&#8217;est pas le protocole SSL ou le chiffrement en général qui est mis en cause mais bien le logiciel OpenSSL.</p>
<p>Au début, on a cru à une faille critique qui permettait à l&#8217;attaquant de lire les communications. Toute personne exploitant cette faille aurait pu récupérer vos identifiants de banque au moment de votre login par exemple.</p>
<p>Il s&#8217;est avéré que c&#8217;était <a href="https://www.schneier.com/blog/archives/2014/04/heartbleed.html">bien pire encore</a>.</p>
<p>La faille permet de récupérer, à chaque heart beat (d&#8217;où le surnom) &#8211; c&#8217;est à dire à chaque fois qu&#8217;un client dit au serveur &#8220;je suis toujours connecté&#8221; &#8211; 64K de mémoire de l&#8217;ordinateur cible, au hasard. Parce que cette faille utilise le heart beat, elle n&#8217;implique pas d&#8217;authentification ou de log, elle est donc parfaitement silencieuse, ne laisse pas de trace, et n&#8217;importe qui sans autorisation peut se connecter et en tirer parti.</p>
<p><a href="http://www.scribd.com/doc/217805356/9/NCSC-FI-Advisory-on-OpenSSL">Tous les sites les plus importants sont concernés</a> incluant tous les réseaux sociaux, fournisseurs d&#8217;email, banque, etc. En fait, même les services en ligne qui ne sont pas des sites, comme Steam, sont affectés.</p>
<p>On ne peut pas choisir les 64K sur la machine, mais si on répète l&#8217;opération suffisamment longtemps, on peut récupérer la plupart des choses en mémoire. Comme un serveur a généralement énormément de cache en mémoire, il y a de tout dedans : les mots de passe, adresses emails, clés privées, certificats d&#8217;authentification, présents dans le programme, etc. En prime, en récupérant la clé privée, on peut écouter les connections au site ou carrément se faire passer pour le site, puis facilement récupérer numéros de carte de crédit, emails, messages privés, et tout ce qui transite.</p>
<href="https://filippo.io/Heartbleed/">La plupart des services</a> ont réagit très vite et ont corrigé le problème, seulement la faille a été dans la nature pendant 2 ans.</p>
<p>C&#8217;est une catastrophe.</p>
<h2>A qui profite le crime ?</h2>
<p>La question n&#8217;est pas qui peut en tirer parti. La réponse à cela est tous les attaquants : pirates, gouvernements, armées, services secrets et même script kiddies.</p>
<p>Non. Le débat est plutôt de savoir si la faille était intentionnelle ou pas.</p>
<p>D&#8217;un côté, j&#8217;aime beaucoup cette phrase attribuée à Napoléon :</p>
<blockquote><p>N&#8217;attribuez jamais à la malveillance ce qui s&#8217;explique très bien par l&#8217;incompétence.</p></blockquote>
<p>Et l&#8217;incompétence, il en a fallu, car il ne s&#8217;agit pas d&#8217;une faille de cryptographie complexe, mais d&#8217;<a href="http://blog.existentialize.com/diagnosis-of-the-openssl-heartbleed-bug.html">une erreur de débutant en programmation C</a>. Dans un logiciel qui a la portée de OpenSSL, ça amène sérieusement à se poser des questions, malgré <a href="http://www.smh.com.au/it-pro/security-it/man-who-introduced-serious-heartbleed-security-flaw-denies-he-inserted-it-deliberately-20140410-zqta1.html">le déni de l&#8217;auteur</a>.</p>
<p>Par dessus se rajoute <a href="http://igurublog.wordpress.com/2014/04/08/julian-assange-debian-is-owned-by-the-nsa/">une déclaration d&#8217;Assange</a>, qui enfonce un clou dans le cercueil, en expliquant que de nombreux logiciels Open Source sont complètement vérolés par la NSA, incluant des distributions Linux aussi réputées que Debian.</p>
<p>Comme souvent sur Internet, ce sont les commentaires de l&#8217;article qui sont les plus intéressants. On y note notamment plusieurs personnes, se présentant comme des professionnels de la cryptographies, débattant avec des argumentaires très bien construits de l&#8217;implication probable de la NSA et d&#8217;autres services secret dans la mise en œuvre de cette faille, et de son exploitation.</p>
<p>D&#8217;un côté, Bloomberg a annoncé que la NSA, a défaut d&#8217;avoir créé le bug, <a href="http://www.bloomberg.com/news/2014-04-11/nsa-said-to-have-used-heartbleed-bug-exposing-consumers.html">savait à son propos</a> depuis le début et l&#8217;a exploité. De l&#8217;autre, <a href="https://twitter.com/NSA_PAO/status/454720059156754434">la NSA nie</a> (putain la NSA a un compte Twitter ?).</p>
<p>En tout cas, avec la révélation de Prism, il ne tient plus de la théorie du complot mais de faits que ces entités cherchent par tous les moyens à obtenir la main mise sur les réseaux d&#8217;information. L&#8217;idée qu&#8217;ils aient créé cette back door parait donc plausible, bien qu&#8217;improuvable.</p>
<p>Et surtout, si c&#8217;est le cas, combien d&#8217;autres accès aussi radicaux ont-ils à leur disposition ? Mon frère me disait dernièrement :</p>
<blockquote><p>Je ne sais pas pourquoi ça te surprend encore. Tout en informatique a été craqué. Tout. Depuis toujours. On crack les playstations, Windows&#8230; Pourquoi tu crois que tes systèmes de sécurités ne sont pas craqués aux aussi ?</p></blockquote>
<p>Sous prétexte que tout le monde les utilise, qu&#8217;ils sont Open source et que des gens vachement plus intelligents que nous les ont vérifié, on fait confiance à ces systèmes. Mais si la porte blindée est attachée à un mur en BA13 et qu&#8217;on ne le sait pas ?</p>
<h2>Que faire pour l&#8217;utilisateur ?</h2>
<p>Comme l&#8217;a recommandé <a href="http://mathieu.agopian.info/blog/heartbleed-consequences-pour-les-utilisateurs.html">Mathieu Agopian</a>, d&#8217;abord changer tous ses mots de passe, pour tous ses sites. C&#8217;est là qu&#8217;on apprécie <a href="http://sametmax.com/les-10-meilleures-extensions-firefox-chrome/">lastpass</a>.</p>
<p>Je sais pertinemment que personne ne va le faire. Les gens ont une forte tendance à se plaindre que tout le monde est pourri et qu&#8217;on ne peut rien y changer, mais dès qu&#8217;il faut mettre la main à la pâte, y a plus personne. C&#8217;est pareil pour le recyclage, le boycott ou la lecture des programmes électoraux.</p>
<p>Et puis ils n&#8217;ont <a href="https://xkcd.com/1353/">rien à cacher</a>, pas vrai ?</p>
<p>De plus, si il existe d&#8217;autres failles de ce genre, ça ne résoudra pas le problème général, qui est politique et social. L&#8217;informatique n&#8217;est qu&#8217;un outil, on ne résout pas avec de la technique les problèmes d&#8217;un peuple. Même si ça aide.</p>
<p>De plus, le problème n&#8217;est pas complètement résolu côté fournisseur. Il faut que tout le monde mette à jour ses certificats, et les autorités de certifications croulent sous les demandes. Elles n&#8217;ont pas une infra prévue pour ça. Ensuite, certains outils ne pourront pas se changer. OpenSSL est présent dans de nombreux systèmes embarqués. Si vous mettre en sécurité implique jeter votre appareil et en racheter un neuf, vous pouvez être certain que que ça se fera encore moins que changer les mots de passe. Et je ne vous parle même pas de l&#8217;industrie. Je met ma bite à couper que dans le domaine des transports il y a des tas d&#8217;équipements bien trop chers à changer pour qu&#8217;ils soient sécurisés. Les professionnels vont donc jouer la carte de l&#8217;obscurité et serrer les fesses.</p>
<h2>La désillusion sur l&#8217;Open Source</h2>
<p>Ce qui fait mal au fion, c&#8217;est l&#8217;évidence de la réponse de <em>Wolf</em> dans un des commentaires de l&#8217;article sur Asssange, quand quelqu&#8217;un demande des solutions :</p>
<blockquote><p>I think the reason you’re not receiving much of an answer on this is the reason I gave above – there are none. We’re in a place of no good options.</p></blockquote>
<p>Car quand il s&#8217;agit du système général qui joue contre celui qu&#8217;il est censé servir, changer de logiciel ne sert à rien. On pensait que parce que les systèmes ouverts étaient transparents, ils n&#8217;étaient pas attaquables de cette manière. Des milliers d&#8217;yeux pour regarder le code source, qu&#8217;ils disaient.</p>
<p>Heartbleed nous montre une histoire bien différente.</p>
<p>OpenSSL s&#8217;est révélé être extrêmement difficile à auditer, car il est très complexe, sa documentation est réputée lacunaire sans compter qu&#8217;il faut de sacrées compétences pour ne serait-ce que commencer à proposer de participer.</p>
<p>En clair, la taille, la complexité et l&#8217;accessibilité des projets libres les plus importants font un sérieux contre poids à la fameuse garantie de la revue de pairs. C&#8217;est pour cette raison que des projets comme Android ne sont pas considérés comme libres par beaucoup : seul Google a les ressources pour étudier tout le code source. On manque de gens compétents, ainsi que de temps et d&#8217;argent. Il y a de plus en plus d&#8217;informaticiens, mais de moins en moins, proportionnellement, sont qualifiés. Beaucoup de techniciens, peu d&#8217;ingénieurs ou de hackers, malgré le titre sur le CV. Et encore moins qui sont motivés pour mettre les mains dans le cambouis du FOSS.</p>
<p>Cela veut-il dire qu&#8217;il faut jeter le bébé avec l&#8217;eau du bain ?</p>
<p><a href="http://sebsauvage.net/links/?CjQyCg">Certainement pas.</a></p>
<p>En fait, si cette faille avait été dans un logiciel propriétaire, nous n&#8217;aurions jamais été au courant. Elle a été découverte par hasard lors d&#8217;un audit d&#8217;un système qui n&#8217;a absolument rien à voir, par une équipe de sécurité Finlandaise. Les ingénieurs ont matraqué leur cible de tests aléatoires et sont tombés sur un problème. En cherchant l&#8217;origine du problème, ils se sont aperçus que le souci ne venait pas du produit testé, mais d&#8217;OpenSSL. <strong>Parce qu&#8217;ils avaient le code source</strong>, ils ont pu pointer du doigt la faille et prévenir les auteurs d&#8217;OpenSSL.</p>
<p>Entre temps, l&#8217;équipe de sécurité de Google (là encore, ça fait jaser car ils ont la réputation d&#8217;être proches de la NSA) a publié le bug et le correctif, et la couverture de presse vend le tout comme étant leur propre découverte.</p>
<h2>L&#8217;Emo de la fin</h2>
<p>Donc non, les logiciels Open Source ne sont pas vaccinés contre les failles majeures sous prétexte que le code est public.</p>
<p>Oui, il y a un soupçon grave de sabotage, à l&#8217;heure actuelle (et probablement pour longtemps) il n&#8217;y a aucune preuve. On peut s&#8217;attendre à une grosse vague de rejet de cette idée pour cause de &#8220;théorie du complot&#8221;. Ça ne change pas beaucoup des débats habituels dès qu&#8217;on parle de sécurité. C&#8217;est fou comme les gens sont prêt à jouer la carte de la présomption d&#8217;innocence pour défendre des grosses institutions boîtes noires au passé trouble et désignent coupable les accusés de pédophilie dès qu&#8217;ils voient leur tête au 20H&#8230;</p>
<p>La différence, c&#8217;est l&#8217;enjeu, et il est de taille. On parle pas d&#8217;une déchirure du slip, on parle d&#8217;être complètement à poil avec un bout du string cassé qui sort de l&#8217;anus.</p>
<p>Enfin oui, l&#8217;Open Source, offre toujours de meilleures garanties de sécurité en la matière que le logiciel fermé. Plus de transparence, plus de vitesse de réaction, disponibilité immédiate et pour toujours des correctifs, etc. Mais surtout, on vient d&#8217;en parler, si il s&#8217;agit de sabotage, le problème est politique et social, pas juste technique. Face à cela, un système démocratique, comme l&#8217;Open Source, a plus de chance de jouer en notre faveur qu&#8217;un système oligarchique de logiciel propriétaire. Reste à vérifier si l&#8217;élitisme du savoir ne risque pas de créer une oligarchie d&#8217;un autre genre côté FOSS. Sans compter les innombrables problèmes d&#8217;ego.</p>
<p>Mais ça ne suffit pas. Et à la lueur de ce genre d&#8217;affaire, il va falloir que la communauté du libre, principale gardienne des plus gros codes sources ouverts, se réorganise pour à la fois faire le ménage dans la base de code existante et filtrer à l&#8217;entrée les potentiels saboteurs. Qu&#8217;ils soient incompétents ou malveillants.</p>
<p>J&#8217;aimerais pas être dans les chaussettes de Linus en ce moment.</p>
<p>Malheureusement wikipedia est la preuve que des règles plus restrictives pour participer n&#8217;empêche pas les lobbyistes de pourrir le contenu mais apporte bel et bien un énorme frein à l&#8217;entrée de sang neuf. Ce qui n&#8217;arrange pas nos affaires, dans un monde où la complexité des sujets augmente plus vite que la compétence des gens qui pourraient participer. La revue communautaire reste le moins pire des systèmes, comme la démocratie pour Churchill, mais ça me colle un petit coup de blues tout ça quand même.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10007&amp;md5=5f1bc14d3b056b056723256ed775d6a0" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10029
title: Générer des données factices avec faker
uri: Générer-des-données-factices-avec-faker
url: http://sametmax.com/generer-des-donnees-factices-avec-faker/
content:
<p><a href="https://github.com/joke2k/faker">faker</a> fait partie de ses libs que j&#8217;ai toujours voulu écrire sans jamais prendre le temps de le faire. Comme <a href="http://sametmax.com/les-time-zones-en-python/">arrow</a> par exemple. Et puis un jour quelqu&#8217;un le fait, et je suis à la fois soulagé de ne pas avoir tenté de le faire (au risque de ne pas réussir aussi bien) et un peu déçu d&#8217;être passé à côté de la bonne idée.</p>
<p>Le principe de la lib est très simple : générer des données bidons. Noms, numéros de téléphone, adresses physiques ou email&#8230; C&#8217;est utile pour tout un tas de choses :</p>
<ul>
<li>Faire des tests, évidement.</li>
<li>Créer des bots, des crawlers et tout autre programme qui doit se faire passer pour un utilisateur.</li>
<li>Remplir une base de données vide en attendant que les utilisateurs réels remplissent le site. Cela évite le sentiment d&#8217;arriver sur un service désert. Tous les sites de rencontre font ça.</li>
<li>Générer un contexte artificiel, par exemple pour un jeu vidéo.</li>
</ul>
<p>Faker est déjà très simple à utiliser :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> faker <span style="color: #ff7700;font-weight:bold;">import</span> Faker
<span style="color: #66cc66;">&gt;&gt;&gt;</span> f = Faker<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> f.<span style="color: black;">phone_number</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'+69(4)8833689405'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> f.<span style="color: black;">phone_number</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'1-201-240-9452'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> f.<span style="color: black;">phone_number</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'+95(8)7680219065'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> f.<span style="color: black;">phone_number</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'754-833-9664x654'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> f.<span style="color: #dc143c;">email</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'bentley.gaylord@batz.org'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> f.<span style="color: #dc143c;">email</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'ludwig.rohan@adamskoch.info'</span></pre></div></div>

<p>Et surtout déjà très riche. Il y a <strong>plus d&#8217;une centaine</strong> de choses que vous pouvez générer. Quelques exemples :</p>
<ul>
<li><code>f.city</code></li>
<li><code>f.company</code></li>
<li><code>f.credit_card_number</code></li>
<li><code>f.date_time_this_decade</code></li>
<li><code>f.geo_coordinate</code></li>
<li><code>f.hex_color</code></li>
<li><code>f.ipv4</code></li>
<li><code>f.language_code</code></li>
<li><code>f.md5</code></li>
<li><code>f.mime_type</code></li>
<li><code>f.month_name</code></li>
<li><code>f.paragraph</code></li>
<li><code>f.password</code></li>
<li><code>f.postcode</code></li>
<li><code>f.ssn</code></li>
<li><code>f.street_address</code></li>
<li><code>f.url</code></li>
<li><code>f.user_agent</code></li>
<li><code>f.word</code></li>
</ul>
<p>faker est très flexible. En effet, beaucoup d&#8217;éléments existent en plusieurs versions ou de manière composée et utilisables séparément. Ainsi, on peut prendre l&#8217;IPV4 ou V6, choisir l&#8217;adresse entière ou le code postal seul, récupérer le nom complet, ou juste le prénom :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> f.<span style="color: black;">name</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'Olin McCullough'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> f.<span style="color: black;">first_name</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'Brandie'</span></pre></div></div>

<p>Mais en plus, faker est localisé :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> f = Faker<span style="color: black;">&#40;</span><span style="color: #dc143c;">locale</span>=<span style="color: #483d8b;">&quot;fr_FR&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> f.<span style="color: black;">name</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'Martine de la Petitjean'</span></pre></div></div>

<p>Enfin, on peut créer ses propres générateurs et fournisseurs de données au besoin.</p>
<p>Comme dirait Max, c&#8217;est d&#8217;la balle baby !</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10029&amp;md5=6c79ec4bd68cf9513e85161d9af76a36" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10038
title: Le manifeste du cache du mode hors ligne pour HTML5
uri: Le-manifeste-du-cache-du-mode-hors-ligne-pour-HTML5
url: http://sametmax.com/mode-le-manifeste-du-cache-du-mode-hors-ligne-pour-html5/
content:
<p>La bataille app native VS site responsive va faire rage pendant pas mal de temps, et pour le moment les apps gagnent : performances plus élevées, meilleures intégration visuelle dans l&#8217;OS, accès à une API plus riche&#8230; Les utilisateurs les préfèrent, et du coup les pros sont obligés de se les coltiner. C&#8217;est chiant, mais c&#8217;est la réalité du terrain pour les dev sur mobile.</p>
<p>Mais pour les sites Web ou les apps simples, il est super intéressant d&#8217;exploiter les capacités HTLM5 au max pour une obtenir une expérience plus &#8220;app&#8221; et moins &#8220;site web&#8221;.</p>
<p>Parmi ces possibilités : le mode hors ligne. D&#8217;un côté, il y a le stockage des données dans le navigateur, mais <a href="http://sametmax.com/stockez-vos-donnees-dans-le-navigateur-de-lutilisateur-avec-localstorage-html-5/">on vous en a déjà parlé</a>.</p>
<p>De l&#8217;autre, il y a le cache des ressources. Cela consiste à déclarer quels fichiers (html, css, js, images, fonts, n&#8217;importe quoi&#8230;) garder en mémoire afin de les charger directement depuis le disque dur au lieu de le faire en ligne.</p>
<p>Pour cela, il faut déclarer un manifeste dans son HTML :</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;html manifest=&quot;cache.manifest&quot;&gt;</pre></div></div>

<p>Ensuite, on créer le fichier <code>cache.manifest</code> dans son projet, qui est un fichier de texte simple.</p>
<p>Il faut le faire servir avec le mime-type
<pre lang="python bash">text/cache-manifest</pre>
<p> sinon ça ne marche pas. Si vous le nommez
<pre lang="python bash">*.manifest</pre>
<p> et que vous le servez avec un serveur de dev, ça marchera tout seul. Pour la prod, il faut le spécifier à votre serveur. Par exemple avec nginx, il faut éditer le fichier <code>/etc/nginx/mime.types</code> et y ajouter :</p>
<pre>text/cache-manifest                   manifest;</pre>
<p>Pour apache, c&#8217;est un truc du genre dans le <code>.htaccess</code>:</p>
<pre>AddType text/cache-manifest .manifest</pre>
<p>Ensuite, le manifeste ressemble à ça :</p>
<pre>CACHE MANIFEST
# 2014-04-20 13:25:00

# Toutes les ressources à sauvegarder en local. Le navigateur
# va toujours chercher ces ressources sur le disque.
# Si on est déconnecté, la page index.html, ses styles et javascript
# s'afficheront donc quand même.
CACHE:
index.html
/favicon.ico
stylesheet.css
images/logo.png
scripts/main.js
fonts/font.woff

# Ressources qui ne sont chargées que si on est en ligne.
# Par exemple, on charge le module de stats de visiteurs que si on est
# en ligne car impossible de compter les vues sans le serveur.
NETWORK:
js/visits.js

# Ressources alternatives si les précédentes sont inacessibles.
# Par exemple, pour afficher un point rouge si on est hors ligne
# et un point vert si on est en ligne :
# images/offline.png sera servi si images/online.png est inaccessible
FALLBACK:
images/online.png images/offline.png</pre>
<p>Notez le commentaire <code># 2014-04-20 13:25:00</code> tout en haut. C&#8217;est<br />
une convention qu&#8217;on utilise pour donner la dernière date de modification des<br />
fichiers cachés. En effet, <strong>les fichiers de la section <code>CACHE</code> ne seront<br />
pas rechargés tant que le manifeste n&#8217;a pas été modifié. </strong></p>
<p>Cela veut dire que si vous modifiez <code>index.html</code>, l&#8217;utilisateur<br />
ne verra pas la modification. Mais si vous changez la date du fichier manifeste,<br />
le fichier est modifié, et le navigateur rechargera donc toutes les ressources<br />
qu&#8217;il a mis en cache. Ainsi, vous permettez aux utilisateurs de voir les<br />
ressources cachées qui ont été modifiées.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10038&amp;md5=f5fda6374fb3bbe75d28d576c909b894" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10051
title: Complexité algorithmique : pourquoi tant de “n” ?
uri: Complexité-algorithmique-pourquoi-tant-de-n
url: http://sametmax.com/complexite-algorithmique-pourquoi-tant-de-n/
content:
<p>Que ayez eu un prof à l&#8217;ancienne durant vos études, où que vous vous soyez plongé dans des documents traitant d&#8217;optimisation, vous êtes peut être un jour tombé sur ces fameuses notations : O(n), O(1), O(log(n)), etc.</p>
<h2>Qu&#8217;est-ce que cela signifie-t-il donc, alors, hein ?</h2>
<p>C&#8217;est une manière de décrire l&#8217;ordre de grandeur de temps que va prendre un algo pour s&#8217;exécuter pour un nombre &#8220;n&#8221; d&#8217;éléments.</p>
<p>Par exemple, si je fais ceci en Python :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">elements = <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> elements:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## 1</span>
<span style="color: #808080; font-style: italic;">## 2</span>
<span style="color: #808080; font-style: italic;">## 3</span></pre></div></div>

<p>Ici, j&#8217;ai 3 éléments, donc n = 3. Mon algorithme va tous les utiliser une fois, mais pas plus d&#8217;une. Il va donc faire un nombre d&#8217;opérations proportionnel au nombres d&#8217;éléments. On note ce type de comportement O(n). Cela signifie que le temps de traitement de mon code suit à peu près &#8220;n&#8221;.</p>
<p>Je dis à peu près car le nombre d&#8217;éléments n&#8217;est pas uniquement ce qui va rentrer en compte. La taille des éléments, l&#8217;état de la machine au moment de l&#8217;exécution et tout un tas d&#8217;autres paramètres vont être des facteurs. Mais, globalement, je peux donner une évaluation convenable du temps que le code va prendre en notant le temps de traitement d&#8217;un seul élément, et en le multipliant par le nombre total d&#8217;éléments.</p>
<p>La notation O(truc), que l&#8217;on prononce &#8220;Oh de truc&#8221;, sert juste à indiquer quel type de comportement un algo a : est-ce qu&#8217;il prend du temps par rapport au nombre d&#8217;éléments ? Si oui à quel point ?</p>
<p>&#8220;A quel point&#8221; est une question importante, car si mon algo est celui ci:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">elements = <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> elements:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> elements:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>i, end=<span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## 123</span>
<span style="color: #808080; font-style: italic;">## 123</span>
<span style="color: #808080; font-style: italic;">## 123</span></pre></div></div>

<p>Alors, si n est grand, non seulement ma première boucle s&#8217;allonge, mais ma seconde boucle s&#8217;allonge aussi car j&#8217;affiche TOUS les éléments pour CHAQUE élément. Mon temps d&#8217;exécution dépend alors de &#8220;n&#8221; multiplié par lui-même : n X n. En effet, si j&#8217;ai 2 éléments, je vais faire 2 x 2 = 4 <code>print()</code>, si j&#8217;en ai 3, je vais faire 3 x 3 <code>print()</code>, etc.</p>
<p>Bien sûr, je pourrais faire des choses beaucoup plus compliquées qu&#8217;un <code>print()</code>, mais ça n&#8217;a pas d&#8217;importance. On en mesure pas le temps de tout le programme, seulement l&#8217;efficacité d&#8217;un algorithme. Ici, cela dépend du nombre d&#8217;éléments fois lui-même, soit au carré. On le note O(n²).</p>
<p>Il existe tout <a href="http://fr.wikipedia.org/wiki/Analyse_de_la_complexit%C3%A9_des_algorithmes">un tas de ces notations</a>. Par exemple, 0(1) signifie un temps &#8220;constant&#8221;, c&#8217;est un abus de langage pour dire que le temps que met l&#8217;ago à s&#8217;effectuer ne dépend pas du nombre d&#8217;éléments.</p>
<p>Par exemple :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">elements = <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>elements<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## 1</span></pre></div></div>

<p>Afficher le premier élément prend un temps du même ordre de grandeur &#8211; car c&#8217;est ça l&#8217;important, l&#8217;ordre de grandeur &#8211; si il y a 1 ou 10000 éléments. On note donc cet algo O(1).</p>
<p>Il y a des cas plus complexes. Imaginez celui-ci :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">random</span>
&nbsp;
number = <span style="color: #dc143c;">random</span>.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Choosing: %s&quot;</span> <span style="color: #66cc66;">%</span> number<span style="color: black;">&#41;</span>
smallest = <span style="color: #ff4500;">0</span>
biggest = <span style="color: #ff4500;">100</span>
guess = <span style="color: #ff4500;">50</span>
<span style="color: #ff7700;font-weight:bold;">while</span> guess <span style="color: #66cc66;">!</span>= number:
    <span style="color: #ff7700;font-weight:bold;">if</span> number <span style="color: #66cc66;">&gt;</span>= guess:
        smallest = guess
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        biggest = guess
&nbsp;
    guess = <span style="color: black;">&#40;</span>biggest - smallest<span style="color: black;">&#41;</span>//<span style="color: #ff4500;">2</span> + smallest
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;New guess: %s&quot;</span> <span style="color: #66cc66;">%</span> guess<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Last guess: %s&quot;</span> <span style="color: #66cc66;">%</span> guess<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## Choosing: 69</span>
<span style="color: #808080; font-style: italic;">## New guess: 75</span>
<span style="color: #808080; font-style: italic;">## New guess: 62</span>
<span style="color: #808080; font-style: italic;">## New guess: 68</span>
<span style="color: #808080; font-style: italic;">## New guess: 71</span>
<span style="color: #808080; font-style: italic;">## New guess: 69</span>
<span style="color: #808080; font-style: italic;">## Last guess: 69</span></pre></div></div>

<p>Dans cet exemple, le nombre d&#8217;opérations dépend du nombre d&#8217;éléments &#8220;n&#8221; (ici 100) mais on divise l&#8217;interval de recherche par deux à chaque tour de boucle. On note cette complexité O(log n), puisque la fonction log illustre bien le concept d&#8217;avoir une mi-molle sur la fin de son algo :)</p>
<p>Il y a aussi l&#8217;inverse :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">elements = <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span>, <span style="color: #ff4500;">4</span>, <span style="color: #ff4500;">5</span><span style="color: black;">&#93;</span>
copies = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> elements:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> copies:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>i, end=<span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span>
    copies.<span style="color: black;">extend</span><span style="color: black;">&#40;</span>elements<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## 12345</span>
<span style="color: #808080; font-style: italic;">## 1234512345</span>
<span style="color: #808080; font-style: italic;">## 123451234512345</span>
<span style="color: #808080; font-style: italic;">## 12345123451234512345</span></pre></div></div>

<p>Ici on augment la charge à traiter à chaque tour de boucle, et cette augmentation dépend du nombre d&#8217;éléments &#8220;n&#8221;. On parle d&#8217;une augmentation exponentielle de la charge de travail et on le note O(e<sup>n</sup>).</p>
<h2>A quoi ça sert ?</h2>
<p>Essentiellement à avoir une idée d&#8217;où on met les pieds. Si vous lisez une doc, et qu&#8217;on vous dis &#8220;cet algo met un temps O(log(n))&#8221;, vous savez que même sur un grand ensemble de données, le traitement ne sera pas trop agressif. Si plus tard vous rencontrez des problèmes de perf, ce ne sera pas le premier endroit à regarder.</p>
<p>Par contre si vous lisez qu&#8217;un algo est O(n!) &#8211; là on tape dans les factoriels, c&#8217;est énorme &#8211; alors au premier ralentissement il faut jeter un coup d’œil sur ce bout de code.</p>
<p>C&#8217;est aussi utile pour comparer l&#8217;efficacité de deux implémentations.</p>
<p>Imaginez la structure suivante :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Examen:
    <span style="color: #483d8b;">&quot;&quot;&quot;C'est un exemple pédagogique, ne faites pas ça chez vous les enfants&quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">notes</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> ajouterNote<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, note<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">notes</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>note<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> moyenne<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        total = <span style="color: #ff4500;">0</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> note <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">notes</span>:
            total += note
        <span style="color: #ff7700;font-weight:bold;">return</span> total / <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">notes</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Récupérer la moyenne est une opération O(n). En revanche, si on a :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Examen:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">notes</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">moyenne</span> = <span style="color: #008000;">None</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> ajouterNote<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, note<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">moyenne</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">moyenne</span> = note
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">moyenne</span> = <span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">notes</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">*</span><span style="color: #008000;">self</span>.<span style="color: black;">moyenne</span> + note<span style="color: black;">&#41;</span> / <span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">notes</span><span style="color: black;">&#41;</span>+<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">notes</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>note<span style="color: black;">&#41;</span></pre></div></div>

<p>Là, récupérer la moyenne devient une opération O(1), on a déchargé et réparti le calcul sur l&#8217;ajout des notes. Selon que l&#8217;application va lire souvent la moyenne ou non, l&#8217;un ou l&#8217;autre algo est préférable, et la notation Big O va donner une idée duquel utiliser si on est face à la doc et pas au code, qui est généralement vachement plus compliqué que ça.</p>
<p>Bon, ok, dans la VVV, aucune de ces deux solutions n&#8217;est un problème, on s&#8217;en branle. Mais sur des algos plus riches, sur du matos plus limité, ou un jeu de données plus grand, c&#8217;est important. Ainsi, <a href="http://redis.io/commands/zremrangebyrank">la doc de redis donne la notation Big O de toutes les commandes</a>.</p>
<h2>En Python, qui est quoi ?</h2>
<p>Parcourir un itérable, c&#8217;est généralement du O(n), en tout cas pour les listes, les tuples, les dicos, les strings et les sets. Ajouter un élément ou en retirer un, c&#8217;est du O(1). Récupérer leurs tailles, c&#8217;est du O(1) aussi (elle est mise en cache), donc vous pouvez y aller avec <code>len()</code>.</p>
<p>En revanche, l&#8217;opérateur <code>in</code> a un temps moyen de O(n) pour les strings, les tuples et les listes (il doit parcourir l&#8217;itérable jusqu&#8217;à trouver l&#8217;élément), et un temps de O(1) pour les sets et les dicos. Ces derniers utilisent des hash, rendant la recherche très très rapide. C&#8217;est pour cela qu&#8217;on vous dit d&#8217;utiliser la bonne structure de données pour le bon usage.</p>
<p>Attention cependant, c&#8217;est de l&#8217;optimisation de poil de cul, mais c&#8217;est pour la culture, O(1) ne veut pas dire &#8220;plus rapide que O(n)&#8221;. O(1) veut juste dire que le temps est indépendant du nombre d&#8217;éléments. Ainsi :</p>
<p><code>1 in [1, 2, 3]</code> sera beaucoup plus rapide que <code>1 in [1, 2, 3..., 1000].</code></p>
<p>Et :</p>
<p><code>1 in {1, 2, 3}</code> prendra un temps similaire à 1 in <code>{1, 2, 3..., 1000}</code></p>
<p>Mais :</p>
<p><code>1 in {1, 2, 3}</code> peut tout à faire être plus lent que <code>1 in [1, 2, 3]</code></p>
<p>Par contre, il est presque certain que :</p>
<p><code>1 in {1, 2, 3..., 1000}</code> est BEAUCOUP plus rapide que <code>1 in [1, 2, 3..., 1000]</code></p>
<p>De plus, il y énormément de structures de données dans la stdlib Python, toutes avec des capacités différentes. <a href="http://sametmax.com/heapq-le-module-python-incompris/">Heapq</a> assure que votre structure de données est toujours ordonnées pour un coût de O(log n) à l&#8217;insertion. Les <a href="http://sametmax.com/implementer-une-fenetre-glissante-en-python-avec-un-deque/">deques</a> sont très rapides comme FIFO/LIFO (O(1)), mais récupérer une donnée au milieu est une opération O(n). Certaines opérations, comme retirer un élément d&#8217;un type <code>list</code> sont étonnamment coûteuses ((O(n) dans le cas du del).</p>
<p>Voici <a href="https://wiki.python.org/moin/TimeComplexity">quelques notations</a> de la doc de Python.</p>
<h2>La théorie, la pratique, et la mauvaise foi</h2>
<p>La notation O est une bonne indication pour faire un choix d&#8217;algo ou pour commencer ses recherches de goulot d&#8217;étranglement dans un code.</p>
<p>Néanmoins, c&#8217;est la performance sur la papier. En pratique, on peut obtenir des résultats un peu différents, voir carrément surprenant. Il peut y avoir de multiples causes :</p>
<ul>
<li>L&#8217;implémentation ne se comporte pas comme prévu. CPython et Jython n&#8217;ont pas les mêmes perfs pour les mêmes choses. Jython n&#8217;a pas de GIL.</li>
<li>Vous avez oublié un paramètre. Un accès disque ou un accès réseau au mauvais endroit, et bam, votre évaluation est à revoir. </li>
<li>Les données de la vie réelle ont généralement des tendances. Par exemple elles sont souvent un peu triées plutôt que complètement en bordel. C&#8217;est pour cette raison que Python utilise <a href="http://en.wikipedia.org/wiki/Timsort">Timsort</a>.</li>
<li>Le matos ne fait pas ce que vous croyez. Les processeurs / cartes graphiques actuels sont devenus <a href="http://www.grantjenks.com/docs/sortedcontainers/implementation.html">incroyablement efficaces à certaines opérations réputées lentes</a></li>
<li>Votre machine ne fait pas que faire tourner votre algo. Il y a d&#8217;autres processus, avec des conséquences.</li>
</ul>
<p>Donc si les perfs sont importantes, comme toujours en informatique, on a le dernier mot en mesurant soi-même.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10051&amp;md5=800187eb307efbdf9d5b3cf0232b9904" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10065
title: Not invented here
uri: Not-invented-here
url: http://sametmax.com/not-invented-here/
content:
<p>À la maison on joue beaucoup. Aux jeux vidéo, bien entendu, mais aussi à tout un tas d&#8217;autres trucs, incluant des jeux de rôles, de société, de carte&#8230; Ça joue même de la musique. Il y a un carton qui déborde de cartes magic, l&#8217;indispensable pot plein de dés 6/10/20, et des dizaines de boîtes en tout genre, parfois des titres dont moi-même je n&#8217;ai jamais entendu parlé, un piano à queue, divers lots de baffles et même des contentions psychiatriques. Pour d&#8217;autres jeux.</p>
<p>Je me tâte à faire une rubrique &#8220;jeu&#8221; d&#8217;ailleurs, pour introduire un jeu de plateau de temps en temps.</p>
<p>Évidement, à force de parties, on commence à en avoir plein le cul d&#8217;attendre le tour de l&#8217;autre, donc on joue au chrono. On a tenté le sablier, la montre, le portable, l&#8217;app, et rien n&#8217;est vraiment satisfaisant.</p>
<p>Que fait un programmeur dans ce cas ? Il réinvente la roue, bien sûr !</p>
<p>Voici donc <a href="http://allthatcounts.net/">All That Counts</a>, une Web app qui contient :</p>
<ul>
<li>Des timers.</li>
<li>Des chronos.</li>
<li>Des compteurs de points.</li>
</ul>
<p>C&#8217;est du HTML5 + Javascript, il n&#8217;y a pas de backend. Est inclus un mode offline, donc il suffit de visiter l&#8217;app une fois pour pouvoir toujours l&#8217;utiliser sauf vidange du cache. Magie de Bootstrap, ça marche sur mobile, tablette et destop. Comprendre : design responsive générique.</p>
<p>Sur les navs supportant l&#8217;élément audio, ça gong à la fin des timers.</p>
<p>La page &#8220;Count Down&#8221; est pratique pour faire sa gym, cuire ses œufs et organiser une partie avec des tours limités dans le temps pour 3 joueurs ou plus. Les widgets incluent le temps de dépassement si on a besoin de mettre des pénalités aux escargots et aux stallers.</p>
<p>La partie &#8220;Chrono&#8221;, c&#8217;est gadget pour moi, mais ça pourra peut être servir à certains. J&#8217;y ai collé la possibilité de cumuler des temps de tours, pour les sportifs. Je ne sais pas si c&#8217;est utile, les coureurs me diront. A la limite pour les concours d&#8217;apnée&#8230;</p>
<p>L&#8217;onglet &#8220;Counter&#8221; c&#8217;est pour compter les points quand on a pas de papier ou de jeton, c&#8217;est du dépannage. Ça peut servir aussi pour les gens dont le métier implique de compter des têtes de pipe comme les videurs, les hôtesses de l&#8217;air, etc.</p>
<p>Ce qu&#8217;on utilise le plus est le mode &#8220;Versus&#8221;, qui sert aux duels. C&#8217;est une sorte de <a href="http://fr.wikipedia.org/wiki/Pendule_d%27%C3%A9checs">pendule d&#8217;échecs</a>, avec plusieurs comportements réglables. Par défaut, le passage d&#8217;un décompte à l&#8217;autre se fait automatiquement et manuellement, chaque changement de joueur impliquant une remise à zéro.</p>
<p><del datetime="2014-04-24T08:11:17+00:00">Comme il n&#8217;y a pas de backend, vous pouvez avoir le code source en faisant Ctrl + S, donc je vais pas vraiment me faire chier à le mettre sur github. Déjà, j&#8217;ai du codé en pur JS. Moi. Heureusement qu&#8217;il y a AngularJS, sinon je changeais de métier. Le déploiement, pareil, c&#8217;est Ctrl + C, Ctrl + V, donc je vais pas écrire de doc. L&#8217;utilisation, bon, c&#8217;est des clics sur des boutons labellisés&#8230;</del></p>
<p><a href="https://github.com/sametmax/allthatcounts">Le code source est dispo sur github</a>.</p>
<p>La seule astuce, c&#8217;est qu&#8217;en mode versus, CTRL permet de faire un switch, et SPACE permet de faire pause et resume. Je pense que vous vous en sortirez. C&#8217;est un compteur, pas une navette spatiale.</p>
<p>Si l&#8217;envie incroyable de rajouter des features vous prend, mettez un comment, et je me bougerais le cul pour githuber tout ça.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10065&amp;md5=4a12e383844a0e6addde9bf9f1ac7bd7" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10076
title: Comment figer son app hors ligne pour plus d’un mois
uri: Comment-figer-son-app-hors-ligne-pour-plus-d-un-mois
url: http://sametmax.com/comment-figer-son-app-hors-ligne-pour-plus-dun-mois/
content:
<p>Je sers <a href="http://allthatcounts.net/">All That Counts</a> avec nginx, et le fichier de config est super simple :</p>
<pre>server {
        listen       80;
        server_name allthatcounts.net;

        error_log  /var/log/nginx/error_allthatcounts.log;
        access_log  /var/log/nginx/access_allthatcounts.log;

        location / {
            root /home/allthatcounts/www/;
            gzip  on;
            gzip_http_version 1.0;
            gzip_vary on;
            gzip_comp_level 6;
            gzip_proxied any;
            gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
            gzip_buffers 16 8k;
            gzip_disable ~@~\MSIE [1-6].(?!.*SV1)~@~];
            expires modified +90d;
        }
}</pre>
<p>En gros c&#8217;est juste du log et servir les fichiers statiques compressés avec gzip. Il n&#8217;y a rien de plus à faire parce qu&#8217;il n&#8217;y a pas de backend. Simple. Efficace.</p>
<p>La couille c&#8217;est que c&#8217;est un copier / coller d&#8217;un autre projet que j&#8217;ai fais sans trop réfléchir, et quand j&#8217;ai mis en prod de nouvelles modifications sur le serveurs, mon Firefox me les affichait pas. Pourtant j&#8217;avais bien modifié le manifeste, donc il aurait du tout recharcher&#8230;</p>
<p>Sauf que, con de ma race, j&#8217;ai copié la ligne :</p>
<pre>expires modified +90d;</pre>
<p>Qui dit techniquement, met en cache tous les fichiers statiques pour 90 jours. Donc aussi le manifeste. Du coup, toutes les personnes qui ont visité le site ne verront aucune mise à jour pour un bon mois et demi.</p>
<p>Bravo Sam.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10076&amp;md5=d40b4a94525fa78960702c4f5f673c8e" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=9851
title: Un Tic-Tac-Toe en HTML écrit en Python, sans framework, mais avec les pieds.
uri: Un-Tic-Tac-Toe-en-HTML-écrit-en-Python-sans-framework-mais-avec-les
url: http://sametmax.com/un-tic-tac-toe-en-html-ecrit-en-python-sans-framework-mais-avec-les-pieds/
content:
<p style="text-align: center;"><em><small>Ceci est un post invité de <a href="http://sametmax.com/author/01ivier/">01ivier</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.</small></em></p>
<h2>Mea Sam&#038;Maxima Culpa</h2>
<p>Tout d&#8217;abord, je me dois de vous présenter mes excuses. </p>
<p>Je vous avais laissés miroiter, lors de ma première intervention, des articles avec du code bien dégueulasse afin de décomplexer les plus nuls d&#8217;entre vous, mais, quand je me suis penché sur la rédaction de mon troisième article ainsi que sur le script que je vais vous présenter aujourd&#8217;hui, j&#8217;étais tellement embarrassé de ne pas comprendre moi-même ce que j&#8217;avais fait à l&#8217;époque que j&#8217;ai repoussé cette publication à un jour où j&#8217;aurais le temps de décortiquer mon propre sale travail.</p>
<p>Bien entendu, ce jour n&#8217;est jamais venu et vous n&#8217;avez plus entendu parler de moi.</p>
<p>Quelle misère.<br />
Alors que j&#8217;avais sous les yeux un code illisible, d&#8217;une inutilité profonde et surtout particulièrement long pour ce qu&#8217;il avait à faire, je faisais la fine bouche et vous privais d&#8217;une véritable leçon de vie qui pourrait se résumer par &#8220;Comment faire n&#8217;importe quoi n&#8217;importe comment.&#8221;</p>
<p>Me voilà donc devant vous aujourd&#8217;hui pour tenter de me rattraper.</p>
<h2>L&#8217;idée géniale.</h2>
<p>En 1998, poussé par une intuition qui ne survient sur Terre qu&#8217;une fois tous les 69 ans, mon ami Frédéric s&#8217;est lancé dans l&#8217;écriture informatique d&#8217;un <a target="_blank" href="https://fr.wikipedia.org/wiki/Tic-tac-toe_%28jeu%29">Tic-Tac-Toe</a> afin de rendre un hommage appuyé à <a target="_blank" href="https://fr.wikipedia.org/wiki/L%27Acad%C3%A9mie_des_neuf">l&#8217;accadémie des neufs</a>. Il a donc pondu, à la main, en HTML, toutes les combinaisons possibles pour pouvoir jouer au jeu.</p>
<p>Chez moi, qui découvrais à peine les homepages sur fond gris et les GIF animés &#8220;Work in progress&#8230;&#8221;, je peux vous assurer que cette initiative eut l&#8217;effet d&#8217;une bombe. Mon ami était un génie.</p>
<p>Une dizaine d&#8217;années plus tard, pour son anniversaire, je me suis dit que j&#8217;allais faire la même chose, mais en Python. Compte-tenu de mon niveau et de l&#8217;intérêt de la démarche, j&#8217;étais convaincu d&#8217;arriver à un résultat tout aussi absurde. Je n&#8217;ai pas été déçu.</p>
<h2>Le résultat.</h2>
<p>Avant d&#8217;aborder la manière dont je m&#8217;y suis pris et d&#8217;essuyer, de fait, les ricanements des plus véloces d&#8217;entre vous, je vous propose d&#8217;admirer le résultat. Car, c&#8217;est n&#8217;importe quoi, c&#8217;est fait n&#8217;importe comment, mais ça marche :</p>
<p><a target="_blank" href="http://openatelier.labomedia.org/Tic-Tac-Toe/">Cliquez ici pour être certain de ne pas gagner.</a></p>
<h2>La mise en Œuvre.</h2>
<p>Le script s&#8217;appuie sur la méthode .format() qui permet de faire des choses émouvantes comme :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> toto = <span style="color: #483d8b;">&quot;J'ha{1} Orleans pour son cor{0} artis{3} suc{2}ent.&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> toto.<span style="color: black;">format</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;bite&quot;</span>, <span style="color: #483d8b;">&quot;nichon&quot;</span>, <span style="color: #483d8b;">&quot;anal&quot;</span>, <span style="color: #483d8b;">&quot;cul&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">&quot;J'hanichon Orleans pour son corbite artiscul sucanalent.&quot;</span></pre></div></div>

<p>À noter que si vous faites&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> toto = <span style="color: #483d8b;">&quot;J'ha{1} Orleans pour son cor{0} artis{3} suc{2}ent.&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> titi = <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;bite&quot;</span>, <span style="color: #483d8b;">&quot;nichon&quot;</span>, <span style="color: #483d8b;">&quot;anal&quot;</span>, <span style="color: #483d8b;">&quot;cul&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> toto.<span style="color: black;">format</span><span style="color: black;">&#40;</span>titi<span style="color: black;">&#41;</span></pre></div></div>

<p>&#8230;vous allez récolter un <em>IndexError</em> parce que, même si titi contient 4 éléments, vous ne filez qu&#8217;un seul argument à .format() alors qu&#8217;il en a besoin de 4. Il faut donc faire&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> toto.<span style="color: black;">format</span><span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>titi<span style="color: black;">&#41;</span></pre></div></div>

<p>&#8230; où l&#8217;étoile vous dépackagera votre tuple bien comme il faut (mais ne me demandez pas pourquoi).</p>
<p>Armé de cette subtilité, j&#8217;ai créé une page HTML avec un petit tableau de 3&#215;3 puis j&#8217;ai écrit dans chacune des cellules {0}, {1}, {2}&#8230; pour pouvoir les remplacer par le texte</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;image src=&quot;rond.png&quot; /&gt;</pre></div></div>

<p> si j&#8217;avais besoin d&#8217;y placer un rond, ou par</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;image src=&quot;croix.png&quot; /&gt;</pre></div></div>

<p> si j&#8217;avais besoin d&#8217;y mettre une croix.</p>
<p>Ici, par exemple, je vois bien que j&#8217;ai numéroté les cellules en faisant un petit escargot et non pas ligne par ligne, mais je n&#8217;ai aucune idée de pourquoi j&#8217;ai fait ce choix. J&#8217;ai dû vouloir faire une blague. Si ça vous fait rire, c&#8217;est qu&#8217;elle est réussie. Moi, je suis resté de marbre.</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;table &gt;
  &lt;tr&gt;
    &lt;td&gt;{0}&lt;/td&gt;
    &lt;td&gt;{1}&lt;/td&gt;
    &lt;td&gt;{2}&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;{7}&lt;/td&gt;
    &lt;td&gt;{8}&lt;/td&gt;
    &lt;td&gt;{3}&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;{6}&lt;/td&gt;
    &lt;td&gt;{5}&lt;/td&gt;
    &lt;td&gt;{4}&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;</pre></div></div>

<p>Puis, pour exporter chaque page HTML, j&#8217;ai écrit cette petite fonction&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">  def ecriturePage <span style="color: #7a0874; font-weight: bold;">&#40;</span>namePage, contenuPage<span style="color: #7a0874; font-weight: bold;">&#41;</span>:
    with open <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">'{0}.html'</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>namePage<span style="color: #7a0874; font-weight: bold;">&#41;</span>, <span style="color: #ff0000;">'w'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #c20cb9; font-weight: bold;">as</span> new_file:
        new_file.write <span style="color: #7a0874; font-weight: bold;">&#40;</span>contenuPage<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

<p>&#8230;qui récupère le nom de la page, son contenu et l&#8217;enregistre dans le dossier courant.</p>
<h2>Ensuite&#8230;</h2>
<p>Ensuite, c&#8217;est plus compliqué.<br />
De ce que je comprends, j&#8217;initialise une liste que je réécris partiellement en fonction des combinaisons recherchées.</p>
<p>C&#8217;est un peu flou, mais, ce qui est sûr c&#8217;est que je n&#8217;ai pas automatisé grand chose, surtout sur la fin&#8230;<br />
J&#8217;ai rempli des tas de feuilles de brouillon pour trouver les bonnes positions pour les croix et les ronds à chaque étape&#8230; et je les ai retranscrites avec des <em>for</em> des <em>if</em> et des <em>else</em>&#8230;</p>
<p>Pour la dernière étape, je suis sûr qu&#8217;il eut été plus rapide pour moi d&#8217;écrire les pages HTML directement à la main, mais, j&#8217;aurais alors lamentablement échoué dans ma mission et mon ami m&#8217;aurait sans nul doute frappé violemment au visage si je lui avais présenté ce résultat médiocre comme cadeau pour son anniversaire.</p>
<p>J&#8217;ai donc persévéré.</p>
<h2>La récompense.</h2>
<p>Vous l&#8217;aurez compris, cette décision absurde s&#8217;est révélée extrêmement judicieuse.</p>
<p>En effet, concentré que j&#8217;étais dans l&#8217;obtention de toutes les pages nécessaires pour jouer, je n&#8217;ai absolument pas prêté attention à la non-obtention des pages inutiles&#8230;</p>
<p>Et je me suis retrouvé avec <a target="_blank" href="http://openatelier.labomedia.org/Tic-Tac-Toe/55.html">ce joyau</a>.</p>
<p>J&#8217;avais fait écrire une combinaison qui n&#8217;était pas possible.<br />
J&#8217;avais créé un futur pour le jeu qui, bien qu&#8217;existant, ne lui était pas accessible.</p>
<p><strong>MON DIEU QUEL PUR MOMENT DE BONHEUR !!!</strong></p>
<h2>Le code</h2>
<p>L&#8217;archive avec l&#8217;index.html, les images, le CSS&#8230; est disponible <a href="http://openatelier.labomedia.org/Tic-Tac-Toe/Tic-Tac-Toe.zip">ici</a>.</p>
<p>Pour créer toutes les pages (dont ces bijoux de pages inutiles) il suffit de lancer le fichier <em>GO.py</em>.</p>
<p>Mais pour les plus impatients, voici l&#8217;intégralité du code :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># -*- coding: utf-8 -*-</span>
<span style="color: #666666; font-style: italic;"># Ce programme écrit toutes les pages html nécessaires pour jouer au Tic-Tac-Toe </span>
<span style="color: #666666; font-style: italic;"># En partant du principe que l'ordinateur ne doit pas perdre, donc commence...</span>
&nbsp;
c = range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">10</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
rond = <span style="color: #ff0000;">'&lt;image src=&quot;rond.png&quot; /&gt;'</span>
croix = <span style="color: #ff0000;">'&lt;image src=&quot;croix.png&quot; /&gt;'</span>
croixR = <span style="color: #ff0000;">'&lt;image src=&quot;croixR.png&quot; /&gt;'</span>
back = <span style="color: #ff0000;">&quot;&quot;</span><span style="color: #ff0000;">&quot;&lt;a href=&quot;</span>index.html<span style="color: #ff0000;">&quot;&gt; Pour recommencer, c'est ici... &lt;/a&gt;&quot;</span><span style="color: #ff0000;">&quot;&quot;</span>
&nbsp;
def page <span style="color: #7a0874; font-weight: bold;">&#40;</span>grille<span style="color: #7a0874; font-weight: bold;">&#41;</span>:
    <span style="color: #7a0874; font-weight: bold;">return</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">''</span><span style="color: #ff0000;">'
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;
        &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&nbsp;
 &lt;head&gt;
  &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot; /&gt;
  &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;style.css&quot; /&gt;
  &lt;link rel=&quot;icon&quot; type=&quot;image/png&quot; href=&quot;favicon.png&quot; /&gt;
  &lt;title&gt;Y a matière à... l académie des neuf&lt;/title&gt;
 &lt;/head&gt;  
&nbsp;
&lt;body&gt; 
&nbsp;
&lt;div class=&quot;grille&quot;&gt;
&lt;table &gt;
&lt;tr&gt;
&lt;td&gt;{0}&lt;/td&gt;
&lt;td&gt;{1}&lt;/td&gt;
&lt;td&gt;{2}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;{7}&lt;/td&gt;
&lt;td&gt;{8}&lt;/td&gt;
&lt;td&gt;{3}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;{6}&lt;/td&gt;
&lt;td&gt;{5}&lt;/td&gt;
&lt;td&gt;{4}&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&nbsp;
&lt;div class=&quot;redo&quot;&gt;
{9}
&lt;/div&gt;
&nbsp;
&nbsp;
&lt;/body&gt;
&nbsp;
&lt;/html&gt;
'</span><span style="color: #ff0000;">''</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">*</span>grille<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
def lien <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">link</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
    <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">'&lt;a href=&quot;{0}.html&quot;&gt;&lt;image src=&quot;vide.png&quot; /&gt;&lt;/a&gt;'</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">link</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
&nbsp;
def ecriturePage <span style="color: #7a0874; font-weight: bold;">&#40;</span>namePage, contenuPage<span style="color: #7a0874; font-weight: bold;">&#41;</span>:
    with open <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">'{0}.html'</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>namePage<span style="color: #7a0874; font-weight: bold;">&#41;</span>, <span style="color: #ff0000;">'w'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #c20cb9; font-weight: bold;">as</span> new_file:
        new_file.write <span style="color: #7a0874; font-weight: bold;">&#40;</span>contenuPage<span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
def grilleVide <span style="color: #7a0874; font-weight: bold;">&#40;</span>num<span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
    <span style="color: #000000; font-weight: bold;">for</span> i <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = lien <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>num, i<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">9</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = <span style="color: #ff0000;">&quot;&quot;</span>
&nbsp;
def grilleFin <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
    <span style="color: #000000; font-weight: bold;">for</span> i <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = <span style="color: #ff0000;">'&lt;image src=&quot;vide.png&quot; /&gt;'</span>
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">9</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = back
&nbsp;
&nbsp;
<span style="color: #666666; font-style: italic;">####### 1er clic</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">for</span> i <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
    grilleVide<span style="color: #7a0874; font-weight: bold;">&#40;</span>i<span style="color: #7a0874; font-weight: bold;">&#41;</span>
    c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">1</span> and i <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">5</span>:    
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix        
    <span style="color: #000000; font-weight: bold;">else</span>:
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
    ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>        
&nbsp;
<span style="color: #666666; font-style: italic;">####### 2eme clic</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">for</span> i <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">0</span>:
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> j <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> j <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">5</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">5</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR   
&nbsp;
            <span style="color: #000000; font-weight: bold;">else</span>:
                grilleVide<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">2</span>:
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> j <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> j <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">5</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">5</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
&nbsp;
            <span style="color: #000000; font-weight: bold;">else</span>:
                grilleVide<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">7</span>:
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> j <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> j <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">5</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">5</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
&nbsp;
            <span style="color: #000000; font-weight: bold;">else</span>:
                grilleVide<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">3</span>:
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> j <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> j <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">5</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">5</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
&nbsp;
            <span style="color: #000000; font-weight: bold;">else</span>:
                grilleVide<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #000000; font-weight: bold;">elif</span> i == <span style="color: #000000;">1</span>:
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> j <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> j <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">3</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
            <span style="color: #000000; font-weight: bold;">else</span>:
                grilleVide<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">elif</span> i == <span style="color: #000000;">5</span>:
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> j <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> j <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">3</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
            <span style="color: #000000; font-weight: bold;">else</span>:
                grilleVide<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">elif</span> i == <span style="color: #000000;">6</span>:
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> j <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> j <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">5</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">5</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
            <span style="color: #000000; font-weight: bold;">else</span>:
                grilleVide<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">elif</span> i == <span style="color: #000000;">4</span>:
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> j <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> j <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">5</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">5</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
            <span style="color: #000000; font-weight: bold;">else</span>:
                grilleVide<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #666666; font-style: italic;">#######3eme clic                </span>
&nbsp;
<span style="color: #000000; font-weight: bold;">for</span> i <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">0</span>, <span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
        j = <span style="color: #000000;">5</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> k <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> k <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">2</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
&nbsp;
            <span style="color: #000000; font-weight: bold;">else</span>:
                grilleVide<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">2</span>, <span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
        j = <span style="color: #000000;">5</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> k <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> k <span style="color: #000000; font-weight: bold;">!</span>=<span style="color: #000000;">0</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
&nbsp;
            <span style="color: #000000; font-weight: bold;">else</span>:
                grilleVide<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">7</span>:
&nbsp;
        j = <span style="color: #000000;">5</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> k <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> k <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">0</span>, <span style="color: #000000;">3</span>, <span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
&nbsp;
            <span style="color: #000000; font-weight: bold;">elif</span> k == <span style="color: #000000;">6</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">3</span>:
&nbsp;
        j = <span style="color: #000000;">5</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> k <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> k <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">2</span>, <span style="color: #000000;">6</span>, <span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
&nbsp;
            <span style="color: #000000; font-weight: bold;">elif</span> k == <span style="color: #000000;">4</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">1</span>:
&nbsp;
        j = <span style="color: #000000;">3</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> k <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> k <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">0</span>, <span style="color: #000000;">4</span>, <span style="color: #000000;">5</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
&nbsp;
            <span style="color: #000000; font-weight: bold;">elif</span> k == <span style="color: #000000;">2</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">5</span>:
&nbsp;
        j = <span style="color: #000000;">3</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">for</span> k <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
            <span style="color: #000000; font-weight: bold;">if</span> k <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">0</span>, <span style="color: #000000;">1</span>, <span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR 
&nbsp;
            <span style="color: #000000; font-weight: bold;">elif</span> k == <span style="color: #000000;">2</span>:
                grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
                c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
&nbsp;
            ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #666666; font-style: italic;">######4eme clic</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">for</span> i <span style="color: #000000; font-weight: bold;">in</span> range <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">0</span>:
&nbsp;
        grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
        j = <span style="color: #000000;">5</span>
        k = <span style="color: #000000;">2</span>
        l = <span style="color: #000000;">4</span>
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>l<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
&nbsp;
        ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}{3}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k, l<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
        l = <span style="color: #000000;">7</span>
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>l<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>l<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
        ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}{3}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k, l<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">2</span>:
&nbsp;
        grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
        j = <span style="color: #000000;">5</span>
        k = <span style="color: #000000;">0</span>
        l = <span style="color: #000000;">3</span>
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>l<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
        ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}{3}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k, l<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
        l = <span style="color: #000000;">6</span>
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>l<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
&nbsp;
        ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}{3}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k, l<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">4</span>:
&nbsp;
        grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
        j = <span style="color: #000000;">5</span>
        k = <span style="color: #000000;">2</span>
        l = <span style="color: #000000;">7</span>
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">6</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>l<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
        ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}{3}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k, l<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
        l = <span style="color: #000000;">0</span>
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>l<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
&nbsp;
        ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}{3}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k, l<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">if</span> i == <span style="color: #000000;">6</span>:
&nbsp;
        grilleFin<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
        j = <span style="color: #000000;">5</span>
        k = <span style="color: #000000;">0</span>
        l = <span style="color: #000000;">3</span>
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>i<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>j<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>k<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>l<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croix
&nbsp;
        ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}{3}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k, l<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
        l = <span style="color: #000000;">2</span>
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span>l<span style="color: #7a0874; font-weight: bold;">&#93;</span> = rond
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
        c<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">8</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> = croixR
&nbsp;
        ecriturePage<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;{0}{1}{2}{3}&quot;</span>.format<span style="color: #7a0874; font-weight: bold;">&#40;</span>i, j, k, l<span style="color: #7a0874; font-weight: bold;">&#41;</span>, page<span style="color: #7a0874; font-weight: bold;">&#40;</span>c<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

<p>Je ne doute pas un seul instant que ces lignes vont vous ouvrir les yeux sur le sens de la Vie et que tout le reste n&#8217;aura plus trop d&#8217;importance, mais retenez tout de même que la première personne à être concernée par les commentaires dans vos codes, c&#8217;est vous. Et que <strong>si vous ne voulez pas vous retrouver, comme moi, avec des scripts imbitables, prenez le temps de les commenter</strong> (avec des commentaires à jour, bien entendu, sinon, autant écrire en JavaScript :-p )</p>
<p>À bientôt&#8230;</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=9851&amp;md5=458d1d085d6a4d7cf7d4c9f73df9c561" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10106
title: Input number et spin buttons
uri: Input-number-et-spin-buttons
url: http://sametmax.com/input-number-et-spin-buttons/
content:
<p>Avec HTML5 on a plein de nouveaux widgets, et notamment la possibilité de définir plus de types pour les inputs. Le truc sympa par exemple, c&#8217;est qu&#8217;on peut dire :</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;input type=&quot;number&quot; /&gt;</pre></div></div>

<p>Et là, le navigateur ne vous laisse saisir que des nombres, sans avoir à coder de JS. Mieux, les machines avec claviers virtuels (téléphones, tablettes, etc) affichent généralement un clavier spécial qui permet de saisir facilement des nombres.</p>
<p>Seulement dernièrement, il y a une nouvelle tendance, certains navigateurs affichent aussi <a href="http://css-tricks.com/snippets/css/turn-off-number-input-spinners/">des boutons</a> pour incrémenter et décrémenter le champ.</p>
<p>Ça vous bousille tout votre design car <a href="https://code.google.com/p/chromium/issues/detail?id=62131">c&#8217;est inconsistant selon selon les navs</a>, et en plus ces spin buttons sont inutilisables sur mobiles car bien trop petits. </p>
<p>C&#8217;est quoi déjà les pas de la salsa ? Un pas en avant, un pas sur place, un pas en arrière, un pas sur place ?</p>
<p>Bref, j&#8217;ai d&#8217;abord essayé d&#8217;appliquer une solution CSSisante :</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">input<span style="color: #00AA00;">&#91;</span>type<span style="color: #00AA00;">=</span>number<span style="color: #00AA00;">&#93;</span><span style="color: #00AA00;">:</span><span style="color: #3333ff;">:-webkit-inner-spin-button</span><span style="color: #00AA00;">,</span>
input<span style="color: #00AA00;">&#91;</span>type<span style="color: #00AA00;">=</span>number<span style="color: #00AA00;">&#93;</span><span style="color: #00AA00;">:</span><span style="color: #3333ff;">:-webkit-outer-spin-button </span><span style="color: #00AA00;">&#123;</span>
    -webkit-appearance<span style="color: #00AA00;">:</span> <span style="color: #993333;">none</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">margin</span><span style="color: #00AA00;">:</span> <span style="color: #cc66cc;">0</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span>
&nbsp;
input<span style="color: #00AA00;">&#91;</span>type<span style="color: #00AA00;">=</span>number<span style="color: #00AA00;">&#93;</span><span style="color: #00AA00;">&#123;</span>
    -moz-appearance<span style="color: #00AA00;">:</span>textfield<span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>

<p>Mais bien entendu ça ne marche pas partout, partout. Ça serait trop facile.</p>
<p>En bon dev Web, j&#8217;ai du coup utilisé un contournement tout pourri, c&#8217;est la marque de fabrique du métier :</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;input type=&quot;tel&quot; /&gt;</pre></div></div>

<p>Le browser considère ainsi qu&#8217;il s&#8217;agit d&#8217;un numéro de téléphone. Il check donc si c&#8217;est un numéro (ou quelques signes comme &#8220;.&#8221;, &#8220;-&#8221;, etc, mais c&#8217;est acceptable) et fait apparaitre un clavier virtuel presque similaire au clavier pour type=number.</p>
<p>&#8220;On s&#8217;en contentera&#8221;, la devise de notre profession.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10106&amp;md5=2317f4d9452fa31a1c423e5002ab07d0" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10095
title: Service, factory et provider dans AngularJS
uri: Service-factory-et-provider-dans-AngularJS
url: http://sametmax.com/service-factory-et-provider-dans-angularjs/
content:
<p>AngularJS est un framework difficile à prendre en main. Pas parce qu&#8217;il est particulièrement compliqué, mais parce que ses concepts sont vraiment différents de ceux qu&#8217;on a l&#8217;habitude de rencontrer dans les frameworks habituels. Le pire, c&#8217;est quand on vient de jQuery, car Angular est un peu l&#8217;anti-jQuery et il faut littéralement désapprendre ses habitudes.</p>
<p>Généralement, les gens s&#8217;en sortent avec les contrôleurs. Ils ne mettent pas le bon code dedans, ils ne savent pas comment rendre les bouts de code indépendants et réutilisables, mais ils arrivent à en faire quelque chose. Les directives, ils n&#8217;y touchent pas, mais ils peuvent s&#8217;en passer pendant un certain temps et juste réutiliser du code trouvé sur Github.</p>
<p>Par contre le côté service/factory/provider, ça c&#8217;est un gros problème. On ne peut pas faire sans, mais peu de gens savent faire avec. En codant <a href="http://allthatcounts.net">All that counts</a>, j&#8217;ai réalisé que c&#8217;était un bon tuto à faire. Donc en avant.</p>
<p>Article long = musique, évidement.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="//www.youtube.com/embed/lMLnDuzgkjo" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>On m&#8217;a très justement demandé les prérequis pour suivre cet article : il faut avoir fait des tutos de base sur Angular et notamment comprendre l&#8217;injection de dépendance et le data binding.</p>
<h2>Que font ces trucs là ?</h2>
<p>Techniquement, un service, une factory ou un provider, dans AngularJS, <strong>ça sert à la même chose</strong>. Un service est juste une manière plus facile d&#8217;écrire une factory, qui est juste une manière plus simple d&#8217;écrire un provider.</p>
<p><strong>Les 3 servent à créer un objet Javascript ordinaire, c&#8217;est tout.</strong></p>
<p>Oui, oui, c&#8217;est vraiment tout. C&#8217;est le seul et unique but de cela. Vous allez me dire, mais alors pourquoi se faire chier à les utiliser alors qu&#8217;on peut écrire un objet à la main ? Tout simplement parce qu&#8217;ils permettent d&#8217;encapsuler cette création, l&#8217;isoler du reste du code, un problème toujours difficile en Javascript.</p>
<p>Ils sont là pour éviter de pourrir le namespace global, tout en n&#8217;utilisant pas la technique bien connu de &#8220;je met un gros conteneur avec tout dedans et tout le monde y accède&#8221;, qu&#8217;on a tendance à voir dans la plupart des projets JS. Le code est ainsi plus maintenable et testable.</p>
<p>Chaque service/factory/provider permet d&#8217;avoir un groupe de fonctionnalités séparé du reste. On peut utiliser celui-ci facilement partout ailleurs en utilisant l&#8217;injection de dépendance. <strong>Si vous ne savez pas ce que c&#8217;est, arrêtez-vous tout de suite, c&#8217;est le principe de fonctionnement de base d&#8217;Angular, il faut quitter cet article et prendre un tuto pour débutant.</strong> Revenez ensuite.</p>
<p>Dans un service/factory/provider, on va donc mettre du code métier et/ou des données de l&#8217;app, mais groupés par thème.</p>
<p>Par exemple, sur une app video, on peut en faire un qui va contenir le code pour gérer le profile utilisateur et un pour gérer la playlist.</p>
<p>On aura donc deux services/factories/providers, qui vont créer au final deux objets. Chaque objet va contenir des méthodes et des données. Pour le profile, on peut imaginer qu&#8217;il va contenir le nom d&#8217;utilisateur, son ID, et une méthode de login et de logout :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#123;</span>
    <span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Hodor&quot;</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">&quot;Id&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">7898</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">&quot;login&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// faire un truc pour se loger</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">&quot;logout&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// faire un truc pour se deco</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Pour la playlist, on peut imaginer que ça va contenir la liste des videos, la video en cours de lecture et de quoi passer à la suivante et précédente :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#123;</span>
    <span style="color: #3366CC;">&quot;name&quot;</span> <span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Super playlist&quot;</span>
    <span style="color: #3366CC;">&quot;videos&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
        <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;video 1&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;url&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;http://...&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
        <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;video 2&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;url&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;http://...&quot;</span><span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">&quot;currentVideo&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">&quot;next&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// passer à la vid suivante</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">&quot;previous&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// passer à la vid précédente</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Et c&#8217;est tout. Ce n&#8217;est ni plus ni moins que ça, des objets normaux dans lesquels ont va mettre nos données et nos méthodes. <strong>Ce qui est &#8220;special&#8221;, c&#8217;est comment ils sont créés et utilisés.</strong> Et c&#8217;est ça qu&#8217;on va voir tout de suite.</p>
<h2>Créer un objet via un service/factory/provider</h2>
<p>Voyons le plus compliqué d&#8217;abord : le provider. Les deux autres ne sont que des raccourcis pour écrire un provider, de toute façon.</p>
<p>Le rôle du provider, c&#8217;est de créer et mettre à disposition un objet. C&#8217;est tout. Il n&#8217;y a rien de plus. Je répète, ça ne sert qu&#8217;à ça. &#8220;provider&#8221;, ça veut dire &#8220;fournisseur&#8221; en anglais. Et c&#8217;est ce que ça fait : ça fournit un objet. Supposons que vous avez déjà créé une app &#8220;monApp&#8221;. Écrire un provider pour créer l&#8217;objet &#8220;profile&#8221; ressemble à ça :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// On appelle notre objet qui sera créé &quot;profile&quot;. Ce qui signifie que l'on</span>
<span style="color: #006600; font-style: italic;">// pourra ensuite utiliser le nom &quot;profile&quot; pour annoncer quand</span>
<span style="color: #006600; font-style: italic;">// on souhaite utiliser l'objet issu de ce provider.</span>
monApp.<span style="color: #660066;">provider</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;profile&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// Un provider, au final, c'est juste une fonction anonyme qu'on relie</span>
    <span style="color: #006600; font-style: italic;">// à un nom :)</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// Cette fonction DOIT avoir une méthode nommé &quot;$get&quot; attachée à son &quot;this&quot;</span>
    <span style="color: #000066; font-weight: bold;">this</span>.$get <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// Et la méthode &quot;$get&quot; DOIT retourner l'objet qu'on veut créer.</span>
        <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Anonymous&quot;</span><span style="color: #339933;">,</span>
            <span style="color: #3366CC;">&quot;Id&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span>
            <span style="color: #3366CC;">&quot;login&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
                <span style="color: #006600; font-style: italic;">// faire un truc pour se loger</span>
            <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #3366CC;">&quot;logout&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
                <span style="color: #006600; font-style: italic;">// faire un truc pour se deco</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>C&#8217;est tout. Je vous jure que c&#8217;est tout. C&#8217;est juste une boîte qu&#8217;Angular va prendre, et appeler la méthode <code>$get</code> pour obtenir un objet. En plus, un seul objet, car la méthode ne sera appelée qu&#8217;une fois : l&#8217;objet sera un singleton.</p>
<p>Plus tard dans le code, quand vous ferez un controller :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">mymonAppApp.<span style="color: #660066;">controller</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'UnControlleurCommeUnAutre'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>$scope<span style="color: #339933;">,</span> profile<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    $scope.<span style="color: #660066;">profile</span> <span style="color: #339933;">=</span> profile<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Vous utiliserez <code>profile</code> en paramètre, il va donc être injecté automatiquement. C&#8217;est tout le principe d&#8217;angular, des tas de boîtes qui déclarent quelles autres boîtes elles utilisent via l&#8217;injection de dépendance.</p>
<p>Ici, l&#8217;objet va être créé (si ce n&#8217;est pas déjà fait ailleurs), et c&#8217;est tout. Le boulot d&#8217;un controller, c&#8217;est essentiellement de mettre des objets issus des providers dans le scope pour que le HTML puisse les utiliser. Je vous promet, c&#8217;est 90% des use cases.</p>
<p>Votre objet sera le conteneur que l&#8217;on va manipuler pour changer le nom du profile, se logger, etc. C&#8217;est juste une boîte qui rend un service. D&#8217;ailleurs on appelle souvent les objets issus des providers des &#8220;services&#8221;.</p>
<p>Utiliser des providers évite de créer tout une logique de classes, de gérer des namespaces, des instanciations : on est obligé de faire de l&#8217;encapsulation et de la composition. Ca rend le code (javascript) plus propre et plus testable, bien décomposé et découplé. <strong>Avoir un code propre est le but principal des providers, ils ne fournissent rien comme fonctionnalités qu&#8217;on ne puisse faire autrement</strong>.</p>
<p>Maintenant voyons ce qu&#8217;est une factory. En fait, c&#8217;est juste un raccourci pour écrire un provider :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">monApp.<span style="color: #660066;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'profile'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Anonymous&quot;</span><span style="color: #339933;">,</span>
        <span style="color: #3366CC;">&quot;Id&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span>
        <span style="color: #3366CC;">&quot;login&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            <span style="color: #006600; font-style: italic;">// faire un truc pour se loger</span>
        <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
        <span style="color: #3366CC;">&quot;logout&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            <span style="color: #006600; font-style: italic;">// faire un truc pour se deco</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Ça fait exactement la même chose, et on l&#8217;utilise exactement pareil. C&#8217;est juste plus court. Pas de méthode <code>$get</code> à écrire, on retourne l&#8217;objet cash pistache.</p>
<p>Pourquoi on utilise un provider alors ? Parce que c&#8217;est plus pratique à configurer, comme on le verra plus bas. Mais la factory est suffisante la plupart du temps. Ce qui est marrant, c&#8217;est qu&#8217;en terme informatique, un provider est un design pattern &#8220;factory&#8221;, ce qui m&#8217;a vachement rendu confus au début&#8230;</p>
<p>Et le service alors ? C&#8217;est une syntaxe alternative :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">monApp.<span style="color: #660066;">service</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'profile'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #000066;">name</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;Anonymous&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">id</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">;</span>
    <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">login</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// faire un truc pour se loger</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">logout</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// faire un truc pour se deco</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>La fonction va être utilisée directement (avec <code>new</code>) pour créer l&#8217;objet, donc pas besoin de <code>return</code> : on attache tout à <code>this</code>. Mais le résultat est strictement le même. Le choix entre une factory et un service est vraiment une question de goût. Personnellement je vous conseille d&#8217;utiliser des factories car ça vous évite le casse-tête de la portée de <code>this</code>, grande cause d&#8217;erreurs en JS.</p>
<h2>Dépendances et injections</h2>
<p>Souvenez-vous qu&#8217;on peut faire ça :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">mymonAppApp.<span style="color: #660066;">controller</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'UnControlleurCommeUnAutre'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>$scope<span style="color: #339933;">,</span> profile<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    $scope.<span style="color: #660066;">profile</span> <span style="color: #339933;">=</span> profile<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Pour dire &#8220;mon controller dépend de profile, donc s&#8217;il te plait Angular, crée l&#8217;objet et passe le moi&#8221;.</p>
<p>Et bien ça marche aussi entre les providers/factories/services. Par exemple, si je fais un provider pour ma playlist, mais que la playlist dépend du profile :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">monApp.<span style="color: #660066;">provider</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;playlist&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// En utilisant le nom de l'autre provider ici, je demande à ce qu'il</span>
    <span style="color: #006600; font-style: italic;">// soit injecté ici, et donc disponible ici. Je dis &quot;ce provider</span>
    <span style="color: #006600; font-style: italic;">// est dépendant de l'objet fournit par cet autre provider.&quot;</span>
    <span style="color: #000066; font-weight: bold;">this</span>.$get <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>profile<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
        <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #006600; font-style: italic;">// Et du coup je peux accéder aux attributs de l'objet.</span>
            <span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Playlist de &quot;</span> <span style="color: #339933;">+</span> profile.<span style="color: #000066;">name</span>
            <span style="color: #3366CC;">&quot;videos&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
            <span style="color: #3366CC;">&quot;currentVideo&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span>
            <span style="color: #3366CC;">&quot;next&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
                <span style="color: #006600; font-style: italic;">// passer à la vid suivante</span>
            <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #3366CC;">&quot;previous&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
                <span style="color: #006600; font-style: italic;">// passer à la vid précédente</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Si je le faisais avec une factory, se serait pareil, mais en plus simple :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// l'injection de dépendance se fait au niveau de la fonction anonyme</span>
<span style="color: #006600; font-style: italic;">// car il n'y a pas de méthode &quot;$get&quot;</span>
monApp.<span style="color: #660066;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;playlist&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>profile<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Playlist de &quot;</span> <span style="color: #339933;">+</span> profile.<span style="color: #000066;">name</span>
        <span style="color: #3366CC;">&quot;videos&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
        <span style="color: #3366CC;">&quot;currentVideo&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span>
        <span style="color: #3366CC;">&quot;next&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            <span style="color: #006600; font-style: italic;">// passer à la vid suivante</span>
        <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
        <span style="color: #3366CC;">&quot;previous&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            <span style="color: #006600; font-style: italic;">// passer à la vid précédente</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h2>L&#8217;interêt des providers</h2>
<p>L&#8217;interêt principal d&#8217;utiliser un provider plutôt qu&#8217;une factory, c&#8217;est qu&#8217;on peut le rendre configurable.</p>
<p>Par exemple, je veux que ma playlist ne soit jamais vide, alors si elle l&#8217;en, on met deux vidéos par défaut dedans :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">monApp.<span style="color: #660066;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;playlist&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>profile<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// je ne retourne pas l'objet tout de suite, je vais le modifier</span>
    <span style="color: #003366; font-weight: bold;">var</span> playlist <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Playlist de &quot;</span> <span style="color: #339933;">+</span> profile.<span style="color: #000066;">name</span>
        <span style="color: #3366CC;">&quot;videos&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
        <span style="color: #3366CC;">&quot;currentVideo&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span>
        <span style="color: #3366CC;">&quot;next&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            <span style="color: #006600; font-style: italic;">// passer à la vid suivante</span>
        <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
        <span style="color: #3366CC;">&quot;previous&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            <span style="color: #006600; font-style: italic;">// passer à la vid précédente</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// hop, je m'assure que la playlist n'est jamais vide en modifiant</span>
    <span style="color: #006600; font-style: italic;">// l'objet</span>
    <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>playlist.<span style="color: #660066;">videos</span>.<span style="color: #660066;">length</span> <span style="color: #339933;">===</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        playlist.<span style="color: #660066;">videos</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;video 1&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;url&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;http://...&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;video 2&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;url&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;http://...&quot;</span><span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#93;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// ne pas oublier de retourner l'objet à la fin quand même :)</span>
    <span style="color: #000066; font-weight: bold;">return</span> playlist<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Tout ça sera largement suffisant dans la plupart des cas. Mais dans le rare cas où je veux faire une lib réutilisable, je veux que ces vidéos par défaut soient configurables. Comment alors permettre que l&#8217;utilisateur de ma lib les choisisse ?</p>
<p>En utilisant un provider :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">monApp.<span style="color: #660066;">provider</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;playlist&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// On déclare des données attachée sur le provider. PAS sur l'objet que</span>
    <span style="color: #006600; font-style: italic;">// le provider va créer, attention. Sur le provider lui-même.</span>
    <span style="color: #006600; font-style: italic;">// Le provider, je le rappelle, c'est cette fonction anonyme qui retourne</span>
    <span style="color: #006600; font-style: italic;">// un objet via sa méthode &quot;$get&quot; (oui, les fonctions sont des objets</span>
    <span style="color: #006600; font-style: italic;">// en JS, et peuvent avoir des méthodes. Ce langage est très clair.)</span>
    <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">defaultVideos</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;video 1&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;url&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;http://...&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;video 2&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;url&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;http://...&quot;</span><span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#93;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// ensuite je fais ma méthode &quot;$get&quot; qui va retourner l'objet voulu,</span>
    <span style="color: #006600; font-style: italic;">// comme d'hab</span>
    <span style="color: #000066; font-weight: bold;">this</span>.$get <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>profile<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
        <span style="color: #003366; font-weight: bold;">var</span> playlist <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Playlist de &quot;</span> <span style="color: #339933;">+</span> profile.<span style="color: #000066;">name</span>
            <span style="color: #3366CC;">&quot;videos&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
            <span style="color: #3366CC;">&quot;currentVideo&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span>
            <span style="color: #3366CC;">&quot;next&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
                <span style="color: #006600; font-style: italic;">// passer à la vid suivante</span>
            <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #3366CC;">&quot;previous&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
                <span style="color: #006600; font-style: italic;">// passer à la vid précédente</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// Au moment de la création de l'objet, j'utilise les données</span>
        <span style="color: #006600; font-style: italic;">// attachées au provider pour fournir la valeur par défaut.</span>
        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>playlist.<span style="color: #660066;">videos</span>.<span style="color: #660066;">length</span> <span style="color: #339933;">===</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            playlist.<span style="color: #660066;">videos</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">defaultVideos</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #000066; font-weight: bold;">return</span> playlist<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Jusqu&#8217;ici, vous allez me dire, mais quelle est la différence avec le précédent ? Et bien il se trouve qu&#8217;Angular met à votre disposition automatiquement <code>playlist</code>, <strong>mais également <code>playlistProvider</code></strong>, une référence sur le provider qui va créer l&#8217;objet <code>playlist</code>.</p>
<p>ATTENTION : quand vous déclarez ici &#8220;playlist&#8221;, &#8220;playlist&#8221; est le nom de l&#8217;objet créé par le provider. Angular, lui, va automagiquement attacher le nom &#8220;playlistProvider&#8221; au provider qui a créé l&#8217;objet. Vous n&#8217;avez rien à faire pour cela, il va automatiquement s&#8217;appeler &#8220;nomDeVotreObjetProvider&#8221; et sera mis à votre disposition.</p>
<p>Du coup :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// On peut utiliser &quot;config&quot; pour lancer du code avant la création des objets</span>
<span style="color: #006600; font-style: italic;">// par les providers. Tout le code dans des blocs &quot;config&quot; est toujours lancé en premier,</span>
<span style="color: #006600; font-style: italic;">// avant tous les providers/factories/services de cette app.</span>
monApp.<span style="color: #660066;">config</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>playlistProvider<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">// ici l'utilisateur de votre lib a accès au provider avant la création de</span>
    <span style="color: #006600; font-style: italic;">// l'objet, et à donc le loisir de changer les valeurs par défaut</span>
    playlistProvider.<span style="color: #660066;">defaultVideos</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Autre video&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;url&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;http://...&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#93;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Ce n&#8217;est pas un cas courant, et la plupart du temps, utiliser une factory marchera très bien.</p>
<h2>Et tout ça, je m&#8217;en sers pour quoi ?</h2>
<p>On met dans les providers/services/factories, tout le code qui n&#8217;est pas lié à la navigation ou à la manipulation de DOM. Bref, tout le code de la logique de votre app. Le code qui n&#8217;est pas lié au Web. Un profile n&#8217;a rien à avoir avec le Web. Une playlist n&#8217;a rien à voir avec le Web. Mais il faut un code pour les gérer, et des variables vont devoir êtres mises quelque part.</p>
<p>Généralement, ces providers/services/factories sont utilisés :</p>
<ul>
<li>Par un controller.</li>
<li>Par une directive.</li>
<li>Par d&#8217;autres providers/services/factories.</li>
</ul>
<p>Mais aussi, directement dans le HTML.</p>
<p>En effet, quand vous allez faire ça :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// le boulot du controller, c'est essentiellement d'attacher les bons</span>
<span style="color: #006600; font-style: italic;">// services au scope, je vous dis !</span>
mymonAppApp.<span style="color: #660066;">controller</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'VideoCtrl'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>$scope<span style="color: #339933;">,</span> playlist<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    $scope.<span style="color: #660066;">playlist</span> <span style="color: #339933;">=</span> playlist<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Vous allez ensuite pouvoir déclarer votre controller dans votre HTML. Dans un<br />
bloc de HTML couvert par un controller, vous avez accès à toutes les attributs<br />
du scope, donc à votre service &#8220;playlist&#8221;. Et du coup, paf, à tout son code :</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;div ng-controller=&quot;VideoCtrl&quot;&gt;
    ...
    &lt;p&gt;Playlist :&lt;/p&gt;
    &lt;ul&gt;
       &lt;li ng-repeat=&quot;vid for playlist.videos&quot;&gt;{{ vid.title }}&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p&gt;
    &lt;button ng-click=&quot;playlist.next()&quot;&gt;Next&lt;/button&gt;
    &lt;/p&gt;
&lt;/div&gt;</pre></div></div>

<p>Et c&#8217;est ça la beauté d&#8217;Angular : tout est bien séparé, et bien rangé. Votre code métier dans les providers, votre code d&#8217;interface dans le HTML, votre liaison entre le HTML et les providers à travers les controllers&#8230; Enfin du code JS qui ne ressemble pas à des spaghetti trop cuites par un enfant de 6 ans scatoman.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10095&amp;md5=65b26bfcd6e373e21a6cec349ebd19ec" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=8930
title: La martingale à la roulette en Python
uri: La-martingale-à-la-roulette-en-Python
url: http://sametmax.com/la-martingale-a-la-roulette-en-python/
content:
<p>Sur internet, c&#8217;est bien connu, on peut perdre du poids, trouver une fille facile près de chez soit, et gagner beaucoup d&#8217;argent rapidement et sans risque.</p>
<p>Une de ces techniques qu&#8217;on vous vend est la fameuse <a href="https://fr.wikipedia.org/wiki/Martingale">martingale</a>, mais appliquée aux casinos en ligne. Outre le fait que vous ne pouvez pas vous fier à un serveur distant pour ne pas tricher, les jeux de hasard sont de toute façon toujours en faveur de la banque.</p>
<p>Nous allons nous intéresser à la martingale la plus simple, celle appliquée à la roulette. Quand j&#8217;étais à l&#8217;université, entre deux parties de Munchkins, nous cherchions un moyen de faire du pognon. Et on a failli s&#8217;organiser une session au casino de notre ville pour appliquer la technique suivante :</p>
<ol>
<li>Jouer une petite mise sur une couleur;</li>
<li>Si on perd, revenir en 1 mais avec une mise équivalent au double de ses pertes.</li>
<li>Si on gagne, encaisser, retourner en 1, mais avec la toute petite mise de départ.</li>
</ol>
<p>L&#8217;idée était que si tu perdais, tu doublais ta mise jusqu&#8217;à ce que ça te rembourse tes pertes. Sinon, tu gagnes, et tu empoches. Seulement voilà, la roulette à la couleur, ce n&#8217;est pas 50% de chance, car il y a le zéro, qui n&#8217;est ni rouge, ni noir.</p>
<p>Comme on était des petits cons nuls en probas, mais des petits cons programmeurs, on avait simulé le jeu avec un programme Python, juste au cas où :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">random</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Une roulette (en France), c'est un 0 vert, et des numéros de</span>
<span style="color: #808080; font-style: italic;"># 1 à 36 alternativement rouges et noirs.</span>
roulette = <span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;green&quot;</span><span style="color: black;">&#93;</span>
roulette.<span style="color: black;">extend</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;red&quot;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">37</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
roulette.<span style="color: black;">extend</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;black&quot;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">37</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Regardons ce que donne la proba de choper le rouge avec le générateur</span>
<span style="color: #808080; font-style: italic;"># de nombre pseudo-aléatoires de Python.</span>
count = <span style="color: #ff4500;">0</span>
<span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">100000</span><span style="color: black;">&#41;</span>:
    count += <span style="color: #dc143c;">random</span>.<span style="color: black;">choice</span><span style="color: black;">&#40;</span>roulette<span style="color: black;">&#41;</span> == <span style="color: #483d8b;">&quot;red&quot;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Average chance of picking red: %s&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>count / <span style="color: #ff4500;">100000</span> <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Time to play ! Insérer ici la musique d'un film américain ambiance Las Vegas.</span>
<span style="color: #ff7700;font-weight:bold;">def</span> play<span style="color: black;">&#40;</span>rounds, budget=<span style="color: #ff4500;">10000</span>, color=<span style="color: #483d8b;">&quot;red&quot;</span>, start_bet=<span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>:
    initial_budget = budget
    max_bet = start_bet
    bet = start_bet
    loss = <span style="color: #ff4500;">0</span>
    <span style="color: #808080; font-style: italic;"># On limite le nombre de paris</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> <span style="color: #008000;">round</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>rounds<span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># On mise</span>
        budget -= bet
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">random</span>.<span style="color: black;">choice</span><span style="color: black;">&#40;</span>roulette<span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= color:
            <span style="color: #808080; font-style: italic;"># On a perdu, on mise le double de ses pertes.</span>
            loss += bet
            bet = loss <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">2</span>
            <span style="color: #808080; font-style: italic;"># Si jamais c'est plus que notre pognon, on se couche et on chiale.</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> bet <span style="color: #66cc66;">&gt;</span> budget:
                <span style="color: #ff7700;font-weight:bold;">break</span>
            <span style="color: #808080; font-style: italic;"># On garde une trace de notre mise max pour évaluer le budget max.</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: black;">&#40;</span>max_bet <span style="color: #66cc66;">&lt;</span> bet<span style="color: black;">&#41;</span>:
                max_bet = bet
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #808080; font-style: italic;"># Si on gagne, on récupère notre mise et le gain, et on recommence.</span>
            budget += bet <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">2</span>
            bet = start_bet
            loss = <span style="color: #ff4500;">0</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> budget - initial_budget, max_bet
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;10 rounds | balance: %s (max=%s)&quot;</span> <span style="color: #66cc66;">%</span> play<span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;100 rounds | balance: %s (max=%s)&quot;</span> <span style="color: #66cc66;">%</span> play<span style="color: black;">&#40;</span><span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;1000 rounds | balance: %s (max=%s)&quot;</span> <span style="color: #66cc66;">%</span> play<span style="color: black;">&#40;</span><span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;10000 rounds | balance: %s (max=%s)&quot;</span> <span style="color: #66cc66;">%</span> play<span style="color: black;">&#40;</span><span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Là le budget est large, mais nous on avait 800 euros&#8230; Bref, le résultat :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ python3 roulette.py
Average chance of picking <span style="color: #c20cb9; font-weight: bold;">red</span>: <span style="color: #000000;">48.78</span>
<span style="color: #000000;">10</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #000000;">10</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">90</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">100</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #000000;">1835</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">2430</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">1000</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-3585</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">2430</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">10000</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-3495</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">2430</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
$ python3 roulette.py
Average chance of picking <span style="color: #c20cb9; font-weight: bold;">red</span>: <span style="color: #000000;">48.67</span>
<span style="color: #000000;">10</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #000000;">15</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">30</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">100</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-3620</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">2430</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">1000</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-3180</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">2430</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">10000</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-4670</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">7290</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
$ python3 roulette.py
Average chance of picking <span style="color: #c20cb9; font-weight: bold;">red</span>: <span style="color: #000000;">48.507</span>
<span style="color: #000000;">10</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #000000;">45</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">90</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">100</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #000000;">1800</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">2430</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">1000</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-3370</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">2430</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">10000</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-3455</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">2430</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
$ python3 roulette.py
Average chance of picking <span style="color: #c20cb9; font-weight: bold;">red</span>: <span style="color: #000000;">48.4</span>
<span style="color: #000000;">10</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #000000;">50</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">30</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">100</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #000000;">1940</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">2430</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">1000</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #000000;">1435</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">7290</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">10000</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-970</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">7290</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
$ python3 roulette.py
Average chance of picking <span style="color: #c20cb9; font-weight: bold;">red</span>: <span style="color: #000000;">48.853</span>
<span style="color: #000000;">10</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-115</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">270</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">100</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-3535</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">2430</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">1000</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-2100</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">7290</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">10000</span> rounds <span style="color: #000000; font-weight: bold;">|</span> balance: <span style="color: #660033;">-2120</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">max</span>=<span style="color: #000000;">7290</span><span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

<p>C&#8217;est pas vraiment la fortune assurée et en prime, dès qu&#8217;on veut jouer un peu sérieusement, il faut un budget max énorme. Mais surtout, il y a une grosse contrainte de temps, puisque 10 rounds c&#8217;est une bonne heure de jeu dans un casino réel.</p>
<hr />
<p><a href="https://github.com/sametmax/codes-des-articles/blob/master/2014/mai/roulette.py">Télécharger le code de l&#8217;article.</a></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=8930&amp;md5=b349d541cbe65d5baf601ca4c71624b7" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10194
title: Cet article est trop gay
uri: Cet-article-est-trop-gay
url: http://sametmax.com/cet-article-est-trop-gay/
content:
<p>Je fréquente plus de LBG que la moyenne. Encore plus cette année, puisque deux de mes colocs ne sont pas hétéros, donc forcément avec les amis d&#8217;amis, ça charge mes statistiques.</p>
<p>Du coup, j&#8217;ai l&#8217;occasion de vivre du gay quotidien, et pas juste en soirée, fiesta ou autre événement. Bref, en mode caleçon, bière, pizza, film, sport en plein air et achat de pomme de terre.</p>
<p>Comme toujours, les minorités se tapent leurs lots de stéréotypes, que je peux confronter à mon petit échantillon non représentatif.</p>
<h2>Plus d&#8217;activité sexuelle</h2>
<p>C&#8217;est biaisé. Ce n&#8217;est pas vrai pour la majorité. </p>
<div id="attachment_10200" class="wp-caption aligncenter" style="width: 504px"><a href="media/14534f0e.SexPartnersAll.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/SexPartnersAll.png"><img src="media/14534f0e.SexPartnersAll.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/SexPartnersAll.png" alt="Répartition du nombre de personnes par nombre de partenaires sexuels et orientation sexuelle" title="Piqué à l&#039;article linké plus haut" width="494" height="432" class="size-full wp-image-10200" /></a><p class="wp-caption-text">Piqué à l&#039;article linké plus haut</p></div>
<p>Par contre, c&#8217;est vrai que dans mon entourage,  <strong>proportionnellement</strong>, un plus gros pourcentage de gays ont une vie sexuelle très active que parmi les hétéros. Je ne vais pas m&#8217;aventurer sur une explication du pourquoi, mais c&#8217;est un constat, que ce soit pour les filles et les mecs. D&#8217;ailleurs, ce sont les plus à l&#8217;aise pour en parler, même si généralement chez nous, ça parle de cul de toute façon et que j&#8217;ai des amis franchement délurés (sado-masos, partouseurs, stripteasers, etc). Finalement je suis super classique comme mec comparé à mes fréquentations.</p>
<h2>Les homos essayent de convertir les hétéros</h2>
<p>Non, mais par contre ils les draguent. Et certains font régulièrement des tentatives malgré un &#8220;non&#8221; explicite précédent. Ce n&#8217;est pas méchant, c&#8217;est parfois relou, mais envoyer chier un boulet collant est de bonne guerre pour tous les sexes. En prime, ça vous permet de vous mettre à la place des nanas qui se font draguer par des boulets. </p>
<p>Dans tous les cas, ils essayent, car parfois ça marche. La théorie d&#8217;un de mes potes c&#8217;est &#8220;un hétéro bourré est un hétéro suçable&#8221;. Il a par ailleurs rencontré son petit ami actuel en le pompant dans ma cuisine lors d&#8217;une soirée, ce qui fait qu&#8217;on a pas pu accéder aux petits fours pendant quelques temps.</p>
<div id="attachment_10198" class="wp-caption aligncenter" style="width: 385px"><a href="media/faafd483.88098671.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/88098671.png"><img src="media/faafd483.88098671.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/88098671.png" alt="Dessin de batman enculant Robin" title="Dans certains comics, Robin à 10 ans..." width="375" height="250" class="size-full wp-image-10198" /></a><p class="wp-caption-text">Dans certains comics, Robin à 10 ans...</p></div>
<p>Même parmi ceux qui ne tentent pas, ils en a qui sont juste naturellement très tactiles, et si on est pas à l&#8217;aise avec le fait de faire calin-calin avec un gayzounours velus (les miens sont italienne et espagnol&#8230;), ça peut mettre mal à l&#8217;aise. Ca n&#8217;a rien à voir avec le côté homo/hétéro, c&#8217;est chiant y compris avec des straights.</p>
<p>Ce qui est important c&#8217;est d&#8217;être très simple et direct : oui ou non. Ici est la limite. Pour certain, la limite c&#8217;est &#8220;tu m&#8217;approches pas à moins de 2 m&#8221;, pour d&#8217;autre, c&#8217;est &#8220;ok pour le bisou sur la joue&#8221;. On s&#8217;en fout, tout est acceptable. Mais il faut le dire, et ne pas ruminer dans son coin, c&#8217;est idiot. Votre virilité/féminité n&#8217;est pas en jeu, votre confort, oui. </p>
<p>Qu&#8217;on se le dise, vous ne tomberez pas sur un gang bang surprise, et comme tout le monde, il y a les introvertis et les extravertis, donc ne pas partir sur une idée reçue. Les filles sont moins rentre dedans que les garçons en milieu mixte, par contre en boîte, tout est permis. C&#8217;est un peu le but.</p>
<p>On me signale dans la gayreillette : &#8220;nan mais moi je fais pas ça&#8221;. C&#8217;est vrai. Lui il fait pas ça. Vous voulez dire que les gays peuvent être des gens ordinnaires et classiques ? Noooooon ? Surpris ?</p>
<h2>Les gays ont de l&#8217;argent</h2>
<p>Encore une fois pas forcément, mais la majorité que je connais vivent bien. Genre, bien, bien. Mon pote qui lit l&#8217;article est en train de me dire &#8220;bon, ben tu me fileras mon chèque de gay alors, je l&#8217;attends toujours&#8221;. Mais il est de mauvaise foi, il vit avec moi dans un 200m2 avec 1000m2 de jardin. A 10m du tram, en ville. Y a pire.</p>
<p>En même temps, quand on a pas d&#8217;enfant à 30 ans, c&#8217;est généralement plus facile. Après j&#8217;ai une amie lesbienne qui galère tout le temps, elle est prof et elle roule à vélo, faut pas déconner, il n&#8217;y a pas un fond de financement secret des gays dont la mission est de les maintenir dans un état d&#8217;opulence. C&#8217;est pas con comme idée ça, je vais breveter.</p>
<div id="attachment_10195" class="wp-caption aligncenter" style="width: 510px"><a href="media/8b80d41b.zombieland_gif.gif" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/zombieland_gif.gif"><img src="media/8b80d41b.zombieland_gif.gif" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/zombieland_gif.gif" alt="Gir animé du film zombiland montrant un personnage essuyant ses larmes avec des billets" title="MRW I&#039;m single with no children" width="500" height="236" class="size-full wp-image-10195" /></a><p class="wp-caption-text">MRW I&#039;m single with no children</p></div>
<h2>Les gays sont sociables</h2>
<p>J&#8217;ai envie de dire, pas plus que les autres. Mais en réfléchissant deux secondes, j&#8217;ai un couple qui est toujours fourré en soirée, un lesbienne qui est la fille la plus caline du monde, deux colocs qui font des soirées toutes les semaines, occasionnellement à 200 invités&#8230; Alors je vais rien dire&#8230; C&#8217;est peut être une coincidence&#8230;</p>
<div id="attachment_10204" class="wp-caption aligncenter" style="width: 522px"><a href="media/61e6bcc1.20111207002912S.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/20111207002912S.jpg"><img src="media/61e6bcc1.20111207002912S.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/20111207002912S.jpg" alt="Dessin de bisounours mangeant un humain" title="Ce qu&#039;on fait vraiment dans les soirées à la maison" width="512" height="384" class="size-full wp-image-10204" /></a><p class="wp-caption-text">Ce qu&#039;on fait vraiment dans les soirées à la maison</p></div>
<h2>Les homosexuels sont des folles</h2>
<p>Je n&#8217;en ai rencontré qu&#8217;un dans ma vie, donc c&#8217;est plutôt rare. Oui il y a des trais parfois particuliers, mais pas nécessairement le côté éphéminé pour les mecs ou camioneur pour les nanas. J&#8217;ai un très mauvais gaydar donc je ne saurais pas vous faire une liste, cela dit. Un gay n&#8217;est pas forcément artiste, honête, joyeux, fêtard, ou autre. Par contre, je note que tous ont une forme de sensibilité plus assumée. Bon, je note, je note, sur ceux que je connais, hein. Je note ce que je peux noter.</p>
<p>Le truc c&#8217;est que quand un gay est discret, vous ne saurez juste jamais qu&#8217;il l&#8217;est. C&#8217;est pas écrit sur sa tronche. Il y a les timides, ceux qui ne s&#8217;assument pas, ceux qui font comme tout le monde, etc. </p>
<p>Comprenez en tout cas, que la gay pride, c&#8217;est juste un événement festif, ce n&#8217;est pas représentatif d&#8217;un mode de vie. La fistinière non plus. Ca ne veut pas dire que ça ne peut pas l&#8217;être, évidement, mais perso notre dernière activité mixte, c&#8217;était une partie de magic bi VS lesbienne vs hétéro. Pas un défilé de cuir.</p>
<div id="attachment_10205" class="wp-caption aligncenter" style="width: 580px"><a href="media/0f16ecc9.the-new-normal.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/the-new-normal.jpg"><img src="media/0f16ecc9.the-new-normal.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/the-new-normal.jpg" alt="Affiche de la série &quot;the new normal&quot;" title="Je trouve génial que quand les médias essayent de rendre quelque chose ordinaire, ils le rendent tout de suite caricatural" width="570" height="300" class="size-full wp-image-10205" /></a><p class="wp-caption-text">Je trouve génial que quand les médias essayent de rendre quelque chose ordinaire, ils le rendent tout de suite caricatural</p></div>
<h2>Les bis aiment autant les mecs que les filles</h2>
<p>Généralement, bien qu&#8217;ils puissent avoir des aventures avec les deux, il y a toujours un sexe qui prédomine. Il n&#8217;y a pas de régle, car il y autant de degré de biitude qu&#8217;il y a de bis, mais quand on aime la vanille et le chocolat, on a souvent une préférence pour un parfum, particulièrement pour les relations à long terme. Ce n&#8217;est pas forcément ce qu&#8217;ils vous diront, mais ça se voit dans les stats de dating, comme ont dit dans les milieux autorisés.</p>
<p>Si on essaye dresser un profile type, on va se planter dans tous les cas. On a aussi les asexuels, les asexués, les trans opérés, les trans non opérés, et je soupçonne un de mes amis d&#8217;aimer beaucoup son chien&#8230;</p>
<h2>Ils / elles ont envie de me baiser</h2>
<p>C&#8217;est possible. Moi y a plein de nana que j&#8217;ai envie de baiser. </p>
<div id="attachment_10206" class="wp-caption aligncenter" style="width: 600px"><a href="media/34d77f58.humour0043.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/humour0043.jpg"><img src="media/34d77f58.humour0043.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/humour0043.jpg" alt="Fille à gros seins et godzilla" title="Moi non plus" width="590" height="745" class="size-full wp-image-10206" /></a><p class="wp-caption-text">Moi non plus</p></div>
<p>L&#8217;inverse est aussi tout à fait courant : aimer quelqu&#8217;un sans avoir envie de le baiser. Wow. Shoker.</p>
<h2>Ils / elles ont le sida</h2>
<p>Meh.</p>
<div id="attachment_10196" class="wp-caption aligncenter" style="width: 282px"><a href="media/b97a8bd8.Sida-c-est-plus-fort-que-toi.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/Sida-c-est-plus-fort-que-toi.jpg"><img src="media/b97a8bd8.Sida-c-est-plus-fort-que-toi.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/Sida-c-est-plus-fort-que-toi.jpg" alt="Le logo SEGA parodié en SIDA" title="Le sida, communément représenté par une boule pleine de pique qui court et ramasse des anneaux. Heu..." width="272" height="133" class="size-full wp-image-10196" /></a><p class="wp-caption-text">Le sida, communément représenté par une boule pleine de pique qui court et ramasse des anneaux. Heu...</p></div>
<h2>Ce sont des drogués</h2>
<p>Beaucoup de mes amis consomment au moins une drogue (au minimum clope ou alcool), parfois 2/3 voir 4. Personnellement je ne fume pas et bois peu. Mais il n&#8217;y aucune différence entre les homos et les hétéros. C&#8217;est tout pareil.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/kJ9C1VfuWok" frameborder="0" scrolling="no" class="iframe-class"></iframe>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10194&amp;md5=3941008fcf47457c799581d4109b8ec2" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10217
title: Quelle est la différence entre un bug et un virus ?
uri: Quelle-est-la-différence-entre-un-bug-et-un-virus
url: http://sametmax.com/quelle-est-la-difference-entre-un-bug-et-un-virus/
content:
<p>Article ultra débutant, mais hey, encore un truc très peu expliqué sur Internet pour l&#8217;excuse bidon que &#8220;c&#8217;est évident&#8221;.</p>
<h2>Un virus, c&#8217;est un programme malveillant</h2>
<p>Il a été conçu dans le but de nuire en utilisant la machine qu&#8217;il infecte. C&#8217;est donc un logiciel en plus sur votre machine, et qui pose des problèmes. Attention, un virus ne va pas forcément ralentir votre ordinateur ou le faire planter. Les virus modernes vont justement, en général, essayer de garder votre ordinateur en bon état (parfois en désinstallant d&#8217;autres virus !), afin d&#8217;avoir confortablement l&#8217;usage de votre machine.</p>
<p>Le virus entre dans la catégorie des programmes dits &#8220;malwares&#8221;, c&#8217;est à dire des logiciels nuisibles. Mais il n&#8217;est pas le seul, il y en a un paquet d&#8217;autres qui <strong>ne sont pas des virus</strong> : spywares (logiciels qui vous espionnent), adwares (logiciels qui vous affichent de la publicité tout le temps), ransomwares (logiciels qui prennent vos données en otage). Ce sont tous des malwares, c&#8217;est à dire des programmes nuisibles, mais pas des virus.</p>
<p>Généralement un virus a pour but de prendre le contrôle de votre machine, soit pour vous voler des données, soit pour se propager, soit pour l&#8217;utiliser comme machine zombie. Dans ce dernier cas, votre machine servira à un pirate qui pourra l&#8217;utiliser pour attaquer d&#8217;autres machines, envoyer du spam avec ou simplement vendre sa puissance sur Internet.</p>
<p><strong>Ne pensez jamais que votre machine n&#8217;est &#8220;pas intéressante&#8221; pour les pirates sous prétexte que vous ne faites rien de particulier avec votre ordinateur.</strong> À partir du moment où votre ordinateur est connecté à Internet, il est intéressant, il peut rapporter de l&#8217;argent de bien des façons à un attaquant, même sans que l&#8217;argent vienne (directement) de vous.</p>
<p>Pour se protéger des virus, il faut avoir TOUS ses logiciels à jour, mais aussi éviter d&#8217;utiliser des systèmes trop sensibles aux virus. Si vous devez utiliser l&#8217;un d&#8217;entre eux (par exemple Windows), il faut rajouter un antivirus ET un firewall, même si vous ne faites qu&#8217;afficher des pages web sur des sites de confiance.</p>
<p><a href="http://fr.wikipedia.org/wiki/Conficker">Conficker</a> est un virus.</p>
<h2>Un bug, c&#8217;est une erreur humaine</h2>
<p>Un bug n&#8217;est pas un programme en plus, c&#8217;est une erreur de conception qui existe dans un des programmes qui est déjà sur votre machine.</p>
<p>Les machines sont stupides, elles ne font que ce qu&#8217;on leur dit. Quand vous voyez une application fonctionner, cela n&#8217;est que le résultat de millions d&#8217;instructions écrites à la main par les hommes qui ont créé vos logiciels, et ces hommes sont faillibles. Parfois, ils font une erreur dans le programme, et cette erreur peut avoir tout un cas de conséquences inattendues : le programme ne fait pas ce que vous voulez, il le fait mais mal, il est lent, il plante, etc.</p>
<p>Tout, absolument TOUT sur votre machine, est un programme. Et TOUT peut contenir un bug. <strong>En fait, aujourd&#8217;hui les systèmes informatiques sont tellement complexes qu&#8217;il y a forcément des bugs sur votre machine.</strong> Mais souvent ce sont des bugs discrets, qui ne sont pas très graves.</p>
<p>Dites-vous qu&#8217;un téléphone ou une tablette, si cela vous parait simple à utiliser, est bien plus complexe qu&#8217;un avion ou une fusée dans son fonctionnement en détail. Pas parce que c&#8217;est techniquement plus poussé, mais parce qu&#8217;il y a tellement de couches et de parties qui interagissent entre elles. Et dans ce gros fouillis il y a des erreurs, les fameux bugs.</p>
<p>On peut difficilement se protéger des bugs. Garder vos logiciels à jour peut aider à corriger les bugs précédents, mais parfois en ajouter des nouveaux. Les bugs font partie de la vie, aucun système n&#8217;est parfait. En revanche, plus un système est simple et maitrisé, moins il a de chance de contenir de bug. Si les bugs vous font peur, choisir un produit qui ne fait qu&#8217;une seule chose, mais bien, ou choisir un produit éprouvé, vous permet d&#8217;espérer une expérience avec moins de bugs.</p>
<p><a href="http://sametmax.com/heartbleed-une-semaine-plus-tard/">Heartbleed</a> est un bug.</p>
<h2>Subtilités</h2>
<p>Un virus utilise souvent un bug pour attaquer votre système. Le virus a en effet un objectif (au moins celui de se reproduire), et le logiciel qu&#8217;il attaque n&#8217;est généralement pas conçu pour lui permettre de l&#8217;atteindre. Le virus va donc souvent utiliser un bug du système pour obtenir ce qu&#8217;il veut.</p>
<p>A l&#8217;inverse, un bug n&#8217;a pas d&#8217;objectif, c&#8217;est une erreur, et donc il ne peut pas &#8220;causer un virus&#8221;. Ça ne veut rien dire.</p>
<p>Généralement, tout ce petit monde va donc ensemble, un virus peut exploiter un bug, dans le but d&#8217;installer un adware sur votre machine, afin de gagner de l&#8217;argent via la publicité, un keylogger pour récupérer votre numéro de carte bleue et un rootkit pour garder votre machine sous contrôle. Il y a donc 5 choses ici : le virus, le bug, l&#8217;adware, le spyware et le rootkit. Ce sont 5 choses différentes, mais la raison pour laquelle vous en entendez souvent parler en même temps, c&#8217;est qu&#8217;elles sont liées.</p>
<h2>Mythes</h2>
<h3>Mon ordinateur n&#8217;a pas de bug</h3>
<p>C&#8217;est impossible. C&#8217;est comme dire qu&#8217;il n&#8217;y a pas de fourmis dans vote jardin. Ce qui est possible, c&#8217;est qu&#8217;un bug ne vous gène pas et que vous n&#8217;en ayez vu aucun.</p>
<h3>Je ne peux pas attraper de virus, parce que je ne fais rien de dangereux</h3>
<p>Vous n&#8217;avez aucune idée de ce qui est dangereux. Croyez-moi, si auparavant vous ne saviez pas la différence entre un bug et un virus, vous n&#8217;avez pas la compétence (ce n&#8217;est pas une insulte) pour savoir ce qui met en danger votre machine. Et donc, vous le faites.</p>
<h3>Mon ordinateur tourne bien, je n&#8217;ai pas de virus</h3>
<p>Les virus modernes essayent le plus souvent d&#8217;être discrets et de ne pas vous causer de souci pour éviter que vous ayez envie de les supprimer.</p>
<h3>Mon ordinateur affiche plein de pubs, j&#8217;ai un virus</h3>
<p>Il y a des tas d&#8217;autres malwares qui causent cela. Il y a très peu de chance que ce soit un virus. Ça ne veut pas dire qu&#8217;il ne faut pas traiter votre ordinateur, mais un anti-virus ne suffira pas. Il vous faut des programmes anti-malwares plus généralistes.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10217&amp;md5=43945554c4397b48f33031b16ccc3c28" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10228
title: ………………………………………… Arg
uri: Arg
url: http://sametmax.com/arg/
content:
<p>Je suis en train de rendre visite à Max. Il va bien, il a toutes ses dents, la truffe humide et le poil soyeux.</p>
<p>Par contre :</p>
<pre>⟩ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=36 time=384 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=36 time=1134 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=36 time=1351 ms
64 bytes from 8.8.8.8: icmp_seq=5 ttl=36 time=873 ms
64 bytes from 8.8.8.8: icmp_seq=6 ttl=36 time=1258 ms
64 bytes from 8.8.8.8: icmp_seq=7 ttl=36 time=1299 ms
64 bytes from 8.8.8.8: icmp_seq=8 ttl=36 time=1431 ms
64 bytes from 8.8.8.8: icmp_seq=9 ttl=36 time=1461 ms
64 bytes from 8.8.8.8: icmp_seq=10 ttl=36 time=1474 ms
64 bytes from 8.8.8.8: icmp_seq=11 ttl=36 time=1178 ms
64 bytes from 8.8.8.8: icmp_seq=12 ttl=36 time=1932 ms
64 bytes from 8.8.8.8: icmp_seq=13 ttl=36 time=2023 ms
64 bytes from 8.8.8.8: icmp_seq=14 ttl=36 time=1818 ms
64 bytes from 8.8.8.8: icmp_seq=15 ttl=36 time=1546 ms
64 bytes from 8.8.8.8: icmp_seq=16 ttl=36 time=1188 ms
64 bytes from 8.8.8.8: icmp_seq=17 ttl=36 time=1110 ms
64 bytes from 8.8.8.8: icmp_seq=18 ttl=36 time=998 ms
^C
--- 8.8.8.8 ping statistics ---</pre>
<p>Et je vous raconte pas comme c&#8217;est chiant avec WordPress. </p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10228&amp;md5=b3e8242270c0619f0aebb48a4ec01e0f" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10113
title: Le pandas c’est bon, mangez en
uri: Le-pandas-c-est-bon-mangez-en
url: http://sametmax.com/le-pandas-cest-bon-mangez-en/
content:
<p style="text-align: center;"><em><small>Ceci est un post invité de <a href="http://sametmax.com/author/joshuafr/">joshuafr</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.</small></em></p>
<p>Bonjour à tous, jeunes tailleurs de bambou, suite à un article d&#8217;introduction à numpy par le grand maître Sam <a href="http://sametmax.com/les-bases-de-numpy/" title="Les bases de Numpy" target="_blank">Les bases de Numpy</a>, je m&#8217;en vais vous présenter une lib qui roxx du poney dans le calcul numérique : <a href="http://pandas.pydata.org/" title="Pandas" target="_blank">Pandas</a>.</p>
<p>Pour faire simple, Pandas apporte à Python la possibilité de manipuler de grands volumes de données structurées de manière simple et intuitive, chose qui faisait défaut jusqu&#8217;ici. Il y a bien eu quelques tentatives comme <a href="https://pypi.python.org/pypi/la">larry</a>, mais rien n&#8217;avait jamais pu égaler les fonctionnalités du langage R. Aujourd&#8217;hui Pandas y arrive en fournissant notamment le célèbre type <strong>dataframe</strong> de R, avec en prime tout un tas d&#8217;outils pour agréger, combiner, transformer des données, et tout ça sans se casser le cul. Que du bonheur!</p>
<p>Donc pour commencer, on installe le bousin par un simple : <code>pip install pandas</code> qui va si vous ne l&#8217;avez pas déjà fait, aussi télécharger/compiler/installer tout un tas de librairies dont numpy. Je vous conseille aussi d&#8217;utiliser <a href="http://ipython.org/">ipython</a> afin d&#8217;avoir une meilleure interaction avec les libs, notamment avec <a href="http://matplotlib.org/">matplotlib</a> en utilisant le switch <code>ipython --pylab</code> afin d&#8217;avoir directement les graphiques en mode interactif, ainsi que toute la bibliothèque numpy directement importée (en interne, ipython fera un <code>import numpy as np</code>).<br />
On appelle la bête d&#8217;un simple:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>: <span style="color: #ff7700;font-weight:bold;">import</span> pandas <span style="color: #ff7700;font-weight:bold;">as</span> pd</pre></div></div>

<p>Oui je sais, la grande classe&#8230;</p>
<h2>Tout est Series</h2>
<p>Le type de base en Pandas et la Series. On peut le voir comme un tableau de données à une dimension:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>: pd.<span style="color: black;">Series</span><span style="color: black;">&#40;</span>np.<span style="color: black;">arange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>: 
<span style="color: #ff4500;">0</span>    <span style="color: #ff4500;">1</span>
<span style="color: #ff4500;">1</span>    <span style="color: #ff4500;">2</span>
<span style="color: #ff4500;">2</span>    <span style="color: #ff4500;">3</span>
<span style="color: #ff4500;">3</span>    <span style="color: #ff4500;">4</span>
dtype: int64</pre></div></div>

<p>La colonne de gauche représente l&#8217;index de la Series, normalement unique pour chaque entrée. La colonne de droite correspond à nos valeurs sur lesquelles nous voulons travailler.<br />
L&#8217;index n&#8217;est pas forcément une suite d&#8217;entiers, et la Series peut être nommée:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>: s=pd.<span style="color: black;">Series</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">2</span>,<span style="color: #ff4500;">3.14</span>,1e6<span style="color: black;">&#93;</span>, index=<span style="color: #008000;">list</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'abcd'</span><span style="color: black;">&#41;</span>, name=<span style="color: #483d8b;">'ma_series'</span><span style="color: black;">&#41;</span>
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">4</span><span style="color: black;">&#93;</span>: s
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">4</span><span style="color: black;">&#93;</span>: 
a          <span style="color: #ff4500;">1.00</span>
b          <span style="color: #ff4500;">2.00</span>
c          <span style="color: #ff4500;">3.14</span>
d    <span style="color: #ff4500;">1000000.00</span>
Name: ma_series, dtype: float64</pre></div></div>

<p>A noter qu&#8217;un type-casting est systématiquement appliqué afin d&#8217;avoir un tableau de type uniforme (ici le data-type est du float64) qui peut être modifié (dans une certaine mesure) via <code>Series.astype</code>.</p>
<p>Le slicing c&#8217;est comme du fisting avec une bonne dose de vaseline, ça glisse tout seul:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span><span style="color: black;">&#93;</span>: s<span style="color: black;">&#91;</span><span style="color: #483d8b;">'b'</span>:<span style="color: #483d8b;">'d'</span><span style="color: black;">&#93;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span><span style="color: black;">&#93;</span>: 
b          <span style="color: #ff4500;">2.00</span>
c          <span style="color: #ff4500;">3.14</span>
d    <span style="color: #ff4500;">1000000.00</span>
Name: ma_series, dtype: float64</pre></div></div>

<p>Et oui, la sélection par indexation se fait sur&#8230; l&#8217;index de la Series. Ainsi s['a'] renverra la ligne dont l&#8217;index est &#8216;a&#8217;, mais Pandas est assez intelligent pour reconnaître si on lui demande de nous renvoyer des valeurs suivant l&#8217;ordonnancement du tableau de valeurs (comme numpy). Ainsi s[0] renverra la première valeur du tableau, qui ici est égale à s['a'].<br />
Là où ça peut poser problème c&#8217;est quand notre index est une suite d&#8217;entiers, comme par exemple avec <code>x=pd.Series(np.arange(1,5), index=np.arange(1,5))</code>. Si vous demandez <code>x[1]</code>, Pandas ne retrouve pas ses petits et vous retournera une zolie <code>KeyError</code>. Pour ces cas ambigus, il existe l&#8217;indexation stricte sur le nom de index de la Series via <code>x.loc[nom_d'index]</code>, et l&#8217;indexation stricte sur le numéro d&#8217;ordre dans le tableau via <code>x.iloc[numéro_d'ordre]</code>. Essayez <code>x.loc[0]</code> et <code>x.iloc[0]</code> pour vous rendre compte de la différence.<br />
Comme pour les préliminaires où il est bon de tâter un peu de tout avec de pénétrer dans le vif du sujet, laissons pour le moment l&#8217;indexation sur laquelle nous reviendrons plus tard, pour regarder d&#8217;un peu plus près comment faire joujou avec nos valeurs.</p>
<p>Un peu à la manière des arrays de numpy, on peut appliquer des fonctions mathématiques directement sur la Serie, ou passer par des fonctions raccourcis:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">6</span><span style="color: black;">&#93;</span>: s.<span style="color: #008000;">sum</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">6</span><span style="color: black;">&#93;</span>: <span style="color: #ff4500;">1000006.14</span></pre></div></div>

<p>Ce qui revient au même que de faire <code>np.sum(s)</code> (rappelez vous, ipython avec &#8211;pylab a importé numpy dans la variable np).</p>
<p>La fonction <code>describe</code> est bien utile pour avoir un aperçu rapide de ce à quoi on a affaire:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">7</span><span style="color: black;">&#93;</span>: s.<span style="color: black;">describe</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">7</span><span style="color: black;">&#93;</span>: 
count          <span style="color: #ff4500;">4.000000</span>
mean      <span style="color: #ff4500;">250001.535000</span>
std       <span style="color: #ff4500;">499998.976667</span>
<span style="color: #008000;">min</span>            <span style="color: #ff4500;">1.000000</span>
<span style="color: #ff4500;">25</span><span style="color: #66cc66;">%</span>            <span style="color: #ff4500;">1.750000</span>
<span style="color: #ff4500;">50</span><span style="color: #66cc66;">%</span>            <span style="color: #ff4500;">2.570000</span>
<span style="color: #ff4500;">75</span><span style="color: #66cc66;">%</span>       <span style="color: #ff4500;">250002.355000</span>
<span style="color: #008000;">max</span>      <span style="color: #ff4500;">1000000.000000</span>
Name: ma_series, dtype: float64</pre></div></div>

<p>ce qui donne le nombre de données, la moyenne globale, la déviation standard, le minimum, les quartiles et le maximum de la Serie. </p>
<p>Le truc à retenir est que c&#8217;est l&#8217;index qui est primordial dans un grand nombre d&#8217;opérations. Ainsi si l&#8217;on veut additionner 2 Series ensemble, il faut que leurs index soient alignés :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">8</span><span style="color: black;">&#93;</span>: s2=pd.<span style="color: black;">Series</span><span style="color: black;">&#40;</span>np.<span style="color: #dc143c;">random</span>.<span style="color: black;">rand</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>, index=<span style="color: #008000;">list</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'cdef'</span><span style="color: black;">&#41;</span>, name=<span style="color: #483d8b;">'autre_serie'</span><span style="color: black;">&#41;</span>
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span><span style="color: black;">&#93;</span>: s+s2
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span><span style="color: black;">&#93;</span>: 
a               NaN
b               NaN
c          <span style="color: #ff4500;">4.021591</span>
d    <span style="color: #ff4500;">1000000.401511</span>
e               NaN
f               NaN
dtype: float64</pre></div></div>

<p>Ici, seuls les index &#8216;c&#8217; et &#8216;d&#8217; étaient présents dans les 2 Series, Pandas effectuant avant l&#8217;opération d&#8217;addition une union basée sur l&#8217;index. Les autres entrées sont marquées en <code>NaN</code>, soit Not a Number. Une possibilité pour contrer ce phénomène et de dire à Pandas de remplacer les résultats manquants lors de l&#8217;union par 0:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#93;</span>: s.<span style="color: black;">add</span><span style="color: black;">&#40;</span>s2, fill_value=<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#93;</span>: 
a          <span style="color: #ff4500;">1.000000</span>
b          <span style="color: #ff4500;">2.000000</span>
c          <span style="color: #ff4500;">4.021591</span>
d    <span style="color: #ff4500;">1000000.401511</span>
e          <span style="color: #ff4500;">0.563508</span>
f          <span style="color: #ff4500;">0.655915</span>
Name: ma_series, dtype: float64</pre></div></div>

<p>Mais si ce sont uniquement les valeurs qui nous intéressent, et non les indexations, il est possible de les supprimer:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">11</span><span style="color: black;">&#93;</span>: s.<span style="color: black;">reset_index</span><span style="color: black;">&#40;</span>drop=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>+s2.<span style="color: black;">reset_index</span><span style="color: black;">&#40;</span>drop=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">11</span><span style="color: black;">&#93;</span>: 
<span style="color: #ff4500;">0</span>          <span style="color: #ff4500;">1.881591</span>
<span style="color: #ff4500;">1</span>          <span style="color: #ff4500;">2.401511</span>
<span style="color: #ff4500;">2</span>          <span style="color: #ff4500;">3.703508</span>
<span style="color: #ff4500;">3</span>    <span style="color: #ff4500;">1000000.655915</span>
dtype: float64</pre></div></div>

<p>Oh joie, oh bonheur, je peux faire ce que je veux avec mes cheveux, enfin mes données&#8230;</p>
<h2>Et PAN! dans ta frame</h2>
<p>La DataFrame est l&#8217;extension en 2 dimensions des Series. Elle peut être vue comme un empilement de Series dont les index sont partagés (et donc intrinsèquement alignés), ou comme dans un tableur où les index sont les numéros de lignes et les noms des Series les noms des colonnes. Je ne vais pas décrire toutes les manières de créer une DataFrame, sachez juste qu&#8217;on peut les obtenir à partir de dictionnaires, de liste de liste ou de liste de Series, d&#8217;arrays ou de records numpy, de fichier excel ou csv et même depuis des bases de données, de fichier JSON ou HTML, et depuis le presse-papiers.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">14</span><span style="color: black;">&#93;</span>: genre=<span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'femme'</span>,<span style="color: #483d8b;">'homme'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>x<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> np.<span style="color: #dc143c;">random</span>.<span style="color: black;">random_integers</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">15</span><span style="color: black;">&#93;</span>: lateral=<span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'droite'</span>,<span style="color: #483d8b;">'gauche'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>x<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> np.<span style="color: #dc143c;">random</span>.<span style="color: black;">random_integers</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">16</span><span style="color: black;">&#93;</span>: age=np.<span style="color: #dc143c;">random</span>.<span style="color: black;">random_integers</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">100</span>,<span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span>
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">17</span><span style="color: black;">&#93;</span>: df=pd.<span style="color: black;">DataFrame</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'Genre'</span>:genre, <span style="color: #483d8b;">'Lateral'</span>:lateral, <span style="color: #483d8b;">'Age'</span>:age<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">18</span><span style="color: black;">&#93;</span>: df
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">18</span><span style="color: black;">&#93;</span>: 
    Age  Genre Lateral
<span style="color: #ff4500;">0</span>    <span style="color: #ff4500;">69</span>  femme  droite
<span style="color: #ff4500;">1</span>    <span style="color: #ff4500;">46</span>  homme  droite
<span style="color: #ff4500;">2</span>    <span style="color: #ff4500;">89</span>  homme  droite
<span style="color: #ff4500;">3</span>    <span style="color: #ff4500;">14</span>  homme  droite
<span style="color: #ff4500;">4</span>    <span style="color: #ff4500;">74</span>  homme  droite
<span style="color: #ff4500;">5</span>     <span style="color: #ff4500;">5</span>  femme  gauche
<span style="color: #ff4500;">6</span>    <span style="color: #ff4500;">66</span>  femme  droite
<span style="color: #ff4500;">7</span>    <span style="color: #ff4500;">73</span>  homme  gauche
<span style="color: #ff4500;">8</span>    <span style="color: #ff4500;">99</span>  homme  gauche
<span style="color: #ff4500;">9</span>    <span style="color: #ff4500;">17</span>  homme  gauche
    ...    ...     ...
&nbsp;
<span style="color: black;">&#91;</span><span style="color: #ff4500;">100</span> rows x <span style="color: #ff4500;">3</span> columns<span style="color: black;">&#93;</span></pre></div></div>

<p>L&#8217;affichage par défaut depuis la version 0.13 est en mode &#8216;truncate&#8217; où la fin de la DataFrame est tronquée suivant la hauteur de votre terminal, mais ça peut se changer via les divers paramètres à regarder sous <code>pd.options.display</code>.</p>
<p>Là donc nous avons une DataFrame de 3 colonnes (plus un index), chaque colonne étant en réalité une Serie :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">20</span><span style="color: black;">&#93;</span>: <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>df<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Age'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">20</span><span style="color: black;">&#93;</span>: pandas.<span style="color: black;">core</span>.<span style="color: black;">series</span>.<span style="color: black;">Series</span></pre></div></div>

<p>La sélection peut se faire de plusieurs manières, à chacun de choisir sa préférée (moi c&#8217;est Dafnée avec ses gros nénés). Ainsi pour avoir les 3 premières lignes des âges</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">21</span><span style="color: black;">&#93;</span>: df<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Age'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">21</span><span style="color: black;">&#93;</span>: 
<span style="color: #ff4500;">0</span>    <span style="color: #ff4500;">69</span>
<span style="color: #ff4500;">1</span>    <span style="color: #ff4500;">46</span>
<span style="color: #ff4500;">2</span>    <span style="color: #ff4500;">89</span>
Name: Age, dtype: int64
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">22</span><span style="color: black;">&#93;</span>: df<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'Age'</span><span style="color: black;">&#93;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">22</span><span style="color: black;">&#93;</span>: 
<span style="color: #ff4500;">0</span>    <span style="color: #ff4500;">69</span>
<span style="color: #ff4500;">1</span>    <span style="color: #ff4500;">46</span>
<span style="color: #ff4500;">2</span>    <span style="color: #ff4500;">89</span>
Name: Age, dtype: int64
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">23</span><span style="color: black;">&#93;</span>: df.<span style="color: black;">Age</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">23</span><span style="color: black;">&#93;</span>: 
<span style="color: #ff4500;">0</span>    <span style="color: #ff4500;">69</span>
<span style="color: #ff4500;">1</span>    <span style="color: #ff4500;">46</span>
<span style="color: #ff4500;">2</span>    <span style="color: #ff4500;">89</span>
Name: Age, dtype: int64
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">24</span><span style="color: black;">&#93;</span>: df.<span style="color: black;">loc</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>:<span style="color: #ff4500;">3</span>, <span style="color: #483d8b;">'Age'</span><span style="color: black;">&#93;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">24</span><span style="color: black;">&#93;</span>: 
<span style="color: #ff4500;">0</span>    <span style="color: #ff4500;">69</span>
<span style="color: #ff4500;">1</span>    <span style="color: #ff4500;">46</span>
<span style="color: #ff4500;">2</span>    <span style="color: #ff4500;">89</span>
<span style="color: #ff4500;">3</span>    <span style="color: #ff4500;">14</span>
Name: Age, dtype: int64</pre></div></div>

<p>et oui, les noms de colonnes peuvent aussi être utilisés comme des attributs de la DataFrame. Pratique (qu&#8217;on n&#8217;attend pas).</p>
<p>L&#8217;une des forces de Pandas est de nous proposer tout un tas de solutions pour répondre à des questions existentielles tel que &#8220;quel est l&#8217;âge moyen par genre et par latéralité?&#8221;. Comme en SQL où la réponse sortirait du fondement d&#8217;une clause GROUP BY et d&#8217;une fonction d’agrégation, il en va de même ici :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">25</span><span style="color: black;">&#93;</span>: df.<span style="color: black;">groupby</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'Genre'</span>,<span style="color: #483d8b;">'Lateral'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>.<span style="color: black;">aggregate</span><span style="color: black;">&#40;</span>np.<span style="color: black;">mean</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">25</span><span style="color: black;">&#93;</span>: 
                     Age
Genre Lateral           
femme droite   <span style="color: #ff4500;">45.476190</span>
      gauche   <span style="color: #ff4500;">49.208333</span>
homme droite   <span style="color: #ff4500;">41.571429</span>
      gauche   <span style="color: #ff4500;">55.823529</span>
&nbsp;
<span style="color: black;">&#91;</span><span style="color: #ff4500;">4</span> rows x <span style="color: #ff4500;">1</span> columns<span style="color: black;">&#93;</span></pre></div></div>

<p>OMG! c&#8217;est quoi c&#8217;t'index de malade? Un <strong>MultiIndex</strong> jeune padawan, qui te permettra d&#8217;organiser tes données par catégorie/niveau, et d&#8217;y accèder par le paramètre <code>level</code> dans pas mal de fonctions, mais ça je te laisse le découvrir par toi-même. Je ne vais pas non plus m&#8217;étendre plus sur toutes les possibilités offertes par les DataFrame, il y a tellement à dire qu&#8217;il faudrait plusieurs articles pour en faire le tour. Juste conclusionner sur la facilité d&#8217;intégration Pandas/matplotlib en vous disant que les Series et DataFrame ont une fonction <code>plot</code> permettant directement de visualiser les données, et ça, c&#8217;est juste jouissif.</p>
<h2>Datetime dans les index</h2>
<p>Je vous avez dit qu&#8217;on reviendrait sur les indexes, et là c&#8217;est pour rentrer dans le lourd (mais non pas toi Carlos). Pandas donc supporte l&#8217;indexation sur les dates, en reprenant et en élargissant les possibilités offertes par feu le module <a href="http://pytseries.sourceforge.net/">scikits.timeseries</a>.<br />
Prenons l&#8217;exemple de données (complètement bidons) fournies par un capteur à intervalle régulier sur un pas de temps horaire:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">26</span><span style="color: black;">&#93;</span>: dtindex=pd.<span style="color: black;">date_range</span><span style="color: black;">&#40;</span>start=<span style="color: #483d8b;">'2014-04-28 00:00'</span>, periods=<span style="color: #ff4500;">96</span>, freq=<span style="color: #483d8b;">'H'</span><span style="color: black;">&#41;</span>
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">27</span><span style="color: black;">&#93;</span>: data=np.<span style="color: #dc143c;">random</span>.<span style="color: black;">random_sample</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">96</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">*</span><span style="color: #ff4500;">50</span>
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">28</span><span style="color: black;">&#93;</span>: df=pd.<span style="color: black;">DataFrame</span><span style="color: black;">&#40;</span>data, index=dtindex, columns=<span style="color: black;">&#91;</span><span style="color: #483d8b;">'mesure'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">29</span><span style="color: black;">&#93;</span>: df.<span style="color: black;">head</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">29</span><span style="color: black;">&#93;</span>: 
                        mesure
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:00:00  <span style="color: #ff4500;">49.253929</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:00:00   <span style="color: #ff4500;">1.910280</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 02:00:00   <span style="color: #ff4500;">7.534761</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 03:00:00  <span style="color: #ff4500;">39.416415</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 04:00:00  <span style="color: #ff4500;">44.213409</span>
&nbsp;
<span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span> rows x <span style="color: #ff4500;">1</span> columns<span style="color: black;">&#93;</span>
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">30</span><span style="color: black;">&#93;</span>: df.<span style="color: black;">tail</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">30</span><span style="color: black;">&#93;</span>: 
                        mesure
<span style="color: #ff4500;">2014</span>-05-01 <span style="color: #ff4500;">19</span>:00:00  <span style="color: #ff4500;">25.291453</span>
<span style="color: #ff4500;">2014</span>-05-01 <span style="color: #ff4500;">20</span>:00:00  <span style="color: #ff4500;">26.520291</span>
<span style="color: #ff4500;">2014</span>-05-01 <span style="color: #ff4500;">21</span>:00:00  <span style="color: #ff4500;">33.459766</span>
<span style="color: #ff4500;">2014</span>-05-01 <span style="color: #ff4500;">22</span>:00:00  <span style="color: #ff4500;">44.521813</span>
<span style="color: #ff4500;">2014</span>-05-01 <span style="color: #ff4500;">23</span>:00:00  <span style="color: #ff4500;">28.486003</span>
&nbsp;
<span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span> rows x <span style="color: #ff4500;">1</span> columns<span style="color: black;">&#93;</span></pre></div></div>

<p><code>dtindex</code> est un <strong>DatetimeIndex</strong> initialisé au 28 avril 2014 à 0 heure comportant 96 périodes de fréquence horaire, soit 4 jours. La fonction <code>date_range</code> peut aussi prendre en arguments des objets datetime purs au lieu de chaine de caractère (manquerait plus que ça&#8230;), et le nombre de périodes peut être remplacé par une date de fin.<br />
Si l&#8217;on veut calculer, disons le maximum (horaire) par jour, rien de plus simple, il suffit de &#8220;resampler&#8221; en données journalières (&#8216;D&#8217; pour Day) et de dire comment aggréger le tout:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">31</span><span style="color: black;">&#93;</span>: df.<span style="color: black;">resample</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'D'</span>, how=np.<span style="color: #008000;">max</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">31</span><span style="color: black;">&#93;</span>: 
               mesure
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span>  <span style="color: #ff4500;">26.298282</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">29</span>  <span style="color: #ff4500;">28.385418</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">30</span>  <span style="color: #ff4500;">26.723353</span>
<span style="color: #ff4500;">2014</span>-05-01  <span style="color: #ff4500;">24.106092</span>
&nbsp;
<span style="color: black;">&#91;</span><span style="color: #ff4500;">4</span> rows x <span style="color: #ff4500;">1</span> columns<span style="color: black;">&#93;</span></pre></div></div>

<p>Mais on peut aussi convertir en données quart-horaire (upsampling) en remplissant les données manquantes par celles de l&#8217;heure fixe:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">32</span><span style="color: black;">&#93;</span>:  df<span style="color: black;">&#91;</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>.<span style="color: black;">resample</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'15min'</span>, fill_method=<span style="color: #483d8b;">'ffill'</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">32</span><span style="color: black;">&#93;</span>: 
                        mesure
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:00:00  <span style="color: #ff4500;">49.253929</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">15</span>:00  <span style="color: #ff4500;">49.253929</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">30</span>:00  <span style="color: #ff4500;">49.253929</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">45</span>:00  <span style="color: #ff4500;">49.253929</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:00:00   <span style="color: #ff4500;">1.910280</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">15</span>:00   <span style="color: #ff4500;">1.910280</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">30</span>:00   <span style="color: #ff4500;">1.910280</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">45</span>:00   <span style="color: #ff4500;">1.910280</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 02:00:00   <span style="color: #ff4500;">7.534761</span>
&nbsp;
<span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span> rows x <span style="color: #ff4500;">1</span> columns<span style="color: black;">&#93;</span></pre></div></div>

<p>Cependant, Pandas propose aussi d&#8217;autres possibilités non dépendantes des DatetimeIndex mais qu&#8217;il est bon de connaître, notamment celle pour remplacer les données manquantes avec <code>fillna</code> ou celle pour interpoler entre les données valides avec <code>interpolate</code></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">In <span style="color: black;">&#91;</span><span style="color: #ff4500;">52</span><span style="color: black;">&#93;</span>:  df<span style="color: black;">&#91;</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>.<span style="color: black;">resample</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'15min'</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">52</span><span style="color: black;">&#93;</span>: 
                        mesure
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:00:00  <span style="color: #ff4500;">49.253929</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">15</span>:00        NaN
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">30</span>:00        NaN
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">45</span>:00        NaN
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:00:00   <span style="color: #ff4500;">1.910280</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">15</span>:00        NaN
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">30</span>:00        NaN
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">45</span>:00        NaN
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 02:00:00   <span style="color: #ff4500;">7.534761</span>
&nbsp;
<span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span> rows x <span style="color: #ff4500;">1</span> columns<span style="color: black;">&#93;</span>
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">53</span><span style="color: black;">&#93;</span>:  df<span style="color: black;">&#91;</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>.<span style="color: black;">resample</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'15min'</span><span style="color: black;">&#41;</span>.<span style="color: black;">fillna</span><span style="color: black;">&#40;</span>df.<span style="color: black;">mean</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">53</span><span style="color: black;">&#93;</span>: 
                        mesure
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:00:00  <span style="color: #ff4500;">49.253929</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">15</span>:00  <span style="color: #ff4500;">26.378286</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">30</span>:00  <span style="color: #ff4500;">26.378286</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">45</span>:00  <span style="color: #ff4500;">26.378286</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:00:00   <span style="color: #ff4500;">1.910280</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">15</span>:00  <span style="color: #ff4500;">26.378286</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">30</span>:00  <span style="color: #ff4500;">26.378286</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">45</span>:00  <span style="color: #ff4500;">26.378286</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 02:00:00   <span style="color: #ff4500;">7.534761</span>
&nbsp;
<span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span> rows x <span style="color: #ff4500;">1</span> columns<span style="color: black;">&#93;</span>
&nbsp;
In <span style="color: black;">&#91;</span><span style="color: #ff4500;">54</span><span style="color: black;">&#93;</span>:  df<span style="color: black;">&#91;</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>.<span style="color: black;">resample</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'15min'</span><span style="color: black;">&#41;</span>.<span style="color: black;">interpolate</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Out<span style="color: black;">&#91;</span><span style="color: #ff4500;">54</span><span style="color: black;">&#93;</span>: 
                        mesure
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:00:00  <span style="color: #ff4500;">49.253929</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">15</span>:00  <span style="color: #ff4500;">37.418016</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">30</span>:00  <span style="color: #ff4500;">25.582104</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 00:<span style="color: #ff4500;">45</span>:00  <span style="color: #ff4500;">13.746192</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:00:00   <span style="color: #ff4500;">1.910280</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">15</span>:00   <span style="color: #ff4500;">3.316400</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">30</span>:00   <span style="color: #ff4500;">4.722520</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 01:<span style="color: #ff4500;">45</span>:00   <span style="color: #ff4500;">6.128641</span>
<span style="color: #ff4500;">2014</span>-04-<span style="color: #ff4500;">28</span> 02:00:00   <span style="color: #ff4500;">7.534761</span>
&nbsp;
<span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span> rows x <span style="color: #ff4500;">1</span> columns<span style="color: black;">&#93;</span></pre></div></div>

<p>Voilà, j&#8217;espère que vous aurez plaisir à travailler avec cette librairie, il manquait vraiment un outil de cette trempe en Python pour l&#8217;analyse de données et je pense qu&#8217;on n&#8217;a plus trop grand chose à envier maintenant par rapport à des langages spécilisés. Je n&#8217;ai pas parlé de <code>Panel</code> qui est le passage à la troisième dimension, ni des possibilités d&#8217;export, notamment la <code>df.to_html</code> que je vous laisse le soin de découvrir.</p>
<p>A plus, et amusez vous bien avec votre bambou.</p>
<p>\o/</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10113&amp;md5=4cb55217f98c6055115d0fb06ed7f887" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10245
title: Peut-on compiler un programme Python ?
uri: Peut-on-compiler-un-programme-Python
url: http://sametmax.com/peut-on-compiler-un-programme-python/
content:
<p>Sans répit, des hordes d&#8217;OP ont demandé sur Stackoverflow comment compiler un programme Python. La plupart du temps, pour des raisons d’obfuscation ou pour faire un joli .exe. Et inlassablement, les devs bienveillants leur répondaient que Python était un langage interprété, et donc non compilable.</p>
<p>Commença alors la lente fuite des impatients vers Go qui permettait de le faire si facilement.</p>
<p>Et puis arriva <a href="http://cython.org/">Cython</a>, qui promettait de permettre de transformer du Python en C, afin de l&#8217;embarquer dans un autre code C, ou permettre des appels de C vers Python et inversement plus facile.</p>
<p>Cela visait les perfs, l&#8217;intégration, faire des dll/so en Python, et du coup, dans l&#8217;excitation, tout le monde a loupé un petit détail minuscule.</p>
<p>Les mecs avaient implémenté un compilateur Python => C complet.</p>
<p>En fait, Cython permet &#8211; et c&#8217;est la que c&#8217;est fun car c&#8217;est un effet de bord presque involontaire &#8211; de créer un programme compilé <strong>autonome</strong> en Python. Et avec la toolchain classique en plus.</p>
<p>Ça peut gérer les dépendances, et ça marche même avec des trucs compilés balèzes du genre PyQT. </p>
<p>Je sens le chapiteau se dresser sous la braguette, alors voici la démo&#8230;</p>
<p>Pour montrer qu&#8217;on ne fait pas que du &#8220;Hello World&#8221;, je vais utiliser des dépendances assez complexes : <a href="http://lxml.de">lxml</a> (qui contient une extension C compilée), <a href="http://sametmax.com/sept-petites-libs-qui-changent-la-vie-dun-dev-python/">path.py, requests</a> et <a href="http://sametmax.com/la-plus-belle-maniere-de-parser-les-arguments-de-script-en-python/">docopt</a> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
    Download a file and save it to a location.
&nbsp;
    Usage:
        downloader.py &lt;target&gt; [&lt;location&gt;]
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> requests
<span style="color: #ff7700;font-weight:bold;">import</span> docopt
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> lxml.<span style="color: black;">html</span> <span style="color: #ff7700;font-weight:bold;">import</span> parse
<span style="color: #ff7700;font-weight:bold;">from</span> path <span style="color: #ff7700;font-weight:bold;">import</span> path
&nbsp;
args = docopt.<span style="color: black;">docopt</span><span style="color: black;">&#40;</span>__doc__<span style="color: black;">&#41;</span>
&nbsp;
p = path<span style="color: black;">&#40;</span>args<span style="color: black;">&#91;</span><span style="color: #483d8b;">'&lt;location&gt;'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>.<span style="color: black;">realpath</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> p.<span style="color: black;">isdir</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    p = p / path<span style="color: black;">&#40;</span>args<span style="color: black;">&#91;</span><span style="color: #483d8b;">'&lt;target&gt;'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>.<span style="color: black;">namebase</span>
&nbsp;
p.<span style="color: black;">write_bytes</span><span style="color: black;">&#40;</span>requests.<span style="color: black;">get</span><span style="color: black;">&#40;</span>args<span style="color: black;">&#91;</span><span style="color: #483d8b;">'&lt;target&gt;'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>.<span style="color: black;">content</span><span style="color: black;">&#41;</span>
&nbsp;
title = parse<span style="color: black;">&#40;</span>p<span style="color: black;">&#41;</span>.<span style="color: black;">getroot</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'head'</span><span style="color: black;">&#41;</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'title'</span><span style="color: black;">&#41;</span>.<span style="color: black;">text</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Downloaded &quot;%s&quot;'</span> <span style="color: #66cc66;">%</span> title<span style="color: black;">&#41;</span></pre></div></div>

<p>Je ne m&#8217;encombre pas de gestion d&#8217;erreurs, juste suffisamment d&#8217;appels pour faire travailler les dépendances.</p>
<p>Qui dit compilation, dit environnement. Pour ma part, je suis sous Ubuntu 14.04 et je vais me compiler un petit programme en Python 3, avec lesquels il me faut installer Cython et <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a> pour Python 3, de quoi compiler du C, et les dépendances de notre script :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> <span style="color: #c20cb9; font-weight: bold;">install</span> <span style="color: #c20cb9; font-weight: bold;">gcc</span> cython3 python-pip3 python3-lxml
$ pip3 <span style="color: #c20cb9; font-weight: bold;">install</span> requests docopt path.py</pre></div></div>

<p>Je n&#8217;ai même pas eu besoin d&#8217;installer les headers de lxml. Vive le Dieu des geeks.</p>
<p>L&#8217;utilisation de Cython dans notre cas est assez simple : on lui dit de transformer notre module en module C. <code>--embed</code> lui dit d&#8217;inclure l&#8217;interpréteur Python dedans.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ cython3 downloader.py <span style="color: #660033;">-o</span> downloader.c <span style="color: #660033;">--embed</span></pre></div></div>

<p>On obtient un fichier C bien copieux :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">head</span> downloader.c
<span style="color: #000000; font-weight: bold;">/*</span> Generated by Cython 0.20.1post0 <span style="color: #7a0874; font-weight: bold;">&#40;</span>Debian 0.20.1+git90-g0e6e38e-1ubuntu2<span style="color: #7a0874; font-weight: bold;">&#41;</span> on Sun May <span style="color: #000000;">11</span> <span style="color: #000000;">22</span>:<span style="color: #000000;">53</span>:<span style="color: #000000;">18</span> <span style="color: #000000;">2014</span> <span style="color: #000000; font-weight: bold;">*/</span>
&nbsp;
<span style="color: #666666; font-style: italic;">#define PY_SSIZE_T_CLEAN</span>
<span style="color: #666666; font-style: italic;">#ifndef CYTHON_USE_PYLONG_INTERNALS</span>
<span style="color: #666666; font-style: italic;">#ifdef PYLONG_BITS_IN_DIGIT</span>
<span style="color: #666666; font-style: italic;">#define CYTHON_USE_PYLONG_INTERNALS 0</span>
<span style="color: #666666; font-style: italic;">#else</span>
<span style="color: #666666; font-style: italic;">#include &quot;pyconfig.h&quot;</span>
<span style="color: #666666; font-style: italic;">#ifdef PYLONG_BITS_IN_DIGIT</span>
<span style="color: #666666; font-style: italic;">#define CYTHON_USE_PYLONG_INTERNALS 1</span></pre></div></div>

<p>Il ne reste plus qu&#8217;à compiler ce dernier :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">gcc</span> <span style="color: #660033;">-Os</span> <span style="color: #660033;">-I</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>include<span style="color: #000000; font-weight: bold;">/</span>python3.4m  downloader.c <span style="color: #660033;">-o</span> download -lpython3.4m <span style="color: #660033;">-lpthread</span> <span style="color: #660033;">-lm</span> <span style="color: #660033;">-lutil</span> <span style="color: #660033;">-ldl</span></pre></div></div>

<p>J&#8217;ai mis <code>-I /usr/include/python3.4m</code> et <code>-lpython3.4m</code> car les headers de Python sont là dedans sur ma machine. Le reste, ce sont des options que j&#8217;ai copier / coller sur le Web car GCC a plus de flags qu&#8217;une ambassade américaine et que j&#8217;ai des choses plus importantes à retenir, comme par exemple la recette du guacamole.</p>
<p>On obtient un exécutable tout à fait exécutablatoire :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">chmod</span> u+x downloader
$ .<span style="color: #000000; font-weight: bold;">/</span>downloader <span style="color: #666666; font-style: italic;"># docopt marche :)</span>
Usage:
       downloader.py <span style="color: #000000; font-weight: bold;">&lt;</span>target<span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000; font-weight: bold;">&lt;</span>location<span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span></pre></div></div>

<p>Et ça télécharge comme prévu :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ .<span style="color: #000000; font-weight: bold;">/</span>downloader http:<span style="color: #000000; font-weight: bold;">//</span>sametmax.com index.html
Downloaded <span style="color: #ff0000;">&quot;Sam &amp; Max: Python, Django, Git et du cul | Deux développeurs en vadrouille qui se sortent les doigts du code&quot;</span></pre></div></div>

<p>Le script Python original fait 472 octets, le binaire obtenu 28,7 ko. Mais ce n&#8217;est pas standalone, puisque je n&#8217;ai pas demandé la compilation des dépendances (je viens de le tester sur une autre Ubuntu, il pleure que requests n&#8217;est pas installé). Je vous laisse vous faire chier à trouver comment faire pour répondre à votre cas de figure exact, mais ça implique d&#8217;utiliser <a href="https://github.com/cython/cython/blob/master/bin/cython_freeze">cython_freeze</a>.</p>
<p>Après tout, cet article est intitulé &#8220;Peut on compiler un programme Python ?&#8221; et non &#8220;Tuto pour rendre un script Python stand alone&#8221;. Je ne suis pas fou.</p>
<p>Apparemment ça marche sous Windows et Mac, même si je n&#8217;ai pas de quoi tester sous la main (bon, si j&#8217;ai une partition Windows, mais faut rebooter, tout réinstaller, merde quoi&#8230;).</p>
<p>Donc si vous voulez faire une application en Python et la rendre stand alone, l&#8217;obfusquer, pondre un exe pour rendre le téléchargement facile, rassurer les gens ou simplement ignorer les mises à jours des libs de l&#8217;OS, Cython est une bonne piste.</p>
<p>Petit bonus, votre programme sera plus rapide, car il saute l&#8217;étape d&#8217;interprétation. Bien entendu, vous récoltez les galères qui viennent avec la compilation, à savoir les différentes architectures, le linking vers les libs qui peuvent changer de place ou de versions, etc.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10245&amp;md5=aca3a675be00b8ed30202b7be62ec457" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10270
title: Le déploiement par conteneurs avec Docker
uri: Le-déploiement-par-conteneurs-avec-Docker
url: http://sametmax.com/le-deploiement-par-conteneurs-avec-docker/
content:
<p>Mettre son projet en production, c&#8217;est la galère. Tellement que mille méthodes ont vu le jour pour automatiser tout ça. Chef, salt, fabric, des script bash, virtualenv, git hooks, etc.</p>
<p>Après, il y a ceux qui utilisent des VM, qui elles, ont leur propres outils d&#8217;automatisation type Vagrant.</p>
<p>Et comme ça ne suffit pas, des services ce sont mis en place pour faciliter la mise en prod dans le cloud comme Heroku, Gondor, dotCloud&#8230;</p>
<p>Malgré ça, Max fait encore beaucoup de trucs à la main parce que &#8220;ça marche jamais comme prévu&#8221;. Pas très scalable.</p>
<p>Dernièrement, grâce à notre cher <a href="http://sametmax.com/author/cortex/">Cortex</a>, j&#8217;ai découvert un projet écrit en Go nommé <a href="http://docker.io/">Docker</a>, qui propose encore une autre approche du problème.</p>
<p>J&#8217;ai été intrigué après avoir visionné une conf sur le sujet car le principe est très cool, mais aussi parce que j&#8217;ai bossé à une époque avec <a href="https://github.com/jpetazzo">un des mecs</a> de chez docker. Et ce gars est un monstre. Mais vraiment. Une brute. Le genre qui n&#8217;a pas besoin de souris ni de gestionnaire de fenêtre, mais qui peut vous régler votre problème en tapant d&#8217;une main tout en vous expliquant ce qu&#8217;il fait dans votre domaine d&#8217;expertise alors que ce n&#8217;est pas le sien. Je l&#8217;ai vu faire. C&#8217;est énervant.</p>
<p>Pour le moment, je dois dire que Docker est vraiment sympa. Petit tour du propriétaire.</p>
<h2>C&#8217;est comme si chaque process avait sa mini VM</h2>
<p>Pour faire simple, docker, c&#8217;est de la virtualisation légère.</p>
<p>Ça marche comme cela : on prend une image d&#8217;un Linux de base qu&#8217;on fait tourner dans docker, on lui installe de quoi faire tourner un process &#8211; par exemple redis &#8211; et on obtient une nouvelle image qui contient juste la différence avec l&#8217;image précédente. On fait ça avec plein d&#8217;autres process, et quand on a besoin de l&#8217;un d&#8217;entre eux, on lance l&#8217;image qui contient l&#8217;install de ce celui-ci.</p>
<p>Ce sont des images très légères, on peut en lancer 100 sur une même machine si on le souhaite. Mais elles sont parfaitement isolées : elles ont leur propre système de fichier, leurs propres arbres de processus, utilisateurs, permissions, ports&#8230; Donc si par exemple je fais un nginx compilé avec des extensions exotiques et une config zarb, je peux en faire une image puis l&#8217;utiliser sur n&#8217;importe quel serveur qui contient Docker.</p>
<p>Le but, c&#8217;est de créer plein de petits conteneurs légers et isolés de votre machine. Et au lieu de configurer chaque serveur, on envoie juste les conteneurs dont on a besoin, et on est certain qu&#8217;ils marchent partout pareil, peu importe la config à l&#8217;arrivée. <strong>On virtualise des services, qu&#8217;on combine, et non une machine complète.</strong></p>
<p>Quand je vous dis que c&#8217;est léger, c&#8217;est VRAIMENT léger. A peine plus gourmand que le process sans la VM. En fait, un conteneur docker démarre presque instantanément, il n&#8217;y a pas de &#8220;boot&#8221; comme pour une vraie VM. Mais on en a les avantages car votre redis dockerisé marchera pareil sur une Fedora et une Ubuntu.</p>
<p>Docker ne marche que sur Linux pour le moment, et encore, sur un Linux pas trop vieux  car il utilise une technologie récente, dont vous avez probablement peu entendu parlé : <a href="https://fr.wikipedia.org/wiki/LXC">LXC</a>.</p>
<p>Détail amusant : Docker est pas mal utilisé dans la communauté des devs sous Mac, qui du coup ont une VM Ubuntu dans laquelle ils font tourner Docker pour travailler. N&#8217;est-ce pas merveilleux ?</p>
<h2>La démonstration obligatoire</h2>
<p>Je ne vais pas vous laisser comme ça et vous demander de vous la mettre derrière l&#8217;oreille, donc exemple d&#8217;utilisation sous Bubuntoune.</p>
<p>Je suis en 14.04, mais je pense que ça marche pareil depuis la 12.04.</p>
<p>Installation :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> <span style="color: #c20cb9; font-weight: bold;">install</span> docker.io</pre></div></div>

<p>Cela va mettre la commande <code>docker.io</code> à votre disposition, mais sous d&#8217;autres systèmes, elle s&#8217;appelle juste <code>docker</code>. Perso je fais un
<pre lang="python bash">alias docker="sudo docker.io"</pre>
<p> puisque de toute façon il faut toujours lancer cette commande avec les droits admin.</p>
<p>Ensuite, on va télécharger une image de base sur laquelle baser toutes nos images :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ docker pull ubuntu</pre></div></div>

<p>Docker.io, ce n&#8217;est pas juste un software, c&#8217;est aussi un service qui héberge les images. Vous pouvez bien entendu créer vos propres images de base, et héberger votre  dépôt personnel d&#8217;images, mais on ne va pas se faire chier à faire ça ici. Prévoyez quelques gigas de place, Docker ne prend pas beaucoup de ressources CPU/RAM, mais par contre ça bouffe en espace disque.</p>
<p>Donc là, je demande la récupération des images &#8220;ubuntu&#8221;, qui vont nous servir d&#8217;images de base. Elles sont toutes faites et prêtes à l&#8217;emploie, que demande le peuple ?</p>
<p><strong>Ça va downloader pendant pas mal de temps</strong>, puis vous aurez plusieurs images à votre disposition, que l&#8217;on peut lister ainsi :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              <span style="color: #000000;">12.04</span>               8dbd9e392a96        <span style="color: #000000;">4</span> months ago        <span style="color: #000000;">131.5</span> MB <span style="color: #7a0874; font-weight: bold;">&#40;</span>virtual <span style="color: #000000;">131.5</span> MB<span style="color: #7a0874; font-weight: bold;">&#41;</span>
ubuntu              <span style="color: #000000;">12.10</span>               b750fe79269d        <span style="color: #000000;">5</span> months ago        <span style="color: #000000;">24.65</span> kB <span style="color: #7a0874; font-weight: bold;">&#40;</span>virtual <span style="color: #000000;">180.1</span> MB<span style="color: #7a0874; font-weight: bold;">&#41;</span>
ubuntu              latest              8dbd9e392a96        <span style="color: #000000;">4</span> months ago        <span style="color: #000000;">131.5</span> MB <span style="color: #7a0874; font-weight: bold;">&#40;</span>virtual <span style="color: #000000;">131.5</span> MB<span style="color: #7a0874; font-weight: bold;">&#41;</span>
ubuntu              precise             8dbd9e392a96        <span style="color: #000000;">4</span> months ago        <span style="color: #000000;">131.5</span> MB <span style="color: #7a0874; font-weight: bold;">&#40;</span>virtual <span style="color: #000000;">131.5</span> MB<span style="color: #7a0874; font-weight: bold;">&#41;</span>
ubuntu              quantal             b750fe79269d        <span style="color: #000000;">5</span> months ago        <span style="color: #000000;">24.65</span> kB <span style="color: #7a0874; font-weight: bold;">&#40;</span>virtual <span style="color: #000000;">180.1</span> MB<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

<p>Vous faites votre marché : quelle image de base voulez-vous utiliser ?</p>
<p>La 12.04 est une LTS qui est déjà bien field testée, donc je vais prendre celle là.</p>
<p>Ensuite, pour lancer une commande avec, il faut faire <code>docker run id_image commande</code>. Ceci va lancer l&#8217;image, lancer la commande, et dès que la commande se termine, arrêter l&#8217;image :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ docker run 74fe38d11401 <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">'YEAHHHHHHHHHHHHHH'</span>
WARNING: Local <span style="color: #7a0874; font-weight: bold;">&#40;</span>127.0.0.1<span style="color: #7a0874; font-weight: bold;">&#41;</span> DNS resolver found <span style="color: #000000; font-weight: bold;">in</span> resolv.conf and containers can<span style="color: #ff0000;">'t use it. Using default external servers : [8.8.8.8 8.8.4.4]
YEAHHHHHHHHHHHHHH</span></pre></div></div>

<p>Mesurons le temps pris en tout pour faire cela :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #000000; font-weight: bold;">time</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;%e seconds&quot;</span> <span style="color: #c20cb9; font-weight: bold;">sudo</span> docker.io run 74fe38d11401 <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">'YEAHHHHHHHHHHHHHH'</span>
WARNING: Local <span style="color: #7a0874; font-weight: bold;">&#40;</span>127.0.0.1<span style="color: #7a0874; font-weight: bold;">&#41;</span> DNS resolver found <span style="color: #000000; font-weight: bold;">in</span> resolv.conf and containers can<span style="color: #ff0000;">'t use it. Using default external servers : [8.8.8.8 8.8.4.4]
YEAHHHHHHHHHHHHHH
0.45 seconds</span></pre></div></div>

<p>Comme vous le voyez, démarrer un conteneur, c&#8217;est vraiment rapide. Mais faire un
<pre lang="python bash">echo</pre>
<p>, ça ne sert pas à grand chose :)</p>
<p>Faisons quelque chose de plus utile : lançons un terminal bash et demandons un accès à stdin/stdout (<code>-i</code>) ainsi qu&#8217;un tty (<code>-t</code>) :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ docker run <span style="color: #660033;">-i</span> <span style="color: #660033;">-t</span> 74fe38d11401 <span style="color: #c20cb9; font-weight: bold;">bash</span>
WARNING: Local <span style="color: #7a0874; font-weight: bold;">&#40;</span>127.0.0.1<span style="color: #7a0874; font-weight: bold;">&#41;</span> DNS resolver found <span style="color: #000000; font-weight: bold;">in</span> resolv.conf and containers can<span style="color: #ff0000;">'t use it. Using default external servers : [8.8.8.8 8.8.4.4]
root@8195e92a5e62:/#</span></pre></div></div>

<p>Et hop, comme le process ne se termine pas tant qu&#8217;on est connecté au tty, on a le conteneur qui continue de tourner, mais on a un terminal dessus, nous permettant d&#8217;entrer n&#8217;importe quelle commande.</p>
<p>Si on installait <a href="http://0bin.net/">0bin</a> ?</p>
<p>D&#8217;abord, on a besoin de pip dans le conteneur:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># apt-get install python-pip</span></pre></div></div>

<p>Notez qu&#8217;on est toujours root dans son conteneur. Après tout, c&#8217;est virtuel et isolé, donc pas de raison de se faire chier.</p>
<p>Ensuite, on tape dans pypi :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># pip install zerobin</span></pre></div></div>

<p>Pas besoin de virtualenv, on est déjà dans un environnement isolé.</p>
<p>Faisons un petit fichier de config. On va avoir besoin de vim :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># apt-get install vim</span>
<span style="color: #666666; font-style: italic;"># cd /home</span>
<span style="color: #666666; font-style: italic;"># vi settings.py</span></pre></div></div>

<p>On met des settings perso pour zerobin, histoire de montrer le principe de faire un conteneur avec un setup sur mesure (on peut, bien entendu, faire 1000 fois plus compliqué, c&#8217;est un exemple bande de bananes) :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># on le fait ecouter sur l'exterieur</span>
HOST = <span style="color: #483d8b;">&quot;0.0.0.0&quot;</span>
<span style="color: #808080; font-style: italic;"># on change le menu de la page d'accueil</span>
MENU = <span style="color: black;">&#40;</span>
    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Home'</span>, <span style="color: #483d8b;">'/'</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Contact'</span>, <span style="color: #483d8b;">'mailto:mysupermail@awesomesite.com'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#41;</span></pre></div></div>

<p>Et on lance notre petit zerobin :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># zerobin --settings-file=settings.py</span></pre></div></div>

<p>Et voilà, on a un zerobin qui tourne dans notre conteneur isolé.</p>
<p>On va sauvegarder tout ça. Sur notre machine hôte (donc pas dans le conteneur), on va sauvegarder notre nouvelle image. D&#8217;abord, on va trouver l&#8217;ID du conteneur qui tourne :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ docker <span style="color: #c20cb9; font-weight: bold;">ps</span>
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                     NAMES
8195e92a5e62        ubuntu:<span style="color: #000000;">12.04</span>        <span style="color: #c20cb9; font-weight: bold;">bash</span>                <span style="color: #000000;">37</span> minutes ago      Up <span style="color: #000000;">37</span> minutes                                 boring_mccarthy</pre></div></div>

<p>Ensuite on commit ce conteneur pour obtenir une nouvele image. Pour faire simple, on va l&#8217;appeller &#8220;zerobin&#8221; :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ docker commit 8195e92a5e62 zerobin</pre></div></div>

<p>On peut alors tranquillement arrêter notre conteneur :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ docker stop 8195e92a5e62</pre></div></div>

<p>Maintenant on peut pusher notre image tout neuve sur un repo distant avec <code>docker push</code> pour pouvoir la puller plus tard. Il faut ouvrir un compte sur leur service ou créer son propre depot, je vous laisse trouver <a href="http://docs.docker.io/use/workingwithrepository/">comment faire</a>. Plus simplement, on peut juste dumper l&#8217;image avec <code>docker save id_image > nom_image.tar</code>, la copier sur une clé USB, et la recharger avec <code>docker load < nom_image.tar</code>.</p>
<p>Dans tous les cas, une fois sur le serveur, vous pouvez lancer votre image "zerobin", ici encore une fois avec la commande bash:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># docker run -t -i -p 7777:8000 zerobin bash</span></pre></div></div>

<p>Cette fois, on rajoute une option de plus : <code>-p 7777:8000</code> dit à docker de relier le port <code>7777</code> de ma machine au port <code>8000</code> (port de 0bin par défaut) de mon conteneur. Ainsi, si une app va sur le port <code>7777</code> de ma machine, elle va en fait parler au port <code>8000</code> du conteneur sans s'en rendre compte.</p>
<p>Du coup, je peux lancer mon petit zerobin depuis mon contenur :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># cd /home</span>
<span style="color: #666666; font-style: italic;"># zerobin --settings-file=settings.py</span></pre></div></div>

<p>Et voilà ! J'ai un zerobin qui marche, qui est préconfiguré, isolé et portable. Si je change de serveur, ou même d'OS, je peux juste reprendre le même conteneur et le relancer tel quel. Et je peux faire ça avec plein de process et les faire communiquer entre eux.</p>
<div id="attachment_10271" class="wp-caption aligncenter" style="width: 336px"><a href="media/73e7747e.Capture-du-2014-05-16-015832.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/Capture-du-2014-05-16-015832.png"><img src="media/73e7747e.Capture-du-2014-05-16-015832.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/Capture-du-2014-05-16-015832.png" alt="Capture d&#039;écran de zerobin" title="J&#039;accède à 7777 sur la machine, mais ça tape sur 8000 dans mon conteneur" width="326" height="179" class="size-full wp-image-10271" /></a><p class="wp-caption-text">J&#039;accède à 7777 sur la machine, mais ça tape sur 8000 dans mon conteneur</p></div>
<p>Docker est un outil très riche, et vous vous doutez bien que je ne vous ai montré que le début.</p>
<p>Par exemple, vous voulez sans doute ne pas avoir à lancer bash, puis un <code>cd</code>, puis zerobin. Ça peut s'automatiser avec un <a href="https://www.docker.io/learn/dockerfile/">dockerfile</a>. Vous voulez aussi peut être lancer le conteneur en arrière plan, ça se fait avec l'option <code>-d</code>. Ou peut être voulez-vous un dossier partagé entre tous les conteneurs ? C'est possible avec l'option <a href="http://docs.docker.io/use/working_with_volumes/">volume</a>.</p>
<p>Parmi les usages vraiment intéressants de dockers : packager les services très custos comme les nginx ou ffmpeg compilés avec des options cryptiques, deployer son app django avec toutes les libs Python et les settings qui vont bien, remplacer une app à chaud en redirigeant juste le load balancer sur le nouveau conteneur, ou encore fournir un env de test à un client. Perso, rien que pour tester des nouveaux logiciels sans pourir ma machine, je trouve ça pratique : on a bien moins peur de faire un <code>make install</code>.</p>
<p>Je vous laisse prendre en main le nouveau joujou, j'ai des serveurs à planter.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10270&amp;md5=8f433005660e2f39d8d2098a80d502ca" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10288
title: Qu’est-ce que la bibliothèque standard Python ?
uri: Qu-est-ce-que-la-bibliothèque-standard-Python
url: http://sametmax.com/quest-ce-que-la-bibliotheque-standard-python/
content:
<p>La lib standard ou stdlib, on vous en parle partout. Ce tuto vous explique comment faire telle tâche avec la lib standard. Ce README dit qu&#8217;il n&#8217;y a que la lib standard comme dépendance, c&#8217;est génial ! Cet article voudrait que le code X soit intégré dans la lib standard.</p>
<p>Mais au fait, c&#8217;est quoi la lib standard ?</p>
<p>Et bien c&#8217;est tout simplement l&#8217;ensemble du code qui est disponible si vous avez Python installé sur votre machine. Si un module fait partie de la bibliothèque standard, vous êtes certain que votre programme Python peut toujours l&#8217;utiliser : il n&#8217;y a rien à installer.</p>
<p>Cette lib standard est également intégralement <a href="https://docs.python.org/3/">documentée</a> sur le site de Python, si bien que si vous <a href="https://docs.python.org/3/download.html">téléchargez</a> la doc hors ligne, vous pouvez quasiment dev en totale autonomie. En effet, même si le principe de la lib standard est le même pour tous les langages, en Python, elle est particulièrement intéressante car vraiment <a href="http://sametmax.com/tres-grand-listing-des-libs-standard-partie-les-plus-utiles-en-python/">énorme</a>. Et en plus vous avez <a href="https://github.com/sametmax/miroir-du-blog">le dump de notre blog</a> :)</p>
<p>Le code de la lib standard évolue lentement, contrairement aux libs tierces parties, car elles sont soumises à des règles strictes et la revue de la communauté à travers des documents officiels : <a href="http://legacy.python.org/dev/peps/">les PEP</a>. Le PEP le plus célèbre étant le <a href="http://legacy.python.org/dev/peps/pep-0008/">PEP 8</a>, qui décrit le style recommandé pour du code Python. </p>
<p>De fait le code de la lib standard est un code fiable, sans surprise, mais qui proposera rarement les dernières innovations. Pour reprendre <a href="https://mail.python.org/pipermail/python-dev/2010-February/097865.html">les mots de Guido</a> :</p>
<blockquote><p>Le code de la stdlib a un pied dans la tombe.</p></blockquote>
<p>Car Python garanti la compatibilité ascendante de TOUTE la lib standard pour une version majeure. Ce qui veut dire que si vous utilisez un module de la stdlib écrit pour Python 2.5, il marchera en Python 2.7, et un module pour 3.1 marchera pour la 3.4.</p>
<p>Mais ça veut dire aussi que le module pourrira ici quand plus personne ne l&#8217;utilisera. La preuve en est <a href="https://docs.python.org/2/library/getopt.html">getopt</a>, qui a été remplacé par <a href="https://docs.python.org/2/library/optparse.html">optparse</a>, qui a été remplacé par <a href="https://docs.python.org/dev/library/argparse.html">argparse</a>. Deux générations de libs plus tard, getopt est toujours importable en 2.7, bien que plus personne ne s&#8217;en serve, pour garantir cette compatibilité. Et en fait, on peut dire 5 générations, car <a href="http://sametmax.com/la-plus-belle-maniere-de-parser-les-arguments-de-script-en-python/">nous-même utilisons docopt après prôné clize</a>. Le monde de l&#8217;IT est comique.</p>
<p>Certains systèmes ébrèchent le principe de la lib standard, comme Ubuntu, qui package la lib TK séparément, et donc oblige à installer le paquet <code>python-tk</code> pour avoir le module <a href="https://docs.python.org/3/library/tkinter.html">tkinter</a>, normalement inclus dans la lib standard. Ce comportement est heureusement assez rare.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10288&amp;md5=e2cd8b8cc19da7088cef06833ad7a43d" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10298
title: Rejouer un session de terminal avec playitagainsam
uri: Rejouer-un-session-de-terminal-avec-playitagainsam
url: http://sametmax.com/rejouer-un-session-de-terminal-avec-playitagainsam/
content:
<p>Combien de fois, durant une formation, on m&#8217;a demandé si je pouvais donner un dump de la session shell.</p>
<p><a href="https://github.com/rfk/playitagainsam">playitagainsam</a>, ou PIAS, a exactement pour but de faire cela: il lance un shell, enregistre ce qu&#8217;on y a tapé, et quand on quitte le shell, sauvegarde le tout dans un fichier. Ensuite, on peut lire le contenu du fichier et revoir la session shell telle qu&#8217;elle a été tapée.</p>
<p>C&#8217;est un programme Python, on peut donc le <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a> installer :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pip <span style="color: #c20cb9; font-weight: bold;">install</span> playitagainsam <span style="color: #660033;">--user</span></pre></div></div>

<p>Ensuite, on lance une session à enregistrer avec la sous commande record :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pias record nom_du_fichier_ou_sauver_l_enregistrement</pre></div></div>

<p>PIAS va lancer un nouveau shell, par défaut le même que votre shell actuel (souvent bash, pour moi fish), mais vous pouvez préciser un type de shell spécial avec <code>--shell</code>. Ex :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pias record ex1 <span style="color: #660033;">--shell</span> ipython</pre></div></div>

<p>A partir de là il n&#8217;y a rien à faire. On peut travailler normalement et oublier qu&#8217;on a utilisé PIAS. Une fois qu&#8217;on a terminé sa petite affaire, il suffit de sortir du shell (CTRL + D, exit, etc), et la session va être sauvegardée dans un format JSON facile à corriger à la main si vous souhaitez la rendre plus agréable :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#123;</span>
  <span style="color: #ff0000;">&quot;events&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#91;</span>
    <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;act&quot;</span>: <span style="color: #ff0000;">&quot;OPEN&quot;</span>,
      <span style="color: #ff0000;">&quot;size&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#91;</span>
        <span style="color: #000000;">162</span>,
        <span style="color: #000000;">33</span>
      <span style="color: #7a0874; font-weight: bold;">&#93;</span>,
      <span style="color: #ff0000;">&quot;term&quot;</span>: <span style="color: #ff0000;">&quot;1c53f048e3a74984b2a93af175e24e87&quot;</span>
    <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
    <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;act&quot;</span>: <span style="color: #ff0000;">&quot;PAUSE&quot;</span>,
      <span style="color: #ff0000;">&quot;duration&quot;</span>: <span style="color: #000000;">0.10042214393615723</span>
    <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
    <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;act&quot;</span>: <span style="color: #ff0000;">&quot;WRITE&quot;</span>,
      <span style="color: #ff0000;">&quot;data&quot;</span>: <span style="color: #ff0000;">&quot;\u001b]0;sam@sametmax.com: /tmp\u0007sam@sametmax.com:/tmp$ &quot;</span>,
      <span style="color: #ff0000;">&quot;term&quot;</span>: <span style="color: #ff0000;">&quot;1c53f048e3a74984b2a93af175e24e87&quot;</span>
    <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
    <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;act&quot;</span>: <span style="color: #ff0000;">&quot;ECHO&quot;</span>,
      <span style="color: #ff0000;">&quot;data&quot;</span>: <span style="color: #ff0000;">&quot;touch essai&quot;</span>,
      <span style="color: #ff0000;">&quot;term&quot;</span>: <span style="color: #ff0000;">&quot;1c53f048e3a74984b2a93af175e24e87&quot;</span>
...
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></div></div>

<p>Quand vous voulez rejouer la session :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pias play fichier_d_enregistrement</pre></div></div>

<p>Par défaut il faut appuyer sur une touche quelconque du clavier pour voir apparaitre chaque caractère, donnant l&#8217;impression que vous êtes un hacker de Hollywood. C&#8217;est rigolo, mais parfaitement chiant à la longue. On peut faire jouer la session automatiquement avec l&#8217;option <code>--auto-type</code> qui va taper chaque ligne automatiquement. Il suffira alors d&#8217;appuyer sur entrée à chaque ligne pour avoir le résultat suivant. C&#8217;est mon mode préféré. </p>
<p>Si vous êtes un gros feignant, vous pouvez tout jouer en automatique en rajoutant l&#8217;option <code>--auto-waypoint</code> qui va vous dispenser de taper entrée à chaque fin de ligne. Ex :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pias play ex1 <span style="color: #660033;">--auto-type</span> <span style="color: #660033;">--auto-waypoint</span></pre></div></div>

<p><strong>La session jouée est simulée.</strong> Elle n&#8217;a aucun impacte sur le système. Si vous faites un <code>mkdir</code> dans bash ou un <code>shutil.rmtree</code> dans python, ça ne fera rien.</p>
<p>Néanmoins, parfois il est utile d&#8217;avoir le effets réels des commandes. Dans ce cas on peut utiliser <code>--live-replay</code>. Attention, faites bien gaffe à ce que vous allez jouer&#8230;</p>
<p>playitagainsam est intéressant pour tout ce qui est formation et tutorial, d&#8217;autant plus qu&#8217;il existe un <a href="https://github.com/rfk/playitagainsam-js/">player javascript</a> pour faire la démonstration de vos sessions shell sur un blog ou un slideshow.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10298&amp;md5=f8ad40489789854c2a7e1de921a8839a" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10304
title: Le Web n’est plus HTTP + HTML
uri: Le-Web-n-est-plus-HTTP-HTML
url: http://sametmax.com/le-web-nest-plus-http/
content:
<p>Si vous voulez énerver un blogger technophile, utilisez le mot Web là où vous devriez utiliser le mot <a href="http://sebsauvage.net/~sebsauva/comprendre/internet/index.html">Internet</a> et inversement.</p>
<p>Internet, c&#8217;est beaucoup plus que le Web. C&#8217;est SSH, IMAP, TELNET, DNS, POP, SMTP, FTP, RTSP, NNTP, Bittorent, TOR, Freenet, Bitcoin, et quelques centaines d&#8217;autres protocoles qui se parlent.</p>
<p>Jusqu&#8217;ici, le Web, c&#8217;était juste HTTP. Des ressources Web, sur lesquelles on agissait via une requête textuelle verbalisée (GET, POST, PUT, OPTION, HEAD, etc) et qui retournait une réponse, généralement en forme de HTML.</p>
<p>Ça a un peu évolué, on a eu SSL qui s&#8217;est rajouté, et donc HTTPS, et AJAX, qui n&#8217;a pas changé le protocole, mais rendu la nature des requêtes un peu différente. Rien qui n&#8217;empêche de debugger avec CURL.</p>
<p>Mais c&#8217;est bientôt fini tout ça.</p>
<p>Aujourd&#8217;hui les nouveaux protocoles utilisés dans le cadre du Web sont en passe de prendre le pouvoir. Bien sûr il y a  <a href="https://en.wikipedia.org/wiki/SPDY">SPDY</a> et <a href="http://en.wikipedia.org/wiki/QUIC">QUIC</a>, mais surtout, il a les protocoles basés sur les websockets type <a href="http://wamp.ws/">WAMP.ws</a>, mais également les nouvelles capacités P2P promises par <a href="http://en.wikipedia.org/wiki/WebRTC">WebRTC</a>. Et des apps qui utilisent massivement les données hors ligne, le scripting JS pour des features essentielles, de la video, du son&#8230;</p>
<p>Et donc adios, l&#8217;époque où vous pouviez juste dégainer <a href="http://docs.python-requests.org/">requests</a> et parler à un site. Bye bye le state less, le human readable, le cycle requête / réponse.</p>
<p>Le nombre de technologies qu&#8217;on doit empiler aujourd&#8217;hui pour déployer un site devient énorme : un moteur de recherche, un message broker, un gestionnaire de fil d&#8217;attente, un gestionnaire de déploiement, des technos d&#8217;isolation&#8230;</p>
<p>C&#8217;est fini la simplicité. C&#8217;est fini la transparence. L&#8217;ère du hacker amateur qui pouvait s&#8217;occuper d&#8217;un peu de tout, touche doucement à sa fin.</p>
<p>Au revoir et merci. Je me suis super amusé.</p>
<p>Et désolé pour les mômes qui arrivent maintenant, vous allez en chier. Mais vous avez aussi plus de possibilités qu&#8217;il n&#8217;y en a jamais eu. Plus qu&#8217;un homme ne peut concevoir. Plus que tous les hommes en fait.</p>
<p>Et RIP HTTP. Ou pas, puisqu&#8217;on passe notre temps à faire des APIs REST maintenant, mais aussi car on est en train de récréer un peu tout au dessus d&#8217;HTTP. Long live HTTP, alors, le nouveau TCP/IP. Sauf quand on fait du real time. Ou du P2P. Changement de status : &#8220;c&#8217;est compliqué entre moi et mon navigateur&#8221;.</p>
<p>Internet, phagocyté par le Web, sur lequel on reconstruit Internet et même le desktop ?</p>
<p>Je ne crois pas qu&#8217;il existe un seul métier qui ait autant changé en 10 ans. J&#8217;espère qu&#8217;on en laisse pas trop derrière en courant comme des fous en riant les yeux mi-clos. Pourvu qu&#8217;il y ait pas trop d&#8217;arbres en face. Pourvu qu&#8217;on aille pas dans la direction de la falaise.</p>
<p>En tout cas, c&#8217;est toujours fun. Je crois que je vais descendre la prochaine pente en roulant sur le côté. Et avoir la tête qui tourne. Vomir. Et dire que c&#8217;est la faute de Javascript.</p>
<p>Et recommencer.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10304&amp;md5=13de9b9bf0222d6b72dd32142bca12d2" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10318
title: Les annonces hypes
uri: Les-annonces-hypes
url: http://sametmax.com/les-annonces-hypes/
content:
<blockquote><p>Nous sommes une start up innovante</p></blockquote>
<p>on a pas de business model</p>
<blockquote><p>à fort potentiel</p></blockquote>
<p>c&#8217;est ma première boîte et ma mère me dit que j&#8217;ai toutes mes chances</p>
<blockquote><p>travaillant à la pointe de la pointe de la technologie</p></blockquote>
<p>mon dernier dev a créé un projet NodeJS sans documentation ni commentaire et s&#8217;est barré</p>
<blockquote><p>en utilisant des méthodes agiles.</p></blockquote>
<p>on a pas de cahier des charges ni de formation à l&#8217;embauche</p>
<blockquote><p>Nous somme à la recherche d&#8217;un dev ninja passionné et autonome</p></blockquote>
<p>on veut un mec qui travaille 80 heures / semaine pas cher à payer</p>
<blockquote><p>capable de mener le projet de bout en bout.</p></blockquote>
<p>je ne sais pas parler au client, coder ou même conduire un projet. Je ne sais rien faire. Je ne sert à rien. J&#8217;ai juste eu une idée un soir d&#8217;apéro. A l&#8217;aide.</p>
<blockquote><p>Vous serez en mesure de travailler avec Linux, HTML5, Postgres, Flask, NodeJS, Coffeescript, MongoDB, Mémécash, AmazonS3, Notepad++, duckduckgo et VLC.</p></blockquote>
<p>Je n&#8217;ai aucune idée de quoi je parle, alors j&#8217;ai mis tout ce que je comprends pas sur la même ligne.</p>
<blockquote><p>Télétravail possible.</p></blockquote>
<p>Je ne veux pas parler de la rémunération alors je finis là dessus. Ça sera surement une part des bénéfices potentiels assurés mirobolants. Pas une trop grosse part, c&#8217;est quand même moi qui a eu l&#8217;idée.</p>
<p>Merde c&#8217;est quoi le mail de ma boîte déjà ? Tant pis je met l&#8217;adresse hotmail.</p>
<p><br/><br />
<br/></p>
<p>Ils prennent whatsapp ? Nan vaut mieux pas, faudrait pas que je passe pour un con.</p>
<p><br/><br />
<br/></p>
<p>Je vais rajouter mon num&#8230; MERDEEEEEEE. J&#8217;ai envoyé le formulaire par erreur.</p>
<p><br/><br />
<br/><br />
<br/><br />
<br/></p>
<p>Ah, c&#8217;est pas le bon site en fait.</p>
<p><br/></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10318&amp;md5=54807f563777b509247d60986e8ded44" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10329
title: Crossbar, le futur des applications Web Python ?
uri: Crossbar-le-futur-des-applications-Web-Python
url: http://sametmax.com/crossbar-le-futur-des-applications-web-python/
content:
<p>Je suis <a href="http://crossbar.io/">crossbar.io</a>  depuis quelques temps maintenant, et je suis très, très étonné de ne pas plus en entendre parler dans la communauté Python.</p>
<p>Bon, en fait, à moitié étonné.</p>
<p>D&#8217;un côté, c&#8217;est une techno qui, à mon sens, représente ce vers quoi Python doit se diriger pour faire copain-copain avec Go/NodeJs et proposer une &#8220;killer feature&#8221; dans le monde des applications serveurs complexes.</p>
<p>De l&#8217;autre, hum, leur page d&#8217;accueil explique à quoi ça sert de cette manière :</p>
<blockquote><p> Crossbar.io is an application router which implements the Web Application Messaging Protocol (WAMP). WAMP provides asynchronous Remote Procedure Calls and Publish &#038; Subscribe (with <a href="http://fr.wikipedia.org/wiki/WebSocket" title="WebSocket" target="_blank">WebSocket</a> being one transport option) and allows to connect application components in distributed systems</p></blockquote>
<p>Moui, moui, moui monseigneur, mais concrètement, là, hein, je peux faire quoi avec ?</p>
<p>C&#8217;est toujours le problème avec les gens intelligents (hein Cortex ?) : ils font des trucs super cool, et personne ne comprend à quoi ça sert parce qu&#8217;il ne sont pas foutu de l&#8217;expliquer.</p>
<p>Moi je suis un peu con, alors je vais profiter qu&#8217;on soit tous au même niveau pour vous faire passer le message.</p>
<p>J&#8217;étais persuadé d&#8217;avoir mis la musique habituel&#8230; Je la remet:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/Z4IWG7IyizU" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Web Application Message Protocol</h2>
<p>Je vous avais parlé d&#8217;<a href="http://sametmax.com/un-petit-gout-de-meteor-js-en-python/">autobahn</a> dernièrement, un client WAMP qui embarque aussi un routeur basique. Crossbar est la partie serveur, un routeur WAMP plus serieux.</p>
<p>Crossbar permet à tous les clients d&#8217;échanger des messages WAMP à travers lui. Bien entendu, un client WAMP peut parler au serveur crossbar et inversement comme un client HTTP peut parler à un serveur Apache/Nginx et inversement. Mais plus que ça, <strong>les clients peuvent parler entre eux, de manière transparente et simple.</strong> Comme un client <a href="http://fr.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol" title="Advanced Message Queuing Protocol" target="_blank">AMQP</a> peut parler aux autres à travers un serveur <a href="http://en.wikipedia.org/wiki/RabbitMQ" title="RabbitMQ" target="_blank">RabbitMQ</a>.</p>
<p> Cependant ça ne vous avance pas si vous ne savez pas ce qu&#8217;est WAMP ou à quoi ça sert. La charrue avec la peau de l&#8217;ours, tout ça.</p>
<p>WAMP est un <a href="http://wamp.ws/spec/">protocole standardisé</a> pour échanger des messages entre deux systèmes. Ce n&#8217;est pas particulièrement lié à Python, on peut parler <strong>WAMP dans n&#8217;importe quel langage.</strong></p>
<p>Il fonctionne en effet, principalement, au dessus de Websocket, donc <strong>on peut l&#8217;utiliser directement dans le navigateur</strong>, dans Firefox, Chrome, Opera, Safari et même IE10, via une lib Javascript. Qui est en fait  juste un gros wrapper autour de l&#8217;API websocket standardisant la manière d&#8217;envoyer des données. Il n&#8217;y a rien de magique derrière, pas de formats compliqués, pas de binaire, c&#8217;est vraiment juste des appels websocket contenant des données formatées en JSON avec une certaine convention. <strong>En ce sens il fait penser à <a href="http://fr.slideshare.net/ngocdaothanh/sockjs-intro" title="sockjs" target="_blank">SockJS</a></strong> et (feu) socket.io.</p>
<p>Seulement contrairement aux solutions type SocketJS, <strong>il n&#8217;est pas limité au navigateur</strong>. Il y a <a href="http://wamp.ws/implementations/">des libs</a> pour l&#8217;utiliser dans un code serveur Python, C++ ou NodeJS, dans une app Android et même directement depuis les entrailles de Nginx ou d&#8217;une base de données Oracle (en SQL) avec certains routeurs.</p>
<div id="attachment_10340" class="wp-caption aligncenter" style="width: 567px"><a href="media/f62bdaeb.general1.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/general1.png"><img src="media/93b86887.general.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/general.png" alt="Schéma général du fonctionnement de WAMP" title="Comme HTTP, WAMP est juste un moyen de faire parvenir des données d&#039;un point A à un point B. Mais contrairement à HTTP, WAMP permet aux clients de parler entre eux, et pas juste au serveur." width="557" height="538" class="size-full wp-image-10340" /></a><p class="wp-caption-text">Comme HTTP, WAMP est juste un moyen de faire parvenir des données d&#039;un point A à un point B. Mais contrairement à HTTP, WAMP permet aux clients de parler entre eux, et pas juste au serveur.</p></div>
<p><strong>Comprenez bien, ça veut dire qu&#8217;on peut envoyer et recevoir des données arbitraires, en temps réel, entre tous ces systèmes, sans se prendre la tête, et de manière transparente.</strong></p>
<p>WAMP c&#8217;est donc comme, mais mieux que :</p>
<ul>
<li>des requêtes HTTP, car c&#8217;est du push, asynchrone et temps réel;</li>
<li>des requêtes websocket via SocketJS car c&#8217;est un standard, qui fonctionne SUR et ENTRE plusieurs services côtés serveurs malgré les différents langages;</li>
<li>des messages AMQP car ça marche dans le navigateur et ça se configure facilement.</li>
</ul>
<p>Bien utilisé, Crossbar permet d&#8217;amener Python dans la cours de frameworks &#8220;temps réel&#8221; novateurs comme <a href="http://fr.wikipedia.org/wiki/Meteor_(framework)" title="Meteor" target="_blank">MeteorJS</a>, et potentiellement les dépasser.</p>
<p>Car WAMP permet de faire deux choses. Simplement. Et bien.</p>
<h3>1 &#8211; Du PUB/SUB</h3>
<p>Donc de dire dans son code &#8220;appelle cette fonction quand cet événement arrive&#8221;. <strong>C&#8217;est comme les signaux de Django ou QT, mais ça marche à travers le réseau.</strong> On le fait souvent avec Redis ces temps-ci. Avec WAMP et Javascript, ça donne :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// connection au routeur WAMP (par exemple, crossbar.io)</span>
ab.<span style="color: #660066;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;ws://localhost:9000&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>session<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">// je m'inscris à un événement</span>
    session.<span style="color: #660066;">subscribe</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'un_evenement_qui_vous_plait'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>topic<span style="color: #339933;">,</span> evt<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// faire un truc avec les données reçues</span>
        <span style="color: #006600; font-style: italic;">// à chaque fois que l'événement est envoyé</span>
        <span style="color: #006600; font-style: italic;">// par exemple mettre la page à jour</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<div id="attachment_10343" class="wp-caption aligncenter" style="width: 571px"><a href="media/768088a6.sub.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/sub.png"><img src="media/768088a6.sub.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/sub.png" alt="Schéma de fonctionnement du subscribe de WAMP" title="Des client SUBscribe à un événément. Un événément est un nom arbitrairement choisit par le programmeur, et qu&#039;il va déclencher lui-même quand il pense qu&#039;il se passe quelque chose d&#039;important auquel il faut que le reste du signal réagisse. " width="561" height="572" class="size-full wp-image-10343" /></a><p class="wp-caption-text">Des client SUBscribe à un événément. Un événément est un nom arbitrairement choisit par le programmeur, et qu&#039;il va déclencher lui-même quand il pense qu&#039;il se passe quelque chose d&#039;important auquel il faut que le reste du signal réagisse. </p></div>
<p>Et ailleurs, dans une autre partie du fichier, ou même sur un autre navigateur Web :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">ab.<span style="color: #660066;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;ws://localhost:9000&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>session<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">// création d'un événement auquel on attache des données</span>
    session.<span style="color: #660066;">publish</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'un_evenement_qui_vous_plait'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">'des données'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<div id="attachment_10344" class="wp-caption aligncenter" style="width: 565px"><a href="media/f07cb46a.pub.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/pub.png"><img src="media/f07cb46a.pub.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/pub.png" alt="Schéma de fonctionnement de PUB avec WAMP" title="Le programmeur décide que quelque chose d&#039;important arrive (création d&#039;un contenu, login d&#039;un utilisateur, notification), et PUBlish l&#039;événement" width="555" height="452" class="size-full wp-image-10344" /></a><p class="wp-caption-text">Le programmeur décide que quelque chose d&#039;important arrive (création d&#039;un contenu, login d&#039;un utilisateur, notification), et PUBlish l&#039;événement</p></div>
<p>Et oui, c&#8217;est tout. On se connecte à crossbar, et on discute. La fonction du <code>subscribe</code> sera alors appelée avec les données du <code>publish</code>. Même si il y a 3000 km entre les deux codes. Même si le code A est sur un navigateur et le B sur un autre, ou sur un serveur NodeJS, ou une app Android.</p>
<p>Ce qui fait peur au début, c&#8217;est qu&#8217;il y a TROP de flexibilité :</p>
<ul>
<li>Je dois attendre quoi comme événements ?</li>
<li>Qu&#8217;est-ce que je passe comme données ?</li>
<li>Est-ce que c&#8217;est rapide ? Léger ?</li>
</ul>
<p>Mais en fait c&#8217;est super simple : un événement c&#8217;est juste une action de votre application comme un élément (un post, un commentaire, un utilisateur&#8230;) ajouté, supprimé ou modifié. Finalement c&#8217;est le bon vieux <a href="http://fr.wikipedia.org/wiki/CRUD" title="CRUD" target="_blank">CRUD</a>, mais en temps réel, et en push, au lieu du pull. Vous choisissez un nom qui représente cette action, vous attachez des données à ce nom, voilà, c&#8217;est un événement que tous les abonnés peuvent recevoir.</p>
<p>Avec un bonus : ça marche sur le serveur aussi ! Votre code Python reçoit &#8220;ajouter un commentaire&#8221; comme événement ? Il peut ajouter le commentaire en base de données, envoyer un message à un service de cache ou à un autre site en NodeJS pour le mettre à jour, renvoyer un événement pour mettre à jour les pages Web et l&#8217;app Android, etc.</p>
<p>On peut passer n&#8217;importe quelles données qui peut se JSONiser. En gros n&#8217;importe quoi qu&#8217;on enverrait via HTTP. Donc des données très structurées, imbriquées et complexes comme des données géographiques, ou très simples comme des notifications.</p>
<p><strong>Avec PUB / SUB, WAMP remplace tout ce qu&#8217;on ferait normalement avec des appels AJAX dans le browser, et tout ce qu&#8217;on ferait avec des files de message côté serveur. </strong>Plus puissant encore, il permet de relier ces deux mondes.</p>
<p>Et même si on atteint pas les perfs de <a href="http://en.wikipedia.org/wiki/%C3%98MQ" title="ZeroMQ" target="_blank">ZeroMQ</a> (qui n&#8217;a pas de serveur central), c&#8217;est très <a href="https://into.aalto.fi/download/attachments/12324178/Huang_Fuguo_thesis_2.pdf?version=1&#038;modificationDate=1383290628000">performant et léger</a>.</p>
<h3>2 &#8211; Du RPC</h3>
<p>Appeler une fonction située ailleurs que dans son code. C&#8217;est vieux comme le monde (si vous avez des souvenirs douloureux de CORBA et SOAP, levez la main), et c&#8217;est extrêmement pratique. Pour faire simple, continuons avec un exemple en Javascript, mais rappelez-vous que ça marche pareil en C++ ou Python :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">ab.<span style="color: #660066;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;ws://localhost:9000&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>session<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #003366; font-weight: bold;">function</span> une_fonction<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> b<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span> a <span style="color: #339933;">+</span> b<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #006600; font-style: italic;">// on déclare que cette fonction est appelable à distance</span>
   session.<span style="color: #660066;">register</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'une_fonction'</span><span style="color: #339933;">,</span> une_fonction<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<div id="attachment_10347" class="wp-caption aligncenter" style="width: 574px"><a href="media/48127c83.register1.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/register1.png"><img src="media/a7786312.register.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/register.png" alt="Schéma expliquant register avec WAMP" title="RPC marche à l&#039;envers de PUB/SUB. Un client expose du code, et un autre demande explicitement qu&#039;il soit exécuté." width="564" height="469" class="size-full wp-image-10347" /></a><p class="wp-caption-text">RPC marche à l&#039;envers de PUB/SUB. Un client expose du code, et un autre demande explicitement qu&#039;il soit exécuté.</p></div>
<p>Côté appelant :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">ab.<span style="color: #660066;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;ws://localhost:9000&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>session<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">// on appelle la fonction à distance, on récupère une</span>
    <span style="color: #006600; font-style: italic;">// promise qui nous permet de travailler sur le résultat</span>
   session.<span style="color: #660066;">call</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'une_fonction'</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">then</span><span style="color: #009900;">&#40;</span>
      <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
         console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
   <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<div id="attachment_10348" class="wp-caption aligncenter" style="width: 552px"><a href="media/c8ffda1b.call.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/call.png"><img src="media/c8ffda1b.call.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/call.png" alt="Schéma expliquant CALL en WAMP" title="Contrairement à PUB/SUB, RPC ne concerne que deux clients à la fois. Mais ça reste asynchrone. Le client demandeur n&#039;attend pas le résultat de l&#039;appel de la fonction. Il est signalé par le serveur quand il est prêt." width="542" height="548" class="size-full wp-image-10348" /></a><p class="wp-caption-text">Contrairement à PUB/SUB, RPC ne concerne que deux clients à la fois. Mais ça reste asynchrone. Le client demandeur n&#039;attend pas le résultat de l&#039;appel de la fonction. Il est signalé par le serveur quand il est prêt.</p></div>
<p>Pareil que pour le PUB/SUB, les gens ont du mal à voir l&#8217;utilité à cause du trop de flexibilité que ça apporte. Imaginez que votre projet soit maintenant éclaté en de nombreux petits services qui tournent et qui sont indépendants :</p>
<ul>
<li>Un service pour le site Web.</li>
<li>Un service d&#8217;authentification.</li>
<li>Un service pour l&#8217;API.</li>
<li>Un service pour les tâches longues.</li>
<li>Un service de monitoring et administration technique.</li>
</ul>
<p>Tous ces services peuvent ainsi communiquer entre eux via RPC, mais n&#8217;ont pas besoin d&#8217;être dans le même processus. On peut profiter pleinement de tous les cœurs de sa machine, on peut même les mettre sur des serveurs séparés.</p>
<p>Mieux, avoir un service bloquant ne pénalise pas tout le système. En effet, un problème avec les systèmes asynchrones en Python est que beaucoup de libs sont encore bloquantes (typiquement les ORMs). <strong>Avec ce genre d&#8217;architecture, on peut créer un service qui ne fait que les appels bloquant et laisser les autres services non bloquant l&#8217;appeler de manière asynchrone.</strong> Pendant qu&#8217;il bloque, le reste du système peut traiter d&#8217;autres requêtes.</p>
<h2>Crossbar, plus qu&#8217;un routeur WAMP</h2>
<p>L&#8217;idée des concepteurs de crossbar est de permettre de créer des systèmes avec des services composables qui communiquent entre eux plutôt que tout dans un gros processus central. Ils ne se sont donc pas arrêtés au routing.</p>
<p>Crossar est également un gestionnaire de processus, comme <a href="https://pypi.python.org/pypi/supervisor/3.0">supervisor</a> ou, plus légitimement, <a href="https://pypi.python.org/pypi/circus/0.11.1">circus</a> (Tarek, fait une pause, vient ici !) et sa communication ZeroMQ.</p>
<p>Il se configure avec un simple fichier JSON, et on peut y définir des classes Python qui seront lancées dans un processus séparé et pourront discuter avec les autres clients via WAMP :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#123;</span>
   <span style="color: #3366CC;">&quot;processes&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
      <span style="color: #009900;">&#123;</span> <span style="color: #006600; font-style: italic;">// premier processus</span>
         <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;worker&quot;</span><span style="color: #339933;">,</span>
         <span style="color: #3366CC;">&quot;modules&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span>
               un_worker.<span style="color: #660066;">Classe</span>
            <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span>
               un_autre_worker.<span style="color: #660066;">Classe</span>
            <span style="color: #009900;">&#125;</span>
         <span style="color: #009900;">&#93;</span>
      <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#123;</span>  <span style="color: #006600; font-style: italic;">// second processus</span>
         <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;worker&quot;</span><span style="color: #339933;">,</span>
         <span style="color: #3366CC;">&quot;modules&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span>
               un_autre_worker_dans_un_autre_process.<span style="color: #660066;">Classe</span>
            <span style="color: #009900;">&#125;</span>
         <span style="color: #009900;">&#93;</span>
      <span style="color: #009900;">&#125;</span>
   <span style="color: #009900;">&#93;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Mais si ça ne suffit pas, on peut également lancer des programmes extérieurs non Python dont crossbar va gérer le cycle de vie :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#123;</span>
   <span style="color: #3366CC;">&quot;processes&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
      <span style="color: #009900;">&#123;</span>
         <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;guest&quot;</span><span style="color: #339933;">,</span>
         <span style="color: #3366CC;">&quot;executable&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;/usr/bin/node&quot;</span><span style="color: #339933;">,</span>
         <span style="color: #3366CC;">&quot;arguments&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;votre_script.js&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
         <span style="color: #3366CC;">&quot;stdout&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;log&quot;</span>
      <span style="color: #009900;">&#125;</span>
   <span style="color: #009900;">&#93;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Vous avez donc ainsi les deux atouts pour avoir <strong>une architecture découplée, scalable, exploitant plusieurs cœurs, et compensant en partie les bibliothèques blocantes</strong> :</p>
<ul>
<li>Un protocole flexible, simple, qui permet à tout le monde se parler entre eux (WAMP).</li>
<li>Une API qui permet soit de réagir à un changement (PUB/SUB), soit de demander une action (RPC).</li>
<li>Un programme qui gère cette communication, et le cycle de vie des composants qui parlent entre eux.</li>
</ul>
<h2>Cas concret</h2>
<p>WAMP est typiquement le genre de techno qui ne permet PAS de faire quelque chose qu&#8217;on ne faisait pas avant. Ce n&#8217;est pas nouveau.</p>
<p>En revanche, WAMP permet de le faire mieux et plus facilement.</p>
<p>Prenez le cas d&#8217;un utilisateur qui se connecte sur un forum. Il va sur un formulaire, il post ses identifiants, ça recharche la page, il est connecté. Si les autres utilisateurs rechargent leurs pages, ils verront un utilisateur de plus connecté.</p>
<p>Si on veut rendre ça plus dynamique, il faut utiliser de l&#8217;AJAX, et si on veut avoir une mise à jour presque en temps réel, il faut faire des requêtes Ajax régulière. Ce qui est assez bancal et demande beaucoup de travail manuel.</p>
<p>Certains sites modernes utilisent Websocket, et des serveurs asyncrones comme NodeJS, et un routeur PUB/SUB comme redis, pour faire cela de manière rapide et plus facile. L&#8217;application est très réactive. Mais le système est hétéroclite. Et si on veut envoyer des messages entre des composants serveurs, ça demande encore quelque chose de différent.</p>
<p>WAMP unifie tout ça. Un coup de RPC pour le login pour effectuer l&#8217;action:</p>
<div id="attachment_10351" class="wp-caption aligncenter" style="width: 552px"><a href="media/3ff3af7b.rpc_concret.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/rpc_concret.png"><img src="media/3ff3af7b.rpc_concret.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/rpc_concret.png" alt="Schéma d&#039;un exemple concret de RPC WAMP" title="Notez que le RPC marche de n&#039;importe quel client à n&#039;importe quel client. Il n&#039;y a pas de sens obligatoire. Le login est un exemple simple mais on peut faire des choses bien plus complexes." width="542" height="592" class="size-full wp-image-10351" /></a><p class="wp-caption-text">Notez que le RPC marche de n&#039;importe quel client à n&#039;importe quel client. Il n&#039;y a pas de sens obligatoire. Le login est un exemple simple mais on peut faire des choses bien plus complexes.</p></div>
<p>Et un coup de PUB/SUB pour prévenir tout le monde que quelque chose s&#8217;est passé :</p>
<div id="attachment_10352" class="wp-caption aligncenter" style="width: 549px"><a href="media/a4ce678d.pub_sub_concret.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/pub_sub_concret.png"><img src="media/a4ce678d.pub_sub_concret.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/05/pub_sub_concret.png" alt="Schéma d&#039;exemple concret de PUB/SUB avec WAMP" title="Je n&#039;ai mis que des clients légers ici, mais je vous rappelle qu&#039;un client peut être un serveur NodeJS, une base de données, un code C++..." width="539" height="626" class="size-full wp-image-10352" /></a><p class="wp-caption-text">Je n&#039;ai mis que des clients légers ici, mais je vous rappelle qu&#039;un client peut être un serveur NodeJS, une base de données, un code C++...</p></div>
<p>Bien entendu, on pourrait faire ça avec les technos existantes. C&#8217;est juste moins pratique.</p>
<p>Notez également que Crossbar encourage à avoir un service qui ne se charge que du login, sans avoir à faire une usine à gaz pour cela. Si demain votre service de login a besoin d&#8217;être sur un coeur/serveur/une VM séparé pour des raisons de perfs ou de sécurité, c&#8217;est possible. Crossbar encourage ce genre de design.</p>
<h2>Voici où est le piège</h2>
<p>Car évidement, il y en a toujours un, putain de métier à la con.</p>
<p><strong>Et c&#8217;est la jeunesse du projet.</strong></p>
<p>Le projet est stable, le code marche, et les sources sont propres.</p>
<p>Mais la doc, mon dieu la doc&#8230; Les exemples sont pas à jour, il y a deux versions qui se battent en duel, on sait pas trop quelle partie sert à quoi.</p>
<p>Et comme tout projet jeune, l&#8217;API n&#8217;a pas été assez étudiée. Or la partie Python est basée sur Twisted, sans polish. Twisted, c&#8217;est puissant, c&#8217;est solide, et c&#8217;est aussi une API dégueulasse.</p>
<p>Un exemple ? Comment écouter un événement :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Des imports légers</span>
<span style="color: #ff7700;font-weight:bold;">from</span> twisted.<span style="color: black;">python</span> <span style="color: #ff7700;font-weight:bold;">import</span> log
<span style="color: #ff7700;font-weight:bold;">from</span> twisted.<span style="color: black;">internet</span>.<span style="color: black;">defer</span> <span style="color: #ff7700;font-weight:bold;">import</span> inlineCallbacks
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> autobahn.<span style="color: black;">twisted</span>.<span style="color: black;">wamp</span> <span style="color: #ff7700;font-weight:bold;">import</span> ApplicationSession
<span style="color: #ff7700;font-weight:bold;">from</span> autobahn.<span style="color: black;">twisted</span>.<span style="color: black;">wamp</span> <span style="color: #ff7700;font-weight:bold;">import</span> ApplicationRunner
&nbsp;
<span style="color: #808080; font-style: italic;"># Une bonne classe bien subtile pour copier Java</span>
<span style="color: #ff7700;font-weight:bold;">class</span> ListenForEvent<span style="color: black;">&#40;</span>ApplicationSession<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Deux méthodes de boiler plate obligatoires</span>
    <span style="color: #808080; font-style: italic;"># et parfaitement soulantes pour l'utilisateur</span>
    <span style="color: #808080; font-style: italic;"># final. Cachez moi ça bordel !</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, config<span style="color: black;">&#41;</span>:
        ApplicationSession.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">config</span> = config
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> onConnect<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">config</span>.<span style="color: black;">realm</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Bon, on se décide, soit on fait une classe avec des noms</span>
    <span style="color: #808080; font-style: italic;"># de méthode conventionnés, soit on met des décorateurs, </span>
    <span style="color: #808080; font-style: italic;"># mais pas les deux, pitié !</span>
    @inlineCallbacks
    <span style="color: #ff7700;font-weight:bold;">def</span> onJoin<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, details<span style="color: black;">&#41;</span>:
        callback = <span style="color: #ff7700;font-weight:bold;">lambda</span> x: log.<span style="color: black;">msg</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Received event %s&quot;</span> <span style="color: #66cc66;">%</span> x<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #008000;">self</span>.<span style="color: black;">subscribe</span><span style="color: black;">&#40;</span>callback, <span style="color: #483d8b;">'un_evenement'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Python doit lancer explicitement un event loop.</span>
<span style="color: #808080; font-style: italic;"># Ca pourrait (devrait) aussi être embeded dans une</span>
<span style="color: #808080; font-style: italic;"># sousclasse de ApplicationSession.</span>
<span style="color: #808080; font-style: italic;"># /me prend un colt. BANG !</span>
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
   runner = ApplicationRunner<span style="color: black;">&#40;</span>endpoint=<span style="color: #483d8b;">&quot;tcp:127.0.0.1:8080&quot;</span>,
                              url=<span style="color: #483d8b;">&quot;ws://localhost:8080/ws&quot;</span>,
                              realm=<span style="color: #483d8b;">&quot;realm1&quot;</span><span style="color: black;">&#41;</span>
   runner.<span style="color: black;">run</span><span style="color: black;">&#40;</span>ListenForEvent<span style="color: black;">&#41;</span></pre></div></div>

<p>C&#8217;est la raison pour laquelle je vous ai montré le code JS et pas Python pour vous vendre le truc. Sur sametmax.com, on aura tout vu :(</p>
<p>Voilà à quoi devrait ressembler le code Python si l&#8217;API était mature :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> autobahn.<span style="color: black;">app</span> <span style="color: #ff7700;font-weight:bold;">import</span> App
&nbsp;
app = App<span style="color: black;">&#40;</span>url=<span style="color: #483d8b;">&quot;ws://localhost:8080/ws&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
@event<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;un_evenement&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> handle<span style="color: black;">&#40;</span>details<span style="color: black;">&#41;</span>:
    app.<span style="color: black;">log</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Received event %s&quot;</span> <span style="color: #66cc66;">%</span> x<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
   app.<span style="color: black;">run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Chose que je vais proposer sur <a href="https://groups.google.com/forum/#!forum/autobahnws">la mailing list</a> (ils sont réactifs et sympas, vive les allemands !) dans pas longtemps. Et si ils n&#8217;ont pas le temps de le faire, il est possible que je m&#8217;y colle. Ca me fait mal aux yeux.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10329&amp;md5=2b5a9171d8db1d78ae97c44b719b748b" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10360
title: Requests fait partie de la lib standard !
uri: Requests-fait-partie-de-la-lib-standard
url: http://sametmax.com/requests-fait-partie-de-la-lib-standard/
content:
<p>Enfin, presque :)</p>
<p>J&#8217;étais en train d&#8217;installer en vieux requirements.txt quand soudain :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">  File <span style="color: #483d8b;">&quot;
&nbsp;
/usr/lib/python2.7/dist-packages/pip/download.py&quot;</span>, line <span style="color: #ff4500;">23</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> requests.<span style="color: black;">adapters</span> <span style="color: #ff7700;font-weight:bold;">import</span> BaseAdapter
<span style="color: #008000;">ImportError</span>: No module named adapters</pre></div></div>

<p>Wut ?</p>
<p>Mon erreur était due à une version de requests trop ancienne. J&#8217;upgrade et ça remarche. Mais ça m&#8217;a intrigué :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">⟩ grin <span style="color: #ff0000;">&quot;requests&quot;</span>  <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>python2.7<span style="color: #000000; font-weight: bold;">/</span>dist-packages<span style="color: #000000; font-weight: bold;">/</span>pip<span style="color: #000000; font-weight: bold;">/</span>
<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>python2.7<span style="color: #000000; font-weight: bold;">/</span>dist-packages<span style="color: #000000; font-weight: bold;">/</span>pip<span style="color: #000000; font-weight: bold;">/</span>download.py:
   <span style="color: #000000;">22</span> : import requests, six
   <span style="color: #000000;">23</span> : from requests.adapters import BaseAdapter
   <span style="color: #000000;">24</span> : from requests.auth import AuthBase, HTTPBasicAuth
   <span style="color: #000000;">25</span> : from requests.compat import IncompleteRead
   <span style="color: #000000;">26</span> : from requests.exceptions import InvalidURL, ChunkedEncodingError
   <span style="color: #000000;">27</span> : from requests.models import Response
   <span style="color: #000000;">28</span> : from requests.structures import CaseInsensitiveDict
  <span style="color: #000000;">120</span> :         <span style="color: #666666; font-style: italic;"># Store the new username and password to use for future requests</span>
  <span style="color: #000000;">182</span> :         <span style="color: #666666; font-style: italic;"># We only work for requests with a host of localhost</span>
  <span style="color: #000000;">211</span> : class PipSession<span style="color: #7a0874; font-weight: bold;">&#40;</span>requests.Session<span style="color: #7a0874; font-weight: bold;">&#41;</span>:
  <span style="color: #000000;">548</span> :         except requests.HTTPError <span style="color: #c20cb9; font-weight: bold;">as</span> exc:
<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>python2.7<span style="color: #000000; font-weight: bold;">/</span>dist-packages<span style="color: #000000; font-weight: bold;">/</span>pip<span style="color: #000000; font-weight: bold;">/</span>index.py:
   <span style="color: #000000;">17</span> : import html5lib, requests, pkg_resources
   <span style="color: #000000;">18</span> : from requests.exceptions import SSLError
   <span style="color: #000000;">80</span> :         <span style="color: #666666; font-style: italic;"># The Session we'll use to make requests</span>
  <span style="color: #000000;">689</span> :         except requests.HTTPError <span style="color: #c20cb9; font-weight: bold;">as</span> exc:
  <span style="color: #000000;">692</span> :         except requests.ConnectionError <span style="color: #c20cb9; font-weight: bold;">as</span> exc:
  <span style="color: #000000;">697</span> :         except requests.Timeout:</pre></div></div>

<p>Je regarde le code source github, qui <a href="https://github.com/pypa/pip/blob/develop/pip/download.py">diffère</a> de celui de mon système :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> pip._vendor.<span style="color: black;">requests</span>.<span style="color: black;">adapters</span> <span style="color: #ff7700;font-weight:bold;">import</span> BaseAdapter, HTTPAdapter
<span style="color: #ff7700;font-weight:bold;">from</span> pip._vendor.<span style="color: black;">requests</span>.<span style="color: black;">auth</span> <span style="color: #ff7700;font-weight:bold;">import</span> AuthBase, HTTPBasicAuth
<span style="color: #ff7700;font-weight:bold;">from</span> pip._vendor.<span style="color: black;">requests</span>.<span style="color: black;">compat</span> <span style="color: #ff7700;font-weight:bold;">import</span> IncompleteRead
<span style="color: #ff7700;font-weight:bold;">from</span> pip._vendor.<span style="color: black;">requests</span>.<span style="color: #dc143c;">exceptions</span> <span style="color: #ff7700;font-weight:bold;">import</span> ChunkedEncodingError</pre></div></div>

<p>Mais ça reste bien requests.</p>
<p>Donc, si vous avez la 3.4, vous avez pip installé, qui maintenant embed requests. Donc Python 3.4 vient forcément avec requests \o/</p>
<p>Si vous supportez uniquement cette plateforme, vous pouvez faire :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
    <span style="color: #ff7700;font-weight:bold;">import</span> requests
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">ImportError</span>:
    <span style="color: #ff7700;font-weight:bold;">import</span> pip._vendor.<span style="color: black;">requests</span> <span style="color: #ff7700;font-weight:bold;">as</span> requests</pre></div></div>

<p>Et bénéficier de requests sans rien installer.</p>
<p>Tout ça pour ça.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10360&amp;md5=e11dac73209a8ba3f9bfbd52186e5fd6" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10371
title: 10 raisons égoïstes pour s’investir dans les préliminaires
uri: 10-raisons-égoïstes-pour-s-investir-dans-les-préliminaires
url: http://sametmax.com/10-raisons-egoistes-pour-sinvestir-dans-les-preliminaires/
content:
<p>Je pense que vous vous êtes TOUS fait rabâcher que les préliminaires c&#8217;est important  qu&#8217;il faut s&#8217;occuper de l&#8217;autre, le sexe c&#8217;est du partage, et gna gna gna, bla bla bla, trolololo lololo lololo.</p>
<p>Le truc c&#8217;est que ce genre d&#8217;arguments ne va parler qu&#8217;à des gens qui sont DÉJÀ de nature à en faire. Prêcher des convertis, c&#8217;est bon pour l&#8217;égo mais ça construit pas grand chose. C&#8217;est pas bon comme Lego. Ok, je => [].</p>
<p>Bref, voici 10 bonnes raisons de faire des préliminaires, parce que ça vous rapporte quelque chose <strong>à vous</strong>.</p>
<h2>1 &#8211; On dure plus longtemps</h2>
<p>Passé une certaine durée d’érection, le corps s&#8217;adapte pour passer en mode endurance. Du coup plus de préliminaires = plus de temps à bander sans trop monter en sauce = plus de temps à bander tout court. </p>
<p>Donc plus de baise. Des performances plus flatteuses. Le temps d&#8217;essayer plus de positions.</p>
<p>Et puis plus d&#8217;opportunité de la faire jouir, puisque ça prend souvent plus de temps que pour nous. Et franchement, qu&#8217;est-ce qu&#8217;il y a de plus sexy qu&#8217;une meuf à qui on est en train de faire prendre son pied ?</p>
<h2>2 &#8211; On chope plus</h2>
<p>Les meufs parlent entre elles. Si vous êtes un bon coup, ça se saura : un secret, c&#8217;est quelque chose que l&#8217;on ne répète qu&#8217;à une personne à la fois. Du coup, rapidement, les copines des copines (un degré de séparation est nécessaire le plus souvent pour en bénéficier) vous voient comme un partenaire sexuel valable.</p>
<h2>3 &#8211; On est en meilleure forme</h2>
<p>Les préliminaire impliquent souvent de tenir des positions qui font travailler vos muscles, votre cœur, votre respiration. Plus il y a de préliminaires, plus votre séance de gym en l&#8217;air devient complète.</p>
<p>Franchement, garder la forme en niquant, y a pire.</p>
<h2>4 &#8211; On a une plus belle peau</h2>
<p>Plus de transpiration et plus de caresses, plus de frictions donc un scrubing + hammam gratos. Votre peau va s&#8217;en trouver toute renouvelée.</p>
<p>Or, scoop, la peau est un facteur hyper important de sex appeal. En fait, avoir une belle peau compense beaucoup d&#8217;autres problèmes. Par exemple, si vous êtes en surpoids avec un superbe épiderme, vous paraissez en bonne santé et donc baisable, si vous avez une super silhouette et une peau de merde, vous donnez autant d&#8217;envie qu&#8217;un lépreux.</p>
<p>Désolé pour les gens à peau difficile, je connais ça, j&#8217;ai été victime de tout un tas de trucs dermatologiquement inesthétiques.</p>
<h2>5 &#8211; Plus de chance de pouvoir choisir où vous venez </h2>
<p>Si vous aimez lui gicler dans la bouche, le cul ou sur les nichons, avoir bien fait monter en température la demoiselle aide beaucoup. Dans le feu de l&#8217;action, on accepte beaucoup plus de choses. La sodomie, douloureuse à froid, peut devenir super excitante quand elle est à fond. Avaler se fera parfois naturellement si vous lui avez léché copieusement la touffe avant. Etc.</p>
<h2>6 &#8211; Plus de sexe avec la même partenaire</h2>
<p>Ça stimule la libido. Et donc si vous avez une fille qui à pas souvent envie, tout d&#8217;un coup, paf, elle répond vachement mieux aux sollicitations. Merci capitaine obvious, tu peux refermer ta braguette maintenant.</p>
<h2>7 &#8211; Plus de jeux pervers</h2>
<p>Ça va avec les deux précédents, mais si vous faites frémir votre partenaire, elle sera forcément plus en confiance pour mettre un costume d&#8217;écolière et s&#8217;empaler sur une tentacule en plastique tout en criant &#8220;Yameru, Kyōju-Sama !&#8221;.</p>
<p>Il faut dire que le cul, ça peut facilement tourner en rond. Du coup, faire des trucs funs et osés en entrée, ça amène un peu de renouveau.</p>
<h2>8 &#8211; Plus de temps pour mettre la capote</h2>
<p>Franchement, c&#8217;est toujours mieux d&#8217;enfiler le bout de plastique quand on a sa langue dans sa chatte que de s&#8217;arrêter pour ça.</p>
<h2>9 &#8211; Plus de temps pour voir si c&#8217;est une vraie rousse</h2>
<p>Je me pose toujours la question.</p>
<h2>10 &#8211; Un passport pour les quickies</h2>
<p>Envie de venir en deux minutes ? Vous pouvez, vous lui avez révolutionné la Sardaigne hier ! C&#8217;est le moment de la monter directement sur la table basse, lui baisser le fut de 20 cm, venir, et repartir comme si de rien n&#8217;était.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10371&amp;md5=8429c4b801f4f3460ea2991692e2f6a3" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10380
title: Le potentiel de WAMP, autobahn et crossbar.io
uri: Le-potentiel-de-WAMP-autobahn-et-crossbar-io
url: http://sametmax.com/le-potentiel-de-wamp-autobahn-et-crossbar-io/
content:
<p>Je sais, je sais, je vous fais chier avec <a href="http://sametmax.com/crossbar-le-futur-des-applications-web-python/">crossbar</a> et <a href="http://sametmax.com/un-petit-gout-de-meteor-js-en-python/">autobahn</a>.</p>
<p>Mais ça me tue de ne pas voir plus de monde exploiter cette techno.</p>
<p>Pendant que Max fait la sieste, j&#8217;ai pris mon stylo et j&#8217;ai fait la liste des besoins d&#8217;une app Web actuelle. Quels sont les composants qu&#8217;on utilise presque systématiquement, mais en agrégeant divers bouts de trucs à droite et à gauche ?</p>
<p>Ensuite j&#8217;ai regardé les possibilités des outils WAMP :</p>
<ul>
<li>PUB/SUB et RPC.</li>
<li>Asynchrone.</li>
<li>Gestionnaire de process intégré.</li>
<li>Serveur stand alone qui n&#8217;a pas besoin d&#8217;un proxy pour être en prod.</li>
</ul>
<p>M&#8217;inspirant de cela, et du travail que je suis en train de faire avec l&#8217;équipe de Tavendo pour faire une API flaskesque pour autobahn, j&#8217;ai prototypé une API d&#8217;un framework Web qu&#8217;on pourrait coder au dessus de cette techno.</p>
<p>Voilà ce que ça donne&#8230;</p>
<p>Une API qui mélange flask et nodejs pour le Web</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">app = Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'YourProjectName'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Envoyer et recevoir des requêtes HTTP</span>
@app.<span style="color: black;">http</span>.<span style="color: black;">post</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'/form'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>req, res<span style="color: black;">&#41;</span>:
    res.<span style="color: black;">json</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'data'</span>: <span style="color: #483d8b;">'pouet'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
&nbsp;
@app.<span style="color: black;">http</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'/user/:id/'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>req, res<span style="color: black;">&#41;</span>:
    res.<span style="color: black;">render</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'index.html'</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'data'</span>: <span style="color: #483d8b;">'pouet'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Servir des fichiers statiques</span>
@app.<span style="color: black;">http</span>.<span style="color: black;">serve</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'uri'</span>, <span style="color: #483d8b;">'/path/to/dir'</span>, <span style="color: black;">&#91;</span>allow_index<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
app.<span style="color: black;">run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Comme c&#8217;est asynchrone, on a de très bonnes perfs. Comme c&#8217;est basé sur Twisted, on a pas besoin d&#8217;un serveur wsgi (gunicorn, uwsgi, etc) ni d&#8217;un proxy (nginx) devant. On peut le mettre en prod tel quel.</p>
<p>Parti de ce principe, on peut ajouter la gestion du PUB/SUB et du RPC pour WAMP :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Callback attendant l'événement</span>
@app.<span style="color: black;">wamp</span>.<span style="color: black;">event</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, a, b, c<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># déclenchement de l'événément</span>
app.<span style="color: black;">wamp</span>.<span style="color: black;">pub</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Déclaration du fonnction appelable à distance</span>
@app.<span style="color: black;">wamp</span>.<span style="color: black;">remote</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, a, b, c<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># appel de la fonnction</span>
app.<span style="color: black;">wamp</span>.<span style="color: black;">call</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>On est souvent perdu quand on fait de l&#8217;asynchrone pour la première fois avec Python car on ne sait pas comment lancer du code après <code>.run()</code>. On peut régler la question proposant des hooks pour les instants clés de l&#8217;app.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Callback à lancer quand l'app est prête</span>
@app.<span style="color: black;">on</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'app.ready'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Signalement que l'app est prête (fait automatiquement en interne</span>
<span style="color: #808080; font-style: italic;"># pour les moments les plus importants)</span>
app.<span style="color: black;">emit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'app.ready'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et tant qu&#8217;on y est, puisqu&#8217;on a une event loop, profitons en pour proposer du CRON intégré à l&#8217;app. C&#8217;est moins chiant à déployer qu&#8217;un script CRON, c&#8217;est cross plateforme, et on a accès facilement à toute sa stack.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Lancer du code tous les x temps ou a une date précise</span>
@app.<span style="color: black;">cron</span><span style="color: black;">&#40;</span>every=seconds<span style="color: black;">&#41;</span>
@app.<span style="color: black;">cron</span><span style="color: black;">&#40;</span>every=timedelta, overlap=<span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
@app.<span style="color: black;">cron</span><span style="color: black;">&#40;</span>hour=<span style="color: #ff4500;">7</span>, minute=<span style="color: #ff4500;">30</span>, day_of_week=<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
@app.<span style="color: black;">cron</span><span style="color: black;">&#40;</span>when=<span style="color: #dc143c;">datetime</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Pourquoi s&#8217;arrêter là ? Event loop + message passing + safe queues + workers = tasks queues !</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Créer une file d'attente</span>
queue = @app.<span style="color: black;">queue</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'name'</span>, <span style="color: black;">&#91;</span>workers<span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span>result_backend<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Callback appelé par un worker quand il depop ce </span>
<span style="color: #808080; font-style: italic;"># message dans la file</span>
@queue.<span style="color: black;">task</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'encode.video'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, data<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Envoie d'une tache dans la queu</span>
queue.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'encode.video'</span>, data<span style="color: black;">&#41;</span></pre></div></div>

<p>Comme on utilise Twisted, on a accès à une chiée de protocoles, et on peut aussi créer les siens. On peut donc imaginer un système de plugins qui rajoute des protocoles supportés :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">app = Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'YourProjectName'</span><span style="color: black;">&#41;</span>
app.<span style="color: black;">plug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'lib.ajoutant.sms'</span>, <span style="color: black;">&#91;</span>namespace<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Si on en a beaucoup et que le namespace nous convient :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">app = Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'YourProjectName'</span>, plugins=<span style="color: black;">&#40;</span><span style="color: #483d8b;">'lib1'</span>, <span style="color: #483d8b;">'lib2'</span>, <span style="color: #483d8b;">'etc'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Exemples de plugins possibles :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Recevoir et envoyer des SMS (via un service type twilio, une gateway kannel ou</span>
<span style="color: #808080; font-style: italic;"># un modem physique)</span>
@app.<span style="color: black;">sms</span>.<span style="color: black;">receive</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'LOVE <span style="color: #000099; font-weight: bold;">\w</span>+ <span style="color: #000099; font-weight: bold;">\w</span>+'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
app.<span style="color: black;">sms</span>.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'test'</span>, <span style="color: black;">&#91;</span>contact<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># Envoyer et recevoir des emails (via un server SMTP ou IMAP)</span>
@app.<span style="color: #dc143c;">email</span>.<span style="color: black;">receive</span><span style="color: black;">&#40;</span>src=r<span style="color: #483d8b;">'.*@sametmax.com'</span>, dest=r<span style="color: #483d8b;">'spam.*@*.'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
app.<span style="color: #dc143c;">email</span>.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'test'</span>, <span style="color: black;">&#91;</span>contact, title, attachments<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># techniquement n'importe quel service de message pour lequel on peut écrire</span>
<span style="color: #808080; font-style: italic;"># un backend</span>
@app.<span style="color: black;">tweet</span>.<span style="color: black;">receive</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'Chat'</span><span style="color: black;">&#41;</span>
@app.<span style="color: black;">fb</span>.<span style="color: black;">receive</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'Like'</span><span style="color: black;">&#41;</span>
@app.<span style="color: black;">instagram</span>.<span style="color: black;">receive</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'Bouffe'</span><span style="color: black;">&#41;</span>
@app.<span style="color: black;">irc</span>.<span style="color: black;">message</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'dtc'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Le problème des apps centrées sur un objet, c&#8217;est qu&#8217;elles ont souvent un design monolithique. Ce n&#8217;est pas un problème du concept d&#8217;app, c&#8217;est juste que les auteurs ont pensé &#8220;point d&#8217;entrée&#8221;, et pas &#8220;élément composable&#8221;.</p>
<p>Si besoin, on doit pouvoir composer une app via plusieurs sous-app :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">app = Application<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
app.<span style="color: black;">embed</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'autre.app'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>ou</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">app = Application<span style="color: black;">&#40;</span>embed=<span style="color: black;">&#91;</span><span style="color: #483d8b;">'app1'</span>, <span style="color: #483d8b;">'app2'</span>, <span style="color: #483d8b;">'app3'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Il faut des hooks pour overrider la configuration, mais vous avez compris le principe.</p>
<p>Un autre problème avec les plateformes comme NodeJS, c&#8217;est qu&#8217;il est difficile d&#8217;utiliser plusieurs coeurs. C&#8217;est une des raisons du succès de Go.</p>
<p>Or, Crossbar encourage la division en plusieurs process qui communiquent entre eux (un peu comme les channels). Créons aussi une API pour ça :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">p1 = app.<span style="color: black;">process</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
p2 = app.<span style="color: black;">process</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure dans process 1</span>
@p1.<span style="color: black;">wamp</span>.<span style="color: black;">remote</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure dans process 2</span>
@p2.<span style="color: black;">wamp</span>.<span style="color: black;">event</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Ainsi on profite enfin de plusieurs CPU. La même chose en plus facile à changer:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure</span>
@app.<span style="color: black;">wamp</span>.<span style="color: black;">remote</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure</span>
@app.<span style="color: black;">wamp</span>.<span style="color: black;">event</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
app.<span style="color: black;">processes</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span>
    <span style="color: #ff4500;">1</span>: <span style="color: black;">&#91;</span><span style="color: #483d8b;">'wamp.remote:auth.signin'</span><span style="color: black;">&#93;</span>
    <span style="color: #ff4500;">2</span>: <span style="color: black;">&#91;</span><span style="color: #483d8b;">'wamp.event:auth.signedin'</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>En bonus, on fait la nique au GIL.</p>
<p>Mieux, on peut bouger ses process sur plusieurs machines :</p>
<p>Machine 1 (routeur):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">router = Application<span style="color: black;">&#40;</span>endpoint=<span style="color: #483d8b;">&quot;0.0.0.0:8080&quot;</span><span style="color: black;">&#41;</span>
router.<span style="color: black;">run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Machine 2 (authentification):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># IP du router</span>
auth = Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth'</span>, connect_to=<span style="color: #483d8b;">&quot;182.64.1.15:8080&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Nommage automatique en fonction du nom de la fonction</span>
<span style="color: #808080; font-style: italic;"># et de l'app, avec possibilité d'annuler ou overrider le prefix.</span>
<span style="color: #808080; font-style: italic;"># Ici du coup la fonction s'appellera en RPC via 'auth.signin'</span>
@auth.<span style="color: black;">wamp</span>.<span style="color: black;">remote</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> signin<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
auth.<span style="color: black;">run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Machine 3 (API REST):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">web = Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'site'</span>, connect_to=<span style="color: #483d8b;">&quot;182.64.1.15:8080&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
@web.<span style="color: black;">http</span>.<span style="color: black;">post</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'api/auth/'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>req, res<span style="color: black;">&#41;</span>:
    <span style="color: #dc143c;">user</span> = <span style="color: #ff7700;font-weight:bold;">yield</span> res.<span style="color: black;">wamp</span>.<span style="color: black;">call</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span>,
                               req.<span style="color: black;">POST</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'username'</span><span style="color: black;">&#93;</span>,
                               req.<span style="color: black;">POST</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'password'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">*</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">user</span>
        <span style="color: #dc143c;">user</span> = <span style="color: #ff7700;font-weight:bold;">yield</span> res.<span style="color: black;">wamp</span>.<span style="color: black;">pub</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span>, <span style="color: #dc143c;">user</span>.<span style="color: black;">userid</span><span style="color: black;">&#41;</span>
        res.<span style="color: black;">json</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'token'</span>: <span style="color: #dc143c;">user</span>.<span style="color: #dc143c;">token</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        res.<span style="color: black;">json</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'error'</span>: <span style="color: #483d8b;">'nope'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
@web.<span style="color: black;">http</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'api/stuff/'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>req, res<span style="color: black;">&#41;</span>:
    res.<span style="color: black;">json</span><span style="color: black;">&#40;</span>get_stuff<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
@web.<span style="color: black;">http</span>.<span style="color: black;">serve</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'uri'</span>, <span style="color: #483d8b;">'/path/to/dir'</span>, <span style="color: black;">&#91;</span>allow_index<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
web.<span style="color: black;">run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et vous savez le plus beau dans tout ça ? En Python on a plein de libs qui sont encore bloquantes. En théorie on ne peut pas les utiliser dans les apps asynchrones. Quand on a toute sa logique métiers dans des classes d&#8217;ORM, c&#8217;est balot. Mais pas ici ! On met un process avec tous ces appels bloquants, et on les appelle depuis des process non bloquant en RPC de manière asynchrone. Pif, paf, pouf, problème isolé.</p>
<p>Après, libre à son imagination de rajouter des fonctionnalités de confort&#8230;</p>
<p>Callback qui sera appelé seulement x fois :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure</span>
@p1.<span style="color: black;">wamp</span>.<span style="color: black;">event</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span>, options=<span style="color: black;">&#123;</span><span style="color: #483d8b;">'limit_calls'</span>: x<span style="color: black;">&#125;</span> <span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Raccourcis pour les opérations courantes :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Recevoir et envoyer un événement</span>
@app.<span style="color: black;">sub</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, <span style="color: #66cc66;">*</span>args<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ctx.pub</span>
@app.<span style="color: black;">pub</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure</span>
@app.<span style="color: black;">proc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ctx.call</span>
app.<span style="color: black;">rpc</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Comme je vous l&#8217;avais expliqué, crossbar peut gérer le cycle de vie de services externes à votre application au démarrage. Autant exposer cette API programativement :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@app.<span style="color: black;">service</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'/urs/bin/nodejs'</span>, <span style="color: #483d8b;">'script.js'</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span><span style="color: #dc143c;">user</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span>group<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

<p><code>.run()</code>, c&#8217;est cool, mais si on veut changer des options via la ligne de commande, faut se taper tout le boulot alors que ça pourrait très bien se générer automatiquement :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@app.<span style="color: black;">cmd_run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et si vous faites : <code>python sites.py --debug=true --endpoint=0.0.0.0:5252</code>, ça le prend automatiquement en compte. Y a pas de raison de se faire chier.</p>
<p>En parlant de générer automatiquement des trucs, le fichiers de configs pour les services externes sur lesquels on peut avoir envie de brancher notre app, c&#8217;est toujours galère. Autant fournir un exemple de base qui est sûr de toujours marcher, généré avec les paramètres de notre app :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">python site.py template centos:nginx
python site.py template ubuntu:upstart
python site.py template bsd:systemd <span style="color: #666666; font-style: italic;"># :D</span></pre></div></div>

<p>On peut partir très loin dans le délire &#8220;battery included&#8221;. Typiquement, on peut fournir des services externes nous même puisque crossbar nous le propose, et coder des versions moins bien, mais compatibles (et suffisantes pour les petits sites), de projets toujours utilses :</p>
<ul>
<li>cache (compatible redis)</li>
<li>live settings (compatible etcd) mais avec en prime un event wamp propagé à chaque</li>
<p>  changement de valeur</p>
<li>build (compatible, heu, j&#8217;en sais rien) qui s&#8217;occupe en tâche de fond de surveiller le >système de fichier et lancer les compilations, les minifications, les copies, les tests unittaires, etc.</li
<li>logging centralisé (compatible sentry).</li>
<li>Un bridge WAMP/REST qui permet d&#8217;envoyer et recevoir des events WAMP sur votre app Django ou flask en utilisant HTTP.</li>
</ul>
<p>On plug tout ça a une admin Web.</p>
<p>J&#8217;espère que je vous ai donné maintenant l&#8217;envie de vous plonger un peu plus dans cette techno, et peut être coder quelque chose avec.</p>
<p>Il n&#8217;y a plus d&#8217;excuses pour ne pas avoir de framework web next gen, ultime de la mort qui tue en Python. A part le fait qu&#8217;on soit des feignasses.</p>
<p>Ah, merde, on est foutus.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10380&amp;md5=3eea15c9f696fc0f66b07cf105a749c1" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10398
title: Écrivez à l’arc, envoyez des sioux
uri: Écrivez-à-l-arc-envoyez-des-sioux
url: http://sametmax.com/ecrivez-a-larc-envoyez-des-sioux/
content:
<p>Les gens derrière le développement de Python sont extraordinaires : Python existe depuis 1990, cela fait donc plus de 20 ans qu&#8217;il est là, à évoluer, sans cesse.</p>
<p>Et cela a un coût. Un langage qui permet à Youtube, Dropbox et Instagram de tourner, ça doit douiller non ?</p>
<div id="attachment_10403" class="wp-caption aligncenter" style="width: 510px"><a href="media/4d6bba91.tumblr_n684vge7NJ1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n684vge7NJ1r539hzo1_500.jpg"><img src="media/4d6bba91.tumblr_n684vge7NJ1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n684vge7NJ1r539hzo1_500.jpg" alt="Photo de personnes déguisés en télétubies fumant et buvant" title="Youtube, Dropbox et instagram consomment toujours beaucoup" width="500" height="373" class="size-full wp-image-10403" /></a><p class="wp-caption-text">Youtube, Dropbox et instagram consomment toujours beaucoup</p></div>
<p>Et bien, la partie fun, c&#8217;est que le plus gros du boulot est fait par des volontaires. En fait, le budget total alloué par la Python Software Fundation pour <strong>payer</strong> des dev à travailler sur le langage est <a href="http://pyfound.blogspot.com/2012/01/psf-grants-over-37000-to-python.html">moins de 30 000 euros par an</a>. Même pas le salaire d&#8217;un ingé sénior. Parce qu&#8217;ils n&#8217;ont pas de pognon.</p>
<p>Alors, on peut se gargariser que, trop cool, la communauté Python contribue à mort et ça coute pas cher. Mais moi ce que je vois, ce sont des centaines de mecs qui bossent super dur, gratos, pour qu&#8217;on puisse en bénéficier d&#8217;un côté, et de l&#8217;autre, une fondation qui n&#8217;a pas de thune pour aller au bout de sa mission.</p>
<p>La honte, c&#8217;est bien entendu que des boites comme Google, Apple ou Sony, qui sont blindées, ne renvoient pas l’ascenseur alors qu&#8217;ils utilisent le langage en interne.</p>
<div id="attachment_10400" class="wp-caption aligncenter" style="width: 510px"><a href="media/8f7c1e9b.tumblr_n572kwK67E1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n572kwK67E1r539hzo1_500.jpg"><img src="media/8f7c1e9b.tumblr_n572kwK67E1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n572kwK67E1r539hzo1_500.jpg" alt="Photo d&#039;un homme assi sur un fauteuil luxueux avec un catana et une peau de tigre" title="Ouai c&#039;est Google. Ouai. Ouai. Nan rien à foutre." width="500" height="500" class="size-full wp-image-10400" /></a><p class="wp-caption-text">Ouai c&#039;est Google. Ouai. Ouai. Nan rien à foutre.</p></div>
<p>Mais ça, on peut rien y faire dans la seconde.</p>
<p>Ce qu&#8217;on peut faire tout de suite, en revanche, c&#8217;est filer 10€ &#8211; 100€, nous, en tant que dev, ou boite. Si vous utilisez professionnellement Python, je pense que sur toute une vie, c&#8217;est raisonnable.</p>
<p>Je hais la culpabilisation, donc l&#8217;idée n&#8217;est pas de vous dire &#8220;si vous ne donnez pas vous êtes des connards&#8221;. Simplement je donne régulièrement aux projets que j&#8217;utilise : VLC, Ubuntu, LibreOffice, etc. Et Le blog fait la promotion de Python, alors il est juste que je vous invite à envoyer des sous à la PSF.</p>
<div id="attachment_10399" class="wp-caption aligncenter" style="width: 510px"><a href="media/370288cf.tumblr_n55aed3WRL1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n55aed3WRL1r539hzo1_500.jpg"><img src="media/370288cf.tumblr_n55aed3WRL1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n55aed3WRL1r539hzo1_500.jpg" alt="Photo d&#039;un chat mençant un chien avec un couteau" title="Par contre le chantage ne me gène pas. Si vous ne donnez pas, je posterai une photo de chaton par jour dans la rubrique cul de sam et max. Ouai, nan, c&#039;est plus dur pour moi que pour vous en fait." width="500" height="427" class="size-full wp-image-10399" /></a><p class="wp-caption-text">Par contre le chantage ne me gène pas. Si vous ne donnez pas, je posterai une photo de chaton par jour dans la rubrique cul de sam et max. Ouai, nan, c&#039;est plus dur pour moi que pour vous en fait.</p></div>
<p>Ce n&#8217;est pas une question d&#8217;être une bonne personne. C&#8217;est juste un bon moyen d&#8217;aider au dev d&#8217;un outil qu&#8217;on aime, pour en bénéficier demain.</p>
<p style="text-align:center;  margin:3em">
<a style="font-size:3em;" href="https://www.python.org/psf/donations/">Faites pêter l&#8217;oseille</a>
  </p>
<p>Dommage, ils n&#8217;acceptent pas les bitcoins.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10398&amp;md5=ab455c5aa7df535daf2230b1eeecfc7c" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10392
title: Télécharger une page du blog en PDF
uri: Télécharger-une-page-du-blog-en-PDF
url: http://sametmax.com/telecharger-une-page-du-blog-en-pdf/
content:
<p>On m&#8217;a <a href="http://sametmax.com/le-potentiel-de-wamp-autobahn-et-crossbar-io/#comment-40031">demandé</a> de rendre possible téléchargement des articles en PDF.</p>
<p>Je suis paresseux, donc plutôt que d&#8217;installer un plugin, j&#8217;ai juste fait un lien vers un service externe en haut à droite de toutes les pages.</p>
<p>Si vous cliquez, ça vous génère le PDF pour la page complète, et ça marche pour toutes les URL, pas uniquement les articles.</p>
<p>De rien.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10392&amp;md5=e45b3b95cad9fbaa3dcac5b80957d55d" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


