# articles

feed_id: http://sametmax.com/?p=2110
title: Stockage des données et conservation – kindle, tablette contre un bête livre…
uri: Stockage-des-données-et-conservation-kindle-contre-un-bête-livre
url: http://sametmax.com/stockage-des-donnees-et-conservation-kindle-contre-un-bete-livre/
content:
<p>Depuis quelques mois c&#8217;est l&#8217;hystérie autour du kindle, Amazon qui en fait des tonnes, beaucoup de blogs en parlent, les tests fusent, pratiquement tout le monde trouve ça génial, c&#8217;est une révolution&#8230;</p>
<p>La première chose à laquelle je pense quand je vois ça c&#8217;est: &#8220;Qu&#8217;est-ce qu&#8217;ils ont encore été cherché là à nous vendre&#8221;</p>
<p>La deuxième chose à laquelle je pense c&#8217;est: &#8220;Un truc en noir&#038;blanc qui marche sur batteries, ça marchera jamais&#8230;&#8221;</p>
<p>Et pourtant les ventes explosent&#8230;<br />
<a href="http://sametmax.com/wp-content/uploads/2012/09/Kindle-Books-vs-Physical-Books.png"?9d7bd4"><img src="http://sametmax.com/wp-content/uploads/2012/09/Kindle-Books-vs-Physical-Books.png"?9d7bd4" alt="" title="la vente des kindles s&#039;envole" width="495" height="278" class="alignnone size-full wp-image-2154" /></a></p>
<p>J&#8217;ai du louper un épisode ou je suis plus du tout à la page ou je ne suis pas dans le moule des moutons qui achètent tout sous prétexte que c&#8217;est cool, à la mode et tout et tout&#8230;</p>
<p><strong>Quelques points qu&#8217;un cerveau tel que le mien ne peut pas accepter:<br />
</strong><br />
- ça marche sur batterie (ben merde alors pour l&#8217;emmener en camping ou sur de longs trajets&#8230; <a href="http://fr.wikipedia.org/wiki/Amazon_Kindle">Autonomie entre 2 et sept jours</a>)<br />
- c&#8217;est fragile, faites le tomber, mettez le dans un sac à dos de barroudeur et vous m&#8217;en direz des nouvelles<br />
- c&#8217;est super on peut avoir plein de titres mais si je veux Mein Kampf ou 1984 ? Ben <a href="http://io9.com/5317703/amazon-secretly-removes-1984-from-the-kindle">Amazon peut retirer un livre</a> quand il veut et vous le supprimer même si vous l&#8217;avez acheté<br />
- J&#8217;ai un livre super là je fais comment pour le prêter ? Je file mon kindle à 150euros ?<br />
- J&#8217;ai encore des Edika de 1993 dans mes chiottes, quand serat-il du kindle dans 20 ans ?</p>
<p>Il y aussi d&#8217;autres points plus tatillons je l&#8217;avoue comme l&#8217;odeur des pages, mon grand-père qui me lègue sa collection de livres anciens, etc&#8230; </p>
<p>Le seul avantage que je vois c&#8217;est le côté instantanné pour obtenir le livre souhaité (sous réserve qu&#8217;il soit dispo). Pour le reste tout joue contre. Et pour ceux qui veulent me sortir que ça va économiser des arbres abbatus, je pense que l&#8217;energie necessaire à construire ce gadget doit représenter un bon paquet d&#8217;arbres&#8230;</p>
<p><strong>La grosse arnaque:</strong><br />
A mon avis Amazon a réussi là un super coup marketing, au moins aussi beau qu&#8217;Apple avec son iPhone.<br />
A coup de bourrage de crâne à afficher sur sa page principale le kindle Amazon a réussi à vendre du vent, un objet inutile, qui consomme de l&#8217;energie, qui coûte cher, dont le contenu peut être retiré à tout moment sans votre autorisation, qui ne va pas durer dans le temps.</p>
<p><strong>Bref Amazon a réussi à faire tout le contraire de ce que fait un livre: Apporter une culture variée à un prix accessible à tous<br />
</strong><br />
Et les gens en redemande&#8230;</p>
<p>une image qui m&#8217;a fait bien rire&#8230;<br />
<a href="http://sametmax.com/wp-content/uploads/2012/09/ipad-vs-kindle-vs-rock.jpeg"?9d7bd4"><img src="http://sametmax.com/wp-content/uploads/2012/09/ipad-vs-kindle-vs-rock.jpeg"?9d7bd4" alt="" title="ipad vs kindle vs rock" width="500" height="449" class="alignnone size-full wp-image-2155" /></a></p>
<p>C&#8217;était mon coup de geule de la semaine&#8230; A vous cognac Jay&#8230;</p>


feed_id: http://sametmax.com/?p=2142
title: Mail sur compilation de Python2.7 + PyQT pour Android
uri: Mail-sur-compilation-de-Python2-7-PyQT-pour-Android
url: http://sametmax.com/mail-sur-compilation-de-python2-7-pyqt-pour-android/
content:
<p>Dans la même veine que <a href="http://sametmax.com/cher-julien-a-propos-de-ton-mail-sur-les-tests-en-python/">celui-là</a>, on a reçu ce mail:</p>
<blockquote><p>Hello,</p>
<p>Ma proposition de news:</p>
<p>Projet qui permet de créer un APK pour les codes Python:<br />
https://code.google.com/p/android-python27/ (on zip son code, on le met dans res/raw et voilà)</p>
<p>+ la compilation de Python2.7 + PyQT pour Android.</p>
<p>Tcho</p></blockquote>
<p>Hello cher inconnu, je serai ravi de discuter de tout ça avec vous, mais il faut mettre son mail dans le formulaire de contact, sinon on ne peut pas vous répondre.</p>
<p>En espérant que ce soit pas un nouveau plugin qui ai pêter le formulaire de contact et qui fasse sauter l&#8217;adresse de l&#8217;expéditeur.</p>


feed_id: http://sametmax.com/?p=2088
title: Qu’est-ce qu’on peut faire avec Python ?
uri: Qu-est-ce-qu-on-peut-faire-avec-Python
url: http://sametmax.com/quest-ce-quon-peut-faire-avec-python/
content:
<p>&#8220;Ouai, j&#8217;ai entendu parlé de Python, mais je sais pas&#8230; On peut faire quoi avec ?&#8221;</p>
<h2>Des jeux vidéos et des films</h2>
<p>Python étant très ami avec le langage C (l&#8217;implémentation de base étant CPython, et les bindings C étant faciles et courant), on peut faire des choses demandant pas mal de patate.</p>
<p><a href="http://www.pygame.org/news.html">PyGame</a>, une lib pour créer des jeux en 2D:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://www.youtube.com/embed/xpU-euVqAlw" width="100%" height="400" scrolling="no" class="iframe-class" frameborder="0"></iframe>
<p>Et <a href="http://www.blender.org/">Blender</a>, un modélisateur 3D dont le moteur de scripting est Pythonphone:</p>
<p>
<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://www.youtube.com/embed/1OePNW34-z4" width="100%" height="400" scrolling="no" class="iframe-class" frameborder="0"></iframe><br />
<a href="https://en.wikipedia.org/wiki/List_of_Python_software#Video_games"><br />
Civilization IV utilise également Python pour la plupart de ses tâches, Battlefield 2 pour ses addons, et Eve Online, pour la partie serveur.</a></p>
<h2>Du web</h2>
<p>Ma devise: si <a href="http://python.about.com/b/2006/12/13/holy-web-apps-youtube-is-written-in-python.htm">Youtube est écrit en Python</a>, ça doit suffire pour mon usage.</p>
<p>Python ne vient pas avec des tas de raccourcis pour créer un site Web par défaut comme PHP, mais il existe de nombreux excellents outils pour ça. Nous on a une préférence pour <a href="http://sametmax.com/schema-de-fonctionnement-general-de-django/">Django</a> pour les gros projets, et <a href="http://sametmax.com/creer-un-site-avec-bottle-en-5-minutes-parceque-7-cest-impossible-voyons/">Bottle</a> pour les petits.</p>
<div class="mceTemp mceIEcenter">
<dl id="attachment_659" class="wp-caption aligncenter" style="width: 615px;">
<dt class="wp-caption-dt">
<p><a href="http://sametmax.com/wp-content/uploads/2012/05/0bin.png"?9d7bd4"><br />
<img title="0bin.net" src="http://sametmax.com/wp-content/uploads/2012/05/0bin.png"?9d7bd4" alt="Capture d'écran du logiciel 0bin" width="605" height="370" /></a>
</dt>
<dd class="wp-caption-dd"><a href="http://0bin.net">0bin</a></dd>
<p> a été écrit avec Bottle</dl>
</div>
<h2>Du scripting</h2>
<p>Ben oui quand même, à la base Python c&#8217;est un langage de scripting. Certes, qui peut faire de la POO, de l&#8217;introspection, et tout un <a href="http://sametmax.com/comprendre-les-decorateurs-python-pas-a-pas-partie-1/">tas</a> de <a href="http://sametmax.com/parcourir-un-iterable-par-morceaux-en-python/">trucs</a> <a href="http://sametmax.com/les-context-managers-et-le-mot-cle-with-en-python/#comment-1700">puissants</a>, mais par nature, Python excelle dans la récupération de paramètres, le parsing d&#8217;un fichier, les petits scripts rapides, etc.<br />
Exemple de récupération de paramètre super propres en quelques lignes:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> argparse
&nbsp;
<span style="color: #dc143c;">parser</span> = argparse.<span style="color: black;">ArgumentParser</span><span style="color: black;">&#40;</span>description=<span style="color: #483d8b;">&quot;Description du programme&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">parser</span>.<span style="color: black;">add_argument</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'-o'</span>, <span style="color: #483d8b;">'--option'</span>, default=<span style="color: #483d8b;">'valeur par defaut'</span>, <span style="color: #008000;">type</span>=<span style="color: #008000;">str</span>,
                             <span style="color: #008000;">help</span>=<span style="color: #483d8b;">&quot;Voila a quoi sert cette option&quot;</span>,
                             <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">parser</span>.<span style="color: black;">add_argument</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'text'</span>, <span style="color: #008000;">type</span>=<span style="color: #008000;">str</span>, nargs=<span style="color: #483d8b;">'+'</span>,
                     <span style="color: #008000;">help</span>=<span style="color: #483d8b;">&quot;Un argument positionel obligatoire&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
args = <span style="color: #dc143c;">parser</span>.<span style="color: black;">parse_args</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> args.<span style="color: black;">text</span>
<span style="color: #ff7700;font-weight:bold;">print</span> args.<span style="color: black;">option</span></pre></div></div>

<p>Et le programme génère automatiquement le check des arguments, et un &#8220;usage&#8221;:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ python test.py
usage: test.py <span style="color: #7a0874; font-weight: bold;">&#91;</span>-h<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>-o OPTION<span style="color: #7a0874; font-weight: bold;">&#93;</span> text <span style="color: #7a0874; font-weight: bold;">&#91;</span>text ...<span style="color: #7a0874; font-weight: bold;">&#93;</span>
test.py: error: too few arguments</pre></div></div>

<p>Mais également aussi le <code>--help</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ python test.py <span style="color: #660033;">-h</span>
usage: test.py <span style="color: #7a0874; font-weight: bold;">&#91;</span>-h<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>-o OPTION<span style="color: #7a0874; font-weight: bold;">&#93;</span> text <span style="color: #7a0874; font-weight: bold;">&#91;</span>text ...<span style="color: #7a0874; font-weight: bold;">&#93;</span>
&nbsp;
Description <span style="color: #c20cb9; font-weight: bold;">du</span> programme
&nbsp;
positional arguments:
  text                  Un argument positionel obligatoire
&nbsp;
optional arguments:
  -h, <span style="color: #660033;">--help</span>            show this <span style="color: #7a0874; font-weight: bold;">help</span> message and <span style="color: #7a0874; font-weight: bold;">exit</span>
  <span style="color: #660033;">-o</span> OPTION, <span style="color: #660033;">--option</span> OPTION
                        Voila a quoi sert cette option</pre></div></div>

<p>Et la récupération des arguments est simplissime:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ python test.py Mon option
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #ff0000;">'Mon'</span>, <span style="color: #ff0000;">'option'</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>
valeur par defaut</pre></div></div>

<p>Bonne nouvelle, Linux et Mac viennent avec Python installé par défaut.</p>
<h2>Des pilotes</h2>
<p>Python est un langage de haut niveau, donc on ne l&#8217;attend pas du coté des drivers. Mais depuis Windows XP, on peut utiliser le <a href="http://msdn.microsoft.com/en-us/windows/hardware/gg463294.aspx">User-Mode Driver Framework</a>, et ainsi écrire pas mal de pilotes en appelant utilisant l&#8217;<a href="http://www.devshed.com/c/a/Python/Windows-Programming-in-Python/2/">API COM</a>.</p>
<p>En plus de cela, on peut taper dans le <a href="http://pyserial.sourceforge.net/">serial</a> et l&#8217;<a href="http://sourceforge.net/projects/pyusb/">USB</a>, et même utiliser son téléphone comme modem ou simplement <a href="http://wammu.eu/python-gammu/">envoyer des SMS</a>.</p>
<p>Il y a même des petits malins qui l&#8217;utilisent pour s&#8217;amuser avec la <a href="http://talk.maemo.org/showthread.php?t=60178">wiimote</a>, ou le Kinect:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://www.youtube.com/embed/qwp1DqQt6yI" width="100%" height="400" scrolling="no" class="iframe-class" frameborder="0"></iframe>
<h2>Des applications de tablettes</h2>
<p>De plus en plus d&#8217;initiatives existent pour développer sur Android avec Python. La plus intéressante étant <a href="http://kivy.org/#home">Kivy</a>, qui a la bonne idée de fonctionner en plus sous Linux, Mac et Windows:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://player.vimeo.com/video/22725621" width="100%" height="400" scrolling="no" class="iframe-class" frameborder="0"></iframe>
<h2>Du Desktop</h2>
<p>Python brille dans le domaine du développement rapide et du prototypage. Pour cette raison Ubuntu l&#8217;a choisi comme langage de développement par défaut, et propose même un outil, nommé <a href="https://wiki.ubuntu.com/Quickly">quickly</a>, pour rapidement créer une app:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://www.youtube.com/embed/dx93U10Kkro" width="100%" height="400" scrolling="no" class="iframe-class" frameborder="0"></iframe>
<p>Mais Python fonctionne pour les logiciels plus costauds aussi, puisque BitTorrent est écrit en Python, comme le client DropBox, Gajim ou encore PiTiVi.</p>
<p>D&#8217;une manière générale, Python permet d&#8217;écrire des applications avec WX, GTK et QT (ou directement avec l&#8217;API Win32), donc les développeurs d&#8217;autres langages sont rarement perdus.</p>
<h2>De l&#8217;analyse de données</h2>
<p>Python vient du monde scientifique, il est donc tout à fait naturel de le retrouver dans ce domaine. <a href="http://www.python.org/about/success/usa/">La Nasa l&#8217;utilise</a>, il y a des environnements de type <a href="http://ipython.org/">Matlab</a>, des libs pour bouffer du nombre <a href="http://pandas.pydata.org/">en tas</a>, pour s&#8217;amuser avec <a href="http://www.scipy.org/">les matrices ou les probas</a>, pour la <a href="http://biopython.org/wiki/Main_Page">bio informatique</a>, etc.</p>
<p>D&#8217;une manière générale, Python remplace R, AWK, Perl, PHP, et parfois même le C.</p>
<h2>Comme langage de plugin</h2>
<p>Puisque Python aime bien le C, il est un excellent langage d&#8217;extensions: The Gimp, Inkscape, Nautilus, Gedit, Rhythmbox, Sublime Text&#8230; Tous utilisent Python pour permettre à d&#8217;autre de facilement étendre les fonctionalités de base.</p>
<p>Si vous vous demandez si vous pouvez faire &#8216;x&#8217; en Python, postez un com, on vous répondra. Et si le code commence à vous démanger, on a un tas d&#8217;<a href="http://sametmax.com/tag/python/">articles sur Python</a> pour petits et grands.</p>


feed_id: http://sametmax.com/?p=2098
title: Dois-je apprendre Python 2 ou Python 3 ?
uri: Dois-je-apprendre-Python-2-ou-Python-3
url: http://sametmax.com/dois-je-apprendre-python-2-ou-python-3/
content:
<p>Les deux versions étant incompatibles, et Python 3 ayant plein de super fonctionnalités que Python 2 n&#8217;a pas, mais la V2 étant encore très répandue, on peut se demander lequel on doit apprendre.</p>
<h2>Etat du lard</h2>
<p>Python 3 permet de s&#8217;affranchir de beaucoup de problèmes d&#8217;encoding en utilisant unicode par défaut. A partir de la version 3.3, il va venir avec un virtualenv intégré, et distutils2, rendant le packaging et le déploiement beaucoup plus simple. Sans compter la délégation à un sous générateur. Plus besoin non plus d&#8217;utiliser &#8216;object&#8217; dans l&#8217;héritage, et des tas de libs nettoyées. Bref, un comportement plus simple et un langage plus beau.</p>
<p>Python 2 lui est néanmoins présent encore partout:</p>
<ul>
<li>Ubuntu est toujours en 2.7, et <a href="https://wiki.ubuntu.com/Python/3">passera en 3 dans la prochaine version,</a> mais laissant la possibilité d&#8217;installer la 2.</li>
<li>Mac OS utilise toujours la 2.6 par défaut.</li>
<li>Certains serveurs Web sont toujours en 2.4 (!) si bien que Max  recompile carrément Python 2.6 dessus (oui, c&#8217;est un acharné).</li>
<li>Django est en phase de <a href="https://www.djangoproject.com/weblog/2012/mar/13/py3k/">transition version Python 3</a>, mais pour le moment ce n&#8217;est pas fait, et il sera toujours compatible avec Python 2.7 pour les deux prochaines versions.</li>
<li>Une bonne partie des libs sur pypi et sur github sont <a href="http://python3wos.appspot.com/">toujours en Python 2</a>, ou au moins compatibles avec.</li>
</ul>
<p>Enfin, l&#8217;outil <a href="http://docs.python.org/library/2to3.html">2to3</a> permet de convertir automatiquement, et facilement, la plupart des codes de Python 2 vers Python 3.</p>
<h2>Apprentissage et usage</h2>
<p>Dans la vie de tous les jours, en tant que programmeur Python, vous allez donc forcément être confronté à Python 2 pendant encore 3 ou 4 ans. Je rappelle que Python 2.4 était encore assez courant il y a deux ans, et qu&#8217;il y a 5 ans je lisais encore des questions sur les fora concernant Python 2.2.</p>
<p>Or, Python 2 est plus compliqué que Python 3, il demande des connaissances particulières: gérer l&#8217;encoding, setuper son virtualenv, faire gaffe à bien utiliser &#8216;object&#8217;, connaitre les noms des libs mal standardisés, etc.</p>
<p>Dans tous les cas, il sera toujours <strong>beaucoup</strong> plus simple d&#8217;apprendre Python 2 et de passer à Python 3 que l&#8217;inverse, et il est improbable que vous n&#8217;ayez pas besoin de toucher un code en Python 2. Hey, nous même, nous codons encore tous nos projets en Python 2. On se posera la question de la migration quand Django l&#8217;aura fait, et même là, on aura des tas de projets qui resteront pour toujours en V2.</p>
<p>Donc, si vous apprenez (ou enseignez le Python)<strong>, le choix le plus pragmatique est d&#8217;apprendre avec Python 2, et de rajouter l&#8217;apprentissage des différences entre la V2 et la V3</strong>. Ce faisant vous saurez aussi comment faire migrer un projet, ce dont il est possible que vous ayez un jour besoin.</p>


feed_id: http://sametmax.com/?p=1959
title: Certains films pornos passent le Test Bechdel
uri: Certains-films-pornos-passent-le-Test-Bechdel
url: http://sametmax.com/certains-films-pornos-passent-le-test-bechdel/
content:
<p>Le féministe est un sujet qui fait son come back sur le devant de la toile en ce moment, ce qui est rafraîchissant étant donné qu&#8217;Internet est quand même un domaine très orienté couilles velues, malgré des <a href="http://lesquestionscomposent.fr/">petits villages gaulois</a> qui résistent encore et toujours&#8230;</p>
<p>Et malgré notre propension à faire des blagues machos (et racistes, et antisémites, et pédophiles, et sur les handicapés, et sur les handicapés pédophiles antisémites), on a parfois des discussions plus sérieuses (mais tout aussi inutiles) comme &#8220;putain &#8216;le Seigneur Des Anneaux&#8217; ne passe pas le Bechdel test mais &#8216;Entre Matures 4&#8242; oui&#8221;.</p>
<h2>Qu&#8217;est-ce que le test Bechdel ?</h2>
<p>C&#8217;est un test informel pour vérifier si une œuvre culturelle est formatée par les stéréotypes de notre société patriarcale. En gros pour savoir si un film est macho.</p>
<p>Il a hérité du nom de la dessinatrice <a href="https://fr.wikipedia.org/wiki/Alison_Bechdel">Alison Bechdel</a>, connue principalement au travers de sa bande dessinée <a href="https://en.wikipedia.org/wiki/Dykes_to_Watch_Out_For">Dykes to Watch Out For</a>, qui a la particularité de mettre en scène des personnages principaux lesbiennes. Dans la planche intitulée &#8220;The Rule&#8221;, une protagoniste déclare qu&#8217;elle ne va voir une film que si il répond aux critères suivant:</p>
<ul>
<li>Il y a au moins deux personnages féminins <strong>qui portent un nom</strong>.</li>
<li>Qui ont un dialogue.</li>
<li>A propos d&#8217;autre chose qu&#8217;un homme.</li>
</ul>
<p>Ce qui est marrant quand on regarde la <a href="http://bechdeltest.com">liste des films qui passent ou non</a>, c&#8217;est d&#8217;abord que, ben la majorité ne passent pas, même d&#8217;excellents films comme <a href="http://bechdeltest.com/view/149/back_to_the_future/">Retour vers le futur</a>  ou <a href="http://bechdeltest.com/view/669/star_wars/">Star Wars</a> (c&#8217;est plutôt des histoires de mec), ni encore <a href="http://bechdeltest.com/view/2402/big_fish/">Big Fish</a> ou <a href="http://bechdeltest.com/view/1038/amelie/">Amelie Poulain</a> (alors que c&#8217;est pas forcément orienté testostérone).</p>
<p>Pour passer le test, il faut regarder du côté des héroïnes féminines: Alien, Kill Bill, Juno, etc. Ou alors dans les films avec beaucoup de personnages féminins: Les invasions barbares, 8 femmes, Battle Royale&#8230;</p>
<p>Notez que j&#8217;essaye de lister uniquement des très bons films ici, et qu&#8217;écrire les deux paragraphes ci-dessus, c&#8217;est la moitié du temps de rédaction de l&#8217;article.</p>
<p>Dans tous les cas, le ratio est assez inquiétant. Il faut dire que la majorité des réalisateurs et scénaristes sont des mecs.</p>
<h2>Peut-on se prendre une bite dans le cul avec dignité ?</h2>
<p>Ce qui est marrant avec ce test, c&#8217;est que comme tout règle en socio, on peut trouver des contre exemples. Et dans notre cas, on le retrouve dans le domaine du porno. Car si les films de cul ne brillent pas pour leurs dialogues (surtout les quick shots qui sont maintenant la norme sur les tubes, où il n&#8217;y a même plus de scénario), les personnages sont tous égaux sur le temps de parole. Et les noms, rarement cités dans le film, sont presque toujours sur la jaquette :-)</p>
<p>Mais surtout, les boulards ont une très grande diversité de mise en forme, à défaut de diversité de sujet.</p>
<p>On a donc les films lesbiens, avec des personnages féminins, qui forcément, ne parlent pas d&#8217;un homme. Ce qui est fendard, puisque ces films sont faits avant tout pour un publique masculin. Par exemple, <a href="http://www.youporn.com/watch/281977/best-lesbians-movie-plane-action/">Fly Me</a> et ses HOTesses de l&#8217;air. Penny à l&#8217;air particulièrement conne, mais on lui pardonne.</p>
<p>Et puis il y a la merveille de l&#8217;international, merci-internet-je-t-aime, dans lequel on peut découvrir des genres nouveaux, comme le sexe familial japonais. Notez les <a href="http://xhamster.com/movies/898272/anywhere_bukkake_complete_version_part_5_sex_and_talk.html">deux meufs</a> qui parlent du journal pendant que l&#8217;autre se fait démonter sur une chaise. J&#8217;apprécie aussi le floutage du dit journal. C&#8217;est vrai que ça aurait gâché la prise.</p>
<p>Et bien entendu on a le SM, qui implique <a href="http://www.sextvx.com/fr/video/23443/jordan-talks-to-therapist-about-lesbian-submission-and-fisting">un dialogue de soumission</a>, certes succin (et parfois en Allemand : -)), mais bien réel. Perso si ma machine à laver commence à faire le bruit que Jordan fait à la scène du vibro, je m&#8217;inquiète.</p>
<p>Je n&#8217;ai pas de conclusion intelligente à cet article qui ne l&#8217;est de toute façon pas, alors je vous laisse sur une trouvaille: <a href="http://xxxbunker.com/spider_and_the_fly_lesbian_scene">The Spider and the Fly</a>. Ils se donnaient du mal à l&#8217;époque.</p>


feed_id: http://sametmax.com/?p=2082
title: Se faciliter les imports avec les fichiers *.pth
uri: Se-faciliter-les-imports-avec-les-fichiers-pth
url: http://sametmax.com/se-faciliter-les-imports-avec-les-fichiers-pth/
content:
<p>Dans un article, nous parlions des <a href="http://sametmax.com/astuces-python-en-vrac/">extensions alternatives en Python</a>, et notamment de l&#8217;usage des fichiers <em>*.pth</em>. Néanmoins cette extension est souvent mal comprise, et voici un comment en profiter au maximum.</p>
<p>En Python, on a souvent des problèmes d&#8217;import: la lib est dans un dossier au dessous, ou à côté, ou à l&#8217;autre bout du disque dur, et ça plantouille parceque Python ne trouve pas le module.</p>
<p>Il existe plein de moyens de jouer avec le fameux <code>PYTHON_PATH</code> qui contient la liste des dossiers dans lesquelles chercher les libs, et la plupart sont fort verbeuses et répétitives, du genre:</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;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
&nbsp;
CUR_DIR = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">realpath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span>.<span style="color: black;">extend</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>
    <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>CUR_DIR, <span style="color: #483d8b;">'apps'</span><span style="color: black;">&#41;</span>,
    <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span>CUR_DIR<span style="color: black;">&#41;</span>, <span style="color: #483d8b;">'libs'</span><span style="color: black;">&#41;</span>,
    <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">realpath</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'~'</span><span style="color: black;">&#41;</span>, <span style="color: #483d8b;">'.local_libs'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#93;</span><span style="color: black;">&#93;</span><span style="color: black;">&#125;</span></pre></div></div>

<p>Une manière simple est d&#8217;utiliser un fichier <em>*.pth</em>: on créé un fichier texte, on le nomme <em>comme-on-veut.pth</em> (moi je me fais pas chier, je le nomme .pth comme ça c&#8217;est court et c&#8217;est caché sous nunux), et on liste tous les dossiers qu&#8217;on veut ajouter au <code>PYTHON_PATH</code>, y compris avec des chemins relatifs.</p>
<p>Oui mais, argh parmi les argh, la première fois qu&#8217;on le fait, ça ne marche pas. Alors on cherche dans la doc, et là, fustration, on apprend que les fichiers <em>*.pth</em> ne sont parsés que dans les sites directories, c&#8217;est à dire les dossiers officiels du système dans lesquels sont censés être les libs de la bibliothèque standard. Donc pas le dossier courant.</p>
<p>Eh oui, ces fichiers ont été conçus pour faciliter les déploiements, du genre quand on fait un setup.py pour son app, pas pour nous, pauvres mortels.</p>
<p>Heureusement il y a une solution Sam et Max à tout, et ici elle consiste à faire:</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;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">site</span>
&nbsp;
CUR_DIR = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">realpath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">site</span>.<span style="color: black;">addsitedir</span><span style="color: black;">&#40;</span>CUR_DIR<span style="color: black;">&#41;</span></pre></div></div>

<p>Quelque part dans son code n&#8217;importe où qui est sûr d&#8217;être éxécuté tôt, par exemple dans Django, dans le <em>settings.py</em>. Ca ajoute le dossier du projet en tant que site directory, et donc le fichier <em>.pth</em> est parsé. On peut alors dumper son listing dedans sans avoir à le répéter dans tous les scripts et fichiers qui doivent l&#8217;utiliser (et ainsi modifier cette liste facilement).</p>
<p>Attention cependant, celà rajoute votre dossier de projet dans le <code>PYTHON_PATH</code>, rendant tout ce qu&#8217;il contient importable. Normalement, c&#8217;est ce que vous voulez, mais si ce n&#8217;est pas le cas, vous pouvez avoir une gestion plus fine en ajoutant juste le fichier .pth avec <code>site.addpackage(CUR_DIR, 'fichier.pth', set())</code></p>
<h2>La feature de magie noire</h2>
<p>Dans les fichiers <em>*.pth</em>, il y a un support limité de la syntaxe Python: on peut commenter des lignes avec <code>#</code> et faire des <code>import truc</code>. </p>
<p>Sauf que si vous êtes curieux, vous verrez le détail qui tue dans l&#8217;implémentation:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> line.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;import &quot;</span>, <span style="color: #483d8b;">&quot;import<span style="color: #000099; font-weight: bold;">\t</span>&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">exec</span> line</pre></div></div>

<p>On peut donc virtuellement mettre n&#8217;importe quel code Python dans les fichiers <em>*.pth</em>. Par exemple:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">../foo
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span><span style="color: #66cc66;">;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Foo a été ajouté au PYTHON PATH&quot;</span></pre></div></div>

<p>Va afficher &#8220;Foo a été ajouté au PYTHON PATH&#8221; au démarrage du programme. Amusant. Et tellement de potentiels pour faire des trucs tordus !</p>


feed_id: http://sametmax.com/?p=2049
title: Liste des partitions, de leur type, de la place restante sous Linux – df / du
url: http://sametmax.com/liste-des-partitions-de-leur-type-de-la-place-restante-sous-linux-df-du/
content:
<p>Quelques commandes sympa sous Linux pour connaître les ressources disque de son serveur.</p>
<p><strong>la commande df:</strong><br />
Retourne l&#8217;espace disque utilisé par chaque partition montée sur votre machine.</p>
<p>-h Affiche les résultats sous forme humainement lisible :)<br />
-T indique le type de système de fichiers utilisé</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">df</span> <span style="color: #660033;">-hT</span>
Sys. fich.    Type  Taille  Uti. Disp. Uti<span style="color: #000000; font-weight: bold;">%</span> Monté sur
<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda2      xfs     20G  <span style="color: #000000;">2</span>,9G   17G  <span style="color: #000000;">15</span><span style="color: #000000; font-weight: bold;">%</span> <span style="color: #000000; font-weight: bold;">/</span>
tmpfs        tmpfs    <span style="color: #000000;">3</span>,9G     <span style="color: #000000;">0</span>  <span style="color: #000000;">3</span>,9G   <span style="color: #000000;">0</span><span style="color: #000000; font-weight: bold;">%</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>shm
<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda1      xfs    192M   28M  164M  <span style="color: #000000;">15</span><span style="color: #000000; font-weight: bold;">%</span> <span style="color: #000000; font-weight: bold;">/</span>boot
<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda4      xfs    <span style="color: #000000;">1</span>,8T  220G  <span style="color: #000000;">1</span>,6T  <span style="color: #000000;">12</span><span style="color: #000000; font-weight: bold;">%</span> <span style="color: #000000; font-weight: bold;">/</span>data</pre></div></div>

<p><strong>la commande du:</strong><br />
Retourne l&#8217;espace disque utilisé par un répertoire</p>
<p>-h Affiche les résultats sous forme humainement lisible :)<br />
-s affiche la somme des fichiers du répertoire</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">du</span> <span style="color: #660033;">-hs</span> <span style="color: #000000; font-weight: bold;">/</span>boot<span style="color: #000000; font-weight: bold;">/</span>
18M	<span style="color: #000000; font-weight: bold;">/</span>boot<span style="color: #000000; font-weight: bold;">/</span></pre></div></div>

<p><strong>Edit:</strong><br />
Pour le côté prog on peu utiliser <a href="http://code.google.com/p/psutil/">psutil</a> en python qui permet tout un tas d&#8217;acceès aux infos de la machine.<br />
Merci François</p>


feed_id: http://sametmax.com/?p=2014
title: Votre Python aime les pip
uri: Votre-Python-aime-les-pip
url: http://sametmax.com/votre-python-aime-les-pip/
content:
<p><code>Pip install</code> par-ci, <code>pip install</code> par là. &#8220;Pour installer cette lib, il vous suffit de faire pip install&#8221;.</p>
<p>Mais merde, c&#8217;est quoi <code>pip</code> ?</p>
<h2>Python et les libs externes</h2>
<p>La beauté avec Python, c&#8217;est qu&#8217;on peut prendre une lib, la balancer dans le répertoire courant, et l&#8217;importer. Rien à faire, ça marche tout seul.</p>
<p>Mais.</p>
<p>Car oui, il y a toujours un mais (souvent après le mois de mars).</p>
<p>Quand il faut mettre à jour ses libs, c&#8217;est chiant. Quand il faut recréer un environnement complet en prod, c&#8217;est chiant. Quand il faut trouver la dernière version, avec le bon site Web, et le lien de téléchargement, c&#8217;est chiant. Quand on veut installer une lib automatiquement, vous l&#8217;avez deviné, c&#8217;est chiant.</p>
<p>Mais surtout, quand on a une lib qui a des parties en C à compiler comme les libs de crypto, d&#8217;accès à la base de données, de traitement XML, de parsing ou de sérialisation, de calculs scientifiques, etc. ça ne marche tout simplement pas.</p>
<p>Là, il y a deux écoles. Les mecs qui utilisent les packages *.exe ou *.deb precompilés et qui se retrouvent avec d&#8217;autres problèmes.</p>
<p>Et les mecs qui utilisent setuptools (et qui se retrouvent avec encore d&#8217;autres problèmes, mais c&#8217;est mieux parce que je le dis).</p>
<h2>Setuptools, la solution de skippy à tous vos soucis</h2>
<p>setuptools est une lib et un outil de distribution de code Python, et elle permet notament d&#8217;installer des libs externes automatiquement en les téléchargeant depuis le grand InterBoule.</p>
<p>Comme <code>gem install</code> sous ruby, <code>npm</code> pour NodeJs, Python possède sa commande d&#8217;installation appelée <code>easy_install</code>, qui va piocher dans le site Web <a href="http://pypi.python.org/pypi">pypi.python.org</a>, un équivalent de <a href="http://www.cpan.org/">Cpan</a> de Perl ou des <a href="http://pear.php.net/channels/">channels pear</a> pour PHP.</p>
<p>Bien entendu, ça serait trop simple sinon, Python ne vient pas par défaut installé avec cet outil pourtant indispensable.</p>
<p>Sous Ubuntu c&#8217;est facile:</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> python-setuptools</pre></div></div>

<p>Et il existe un paquet similaire sur toutes les distribs.</p>
<p>Sous windows, c&#8217;est <a href="http://pypi.python.org/pypi/setuptools#downloads">un exe</a> à installer. Choisissez la bonne version selon votre version de Python (<code>python --version</code>). Généralement, la 2.7.</p>
<p>Sous mac, il faut télécharger <a href="http://pypi.python.org/pypi/setuptools#downloads">l&#8217;egg correspondant à sa version</a> puis:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sh</span> setuptools-votre_version.egg <span style="color: #660033;">--prefix</span>=~</pre></div></div>

<p>Et vous avez alors accès à la commande magique, <code>easy_install</code>. Par exemple, pour installer Django:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">easy_install django <span style="color: #660033;">--user</span></pre></div></div>

<p>(ou <code>easy_install django</code> en mode administrateur &#8211; ou avec <code>sudo</code> &#8211; pour l&#8217;installer pour tout le système et pas juste l&#8217;utilisateur courant)</p>
<p>Il faut bien entendu être connecté à internet pour que ça marche.</p>
<p>Notez par ailleurs que la recherche est insensible à la casse, et que tout underscore sera automatiquement remplacé par un tiret.</p>
<h2>Vous avez <code>easy_install</code> ? Oubliez-le !</h2>
<p>Vous n&#8217;utiliserez normalement <code>easy_install</code> que pour une seule chose: installer <code>pip</code>.</p>

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

<p><code>pip</code> est un <code>easy_install</code> en plus court à taper, plus puissant, plus souple, plus mieux.</p>
<p>Il s&#8217;utilise comme <code>easy_install</code> :</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> <span style="color: #660033;">--user</span> bottle</pre></div></div>

<p>(ou <code>sudo pip install bottle</code>, ou en root, mais je sauterai ce genre de détails pour la suite)</p>
<p>Grâce à <code>pip</code>, vous allez avoir accès à des milliers de libs Python en quelques frappes, et donc pouvoir beaucoup plus facilement expérimenter avec des nouveaux bidules.</p>
<p>Mais <code>pip</code> va plus loin qu&#8217;<code>easy_install</code>, et permet carrément de gérer toutes les dépendances de son projet.</p>
<h2>Ce que fait <code>pip</code> que <code>easy_install</code> ne fait pas</h2>
<p>Déjà, <code>pip</code> télécharge toutes les dépendances avant de lancer l&#8217;installation, ce qui évite une installation partielle.</p>
<p>Mais surtout, <code>pip</code> ajoute des opérations qu&#8217;on pourrait attendre de base, notamment, la désinstallation :-)</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pip uninstall bottle</pre></div></div>

<p>Évidement, on peut choisir d&#8217;installer une version particulière:</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> <span style="color: #007800;">bottle</span>==<span style="color: #000000;">0.9</span></pre></div></div>

<p>Et mettre à jour une lib à la dernière version :</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> bottle <span style="color: #660033;">--upgrade</span></pre></div></div>

<p>Ou downgrader vers une version précédente:</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> <span style="color: #007800;">bottle</span>==<span style="color: #000000;">0.9</span> <span style="color: #660033;">--upgrade</span></pre></div></div>

<p>Cependant, le plus intéressant avec <code>pip</code>, c&#8217;est sa capacité à recréer tout un environnement de développement en une commande:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ pip freeze
<span style="color: #007800;">Axiom</span>==0.6.0
<span style="color: #007800;">BeautifulSoup</span>==3.2.0
<span style="color: #007800;">Brlapi</span>==0.5.6
<span style="color: #007800;">BzrTools</span>==2.5.0
<span style="color: #007800;">CherryPy</span>==3.2.2
<span style="color: #007800;">Coherence</span>==0.6.6.2
<span style="color: #7a0874; font-weight: bold;">&#91;</span>...<span style="color: #7a0874; font-weight: bold;">&#93;</span></pre></div></div>

<p><code>pip freeze</code> liste toutes les librairies installées et leurs versions. On peut ensuite les réinstaller sur une autre machine facilement:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pip freeze <span style="color: #000000; font-weight: bold;">&gt;</span> requirements.txt</pre></div></div>

<p>Et sur l&#8217;autre machine:</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> <span style="color: #660033;">-r</span> requirements.txt</pre></div></div>

<p>On est garanti d&#8217;avoir les mêmes libs, avec les mêmes versions. Ca marche de la même manière sous tous les OS, et comme des milliers de libs ne sont pas disponibles en paquets *.deb, *.rpm ou *.exe, c&#8217;est extrêmement pratique.</p>
<p>Si vous vous attendez à être privé de connexion internet ou juste pour accélérer le procédé, <code>pip</code> permet de créer un bundle, c&#8217;est à dire un gros zip qui contient toutes les dépendances et qui peut être installé indépendamment :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pip bundle nom_du_projet.pybundle <span style="color: #660033;">-r</span> requirements.txt</pre></div></div>

<p>Et sur l&#8217;autre machine:</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> nom_du_projet.pybundle</pre></div></div>

<h2>Quelques astuces pour être productif avec <code>pip</code></h2>
<p>Si vous installez beaucoup de fois les mêmes paquets, par exemple dans de nombreux virtualenvs j&#8217;installe toujours ipython + ipdb + requests + clize + peewee, les télécharger à chaque fois est une perte de temps. On peut demander à <code>pip</code> de mettre en cache les paquets déjà installés, pour de futures installations:</p>
<p><code>export PIP_DOWNLOAD_CACHE='~/.pip/cache';</code> dans le <em>.bashrc</em></p>
<p>Pour les windowsiens, je ne sais pas du tout où mettre ça&#8230;</p>
<p>Sachez cependant que le cache ne dispense pas d&#8217;être connecté à Internet.</p>
<p>Si une bibliothèque n&#8217;est pas encore sur pypi, <code>pip</code> est capable, pourvu que le code source vienne avec un fichier <em>setup.py</em>, de l&#8217;installer depuis un fichier local, une URL, ou même un simple repo git. Donc si vous trouvez une lib chouette sur github, on peut l&#8217;installer ainsi:</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> <span style="color: #c20cb9; font-weight: bold;">git</span>+<span style="color: #c20cb9; font-weight: bold;">git</span>:<span style="color: #000000; font-weight: bold;">//</span>github.com<span style="color: #000000; font-weight: bold;">/</span>sametmax<span style="color: #000000; font-weight: bold;">/</span>0bin.git</pre></div></div>

<p>Et elle sera même référencée par le <code>pip freeze</code> !</p>
<p>Remarquez qu&#8217;il faut avoir Git installé, et que le protocole doit être changé pour <em>git+git</em>.</p>
<p>Parfois, pypi est indisponible: un problème sur le site, un problème de dns, un problème de votre FAI&#8230; Dans ce cas là on est un peu désemparé. Heureusement, <code>pip</code> permet aussi de faire un fallback sur des miroirs:</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> <span style="color: #660033;">--use-mirrors</span> requests</pre></div></div>

<p>Dans ce cas pip essayera de trouver le paquet sur une liste de sites miroirs de pypi qu&#8217;il possède en interne. Il va les essayer un par un jusqu&#8217;à en trouver un de disponible.</p>
<p>Dans le cas les plus extrêmes, certains vont jusqu&#8217;à créer leur propre miroir en local. Mais c&#8217;est un article à part entière.</p>
<h2>Installer des bibliothèques avec des extensions en C</h2>
<p>Les bibliothèques avec des extensions en C sont très courantes dans les domaines qui ont besoin de performances: drivers de base de données (m<code>ysql-python</code>), calculs scientifiques (<code>numpy</code>), parsing (<code>lxml</code>), cryptographie (<code>pycrypto</code>), etc.</p>
<p>Pip ne fonctionnera que partiellement pour installer ces libs: il devra en effet lancer la compilation de l&#8217;extension. Bien que le processus soit automatique et bien fait, il arrive souvent qu&#8217;il manque des dépendances.</p>
<p>Pour ce genre de lib, soit vous utilisez un paquet tout fait (*.deb, *.exe, *.rpm, etc.), soit vous tentez d&#8217;installer les dépendances.</p>
<p>La première chose à faire, c&#8217;est installer les headers de Python. Sous Ubuntu, c&#8217;est:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">sudo apt-get install python-dev</pre></div></div>

<p>(et sous CentOs, c&#8217;est un <code>yum install python-devel</code>. Pour Mac, aucune idée.)</p>
<p>Ensuite, on lance l&#8217;installation une fois de la lib, et on voit ce qui plante, pour installer les dépendances en conséquence. Par exemple, <code>lxml</code> a besoin des headers de <code>libxml2</code> et <code>libxslt1</code>. Donc on va installer <code>libxml2-dev</code> et <code>libxslt1-dev</code>. Pour <code>python-mysql</code>, il va falloir installer <code>libmysqlclient-dev</code>.</p>
<p>Quand on est une grosse feignasse, mais que l&#8217;on a quand même envie d&#8217;installer la lib avec <code>pip</code> (typiquement, dans le cas d&#8217;un virtualenv). on peut faire le compromis de l&#8217;installer sur le système avec un paquet, et ensuite de l&#8217;installer avec <code>pip</code>. Ca évite de faire la chasse aux dépendances, mais ça fait double installation.</p>
<p>Enfin, il y a des libs qui ne s&#8217;installeront jamais avec <code>pip</code>. Par exemple, un mastodonte genre <code>PyQT</code>. Oubliez, c&#8217;est tout.</p>


feed_id: http://sametmax.com/?p=2034
title: Récupérer des éléments d’une liste au hasard avec pondération en python
uri: Récupérer-des-éléments-d-une-liste-au-hasard-avec-pondération-e
url: http://sametmax.com/recuperer-des-elements-dune-liste-au-hasard-avec-ponderation-en-python/
content:
<p>Une méthode qui vaut ce qu&#8217;elle vaut mais qui sert pas mal.</p>
<p>Cas de figure, on veut uploader du contenu qui sera mis à disposition d&#8217;utilisateurs sur 3 serveurs sur lesquels il ne reste pas la même place&#8230;<br />
on peut utiliser une commande ssh pour <a title="Executer une commande sur un serveur distant via ssh avec Python" href="http://sametmax.com/executer-une-commande-sur-un-serveur-distant-via-ssh/">récupérer la place sur les serveurs</a> par exemple et mettre le résultat dans une liste:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: black;">&#91;</span><span style="color: black;">&#91;</span>place_restante, nom_du_serveur<span style="color: black;">&#93;</span><span style="color: black;">&#93;</span>
&nbsp;
servers = <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'10'</span>,<span style="color: #483d8b;">'server1'</span><span style="color: black;">&#93;</span>,<span style="color: black;">&#91;</span><span style="color: #483d8b;">'45'</span>,<span style="color: #483d8b;">'server2'</span><span style="color: black;">&#93;</span>,<span style="color: black;">&#91;</span><span style="color: #483d8b;">'34'</span>,<span style="color: #483d8b;">'server3'</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span></pre></div></div>

<p>La logique voudrait qu&#8217;on balance le contenu sur tous les serveurs mais surtout sur le 1 car il a beaucoup de place le salop mais qu&#8217;il faut pas tout mettre dessus car on va bouffer toute sa bande passante lors des downloads du contenu alors qu&#8217;on a 2 autres serveurs qui branlent rien ou presque&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> w_choice<span style="color: black;">&#40;</span>lst, nb=<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
        weighted choice give it a list as this:
        [[45, 'item1'], [12, 'item2'],[88, 'item3']]
        nb= Number of items to return
    &quot;&quot;&quot;</span>
    items = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
    w_items = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># on récupère tous les serveurs de la liste et leur &quot;poids&quot; (place restante en % par ex)</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> weight, item <span style="color: #ff7700;font-weight:bold;">in</span> lst:
        <span style="color: #808080; font-style: italic;"># on créé une liste dans laquelle on multiplie le nom du serveur par son poids, ex si server1 a 4 de poids on aura 4 éléménts server1</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">100</span>-weight<span style="color: black;">&#41;</span>:
            items.<span style="color: black;">append</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># on secoue mais on frappe pas</span>
    <span style="color: #dc143c;">random</span>.<span style="color: black;">shuffle</span><span style="color: black;">&#40;</span>items<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># on récupère x serveurs sur lesquel on uploadera le contenu</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> item <span style="color: #ff7700;font-weight:bold;">in</span> items:
        <span style="color: #ff7700;font-weight:bold;">if</span> item <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> w_items:
            w_items.<span style="color: black;">append</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>w_items<span style="color: black;">&#41;</span>==nb:
                <span style="color: #ff7700;font-weight:bold;">break</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> w_items</pre></div></div>

<p><strong>ci-dessous un petit test pour voir que ça marche:</strong></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">servers = <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'10'</span>,<span style="color: #483d8b;">'server1'</span><span style="color: black;">&#93;</span>,<span style="color: black;">&#91;</span><span style="color: #483d8b;">'45'</span>,<span style="color: #483d8b;">'server2'</span><span style="color: black;">&#93;</span>,<span style="color: black;">&#91;</span><span style="color: #483d8b;">'34'</span>,<span style="color: #483d8b;">'server3'</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span>
&nbsp;
items = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span>:
    lst = w_choice<span style="color: black;">&#40;</span>servers<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> item <span style="color: #ff7700;font-weight:bold;">in</span> lst:
        items.<span style="color: black;">update</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span>item:items.<span style="color: black;">get</span><span style="color: black;">&#40;</span>item, <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>+<span style="color: #ff4500;">1</span><span style="color: black;">&#125;</span> <span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> items</pre></div></div>

<p><strong>On obtient:<br />
</strong><code>{'server1': 414, 'server2': 273, 'server3': 313}</code></p>
<p>Ici server1 sort le plus souvent(414 fois) car la place occupée sur son disque est de 10%, logique qu&#8217;on lui envoie plus souvent du contenu histoire de le remplir.</p>
<p>Je ne trouve pas ma fonction spécialement élégante ceci-dit, si certains ont mieux à proposer qu&#8217;ils se fassent entendre ;)</p>


feed_id: http://sametmax.com/?p=2041
title: Récupérer l’IP client avec Nginx en proxy sous CherryPy/Django/Bottle – proxy_set_header
uri: Récupérer-l-IP-client-avec-Nginx-en-proxy-sous-CherryPy-Django-Bot
url: http://sametmax.com/recuperer-lip-client-avec-nginx-en-proxy-sous-cherrypy-proxy_set_header/
content:
<p>Si vous utilisez Nginx en proxy, vous allez vous heurter à son IP lorsque votre script tentera de récupérer l&#8217;IP du client soit 127.0.0.1.</p>
<p>En rajoutant ces quelques lignes à votre config <a href="http://wiki.nginx.org/HttpProxyModule#proxy_set_header">Nginx</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">location <span style="color: #000000; font-weight: bold;">/</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span> 
 <span style="color: #666666; font-style: italic;"># ici un proxy pass quelconque</span>
 proxy_pass http:<span style="color: #000000; font-weight: bold;">//</span>cherrypy;
&nbsp;
 <span style="color: #666666; font-style: italic;"># et ici la magie opère</span>
 proxy_set_header Host <span style="color: #007800;">$host</span>;
 proxy_set_header X-Real-IP <span style="color: #007800;">$remote_addr</span>;
 proxy_set_header X-Forwarded-For <span style="color: #007800;">$proxy_add_x_forwarded_for</span>;
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></div></div>

<p><strong>Dans votre script python (ici Bottle), vous pouvez du coup la récupérer:<br />
</strong></p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#get user IP</span>
user_ip = request.remote_addr</pre></div></div>


feed_id: http://sametmax.com/?p=2167
title: Un petit alias bash pour git que j’aime bien
uri: Un-petit-alias-bash-pour-git-que-j-aime-bien
url: http://sametmax.com/un-petit-alias-bash-pour-git-que-jaime-bien/
content:
<p>Dans mon <em>.bashrc</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> commit <span style="color: #7a0874; font-weight: bold;">&#123;</span>
    <span style="color: #c20cb9; font-weight: bold;">git</span> commit <span style="color: #660033;">-m</span> <span style="color: #ff0000;">&quot;<span style="color: #780078;">`echo &quot;$*&quot; | sed -e 's/^./\U&amp;\E/g'`</span>&quot;</span>
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
<span style="color: #7a0874; font-weight: bold;">alias</span> <span style="color: #007800;">co</span>=commit;</pre></div></div>

<p>Et du coup au lieu de taper:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> commit <span style="color: #660033;">-m</span> <span style="color: #ff0000;">&quot;Encore merci et bonne chance, nous sommes avec vous&quot;</span></pre></div></div>

<p>Je tape:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">co</span> encore merci et bonne chance, nous sommes avec vous</pre></div></div>

<p>Notez la mise en majuscule automatique, le comble de la feignasse ;-)</p>
<p>Bon, c&#8217;est juste sur ma machine, car sinon <code>co</code> beaucoup de gens l&#8217;utilisent pour <code>checkout</code>.</p>
<p>Pour le reste, j&#8217;utilise <a href="http://sametmax.com/scm-breeze-facilite-la-selection-de-vos-fichiers-a-commiter-sous-git-avec/">SCM breeze</a> bien entendu.</p>


feed_id: http://sametmax.com/?p=2094
title: Les usages légaux de BitTorrent
uri: Les-usages-légaux-de-BitTorrent
url: http://sametmax.com/les-usages-legaux-de-bittorrent/
content:
<p><a href="https://fr.wikipedia.org/wiki/BitTorrent_%28protocole%29">BitTorrent</a> est diabolisé, mais c&#8217;est comme la télévision: ce n&#8217;est pas parce que la majorité des gens en font un mauvais usage qu&#8217;il faut considérer que c&#8217;est une technologie satanique.</p>
<h2>Déploiement de code</h2>
<p>BitTorrent à cela de merveilleux que plus il y a de personnes qui téléchargent, plus le téléchargement est rapide. Pour cette raison, les grandes entreprises l&#8217;utilisent pour déployer leur code en productions sur leurs centaines de serveur, avec des <a href="http://vimeo.com/11280885">gains de vitesse allant jusqu&#8217;à 7500 %</a>.</p>
<p>Twitter et <a href="http://torrentfreak.com/facebook-uses-bittorrent-and-they-love-it-100625/">Facebook</a> sont connus pour utiliser le protocole p2p pour économiser exactement ça.</p>
<h2>Distribution de patch et vente de jeux</h2>
<p>On pense toujours que le peer to peer ce n&#8217;est pas pour le kikoo lol moyen, que c&#8217;est compliqué. Mais en fait énormément de Kevin de base utilisent BitTorrent sans le savoir.</p>
<p>La raison ?</p>
<div id="attachment_2112" class="wp-caption aligncenter" style="width: 366px"><a href="http://sametmax.com/wp-content/uploads/2012/09/patch3.jpg"?9d7bd4"><img class=" wp-image-2112 " title="Vous jouez à Wow, SC2 ou Diablo 3 ? Vous utilisez BitTorrent !" src="http://sametmax.com/wp-content/uploads/2012/09/patch3.jpg"?9d7bd4" alt="Capture d'écran du logiciel de mise à jour des jeux Blizzard" width="356" height="316" /></a><p class="wp-caption-text">Vous jouez à Wow, SC2 ou Diablo 3 ? Vous utilisez BitTorrent !</p></div>
<p>Blizzard utilise en effet BitTorrent dans son fameux logiciel &#8220;Blizzard downloader&#8221; pour distribuer les installeurs des jeux vendus sur Battle.net, mais également toutes les mises à jour des dit jeux.</p>
<p>Quand on a des millions de joueurs qui sont du coup autant de serveurs, on économise un MAX de pognon. On parle de millions d&#8217;euros là.</p>
<h2>Distribution d&#8217;iso</h2>
<p>Quelqu&#8217;un qui surf sur Internet (<a href="http://en.wikipedia.org/wiki/Usage_share_of_operating_systems#Servers">60% des serveurs Web dans le monde</a>), utilise un téléphone Android ou regarde une vidéo sur sa Freebox utilise Linux. Or l&#8217;acquisition d&#8217;une ISO d&#8217;installation Linux se fait massivement à travers BitTorrent, pour justement éviter de surcharger les éditeurs de distro qui ont un budget limité. Votre serviteur tape d&#8217;ailleurs cet article sur une Ubuntu installé depuis une ISO téléchargée via BitTorrent.</p>
<p>D&#8217;une manière générale, si on a un gros fichier à partager sur un blog, le mettre à disposition via BitTorrent est ce qu&#8217;il y a de plus pratique, ça évite de tuer son hébergement. Pour cette raison, <a href="http://noisemore.wordpress.com/2006/03/14/amazon-s3-has-bittorrent-support/">Amazon S3 le supporte par défaut</a>.</p>
<h2>Potentiel</h2>
<p>Parce que des gens stressés par la mutation des mœurs ne voient pas plus loin que le bout de leur narines, et parce que &#8220;BitTorrent, c&#8217;est surtout utilisé pour pirater, il faut pas déconner&#8221;, cette technologie est largement sous exploitée. On pourrait faire la mise à jour de tous les logiciels avec, même la mise à jour des OS, et carrément l&#8217;intégrer dans les gestionnaires de paquets. On pourrait faire du streaming avec: chaque visionneur repartageant des paquets, et allégeant la charge des fournisseurs de VOD.</p>
<p>Si l&#8217;usage de BitTorrent se généralise, ce sont des économies à l&#8217;échelle du monde qui seront réalisées, mais aussi l&#8217;opportunité pour plein de &#8220;petits&#8221; de mettre à disposition du gros contenu pour le grand public. Ce serait fabuleux que tous les navigateurs intègrent le téléchargement BitTorrent par défaut, comme le fait <a href="http://help.opera.com/Windows/9.00/en/bittorrent.html">Opéra</a> (qui est d&#8217;ailleurs aussi <a href="http://www.opera.com/download/torrents/">téléchargeable</a> en torrent). Parce que pour le moment, allez proposer à mamie de télécharger un truc avec BitTorrent&#8230; J&#8217;ai expliqué à mon père il y a quelques semaines, lui qui pourtant sait ce que c&#8217;est qu&#8217;un cable SCSI et qui a été le premier à utiliser CloneCD en son temps, il a eu du mal.</p>
<p>Pour le moment, les ports sont souvent bloqués, le protocole est souvent bridé, les applications <a href="http://torrentfreak.com/apple-sorry-bittorrent-apps-were-approved-by-mistake-120911/">censurées</a> sur les appstores, et tout ce potentiel est perdu.</p>
<p>Chers éditeurs de contenu, même dans le cas improbable ou vous gagniez la bataille de la maîtrise du Net, empêchant les méchants pirates de vous voler de quoi vous acheter votre prochain coupé sport, j&#8217;ai toujours un disque dur externe et des amis. Qui en ont aussi.</p>
<p>Donc puisque vous ne pouvez pas arrêter le piratage sans transformer le pays en dictature stalinienne, ayez au moins la décence de laisser tranquille des technologies brillantes et extraordinairement utiles pour tous. C&#8217;est peut être un détail pour vous, mais pour nous ça veut dire beaucoup.</p>
<p>&nbsp;</p>


feed_id: http://sametmax.com/?p=2176
title: Connaître sa version de Nginx
uri: Connaître-sa-version-de-Nginx
url: http://sametmax.com/connaitre-sa-version-de-nginx/
content:
<p><a href="http://nginx.org/">Nginx</a>, le super serveur web qui n&#8217;est plus à présenter profite de mises à jours régulières. Sa communauté est très active pour le bien de tous. A l&#8217;heure actuelle <a href="http://w3techs.com/technologies/cross/web_server/ranking">Nginx est présent sur plus de 27% des serveurs dont les sites sont dans le top 1000 Alexa </a></p>
<p>Pour savoir si votre version n&#8217;est pas désuète vous pouvez en ligne de commande obtenir la version de Nginx que vous possedez ainsi que les paramètres de compilation.</p>
<p><strong>Connaître sa version de Nginx grace à l&#8217;option -V:</strong></p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">user<span style="color: #000000; font-weight: bold;">@</span>mon_serveur:~<span style="color: #666666; font-style: italic;"># /usr/local/nginx/sbin/nginx -V</span>
nginx version: nginx<span style="color: #000000; font-weight: bold;">/</span>1.3.5
built by <span style="color: #c20cb9; font-weight: bold;">gcc</span> 4.6.3 <span style="color: #7a0874; font-weight: bold;">&#40;</span>Ubuntu<span style="color: #000000; font-weight: bold;">/</span>Linaro 4.6.3-1ubuntu5<span style="color: #7a0874; font-weight: bold;">&#41;</span> 
configure arguments: <span style="color: #660033;">--prefix</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx --with-http_flv_module --with-http_mp4_module --with-http_secure_link_module</pre></div></div>


feed_id: http://sametmax.com/?p=2192
title: Le godemichet ou gode ou encore dildo, sex-toy – origines et usages de nos jours
uri: Le-godemichet-ou-gode-ou-encore-dildo-sex-toy-origines-et-usages
url: http://sametmax.com/le-godemichet-ou-gode-ou-encore-dildo-sex-toy-origines-et-usages-de-nos-jours/
content:
<p>Qui n&#8217;a pas entendu parler de gode dans sa vie ? On en voit dans beaucoup de <a href="http://sextvx.com/fr/video/114921/zafira-actrice-x-gros-lolos-plaisir-solitaire-gode" title="femme qui se gode">films pornos</a>, les godes peuvent faire parti d&#8217;un plaisir solo ou d&#8217;un jeu à deux ou plus entre femmes, couples, hommes, etc&#8230;</p>
<p>Beaucoup de personnes pensent (à tord) que le gode est arrivé avec les sex shop, les tenues de soubrette et autre boutiques de gadgets érotiques.</p>
<p><strong>Les origines du gode:</strong><br />
En fait le godemichet ne date pas d&#8217;hier, ni d&#8217;avant hier d&#8217;ailleur, d&#8217;après Wikipédia <a href="http://fr.wikipedia.org/wiki/Godemichet">on aurait retrouvé un godemichets datant de 2 Siècles avant JC</a>. A croire que déjà à l&#8217;époque ces sales femeles savaient se passer de nous!</p>
<p><strong>L&#8217;Etymologie:</strong><br />
ça vient d&#8217;où ce mot gode ? Toujours d&#8217;après wikipédia (non je n&#8217;ai pas d&#8217;actions chez eux) il y aurait 2 hypotèses:<br />
- du Catalan &#8220;godomacil&#8221; pour &#8220;Cuir de Gadamès&#8221;<br />
- du latin médiéval &#8220;Gaude mihi&#8221; pour &#8220;Réjouis-moi&#8221;<br />
Perso je préfère la seconde, elle me parle plus ^^</p>
<p><strong>Les femmes et les godes:</strong><br />
Là où à mon époque le gode était plus ou moins réservé aux films de cul, ou du moins personne n&#8217;en parlait, de nos jour les femmes affichent sans complexe leurs petits sex-toys (24% des femmes en posséderait un ou plus). Même si une majorité (55%) trouve celà encore vulgaire.</p>
<div id="attachment_2194" class="wp-caption alignnone" style="width: 448px"><a href="http://sametmax.com/wp-content/uploads/2012/09/Sell_Glans_rabbit_vibrator_sex.jpeg"?9d7bd4"><img src="http://sametmax.com/wp-content/uploads/2012/09/Sell_Glans_rabbit_vibrator_sex.jpeg"?9d7bd4" alt="" title="Cherche le lapin blanc..." width="438" height="560" class="size-full wp-image-2194" /></a><p class="wp-caption-text">Le fameux Rabbit Vibrator de Sex&#038;The City</p></div>
<p>La télé a pas mal participée à la banalisation des sex-toys, vous vous rappelez ? non ?! Mais siiiiii dans Sex &#038; the city on y présente le &#8220;Rabbit Vibrator&#8221; :<br />
<iframe width="420" height="315" src="http://www.youtube.com/embed/NIE520LpIds" frameborder="0" allowfullscreen></iframe></p>
<p>Ce sex-toys a d&#8217;ailleurs connu un énorme succès auprès du public de par sa double simulation (anale et clitoridienne).<br />
Pour la petite histoire &#8220;Rabbit&#8221; viendrait de la forme de son stimulateur (rabbit veut dire lapin en anglais) tout droit arrivé du Japon où il est interdit de produire des sex toys ayant pour forme celle d&#8217;un pénis &#8211; Oui ces gens sont bizarres, rappelez-vous l&#8217;article <a href="http://sametmax.com/les-japonais-et-le-sexe-des-gros-malades-ou-pas/">les japonais et le sexe</a> &#8211; forcant donc les concepteurs à imaginer cet engin bizarre.<br />
Aller une petite <a href="http://sextvx.com/fr/video/109712/busty-babe-drilling-a-rabbit-vibrator" title="Vidéo Rabbit Vibrator">vidéo du Rabbit Vibrator</a> en action ;)</p>
<p><strong>Il y a aussi les ceintures godes ou Strap-on en anglais:</strong><br />
<div id="attachment_2195" class="wp-caption alignnone" style="width: 260px"><a href="http://sametmax.com/wp-content/uploads/2012/09/ceinture-gode.jpeg"?9d7bd4"><img src="http://sametmax.com/wp-content/uploads/2012/09/ceinture-gode.jpeg"?9d7bd4" alt="" title="A taaable...." width="250" height="250" class="size-full wp-image-2195" /></a><p class="wp-caption-text">Qui s&#039;y frotte s&#039;y pique!</p></div></p>
<p><strong>Niche récente, les brutal-dildo:</strong><br />
Avec internet et son lot toujours grandissant de consommateurs exigeants on a vu apparaître une niche il y a quelques années, la niche des godes énormes. D&#8217;ailleurs j&#8217;en vends un car il prend beaucoup de place dans le salon&#8230;</p>
<div id="attachment_2196" class="wp-caption alignnone" style="width: 490px"><a href="http://sametmax.com/wp-content/uploads/2012/09/brutal-dildo.jpeg"?9d7bd4"><img src="http://sametmax.com/wp-content/uploads/2012/09/brutal-dildo.jpeg"?9d7bd4" alt="" title="2 pour le prix d&#039;un" width="480" height="640" class="size-full wp-image-2196" /></a><p class="wp-caption-text">Ho le jolie cadeau qu&#039;elle a eu pour Noël...</p></div>
<p>Moins facile à dissimuler dans le sac à main&#8230;</p>
<p><strong>Le godemichet, un danger pour l&#8217;humanité ?</strong><br />
Et si demain toutes les femmes possedaient un godemichet à quoi servirions-nous ? On pourrait se poser la question et flipper un peu. Il serait interressant de connaitre la fréquence des rapports sexuels d&#8217;un couple possédant un sex-toy chez eux et le comparer à coupl n&#8217;en n&#8217;ayant, tout comme ceux qui ont une télé d&#8217;ailleurs&#8230; </p>
<p>Ceci dit étant 7 Milliards sur terre, une petite baisse de la natalité serait la bienvenue :)</p>


feed_id: http://sametmax.com/?p=2183
title: Je voulais juste installer une gem.
uri: Je-voulais-juste-installer-une-gem
url: http://sametmax.com/je-voulais-juste-installer-une-gem/
content:
<pre>
sudo gem install xiki
[sudo] password for sam:
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: sexp_processor-3.2.0.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: ruby_parser-2.3.1.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: ruby2ruby-1.3.1.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: tins-0.5.4.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: file-tail-1.0.11.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: sourcify-0.5.0.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: multi_xml-0.5.1.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: httparty-0.9.0.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
When you HTTParty, you must party hard!
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: i18n-0.6.1.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: activesupport-3.2.8.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: method_source-0.8.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: net-ssh-2.5.2.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: net-scp-1.0.4.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: net-sftp-2.0.5.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: rspec-core-2.11.1.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: diff-lcs-1.1.3.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: rspec-expectations-2.11.3.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: rspec-mocks-2.11.2.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: rspec-2.11.0.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: trogdoro-el4r-1.0.7.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: daemons-1.1.9.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Fetching: xiki-0.6.3.gem (100%)
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Successfully installed sexp_processor-3.2.0
Successfully installed ruby_parser-2.3.1
Successfully installed ruby2ruby-1.3.1
Successfully installed tins-0.5.4
Successfully installed file-tail-1.0.11
Successfully installed sourcify-0.5.0
Successfully installed multi_xml-0.5.1
Successfully installed httparty-0.9.0
Successfully installed i18n-0.6.1
Successfully installed activesupport-3.2.8
Successfully installed method_source-0.8
Successfully installed net-ssh-2.5.2
Successfully installed net-scp-1.0.4
Successfully installed net-sftp-2.0.5
Successfully installed rspec-core-2.11.1
Successfully installed diff-lcs-1.1.3
Successfully installed rspec-expectations-2.11.3
Successfully installed rspec-mocks-2.11.2
Successfully installed rspec-2.11.0
Successfully installed trogdoro-el4r-1.0.7
Successfully installed daemons-1.1.9
Successfully installed xiki-0.6.3
22 gems installed
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z"
Installing ri documentation for sexp_processor-3.2.0...
Installing ri documentation for ruby_parser-2.3.1...
Installing ri documentation for ruby2ruby-1.3.1...
Installing ri documentation for tins-0.5.4...
Installing ri documentation for file-tail-1.0.11...
Installing ri documentation for sourcify-0.5.0...
Installing ri documentation for multi_xml-0.5.1...
Installing ri documentation for httparty-0.9.0...
Installing ri documentation for i18n-0.6.1...
Installing ri documentation for activesupport-3.2.8...

unrecognized option `--encoding'

For help on options, try 'rdoc --help'

ERROR:  While generating documentation for activesupport-3.2.8
... MESSAGE:   exit
... RDOC args: --ri --op /var/lib/gems/1.8/doc/activesupport-3.2.8/ri --encoding UTF-8 lib --title activesupport-3.2.8 Documentation --quiet
</pre>
<p>Je sais, je sais, c&#8217;est encore un troll. Mais ça fait 5 ans que c&#8217;est mon expérience avec Ruby. J&#8217;en est marre des trucs qu&#8217;il faut toujours bricoler pour que ça marche. J&#8217;ai plus 16 ans.</p>
<p>Et encore, si le message d&#8217;erreur, ou une doc quelque part me disait comment fixer ça&#8230;.</p>
<p>C&#8217;est encore pire avec <a href="http://sametmax.com/non-nodejs-nest-pas-mature/">npm</a>, évidement.</p>


feed_id: http://sametmax.com/?p=2211
title: Arnaque sur Facebook avec compte piraté et numéro surtaxé
uri: Arnaque-sur-Facebook-avec-compte-piraté-et-numéro-surtaxé
url: http://sametmax.com/arnaque-sur-facebook-avec-comptes-pirates-et-numeros-surtaxes/
content:
<p>Etant sur le wouebe depuis pas mal de temps et connaissant le monde des numéros surtaxés (ha les joies du cul il y a 10 ans avec les services à 10 francs la minute&#8230;) je reste toujours sur mes gardes quand je reçois des e-mails foireux et autres&#8230;</p>
<p>Mais là je dois dire que j&#8217;ai bien failli me laisser avoir&#8230;</p>
<p><strong> Facebook, l&#8217;arme des nouveaux escrocs</strong><br />
Et voilà un bon titre à la M6 Capital, Bernard si tu nous regarde&#8230;<br />
Le principe est le suivant, des petits malins pirates un compte facebook et utilisent l&#8217;identité de la victime pour demander de l&#8217;aide à leurs amis ( les amis de la victime). En loccurence on m&#8217;a demandé de bien vouloir appeler un numéro pour débloquer un téléphone, après quelques recherches sur le net je me suis aperçu que c&#8217;était un numéro surtaxé de la société <a href="http://www.allopass.com/">Allopass</a>.</p>
<p>voici une copie du discours.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:07:<span style="color: #000000;">40</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Elle: coucou 
bonsoir :<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:09:<span style="color: #000000;">25</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Max: salut poulette
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:09:<span style="color: #000000;">35</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Elle: cava ??
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">12</span>:01<span style="color: #7a0874; font-weight: bold;">&#93;</span> Max: ça roule ouais
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">12</span>:<span style="color: #000000;">20</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Elle: jé un souci
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">12</span>:<span style="color: #000000;">28</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Elle: et je me demande si tu peut m<span style="color: #ff0000;">'aider ??
[20/09/12 19:13:33] Max: dis toujours
[20/09/12 19:15:08] Elle: mon téléphone é bloqué
[20/09/12 19:15:24] Elle: é jé besoin de ton aide pour  que je puisse le débloquer
[20/09/12 19:16:02] Max: j'</span>ai même pas de tel moi :<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">16</span>:<span style="color: #000000;">14</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Max: faut voir la marque et jetter un oeil sur interboule
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">17</span>:01<span style="color: #7a0874; font-weight: bold;">&#93;</span> Max: donne la marque, data d<span style="color: #ff0000;">'achat, opérateur, etc... JE peux regarder les infos, après les manips en général c'</span>est pas compliqué 
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">18</span>:<span style="color: #000000;">54</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Elle: il m<span style="color: #ff0000;">'on demander d'</span><span style="color: #ff0000;">'appeler le numero de service gratuitement
pour que je puisse avoir les codes de débloquage
[20/09/12 19:18:55] Elle: :(
[20/09/12 19:19:03] Max: ha ben voilà
[20/09/12 19:19:19] Elle: le blém cé que jé po une autre carte sim pour que je puisse appeler
[20/09/12 19:19:57] Max: ben gael il a pas de tél ?
[20/09/12 19:20:03] Max: t'</span><span style="color: #c20cb9; font-weight: bold;">as</span> pas de fixe ?
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">20</span>:05<span style="color: #7a0874; font-weight: bold;">&#93;</span> Elle: :<span style="color: #000000; font-weight: bold;">/</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">20</span>:09<span style="color: #7a0874; font-weight: bold;">&#93;</span> Elle: je suis seul ché moi laa
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">20</span>:<span style="color: #000000;">16</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Elle: tu peut esseiller pour moi ??
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">20</span>:<span style="color: #000000;">23</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Max: et ben t<span style="color: #ff0000;">'attends qu'</span>il rentre
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">20</span>:<span style="color: #000000;">29</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Max: t<span style="color: #ff0000;">'es accroc à ce point ? :)
[20/09/12 19:20:34] Max: t'</span><span style="color: #c20cb9; font-weight: bold;">as</span> pas ta DOSE de tél 
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">21</span>:<span style="color: #000000;">26</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Max: ouais donne tjrs le numéro mais à mon avis il svont poser plein de questions de sécurité genre adresse ou truc dans le genre
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">22</span>:<span style="color: #000000;">47</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Elle: 0899 <span style="color: #000000;">233</span> <span style="color: #000000;">549</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">22</span>:<span style="color: #000000;">49</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Elle: nn
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">23</span>:01<span style="color: #7a0874; font-weight: bold;">&#93;</span> Elle: ya un répondeur automatique qui te dicte le code directement apré le bip sonore
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">20</span><span style="color: #000000; font-weight: bold;">/</span>09<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">12</span> <span style="color: #000000;">19</span>:<span style="color: #000000;">25</span>:<span style="color: #000000;">11</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Max: FRANCE : <span style="color: #000000; font-weight: bold;">&gt;</span> Téléphonez au <span style="color: #000000;">0</span> <span style="color: #000000;">899</span> <span style="color: #000000;">233</span> <span style="color: #000000;">549</span> puis suivez les instructions <span style="color: #c20cb9; font-weight: bold;">du</span> robot
<span style="color: #7a0874; font-weight: bold;">&#40;</span>2x <span style="color: #000000;">1</span>,<span style="color: #000000;">34</span> EUR<span style="color: #000000; font-weight: bold;">/</span>appel puis <span style="color: #000000;">0</span>,<span style="color: #000000;">34</span> EUR<span style="color: #000000; font-weight: bold;">/</span>minute, Cout total estimé : <span style="color: #000000;">3</span>,00 EUR<span style="color: #7a0874; font-weight: bold;">&#41;</span>.
&nbsp;
C<span style="color: #ff0000;">'est un numéro allopass ton truc c'</span>est <span style="color: #c20cb9; font-weight: bold;">du</span> flanc</pre></div></div>

<p><strong>Une arme redoutable, LA CONFIANCE</strong><br />
L&#8217;arnaque est pas très originale mais là où j&#8217;ai failli me faire avoir c&#8217;est que cette personne est censée être une amie, donc je part d&#8217;une confiance.<br />
De plus la personne au bout n&#8217;est pas un robot et répond correctement à mes questions pas comme à l&#8217;époque des bots MSN.<br />
Pour un numéro comme celui là l&#8217;affilié (l&#8217;escroc) va toucher une commission de la société Allopass de l&#8217;ordre de 1 ou 2 euros.<br />
C&#8217;est pas beaucoup direz-vous mais imaginez ça mulitplié par 2 ou 3 amis de la personne qu&#8217;il escroque en même temps et ça sur plusieurs comptes dans la journée, c&#8217;est pas négligeable à la fin du mois&#8230;</p>
<p>Il y a de la maille à se faire&#8230;</p>


feed_id: http://sametmax.com/?p=1186
title: Le _ (underscore) dans le shell interactif Python
uri: Le-_-(underscode)-dans-le-shell-interactif-Python
url: http://sametmax.com/le-_-underscode-dans-le-shell-interactif-python/
content:
<p>C&#8217;est une fonctionnalité que peu de gens connaissent, pourtant très utile.</p>
<p>Dans le shell Python, à chaque fois qu&#8217;on évalue une expression, le résultat affiché est référencé dans la variable <code>_</code>.</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: #ff4500;">1</span> + <span style="color: #ff4500;">1</span>
<span style="color: #ff4500;">2</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> _
<span style="color: #ff4500;">2</span></pre></div></div>

<p>On peut évidement la réutiliser comme n&#8217;importe quelle variable:</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: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</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: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: black;">&#91;</span>x <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> _<span style="color: black;">&#93;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">4</span>, <span style="color: #ff4500;">6</span>, <span style="color: #ff4500;">8</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Pour éviter d&#8217;effacer la variable trop souvent, quand le résultat retourné est <code>None</code>, <code>_</code> ne change pas, donc il ne change pas quand on <code>print</code> :-)</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: #ff4500;">1</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #008000;">None</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> _
<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">4</span>, <span style="color: #ff4500;">6</span>, <span style="color: #ff4500;">8</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'a'</span>
a
<span style="color: #66cc66;">&gt;&gt;&gt;</span> _
<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">4</span>, <span style="color: #ff4500;">6</span>, <span style="color: #ff4500;">8</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Ça ne marche que dans le shell, pas dans un script.</p>


feed_id: http://sametmax.com/?p=2234
title: Message subliminal ?
uri: Message-subliminal
url: http://sametmax.com/message-subliminal/
content:
<p>Hier, <strong>36 % du total</strong> des vues du blog venaient des recherches suivantes:</p>
<ul>
<li>sexe japonais;</li>
<li>sex japon;</li>
<li>sexe japon;</li>
<li>sex japonais;</li>
<li>les japonais et le sex;</li>
<li>japonais sexe;</li>
<li>japon et le sexe;</li>
<li>japonaise sexe;</li>
<li>sex japonnaise;</li>
<li>sexe de japon.</li>
</ul>
<p>Vous essayez de nous faire passer un message ?</p>


feed_id: http://sametmax.com/?p=2204
title: Servir un fichier protégé avec Django et Nginx
uri: Servir-un-fichier-protégé-avec-Django-et-Nginx
url: http://sametmax.com/servir-un-fichier-protege-avec-django-et-nginx/
content:
<p>Certains fichiers sont réservés à des personnes ayant payé, avec un compte, ou encore protégés par un mot de passe. Problème: django gère l&#8217;authentification mais ne doit pas gérer l&#8217;upload car c&#8217;est le taff du serveur en front end.</p>
<h2>Etape 1: configurer Nginx</h2>
<p>Je suppose ici que vous avez une config Django classique avec Nginx qui fait un proxy passe vers un serveur WSGI type cherrypy, gunircorn, uwsgi, etc. </p>
<p>Dans votre fichier de config Nginx, rajoutez ceci:</p>
<pre>server {
   ...
   location /chemin/absolu/vers/dossier/du/projet/media {
       internal;
       alias /secure_upload/;
   }
}</pre>
<p>La directive <code>internal</code> s&#8217;assure qu&#8217;une requête extérieur ne peut pas demander d&#8217;accéder à cette adresse.</p>
<h2>Etape 2: authentifier et rediriger avec une vue Django</h2>
<p>Dans cet exemple, on sert uniquement le fichier aux utilisateurs authentifiés. Mais on pourrait très bien le faire sur la saisie d&#8217;un code unique, vérifier les droits d&#8217;accès, etc. J&#8217;ai juste choisi le cas le plus simple.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">contrib</span>.<span style="color: black;">auth</span>.<span style="color: black;">decorators</span> <span style="color: #ff7700;font-weight:bold;">import</span> login_required
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">http</span> <span style="color: #ff7700;font-weight:bold;">import</span> HttpResponse
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">views</span> <span style="color: #ff7700;font-weight:bold;">import</span> static
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span> <span style="color: #ff7700;font-weight:bold;">import</span> settings
&nbsp;
@login_required<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># on accepte uniquement les requête authentifiées</span>
<span style="color: #ff7700;font-weight:bold;">def</span> serve_secure_static<span style="color: black;">&#40;</span>request, path<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># en mode debug, on demande à Django de servir le fichier histoire de pas</span>
    <span style="color: #808080; font-style: italic;"># être forcé de setuper nginx sur sa machine de dev</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> settings.<span style="color: black;">DEBUG</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> static.<span style="color: black;">serve</span><span style="color: black;">&#40;</span>request, path, settings.<span style="color: black;">SECURE_MEDIA_ROOT</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Sinon on retourne une réponse VIDE avec en header le chemin de l'url</span>
    <span style="color: #808080; font-style: italic;"># de l'upload interne</span>
    <span style="color: #808080; font-style: italic;"># Nginx va l'intercepter, réaliser qu'il faut qu'il upload ce qu'il y</span>
    <span style="color: #808080; font-style: italic;"># a à cette URL et faire le reste du boulot</span>
    response = HttpResponse<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    response<span style="color: black;">&#91;</span><span style="color: #483d8b;">'X-Accel-Redirect'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'/secure_upload/%s'</span> <span style="color: #66cc66;">%</span> path
    <span style="color: #ff7700;font-weight:bold;">return</span> response</pre></div></div>

<h2>Etape 3 : configurer Django</h2>
<p>Evidément il vous faut dans le <em>settings.py</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">MEDIA_ROOT = <span style="color: #483d8b;">&quot;/chemin/absolu/vers/dossier/du/projet/media&quot;</span>
SECURE_MEDIA_ROOT = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>MEDIA_ROOT, <span style="color: #483d8b;">'secure'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Les dossiers doivent être créés à la mano.</p>
<p>Et dans <em>urls.py</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">url<span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^download/(?P&lt;path&gt;.*)$'</span>, server_secure_static<span style="color: black;">&#41;</span></pre></div></div>


feed_id: http://sametmax.com/?p=2246
title: Pourquoi if __name__ == '__main__' en Python ?
uri: Pourquoi-if-__name__-__main__-en-Python
url: http://sametmax.com/pourquoi-if-__name__-__main__-en-python/
content:
<p><code>if __name__ == '__main__'</code> est un un idiome qu&#8217;on voit souvent dans les scripts Python.</p>
<h2>A quoi sert-il ?</h2>
<p>Contrairement à d&#8217;autres langages comme le C, le Java ou le C#, Python n&#8217;a pas de fonction ou méthode <code>main()</code>. Quand on lance un script, tout le script est exécute dans tous les cas, et aucune fonction n&#8217;est appelée automatiquement.</p>
<p>Normalement c&#8217;est plutôt une bonne chose. Explicite is better than implicit, tout ça.</p>
<p>Mais cela pose un problème quand on a un script qui contient du code que l&#8217;on souhaite exécuter quand on lance le script directement, mais pas quand on l&#8217;importe dans un autre script. </p>
<p>Par exemple, un script <em>egouts.py</em> qui ne fait rien d&#8217;intéressant (mais qui le fait vachement bien):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> tortues<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;kawabunga&quot;</span>
&nbsp;
tortues<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Si on fait <code>python egouts.py</code>, ça va lancer <code>tortues()</code>. Si on fait <strong>dans un autre script</strong> <code>import egout</code>, ça va aussi lancer <code>tortues()</code>. Pas glop.</p>
<p>Pour éviter ça:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> tortues<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;kawabunga&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    tortues<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Ainsi, si on fait <code>python egouts.py</code>, ça va lancer <code>tortues()</code> mais pas si on fait <code>import egout</code> dans un autre script.</p>
<h2>Comment ça marche ?</h2>
<p>C&#8217;est une condition tout à fait ordinaire, on peut mettre des <code>if</code> n&#8217;importe où dans du code Python.</p>
<p>La seule astuce consiste en l&#8217;existence de la variable <code>__name__</code> qui est une variable automatiquement créée par Python, toujours disponible, n&#8217;importe où, dans tous les scripts.</p>
<p>Cette variable contient le nom du script courant si on importe le script. Ainsi, dans n&#8217;importe quel code, on peut vérifier où on est.</p>
<p>Mais si le script est le script principal, alors <code>__name__</code> ne contient pas le nom du script, il contient la chaîne <code>__main__</code> (oui, c&#8217;est bizarre avec deux underscores, mais c&#8217;est une chaîne normale).</p>
<p>Donc on dit juste: si ce code est exécuté en tant que script principal (appelé directement avec Python et pas importé), alors exécuter cette fonction.</p>


feed_id: http://sametmax.com/?p=2258
title: La théorie de la salle de bain et (un tout petit peu de) Python
uri: La-théorie-de-la-salle-de-bain-et-(un-tout-petit-peu-de)-Python
url: http://sametmax.com/la-theorie-de-la-salle-de-bain-et-un-tout-petit-peu-de-python/
content:
<p>Il y a quelques jours, j&#8217;ai tweeté <a href="http://www.youtube.com/watch?v=F-QA2rkpBSY&#038;feature=list_other&#038;playnext=1&#038;list=SP6A1FD147A45EF50D">une vidéo d&#8217;une heure de mauvaise qualité où l&#8217;on voyait un vieillard parler en anglais de la fonction exponentielle</a>.</p>
<p>Le tweet n&#8217;a pas eu de succès. Je me demande bien pourquoi :-)</p>
<p>C&#8217;est extrêmement fâcheux car cette vidéo est d&#8217;une importance capitale.</p>
<p>En effet, cette petite conf, plus que de maths, parle surtout d&#8217;économie, d&#8217;écologie, de démographie, de la survie de l&#8217;espèce humaine, de sa bêtise, et tout ça avec humour. On en a bien besoin.</p>
<p>J&#8217;ai donc décider de résumer cette vidéo ici, en français, et de mettre un peu de Python dedans pour le lulz.</p>
<h2>La fonction exponentielle, dans votre vie de tous les jours</h2>
<p>Quand vous lisez un truc comme ça dans la presse :</p>
<blockquote><p>Le prix de l&#8217;essence a augmenté de 3 % par an.</p></blockquote>
<p>Vous vous dites &#8220;oh, bah ça va&#8221;</p>
<p>Et puis l&#8217;année suivante:</p>
<blockquote><p>Le prix de l&#8217;essence a doublé depuis les années 90.</p></blockquote>
<p>Et là vous criez &#8220;tous des bâtards, sauf papa parce qu&#8217;il est chauve&#8221;.</p>
<p>Vous aurait-on menti les années précédentes ? Nein. C&#8217;est toute la beauté de la croissance continue, un phénomène mathématique facile à étudier.</p>
<p>Par contre, je sais pas pour vous, mais moi les logs, les e de truc et les epsilons de machin, ça me parle moyen. Alors si on faisait un peu de bruteforce ? Les matheux me pardonneront mes approximations, l&#8217;idée est ici plus importante que la précision des chiffres puisque je suis un charlot.</p>
<p>Prenons une valeur arbitraire, un pourcentage de croissance par an, et regardons combien d&#8217;années ça prend pour doubler:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> calculer_temps_de_doublement<span style="color: black;">&#40;</span>pourcent, valeur=<span style="color: #ff4500;">1000000</span><span style="color: black;">&#41;</span>:
&nbsp;
    double_de_la_valeur = valeur <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">2</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> valeur <span style="color: #66cc66;">&lt;</span> double_de_la_valeur:
        valeur += valeur <span style="color: #66cc66;">*</span> pourcent / <span style="color: #ff4500;">100</span>
        <span style="color: #ff7700;font-weight:bold;">yield</span> valeur</pre></div></div>

<p>Voyons ce que ça donne si on gardait constante la croissance actuelle de la population mondiale:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># croissance de la population mondiale</span>
<span style="color: #ff7700;font-weight:bold;">for</span> i, x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>calculer_temps_de_doublement<span style="color: black;">&#40;</span><span style="color: #ff4500;">1.7</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> i, x
&nbsp;
<span style="color: #ff4500;">0</span> <span style="color: #ff4500;">1017000.0</span>
<span style="color: #ff4500;">1</span> <span style="color: #ff4500;">1034289.0</span>
<span style="color: #ff4500;">2</span> <span style="color: #ff4500;">1051871.913</span>
<span style="color: #ff4500;">3</span> <span style="color: #ff4500;">1069753.73552</span>
...
<span style="color: #ff4500;">39</span> <span style="color: #ff4500;">1962628.57148</span>
<span style="color: #ff4500;">40</span> <span style="color: #ff4500;">1995993.25719</span>
<span style="color: #ff4500;">41</span> <span style="color: #ff4500;">2029925.14256</span></pre></div></div>

<p>Il faut 41 ans pour que ça double. En clair, un minuscule pour-cent virgule sept, et le nombre d&#8217;abrutis sur la Terre double avant que vous ayez atteint la moitié de votre vie.</p>
<p>Voyons la même chose avec la consommation du pétrole:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># croissance de consommation du pétrole</span>
<span style="color: #ff7700;font-weight:bold;">for</span> i, x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>calculer_temps_de_doublement<span style="color: black;">&#40;</span><span style="color: #ff4500;">3.4</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> i, x
&nbsp;
<span style="color: #ff4500;">0</span> <span style="color: #ff4500;">1034000.0</span>
<span style="color: #ff4500;">1</span> <span style="color: #ff4500;">1069156.0</span>
<span style="color: #ff4500;">2</span> <span style="color: #ff4500;">1105507.304</span>
<span style="color: #ff4500;">3</span> <span style="color: #ff4500;">1143094.55234</span>
...
<span style="color: #ff4500;">18</span> <span style="color: #ff4500;">1887514.23841</span>
<span style="color: #ff4500;">19</span> <span style="color: #ff4500;">1951689.72251</span>
<span style="color: #ff4500;">20</span> <span style="color: #ff4500;">2018047.17308</span></pre></div></div>

<p>A votre majorité, la consommation du pétrole de l&#8217;humanité aurait donc doublé. Évidement, ce n&#8217;est vrai que si cette augmentation reste constante, on peut imaginer que notre consommation diminue avec le temps. Jusqu&#8217;ici, la consommation n&#8217;a pas juste augmenté, notre croissance de consommation a presque toujours augmenté. Avec un milliard de chinois et d&#8217;indiens ça va pas s&#8217;arrêter car:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># test avec la croissance chinoise de 2008</span>
<span style="color: #ff7700;font-weight:bold;">for</span> i, x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>calculer_temps_de_doublement<span style="color: black;">&#40;</span><span style="color: #ff4500;">9.8</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> i, x
&nbsp;
<span style="color: #ff4500;">0</span> <span style="color: #ff4500;">1098000.0</span>
<span style="color: #ff4500;">1</span> <span style="color: #ff4500;">1205604.0</span>
<span style="color: #ff4500;">2</span> <span style="color: #ff4500;">1323753.192</span>
<span style="color: #ff4500;">3</span> <span style="color: #ff4500;">1453481.00482</span>
<span style="color: #ff4500;">4</span> <span style="color: #ff4500;">1595922.14329</span>
<span style="color: #ff4500;">5</span> <span style="color: #ff4500;">1752322.51333</span>
<span style="color: #ff4500;">6</span> <span style="color: #ff4500;">1924050.11964</span>
<span style="color: #ff4500;">7</span> <span style="color: #ff4500;">2112607.03136</span></pre></div></div>

<p>En 7 ans, la production de richesse des bridés doublerait.</p>
<p>Mais bon, l&#8217;idée n&#8217;est pas encore de débattre, juste de vous montrer un truc: un petit pourcentage, et ça double vite, très vite. Quand vous lisez dans la presse une croissance constante en pour-cent, il faut tout de suite s&#8217;arrêter et réfléchir: qu&#8217;est-ce que ça représente vraiment ?</p>
<p><strong>Qu&#8217;est-ce que ça représente à l&#8217;échelle d&#8217;une vie ?</strong></p>
<p>Je prends une valeurs arbitraire, je rajoute un pourcentage de croissance par an, et ce, tous les ans pendant 70 ans:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> nombre_de_multiplications_en_une_vie<span style="color: black;">&#40;</span>pourcent, duree_de_vie=<span style="color: #ff4500;">70</span>, valeur=<span style="color: #ff4500;">1000000</span><span style="color: black;">&#41;</span>:
&nbsp;
    valeur_de_depart = valeur
    <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>duree_de_vie<span style="color: black;">&#41;</span>:
        valeur += valeur <span style="color: #66cc66;">*</span> pourcent / <span style="color: #ff4500;">100</span>
        <span style="color: #ff7700;font-weight:bold;">print</span> x, valeur
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span> valeur / valeur_de_depart</pre></div></div>

<p>4 %, en une vie ça multiplie par&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">nombre_de_multiplications_en_une_vie<span style="color: black;">&#40;</span><span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0</span> <span style="color: #ff4500;">1040000</span>
<span style="color: #ff4500;">1</span> <span style="color: #ff4500;">1081600</span>
<span style="color: #ff4500;">2</span> <span style="color: #ff4500;">1124864</span>
<span style="color: #ff4500;">3</span> <span style="color: #ff4500;">1169858</span>
...
<span style="color: #ff4500;">68</span> <span style="color: #ff4500;">14972576</span>
<span style="color: #ff4500;">69</span> <span style="color: #ff4500;">15571479</span>
<span style="color: #ff4500;">15</span></pre></div></div>

<p>15 fois la valeur. </p>
<p>7% ?</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">nombre_de_multiplications_en_une_vie<span style="color: black;">&#40;</span><span style="color: #ff4500;">7</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0</span> <span style="color: #ff4500;">1070000</span>
<span style="color: #ff4500;">1</span> <span style="color: #ff4500;">1144900</span>
<span style="color: #ff4500;">2</span> <span style="color: #ff4500;">1225043</span>
<span style="color: #ff4500;">3</span> <span style="color: #ff4500;">1310796</span>
...
<span style="color: #ff4500;">67</span> <span style="color: #ff4500;">99562171</span>
<span style="color: #ff4500;">68</span> <span style="color: #ff4500;">106531522</span>
<span style="color: #ff4500;">69</span> <span style="color: #ff4500;">113988728</span>
<span style="color: #ff4500;">113</span></pre></div></div>

<p>Vos enfants se retrouvent avec le phénomène multiplié par 100.</p>
<p>Donc, quand on vous parle de développement durable, et qu&#8217;on vous parle de garder la croissance de quelque chose, n&#8217;importe quelle chose, avec un certain seuil en pour-cent, on vous parle en fait juste d&#8217;une croissance normale, massive. Un truc qui va être énormément multiplié. Et très vite.</p>
<p>C&#8217;est ce qu&#8217;on appelle une croissance exponentielle.</p>
<h2>Ok, mais pourquoi tu nous dis ça ?</h2>
<p>Je reprends l&#8217;analogie de notre vieux Albert Bartlett, qui ressemble à l&#8217;<a href="http://www.google.fr/search?source=hp&#038;q=nenuphare%20surface&#038;meta=&#038;aq=f&#038;aqi=g10&#038;aql=&#038;oq=&#038;gs_rfai=#hl=fr&#038;sclient=psy-ab&#038;q=enigme+nenuphare&#038;oq=enigme+nenuphare&#038;gs_l=serp.3..0j0i10i30j0i30l2.1947.3337.1.3455.9.5.0.4.4.0.254.805.0j4j1.5.0...0.0...1c.1.a77dpF0I4NU&#038;pbx=1&#038;bav=on.2,or.r_gc.r_pw.r_qf.&#038;fp=888c038e854cfa89&#038;biw=1861&#038;bih=955">énigme des nénuphars</a>.</p>
<p>Vous avez vu qu&#8217;avec un petit pour-cent, une croissance constante fait très vite doubler une quantité. Qu&#8217;est-ce qui se passe quand on suit l&#8217;évolution de ces doublements ?</p>
<p>Imaginez: une hypothétique bactérie (sous stéroïdes :-)) se divise toutes les secondes, doublant donc sa population chaque seconde.</p>
<p>A 11H, la <a href="https://fr.wikipedia.org/wiki/Bo%C3%AEte_de_Petri">boîte de Pétri</a> dans laquelle vous avez mis la bactérie contient une bactérie. A midi, la boîte est pleine.</p>
<p>Voilà ce que ça donne:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://www.slideshare.net/slideshow/embed_code/14411917" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" class="iframe-class"></iframe>
<p>Maintenant la question piège, à quelle heure reste-t-il la moitié de l&#8217;espace dans la boîte ?</p>
<p>Réponse en slides:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://fr.slideshare.net/slideshow/embed_code/14412173" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" class="iframe-class"></iframe>
<p>En clair, jusqu&#8217;à la dernière minute, nos chères bactéries ont encore l&#8217;impression qu&#8217;il y a encore plein d&#8217;espace.</p>
<p>Le cas des bactéries est un exemple typique de croissance dans un système fermé: il y a une ressource limitée, ici l&#8217;espace.</p>
<p>Le système fermé dans notre cas, vous l&#8217;avez compris, c&#8217;est la Terre. Pour la ressource limitée, prenez celle que vous voulez: l&#8217;air pur, l&#8217;eau potable, l&#8217;espace, le pétrole, la bouffe, le métal, etc. Toutes ces ressources sont limitées, et nous les consommons de manière croissante.</p>
<p>Mais vous allez me dire : &#8220;arrête, y en a encore plein&#8221;. Là on en est pas à la moitié. Et il y les progrès scientifiques. Et les alternatives.</p>
<p>Mais voilà l&#8217;astuce, jusqu&#8217;à quelle heure on a l&#8217;impression qu&#8217;on en a &#8220;encore plein&#8221; ? C&#8217;est ce qui est magnifique avec la croissance exponentielle, ça augmente très vite&#8230;</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://www.slideshare.net/slideshow/embed_code/14412017" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" class="iframe-class"></iframe>
<p>Voilà pourquoi vous entendez plein de gens criez &#8220;attention, on va manquer de (insérer ici une ressource limitée)&#8221;. Et c&#8217;est surtout pour ça que les mecs qui vous disent &#8220;mais nan, on en a encore plein, et on peut encore en découvrir plein, et il y a le progrès, les alternatives, on a de la marge&#8221; n&#8217;ont rien compris au film. </p>
<p>La quantité n&#8217;a AUCUNE importance, <strong>l&#8217;important c&#8217;est qu&#8217;elle est limitée, et qu&#8217;on en consomme toujours plus</strong>. L&#8217;important c&#8217;est que cette croissance ne nous permet pas d&#8217;évaluer sereinement le temps de freinage avant de heurter le mur.</p>
<p>Particulièrement parce que la croissance exponentielle possède une autre caractéristique très intéressante, à chaque fois qu&#8217;on passe le temps de doublement, <strong>la quantité consommée est égale à tout ce qui a été consommé depuis le début</strong>. Tout. A chaque fois, on consomme plus que tout l&#8217;historique:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://fr.slideshare.net/slideshow/embed_code/14412074" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" class="iframe-class"></iframe>
<p>Du coup, supposons que nos bactéries fassent comme nous, et décident de continuer leur croissance, et de la compenser par de nouvelles découvertes. Des bactéries géniales, genre prix Nobel chez les monocellulaires, font une découverte incroyable.</p>
<p>3 autres boîtes de Pétri ! </p>
<p>3 fois plus que ce qui a toujours été consommé, depuis le début de leur existence. C&#8217;est énorme, c&#8217;est comme si on découvrait soudainement que le schiste pouvait en fait nous filer du pétrole. C&#8217;est gigantesque. 3 fois ce qu&#8217;on a fait depuis le début de la consommation. Ça laisse voir venir non ?</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://www.slideshare.net/slideshow/embed_code/14412038" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" class="iframe-class"></iframe>
<p>Voilà, à 12h02, il n&#8217;y a plus rien.</p>
<p>Albert Bartlett pense que pour l&#8217;humanité et le pétrole, il est actuellement 11h58. Mais même si il se trompe, comme toutes les personnes qui ont annoncé la fin du pétrole avant lui, il ne peut pas se tromper sur le principe: la ressource est limitée, et nous la consommons exponentiellement.</p>
<p>Enfin notre cher pépé malin nous rappelle que les solutions posent aussi souvent des problèmes, particulièrement celles qui consistent à essayer de nous maintenir dans notre système de croissance.</p>
<p>Personnellement, je prendrais juste un exemple: les énergies alternatives. Qu&#8217;on s&#8217;y intéresse est une très bonne chose, mais leur existence ne résout pas le problème, elles sont l&#8217;équivalente de la découverte d&#8217;une nouvelle boîte de Pétri !</p>
<p> Elles sont comme les autres, on peut les produire en quantité limité, même celles dites &#8220;renouvellables&#8221;. En effet, les installations et la maintenance pour la production de ces énergies consomment d&#8217;autres ressources: espace, énergie, métal, main d’œuvre qualifiée et bouffe de la main d’œuvre, etc. Sans compter que le pétrole, ce n&#8217;est pas que pour l&#8217;énergie, mais aussi pour la chimie: agriculture, médecine, vêtement, informatique&#8230; On est pas prêt de s&#8217;en passer.</p>
<p>Et rien n&#8217;est gratuit.</p>
<p>Rappel : la quantité disponible n&#8217;a aucune importance. L&#8217;important c&#8217;est qu&#8217;il y a une limite, aussi grande soit-elle, et qu&#8217;on accélère notre consommation.</p>
<h2>Démographie, consommation et démocratie</h2>
<p>Évidement, il y a le problème de consommation. On bouffe trop, on utilise trop la voiture, on jette trop, etc.</p>
<p>Mais si on était un village de Provence, ça n&#8217;aurait aucune importance.</p>
<p>L&#8217;important, c&#8217;est qu&#8217;on est nombreux, et que ça continue d&#8217;augmenter. Qu&#8217;être humain, c&#8217;est essayer de garantir que tous le monde ait les mêmes droits, les mêmes libertés, et les mêmes chances. </p>
<p>Ce n&#8217;est pas possible avec une population qui se compte en milliard. Et surtout, qui continue de croître (et de consommer), de manière exponentielle.</p>
<p>La surpopulation est un problème majeur. La surconsommation est un problème majeur.</p>
<p>Notre société porte aux nues ceux qui font des enfants, c&#8217;est sacré. Et notre société produit des enfants qui vont faire la queue pendant 48H pour acheter l&#8217;iPhone 5. </p>
<p>Exponentiellement. Dans un système fermé.</p>
<p>Mais plus grave que cela, la surpopulation ne permet pas l&#8217;existence de la démocratie.</p>
<p>La vidéo offre une très belle citation de <a href="https://fr.wikipedia.org/wiki/Isaac_Asimov">Isaac Asimov</a>, que je vais paraphraser ici:</p>
<blockquote><p>J&#8217;ai une théorie sur les salles de bain.</p>
<p>Quand vous avez un appartement avec 2 personnes et 2 salles de bains, tout le monde peut profiter des salles de bains, y faire ce qu&#8217;il veut, tout le temps qu&#8217;il veut, au moment qu&#8217;il veut. Et tout le monde peut croire dans &#8220;le droit à la salle de bain&#8221;. D&#8217;ailleurs, il est clair que ça devrait être écrit dans la constitution.</p>
<p>Quand vous avez 20 personnes dans l&#8217;appartement, même dans le cas improbable où tout le monde croit dans le droit à la salle de bain, et même si c&#8217;est écrit dans la constitution, une telle chose ne peut exister. Il faut instaurer des horaires. Des tours. Il faut frapper à la porte et dire &#8220;t&#8217;as bientôt fini ?&#8221;. Il y aura des meilleurs horaires pour certains, et des abus.</p>
<p>La démocratie ne peut pas survivre à la surpopulation. La dignité humaine ne peut pas survivre à la surpopulation. Le confort et la décence ne peuvent pas survivre la surpopulation. Plus on ajoute de personnes sur Terre, plus la valeur de la vie, non seulement diminue, mais disparaît. Cela n&#8217;a aucune importance si une personne meurt, plus il y a de gens, moins l&#8217;individu compte.</p>
</blockquote>
<p>Rappelez-vous, si vous sentez qu&#8217;on en est encore loin, qu&#8217;à 11h55, il reste 97% de la boîte de Pétri. </p>
<h2>La bonne nouvelle et la moins bonne</h2>
<p>Tous les systèmes tendent vers l&#8217;équilibre. Il n&#8217;y a rien à faire, ça se fait tout seul. Ca veut dire &#8211; bonne nouvelle ! &#8211; que tous nos problèmes de consommation de ressources vont se régler tout seuls. On va consommer moins automatiquement. Avoir une population qui va baisser, automatiquement.</p>
<p>La mauvaise nouvelle, c&#8217;est qu&#8217;il est toujours plus facile de détruire que de construire, de mettre le bordel que d&#8217;organiser, de consommer que de produire. </p>
<p>Du coup, il n&#8217;y a pas de solution rapide à un problème que nous avons mis des siècles à installer.</p>
<p>Ainsi, rien ne dit que si on mettait une solution en place maintenant, ce serait elle qui ferait tendre notre système vers l&#8217;équilibre.</p>
<p>Vous ne suivez pas ?</p>
<p>Le système va s&#8217;équilibrer, c&#8217;est une certitude. La question, la question VRAIMENT importante, c&#8217;est <strong>comment</strong>.</p>
<p>Prenez la surpopulation par exemple, voici deux colonnes, l&#8217;une implique que la population continue d&#8217;augmenter, l&#8217;autre va freiner ou compenser cette augmentation:</p>
<p style="text-align: center;"><a href="http://sametmax.com/wp-content/uploads/2012/09/croissance1.png"?9d7bd4"><img class="aligncenter  wp-image-2261" src="http://sametmax.com/wp-content/uploads/2012/09/croissance1.png"?9d7bd4" alt="Colonne de gauche: croissance. Colonne de droite: décroissance" width="508" height="381" /></a></p>
<p>Vous sentez comme certains items sont plus agréables que d&#8217;autres ?</p>
<p>Voilà le truc, le système va s&#8217;équilibrer automatiquement, et dans notre cas, il va s&#8217;équilibrer en diminuant notre nombre, car nous sommes en croissance constante dans un système fermé.</p>
<p>Donc, la nature va prendre des trucs dans la colonne de droite et les mettre en œuvre jusqu&#8217;à ce que le système s&#8217;équilibre.</p>
<p>Ce n&#8217;est pas une prophétie divine, ce n&#8217;est pas magique, ce n&#8217;est pas une prédiction de médium, c&#8217;est juste un fait simple de la vie.</p>
<p>On ne peut pas savoir ce qui sera utilisé dans la colonne de droite. L&#8217;Inde qui va faire la guerre à ses voisins car elle manque d&#8217;eau ? La Chine qui va détruire l&#8217;économie en consommant tout le fer, provocant une récession mondiale et la famine ? Monsanto / Fukushima / le réchauffement climatique qui va nous faire dégénérer ? Le monde entier qui soudainement fait moins de bébés, naturellement ?</p>
<p>On ne peut pas non plus savoir quand ça va arriver. Dans 2 ans ? dans 120 ans ? La précision, c&#8217;est pour les astrologues.</p>
<p>On sait juste que ça va arriver.</p>
<p>En gros, notre problématique, c&#8217;est de choisir le truc le moins désagréable de la colonne de droite et de l&#8217;appliquer rapidement et efficacement avant que les autres items soient utilisés pour nous. Parce qu&#8217;il est clair que personne ne veut mettre le holà sur la colonne de gauche.</p>
<p>Ce n&#8217;est pas pour ça qu&#8217;il faut arrêter le progrès scientifique, cracher sur le pétrole et le nucléaire ou castrer tout le monde. </p>
<p>Mais ne rien faire, c&#8217;est aberrant</p>
<h2>En plus d&#8217;apprendre Python, qu&#8217;est-ce que je peux faire d&#8217;utile ?</h2>
<p>Envisager de ne pas faire des enfants, voir d&#8217;en adopter. Ou au minimum arrêter de se comporter comme un extrémiste religieux qui fait la promotion du Dieu Procréation comme à peu prêt tout le monde actuellement. C&#8217;est grave.</p>
<p>Acheter moins. Réparer. Faire avec moins. Faire sans. Ne pas faire.</p>
<p>Ne pas avoir de voiture. Ne pas changer tous les jours de t-shirt. Ne pas acheter le dernier gadget.</p>
<p>Acheter d&#8217;occasion. Donner. Libérer de l&#8217;espace chez soi, et du temps dans sa vie.</p>
<p>Prendre le vélo. Marcher. Acheter local. Et moins.</p>
<p>Réfléchir, éteindre la télé, lire, parler à ses amis face à face.</p>
<p>Cuisiner.</p>
<p>On ne doit pas viser moins de croissance. On doit viser la décroissance. </p>
<p>Gagner moins d&#8217;argent, faire moins de choses. Avoir une économie qui ne soit pas basée sur le plus.</p>
<p>Vendre moins.</p>
<p>Ce n&#8217;est pas l&#8217;austérité. Ce n&#8217;est pas vivre comme un homme des cavernes. Ça ne veut pas dire vivre moins. C&#8217;est juste ne pas être un parasite suicidaire.</p>


feed_id: http://sametmax.com/?p=2253
title: Connaître la version de Rsync
uri: Connaître-la-version-de-Rsync
url: http://sametmax.com/connaitre-la-version-de-rsync/
content:
<p>Rsync c&#8217;est un super prog pour synchroniser le contenu d&#8217;un serveur à un autre. Voir <a href="http://sametmax.com/rsync-ou-comment-transferer-du-gros-contenu-via-ssh/" title="Rsync ou comment transférer du gros contenu via ssh">transférer du gros contenu via ssh</a>.<br />
Pour connaître la version présente sur votre système rentrez à l&#8217;invite de commande juste &#8220;rsync&#8221;. Et oui c&#8217;es tout con mais des fois on essais -V et autres commandes sans trouver.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#91;</span>max<span style="color: #000000; font-weight: bold;">@</span>toto<span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #666666; font-style: italic;"># rsync</span>
rsync  version 3.0.6  protocol version <span style="color: #000000;">30</span>
Copyright <span style="color: #7a0874; font-weight: bold;">&#40;</span>C<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">1996</span>-<span style="color: #000000;">2009</span> by Andrew Tridgell, Wayne Davison, and others.
Web site: http:<span style="color: #000000; font-weight: bold;">//</span>rsync.samba.org<span style="color: #000000; font-weight: bold;">/</span>
Capabilities:
    <span style="color: #000000;">64</span>-bit files, <span style="color: #000000;">64</span>-bit inums, <span style="color: #000000;">64</span>-bit timestamps, <span style="color: #000000;">64</span>-bit long ints,
    socketpairs, hardlinks, symlinks, IPv6, batchfiles, inplace,
    append, ACLs, xattrs, iconv, symtimes</pre></div></div>


feed_id: http://sametmax.com/?p=2285
title: En Django, le fichier settings.py, c’est juste du Python
uri: En-Django-le-fichier-settings-py-c-est-juste-du-Python
url: http://sametmax.com/en-django-le-fichier-settings-py-cest-juste-du-python/
content:
<p>On a beau répêter dans la doc, &#8220;Django is just Python&#8221;, c&#8217;est difficile de s&#8217;y faire. Surtout dans le fichier settigns.py: c&#8217;est vrai que le paramétrage, c&#8217;est quelque chose qu&#8217;on a l&#8217;habitude d&#8217;être typiquement déclaratif.</p>
<p>Rappel donc, le fichier settings.py, c&#8217;est juste du Python.</p>
<p>Ça veut dire qu&#8217;on peut faire ça en début de fichier:</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;">os</span>
<span style="color: #808080; font-style: italic;"># répérer le dossier du projet</span>
ROOT_DIR = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">realpath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
Et ça un peut partout dans le projet pour éviter les d<span style="color: #483d8b;">'avoir des chemins absolus en dur:
&nbsp;
STATIC_ROOT = os.path.join(ROOT_DIR, '</span>static<span style="color: #483d8b;">')</span></pre></div></div>

<p>On peut aussi faire des choses comme celle-ci, pour avoir un comportement spécial en mode debug:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> DEBUG:
&nbsp;
    <span style="color: #808080; font-style: italic;"># on retire le dernier middleware</span>
    MIDDLEWARE_CLASSES = <span style="color: black;">&#91;</span>:-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>
    <span style="color: #808080; font-style: italic;">#et on en rajoute un au début</span>
    MIDDLEWARE_CLASSES = <span style="color: black;">&#40;</span>
        <span style="color: #483d8b;">'libs.middlewares.MonMiddlewareKilebo'</span>,
    <span style="color: black;">&#41;</span> + MIDDLEWARE_CLASSES</pre></div></div>

<p>Et si un settings n&#8217;existe pas, on peut l&#8217;inventer pour le réutiliser partout dans son code ailleurs:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">SERVER_POOL = <span style="color: black;">&#40;</span>
    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'8.8.8.8'</span>, <span style="color: #483d8b;">&quot;sametmax.com&quot;</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'8.8.4.4'</span>, <span style="color: #483d8b;">&quot;cnd.sametmax.com&quot;</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'208.67.222.222'</span>, <span style="color: #483d8b;">'staging.sametmax.com'</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'208.67.220.220'</span>, <span style="color: #483d8b;">&quot;dev.sametmax.com&quot;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#41;</span></pre></div></div>

<p>Et même se faciliter la vie:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">SERVER_POOL_DICT = <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>SERVER_POOL<span style="color: black;">&#41;</span></pre></div></div>

<p>Dans le même genre on peut faire des calculs:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">CINQ_MINUTES = <span style="color: #ff4500;">60</span> <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">5</span>
...
<span style="color: black;">CACHE_MIDDLEWARE_SECONDS</span> = CINQ_MINUTES <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">2</span></pre></div></div>

<p>Et bien entendu, on peut splitter son fichier de settings en plusieurs fichiers. Il y a le maintenant classique fichier de settings local qui est différent sur chaque marchine, et qu&#8217;on importe en fin de fichier:</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;">from</span> settings_local <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">ImportError</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Ca permet de mettre les paramètres de la base de données dans settings_local.py.</p>
<p>Mais on oublie souvent que peut tout à fait récupérer les paramètres depuis un fichier non Python.</p>
<p>Récupérer des valeurs dans un fichiers ini ? Fastoche !</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;">ConfigParser</span>
config = <span style="color: #dc143c;">ConfigParser</span>.<span style="color: black;">RawConfigParser</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
config.<span style="color: black;">readfp</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/chemin/vers/fichier.ini'</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">locals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">update</span><span style="color: black;">&#40;</span>config.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'section'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>


feed_id: http://sametmax.com/?p=2275
title: Etes-vous accro aux films pornos ? Test en ligne
uri: Etes-vous-accro-aux-films-pornos-Test-en-ligne
url: http://sametmax.com/etes-vous-accro-aux-films-pornos-test-en-ligne/
content:
<p>Le cul est partout présent autour de nous, les pubs, les couvertures de magazine et c&#8217;est lui qui a contribué à faire se démocratiser le VHS entre autre. Avec internet et les connexions à haut débit il est facile de trouver de nos jours des films pornos en ligne en quelques clics sur les moteurs de recherche. Il y a du pour et du contre. On est pas là pour vous blâmer, chacun fait ce qu&#8217;il veut et il y a des outils pour &#8220;brider&#8221; les navigateurs pour ceux qui ont des mômes.</p>
<p>Voici donc un petit test pour savoir si vous êtes accroc au porno :)</p>
<p>1. Vous allez au moins 1 fois par jour sur un site de cul<br />
2. Vous aimer aller dans des sex-shops<br />
3. Vous êtes abonné à un forum ou un chat sur le Web orienté sexe (comme youpie.net)<br />
4. Quand vous sentez l&#8217;excitation venir, vous avez du mal à vous retenir<br />
5. Lorsque vous résistez, vous devenez nerveux ou irascible envers votre entourage<br />
6. Plus le temps passe, plus vous avez besoin de vidéos plus hards<br />
7. Après avoir obtenu satisfaction, vous éprouvez une sorte de lassitude<br />
8. Vous prenez madame en levrette en prenant soin de vous mettre de côté pour bien vous voir dans la glace<br />
9. Vous écourtez vos soirées entre amis pour rentrer chez vous et vous masturber devant un film de cul<br />
10. Vous vous levez en pleine nuit ou au petit matin pour vous masturber sur un site X<br />
11. Si vous êtes en couple, vous préférez vous masturber sur une vidéo porno plutôt que de satisfaire madame<br />
12. Votre partenaire ne vous attire plus sexuellement mais vous faites souvent semblant que &#8220;ça marche&#8221;<br />
13. Vous vous masturbez plusieurs fois par semaine, voire par jour<br />
14. Vous avez plusieurs fois décidé de vous arrêter mais vous n&#8217;y arrivez pas<br />
15. Quand vous voyez une femme dans la rue vous pensez immédiatement à la voir à 4 pattes avec des chaussures à talons aiguilles</p>
<p><strong>RESULTATS</strong></p>
<p>• Si vous avez répondu OUI à moins de 5 questions, vous n&#8217;êtes pas porno dépendant(e), alors cessez de culpabiliser, vous êtes un débutant!<br />
• Si vous avez répondu OUI à plus de 7 questions, vous êtes en train de devenir pornodépendant(e). Le sexe classique ne vous convient plus, il vous faut des sensations toujours plus hards.<br />
• Si vous avez répondu OUI à plus de 10 questions alors là c&#8217;est foutu, on peut plus rien pour vous, votre cerveau est un gros film porno à lui tout seul, pas de place pour le reste. Consultez un médecin si vous voulez mais ça ne servira à rien, en attendant &#8220;<a href="http://www.youporn.com/">bonne branlette</a>&#8220;</p>


feed_id: http://sametmax.com/?p=2297
title: Un peu de Ruby dans du Python
uri: Un-peu-de-Ruby-dans-du-Python
url: http://sametmax.com/un-peu-de-ruby-dans-du-python/
content:
<p>Si vous utilisez un virtualenv, vous n&#8217;avez pas envie d&#8217;installer des libs au niveau du système. </p>
<p>Et si vous n&#8217;êtes pas racistes, vous utilisez peut être quelques tools Ruby, comme <a href="http://compass-style.org/">compass</a>.</p>
<p>Mais du coup, <code>gem install compass</code> ne marche pas, il faut soit faire un <code>sudo</code>, soit plonger dans les méandres de <code>rvm</code>. Pas glop.</p>
<h2>Petit astuce</h2>
<p><a href="http://www.doughellmann.com/projects/virtualenvwrapper/">Virtualenv wrapper</a> vient avec des scripts qui se déclenchent à des évenements. Typiquement, <em>env/bin/postactivate</em> est le script déclenché après l&#8217;activation de l&#8217;env.</p>
<p>Mettez dedans:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">GEM_HOME</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$VIRTUAL_ENV</span>/gems&quot;</span>
<span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">GEM_PATH</span>=<span style="color: #ff0000;">&quot;&quot;</span>
<span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">PATH</span>=<span style="color: #007800;">$PATH</span>:<span style="color: #ff0000;">&quot;<span style="color: #007800;">$GEM_HOME</span>/bin&quot;</span></pre></div></div>

<p>Et voilà,<code> gem install</code> va maintenant installer les gems dans le virtualenv.</p>


feed_id: http://sametmax.com/?p=2298
title: Comment bien manger en 5 étapes :)
uri: Comment-bien-manger-en-5-étapes-)
url: http://sametmax.com/comment-bien-manger-en-5-etapes/
content:
<div id="attachment_2330" class="wp-caption aligncenter" style="width: 470px"><a href="http://sametmax.com/wp-content/uploads/2012/09/cochon-grillé1.jpeg"?9d7bd4"><img class="size-full wp-image-2330" title="Ne jamais mélanger les lipides et les glucides!" src="http://sametmax.com/wp-content/uploads/2012/09/cochon-grillé1.jpeg"?9d7bd4" alt="" width="460" height="287" /></a><p class="wp-caption-text">Résiter à la tentation ? Noooon</p></div>
<p>Article à placer entre Doctissimo et Mode et Travelos.<br />
J&#8217;avais envie de crier mon coup de gueule contre cette populasse qui ne sait pas se nourrir alors que nous sommes dans le Pays de la bonne bouffe, le choix de bien manger est bien présent contrairement à nombre de Pays autour de nous où il n&#8217;est tout simplement pas possible de trouver des aliments de bonne qualité.</p>
<p>Avant toutes choses loin de moi la prétention d&#8217;avoir la science infuse du côté de la bouffe mais mon poids n&#8217;a jamais varié en plus de 15 ans, je n&#8217;ai jamais fais de régime particulier, jamais été malade (j&#8217;entends des grosses maladies pas la grippe&#8230;), et récement mes analyses me font honneur alors que je ne suis plus tout jeune.</p>
<p>Alors bien sur il y a les antécédents génétiques, blablabla, mais ça n&#8217;empêche d&#8217;avoir une bonne hygiène alimentaire.</p>
<p><strong>Pourquoi 5 étapes?<br />
</strong>Parceque 4 c&#8217;est pas possible! 5 c&#8217;est pas dur à suivre, depuis tout petit mes parents m&#8217;ont apris à respecter et aimer la nourriture avec quelques principes simples et non contraignants dont je vous livres les secrets jamais divulgués pour la première fois en exclusivité mondiale.</p>
<p><strong>1. Ne pas faire de régime!<br />
</strong>C&#8217;est incroyable la crédulité qu&#8217;ont les gens de penser que changer son mode alimentaire pendant quelques mois va résoudre tous les problèmes accumulés depuis des années. Le régime est une vaste escroquerie menée de main de maître par des ténors de l&#8217;agro-alimentaire.<br />
Et ça marche encore très bien, le pire c&#8217;est que certains régimes peuvent être dangereux pour la santé.<br />
Mais les gens sont fiers de raconter à leur entourage qu&#8217;ils ont perdu 300 grammes en 4 jours rien qu&#8217;en mangeant des limaces déshydratées et un verre d&#8217;eau. Le hic c&#8217;est que le mois d&#8217;après on les revoit avec 10 kilos de plus car ils ont craqué sur le pot de glace du supermarché en allant chercher leur substitu de repas &#8220;Slim Fat 2000&#8243;&#8230;<br />
Le mot régime à lui seul me fait peur, pourquoi se priver ? Ma mère nous a toujours fait de tout à manger, ça permet d&#8217;apprécier plusieurs aliments et de ne pas se contenter d&#8217;un steack frites tous les midis.<br />
Les régimes sont si réducteurs qu&#8217;ils donnent l&#8217;impression d&#8217;être un malade en phase terminale. Tous ceux qui ont fait des régimes autour de moi sans exception ont échoué dans leur course à la perte de poids.<br />
Ne jamais oublier que les régimes sont une escroquerie et qu&#8217;on n&#8217;équilibrera jamais son poids durablement de la sorte.</p>
<p><strong>2. L&#8217;hygiène de vie<br />
</strong>J&#8217;adore le mot hygiène, il symbolise la pureté des choses à mes yeux. ( <em>du grec hugieion signifiant la santé</em> ) . Le mot hygiène ne doit pas signifier juste &#8220;se laver les mains&#8221;, c&#8217;est toutes les actions que vous allez faire pour rendre votre santé meilleure.<br />
Le sport! C&#8217;est à croire que notre pays n&#8217;a rien compris ou qu&#8217;il n&#8217;a pas envie d&#8217;avoir des gens en bonne santé, les salles de sport devraient être gratuites, cautionnées par l&#8217;Etat et pulluler autour de nous, pourquoi pas des fonctionnaires &#8220;gérants&#8221; de salles de gym. Il y a trop peu d&#8217;endroits où l&#8217;on peut faire correctement du sport avec un suivi pour les débutants.<br />
Et pourtant le sport est à mon avis la clef d&#8217;une bonne santé, il régule l&#8217;organisme et ouvre l&#8217;appétit, un fumeur qui va se mettre au sport réduira sa consomation automatiquement ( je l&#8217;ai constaté) tout comme celui qui mange n&#8217;importe quoi voudra autre chose qu&#8217;une glace après une demi heure de footing (je ne peux pas l&#8217;affirmer mais je l&#8217;ai constaté sur moi).<br />
Il faut se donner la peine de marcher ou courrir le plus souvent possible. Personnellement je vais courir 40 minutes tous les 2 jours,  1 fois par semaine me parrait être un minimum si on ne veut pas souffrir à chaque fois de courbatures et autres. Il y a plein d&#8217;autres activitées pour ceux qui n&#8217;aiment pas la course( salle, piscine, marche, etc)<br />
Je passe la classique critique sur les fumeurs et buveurs, non pas que ce soit du flanc mais c&#8217;est supprimer un &#8220;plaisir&#8221; à quelqu&#8217;un à qui on va déjà demander des efforts (alimentaires, sport, habitudes de vie, etc).<br />
Qui n&#8217;a pas entendu au moins une fois un proche revenir après un bilan et sortir :&#8221;Tout ce que j&#8217;aime est interdit par le docteur&#8217;&#8221; ?<br />
Là encore je trouve ça réducteur, c&#8217;est sur que c&#8217;est le fruit de plusieurs années de laisser aller mais il y a rien de tel pour dégouter quelqu&#8217;un, on se sent résigné après une annonce du genre.</p>
<p><strong>3. Arrêter les saloperies</strong><br />
Pour bien contredire le point du dessus je vais interdire une chose :) Les saloperies.<br />
Bon en fait c&#8217;est pas les interdire mais prendre conscience à quel point c&#8217;est dégueulasse et pour le corps, mais aussi parfois pour l&#8217;environnement. Le fait de prendre conscience par exemple que <a href="http://www.youtube.com/watch?v=0ftiITYwJkk&amp;feature=related">les nuggets de votre fast-food</a> préféré sont fabriqués de la sorte et infligent ce genre de <a href="http://www.youtube.com/watch?v=MW9g_RsZ9RM">traitement aux animaux</a> m&#8217;a fait réfléchir sur 2 points, c&#8217;est plutôt barbare et en plus on bouffe de la merde.<br />
Du coup à chaque fois que je vois des nuggets je pense à ça, ça ne m&#8217;empêcherait pas d&#8217;aller en manger mais j&#8217;ai limité ma consommation de fast-food à quelques fois par an.<br />
J&#8217;ai également arrêté toutes les sucreries lorsque j&#8217;ai pris conscience que le sucre est une <a href="http://www.amessi.org/Le-sucre-drogue-douce#.UGQqHKR1BrQ">drogue</a>. Mais je sais que c&#8217;est dur pour beaucoup vu que justement c&#8217;est une drogue, il faut décrocher françis !<br />
Petite astuce pour ceux qui grignottent souvent entre les repas, il y a des sachets de noix, noisettes, amandes au rayons gâteaux ou pommes de terre, c&#8217;est bourré de bonnes choses et bien meilleur que les sucreries.<br />
Quand je fais mes courses je prends bien soin de regarder un peu sur les emballages pour voir ce que nos chers industriels ont pu mettre comme saloperies dans nos aliments, le problème me direz-vous c&#8217;est que ça prend du temps, justement on y arrive&#8230;</p>
<p><strong> 4. Prendre son temps!<br />
</strong>Et oui on a rien sans rien ma bonne dame. Là encore les gens qui vous disent qu&#8217;on peut se faire bien à manger en 2 minutes ont tout faux, ils vous disent ça en vous sortant les ingrédients tous frais du frigo, oui mais faut avoir le temps d&#8217;aller les acheter, de les choisir !<br />
Qu&#8217;on le veuille ou non bien manger demande du temps, mais avec le temps on met moins de temps :)<br />
Quelques astuces quand même, savoir à l&#8217;avance ce que l&#8217;on va cheter ça peut aider, il faut éviter de se pointer au supermarché ou chez le primeur les mains dans les poches.<br />
Il faut se faire une petite liste de courses qui contient au moins des pâtes, du riz, des légumes, des conserves de tomates, du fromage, de la viande ou du poisson.<br />
Tout le reste c&#8217;est à votre goût. Celà a l&#8217;avantage de savoir où vous allez, de gagner du temps et d&#8217;éviter d&#8217;acheter n&#8217;importe quoi. Mais la bouffe c&#8217;est de l&#8217;amour et l&#8217;amour ça prend du temps&#8230;<br />
Vous pourrez vous rattrapper au moment de cuisiner en faisant preuve d&#8217;imagination et d&#8217;improvisation.</p>
<p><strong>5. Savoir improviser<br />
</strong>Partie très importante à mes yeux, savoir improviser avec ce qu&#8217;on a dans le frigo, rien de plus déprimant que de manquer de lait quand on veut faire des crêpes.<br />
Du coup on claque la porte et on appelle &#8220;Pizza 30 minutes&#8221;.<br />
L&#8217;improvisation ça s&#8217;apprend avec le temps, il ne faut pas se décourager au début et après on s&#8217;aperçoit que ça va tout seul, cherchez sur youtube je pense qu&#8217;il doit y avoir des vidéos là dessus.<br />
Ce que j&#8217;essais d&#8217;avoir en permanence c&#8217;est de la farine et de la levure (en sachet), ça se conserve très longtemps et avec de l&#8217;eau on peut faire&#8230;. Une pizza !<br />
Je rappelle qu&#8217;à la base la pizza consistait à recycler tous les restes de la semaine, je le vois comme ça en tout cas, quand je commence à avoir quelques légumes qui tirent la tronche ou du jambon qui tourne de l&#8217;oeil je fais une pizza et je mets un peu tout ce que je trouve, ça évite le gaspillage et ça vide les restes du frigo.<br />
Les omelettes aussi peuvent servir de fourre-tout à restes et sont plus faciles à réaliser.<br />
Il faut également prendre l&#8217;habitude de mettre de la couleur dans vos plats. Avoir  3 couleurs par plat me parrait pas mal. Par exemple viande (marron) + patates (jaune) + salade (vert), ou encore pates(jaune) + tomate (rouge) + salade(vert), etc&#8230; choisir des couleurs assez éloignées. ça oblige en quelques sortes à avoir plusieurs types de nourriture différents donc une alimentation variée. Si en plus vous pouvez faire une petite entrée du genre tomate ou betterave, etc c&#8217;est encore mieux.<br />
On trouve aussi des astuces pour les tâches pourries comme <a href="http://www.youtube.com/watch?v=anZBo2FmaL8">éplucher les pommes de terre</a>, <a href="http://www.youtube.com/watch?v=_AirVOuTN_M">séparer le jaune du blanc</a>, <a href="https://www.youtube.com/watch?feature=player_detailpage&amp;v=ai9Akl8vQ-c#t=60s">enlever la coquille sur un oeuf dur</a></p>
<p>Vous passez 2 heures par jour sur youtube, regardez un peu du côté des recettes, il y en a des faciles, ça donne des idées et c&#8217;est meilleur que les plats surgelés.<br />
Aller quelques liens pour se mettre en appétit ^^:<br />
<a href="http://www.youtube.com/watch?v=R41_hdpOWiQ">Tomates farcies<br />
</a><a href="http://www.youtube.com/watch?v=7EqEvzobtXk">Côte de boeuf basse température</a><a href="http://www.youtube.com/watch?v=HssCUPPZi2E">Salade grecque<br />
</a><a href="http://www.youtube.com/watch?v=AsRjGxS1BdE">purée de pommes de terre<br />
</a><a href="http://www.youtube.com/watch?v=GoJqrcRH_3g">Recette omelette de pommes de terre ciboulette</a><a href="http://www.youtube.com/watch?v=DxXS8KxYfhg"><br />
Pasta Melanzane e Mozzarella<br />
</a></p>
<div id="attachment_2329" class="wp-caption aligncenter" style="width: 520px"><a href="http://sametmax.com/wp-content/uploads/2012/09/plats-5_33.jpeg"?9d7bd4"><img class="size-full wp-image-2329" title="miam !" src="http://sametmax.com/wp-content/uploads/2012/09/plats-5_33.jpeg"?9d7bd4" alt="" width="510" height="339" /></a><p class="wp-caption-text">il y en aura pour tout le monde!</p></div>
<p>C&#8217;est pas tout mais j&#8217;ai faim moi!</p>
<p>&nbsp;</p>


feed_id: http://sametmax.com/?p=2321
title: Vi vs Emacs vs Sublime Text
uri: Vi-vs-Emacs-vs-Sublime-Text
url: http://sametmax.com/vi-vs-emacs-vs-sublime-text/
content:
<p>Sublime Text est mieux. Point final.</p>
<p>J&#8217;ai fermé les commentaires, ils ne servent à rien puisque j&#8217;ai raison.</p>


feed_id: http://sametmax.com/?p=2343
title: Capturer l’affichage des prints d’un code Python
uri: Capturer-l-affichage-des-prints-d-un-code-Python
url: http://sametmax.com/capturer-laffichage-des-prints-dun-code-python/
content:
<p>Hier j&#8217;ai eu rencontré le travail d&#8217;une de ces fameuses personnes qui pensent que la ré-utilisabilité c&#8217;est pour les pédés, et qui font des scripts dont la moitié des infos renvoyées sont printées au milieu de blocs de code de 50 lignes, sans possibilité de les récupérer.</p>
<p>Heureusement, avec un petit hack, on peut capturer ce qu&#8217;affiche un autre code, et sauver le bébé, l&#8217;eau du bain, et même le canard en plastique.</p>
<h2>Le code pour les gens pressés</h2>
<p>J&#8217;ai enrobé l&#8217;astuce dans un <a href="http://sametmax.com/les-context-managers-et-le-mot-cle-with-en-python/">context manager</a>, ça rend l&#8217;utilisation plus simple.</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;">sys</span>
<span style="color: #ff7700;font-weight:bold;">from</span> io <span style="color: #ff7700;font-weight:bold;">import</span> BytesIO
<span style="color: #ff7700;font-weight:bold;">from</span> contextlib <span style="color: #ff7700;font-weight:bold;">import</span> contextmanager
&nbsp;
@contextmanager
<span style="color: #ff7700;font-weight:bold;">def</span> capture_ouput<span style="color: black;">&#40;</span>stdout_to=<span style="color: #008000;">None</span>, stderr_to=<span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
&nbsp;
        stdout, stderr = <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>, <span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span>
        <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span> = c1 = stdout_to <span style="color: #ff7700;font-weight:bold;">or</span> BytesIO<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span> = c2 = stderr_to <span style="color: #ff7700;font-weight:bold;">or</span> BytesIO<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">yield</span> c1, c2
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">finally</span>:
&nbsp;
        <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span> = stdout
        <span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span> = stderr
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            c1.<span style="color: black;">flush</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            c1.<span style="color: black;">seek</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: black;">&#40;</span><span style="color: #008000;">ValueError</span>, <span style="color: #008000;">IOError</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            c2.<span style="color: black;">flush</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            c2.<span style="color: black;">seek</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: black;">&#40;</span><span style="color: #008000;">ValueError</span>, <span style="color: #008000;">IOError</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Notez l&#8217;usage de <a href="http://sametmax.com/comment-utiliser-yield-et-les-generateurs-en-python/">yield</a>.</p>
<p>Et ça s&#8217;utilise comme ça:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">with</span> capture_output<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> stdout, stderr:
    fonction_qui_fait_que_printer_la_biatch<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> stdout.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># on récupère le contenu des prints</span></pre></div></div>

<p>Attention, le code n&#8217;est pas thread safe, c&#8217;est fait pour hacker un code crade, pas pour devenir une institution. Mais c&#8217;est fort pratique dans notre cas précis.</p>
<h2>Comment ça marche ?</h2>
<p><code>stdin</code> (entrée standard), <code>stdout</code> (sortie standard) et <code>stderr</code> (sortie des erreurs) sont des file like objects, c&#8217;est à dire qu&#8217;ils implémentent l&#8217;interface d&#8217;un objet fichier: on peut les ouvrir, les lire, y écrire et les fermer avec des méthodes portant le même nom et acceptant les mêmes paramètres.</p>
<p>L&#8217;avantage d&#8217;avoir une interface commune, c&#8217;est qu&#8217;on peut du coup échanger un file like objet par un autre.</p>
<p>Par exemple on peut faire ceci:</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;">sys</span>
log = <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/log'</span>, <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span> = log <span style="color: #808080; font-style: italic;"># hop, on hijack la sortie standard</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Hello&quot;</span>
log.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Comme <code>print</code> écrit dans <code>stdout</code>, en remplaçant <code>stdout</code> par un fichier, <code>print</code> va du coup écrire dans le fichier.</p>
<p>Mais ce code est fort dangereux, car il remplace <code>stdout</code> de manière définitive. Du coup, si du code <code>print</code> après, il va écrire dans le fichier, même les libs externes, car <code>stdout</code> est le même pour tout le monde dans le process Python courant.</p>
<p>Du coup, il est de bon ton de s&#8217;assurer la restauration de <code>stdout</code> à son état d&#8217;origine:</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;">sys</span>
log = <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/log'</span>, <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span>
bak = <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span> <span style="color: #808080; font-style: italic;"># on sauvegarde l'ancien stdout</span>
<span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span> = log
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Hello&quot;</span>
log.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span> = bak <span style="color: #808080; font-style: italic;"># on restore stdout</span></pre></div></div>

<p>Comme je le disais plus haut, ceci n&#8217;est évidement pas thread safe, puisqu&#8217;entre la hijacking et la restoration de <code>stdout</code>, un autre thread peut faire un <code>print</code>.</p>
<p>Dans notre context manager, on utilise <code>BytesIO()</code> et non un fichier. <code>BytesIO</code> est un file like objet qui permet de récupérer un flux de bits en mémoire. Donc on fait écrire <code>print</code> dedans, ainsi on a tout ce qu&#8217;on affiche qui se sauvegarde en mémoire.</p>
<p>Bien entendu, vous pouvez créé vos propres file like objects, par exemple un objet qui affiche à l&#8217;écran ET capture la sortie. Par exemple, pour mitiger le problème de l&#8217;absence de thread safe: 99% des libs n&#8217;ont pas besoin du vrai <code>stdout</code>, juste d&#8217;un truc qui <code>print</code>.</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;">sys</span>
<span style="color: #ff7700;font-weight:bold;">from</span> io <span style="color: #ff7700;font-weight:bold;">import</span> BytesIO
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> PersistentStdout<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    old_stdout = <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>
&nbsp;
    <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;">memory</span> = BytesIO<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> write<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, s<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">memory</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>s<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">old_stdout</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>s<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
old_stdout = <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>
<span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span> = PersistentStdout<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;test&quot;</span> <span style="color: #808080; font-style: italic;"># ceci est capturé et affiché</span>
&nbsp;
<span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">memory</span>.<span style="color: black;">seek</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
res = <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">memory</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span> = PersistentStdout.<span style="color: black;">old_stdout</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> res <span style="color: #808080; font-style: italic;"># résultat de la capture</span></pre></div></div>

<p>Pour cette raison le code du context manager permet de passer le file like objet à utiliser en argument. On notera aussi que si on souhaite rediriger <code>stdout</code> mais pas <code>stderr</code> et <a href="https://www.youtube.com/watch?v=WousdWP-5vY">vice-versa</a>, il suffit de passer <code>sys.stdout</code> et <code>sys.stderr</code> en argument :-)</p>


feed_id: http://sametmax.com/?p=2392
title: À ceux qui n’ont pas eu de réponse via le formulaire de contact: désolé
uri: À-ceux-qui-n-ont-pas-eu-de-réponse-via-le-formulaire-de-contact-d
url: http://sametmax.com/qui-nont-pas-eu-de-reponse-via-le-formulaire-de-contact-desole/
content:
<p>Depuis qu&#8217;on a changé de formulaire de contact, on a <a href="http://sametmax.com/mail-sur-compilation-de-python2-7-pyqt-pour-android/">quelques problèmes pour répondre</a>.</p>
<p>Après diagnostique, c&#8217;est une combinaison de deux plugins qui est en cause. On a rechangé le formulaire de contact, il est moche, mais cette fois il marche.</p>
<p>Donc<strong> si vous avez envoyé un message dans les dernières semaines, <span style="text-decoration: underline;">nous sommes désolés</span>, nous n&#8217;avons pas pu répondre</strong>.</p>
<p>Liste de mails pour lesquels on a cliqué aveuglément sur le bouton &#8220;répondre&#8221;, entraînant un doute que la réponse soit jamais arrivé:</p>
<blockquote><p>Je me permet de vous envoyer un email afin d&#8217;avoir une confirmation que l&#8217;initiative de traduction de la doc django (djangoSpirit) est de vous ?</p></blockquote>
<p>Non, ce n&#8217;est pas nous. C&#8217;est une superbe initiative, d&#8217;ailleurs l&#8217;AFPY est en train de faire pareil avec la doc Python. Donc n&#8217;hésitez pas à vous porter volontaire. Je me tâte à le faire moi-même, mais ça voudrait dire moins d&#8217;articles sur le blog.</p>
<blockquote><p>Bonjour, afin d&#8217;eviter que ca parte en vrille voici qd meme des corrections sur l&#8217;orthographe sur le billet http://sametmax.com/javascript-le-conquerant</p></blockquote>
<p>(et d&#8217;autres mails de foxmask). Merci vieux !</p>
<blockquote><p>parfois, firefox (15.0.1 sous GNU/Linux) affiche étrangement votre site. Deux screens (haut et bas de la page) :</p>
<p>http://imgur.com/eE4ex,6OsoB</p></blockquote>
<p>Et:</p>
<blockquote><p>il semble que parfois, sametmax.com prenne mon firefox pour un safari mobile, et il fait des histoires (là je vous envoie ça depuis elinks ^^)</p></blockquote>
<p>Vous n&#8217;êtes pas les seuls. Pour une raison inconnue (<a href="http://sametmax.com/wordpress-je-te-hais/">les joies de WordPress</a>), le site switch de temps en temps tout seul en version mobile pour un browser desktop. Et la version mobile vise les smartphones, qui ont tous toujours JS activé, et table dessus. Même si nous avions le temps, ni Max ni moi n&#8217;avons le courage de nous lancer dans le debuggage du code immonde de ce moteur de blog, ou pire, de celui des plugins. Donc sorry, ça va arriver, encore et encore, et on ne prévoit pas de le corriger.</p>
<blockquote><p>Serait-il possible d&#8217;avoir un flux RSS pour les commentaires des posts ?</p></blockquote>
<p>C&#8217;est fait ! On a rajouté un lien sous les commentaires.</p>
<blockquote><p>je crois qu&#8217;il y a un petit problème avec votre flux RSS: les articles sont à la bonne date, mais en timezone GMT&#8230;du coup les news sont décalées de +2 heures dans mes agrégateurs</p></blockquote>
<p>Mais mon ami, qui a dit que nous vivions actuellement en France ?</p>
<blockquote><p>No Matter what you are selling &#8211; Hit-Booster<br />
will send targeted visitors to your website!</p>
<p>Within 15 minutes you will have your own website<br />
traffic generator that will bring in an ever increasing<br />
amount of hits to your websites! Automatically</p>
<p>This software is perfect for bringing real traffic to<br />
your site&#8230; even if&#8230; it&#8217;s an affiliate link where you<br />
have no control over the website content!</p></blockquote>
<p>Super ! On se recontacte très vite alors ! J&#8217;ai un ami diplomate au Nigeria en train de mourir qui a justement besoin de publicité pour donner son immense fortune.</p>


feed_id: http://sametmax.com/?p=2356
title: Les émoticones cachées de Skype
uri: Les-émoticones-cachées-de-Skype
url: http://sametmax.com/les-emoticones-cachees-de-skype/
content:
<p>Pour ceux qui recoivent des émoticones qu&#8217;ils ne trouvent pas dans leur menu Skype sachez que ce dernier a des émoticones cachées ;) et ce depuis un bout de temps.</p>
<p>Pour afficher les émoticones corrrespondantes tapez les codes ci-dessous dans votre message Skype.</p>
<table width="300" style="background-color:#FFF;margin-left:120px" border="0" cellspacing="1" cellpadding="2">
<tbody>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/mooning.gif"?9d7bd4" alt="" title="mooning" width="25" height="24" class="aligncenter size-full wp-image-2363" /></td>
<td>(mooning)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/finger.gif"?9d7bd4" alt="" title="finger" width="25" height="25" class="aligncenter size-full wp-image-2365" /></td>
<td>(finger)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/bandit.gif"?9d7bd4" alt="" title="bandit" width="25" height="25" class="aligncenter size-full wp-image-2366" /></td>
<td>(bandit)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/toivo.gif"?9d7bd4" alt="" title="toivo" width="25" height="25" class="aligncenter size-full wp-image-2367" /></td>
<td>(toivo)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/ninja.gif"?9d7bd4" alt="" title="ninja" width="25" height="25" class="aligncenter size-full wp-image-2368" /></td>
<td>(ninja)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/smoke.gif"?9d7bd4" alt="" title="smoke" width="25" height="25" class="aligncenter size-full wp-image-2369" /></td>
<td>(smoke)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/headbang.gif"?9d7bd4" alt="" title="headbang" width="25" height="25" class="aligncenter size-full wp-image-2370" /></td>
<td>(headbang)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/rock.gif"?9d7bd4" alt="" title="rock" width="25" height="25" class="aligncenter size-full wp-image-2371" /></td>
<td>(rock)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/poolparty.gif"?9d7bd4" alt="" title="poolparty" width="25" height="25" class="aligncenter size-full wp-image-2372" /></td>
<td>(poolparty)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/kate.gif"?9d7bd4" alt="" title="kate" width="25" height="25" class="aligncenter size-full wp-image-2373" /></td>
<td>(kate)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/drunk.gif"?9d7bd4" alt="" title="drunk" width="25" height="25" class="aligncenter size-full wp-image-2374" /></td>
<td>(drunk)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/tmi.gif"?9d7bd4" alt="" title="tmi" width="25" height="25" class="aligncenter size-full wp-image-2375" /></td>
<td>(tmi)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/fubar.gif"?9d7bd4" alt="" title="fubar" width="25" height="25" class="aligncenter size-full wp-image-2376" /></td>
<td>(fubar)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/bug.gif"?9d7bd4" alt="" title="bug" width="25" height="25" class="aligncenter size-full wp-image-2377" /></td>
<td>(bug)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/swear.gif"?9d7bd4" alt="" title="swear" width="25" height="25" class="aligncenter size-full wp-image-2378" /></td>
<td>(swear)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/heidy-1.gif"?9d7bd4" alt="" title="heidy (1)" width="25" height="25" class="aligncenter size-full wp-image-2379" /></td>
<td>(heidy)</td>
</tr>
<tr>
<td><img src="http://sametmax.com/wp-content/uploads/2012/09/flaguk.gif"?9d7bd4" alt="" title="flaguk" width="25" height="19" class="aligncenter size-full wp-image-2380" /></td>
<td>(flag:uk)</td>
</tr>
</tbody>
</table>


feed_id: http://sametmax.com/?p=2309
title: Le piège de la méthode strip() des chaînes en Python
uri: Le-piège-de-la-méthode-strip()-des-chaînes-en-Python
url: http://sametmax.com/le-piege-de-la-methode-strip-des-chaines-en-python/
content:
<p><a href="http://docs.python.org/library/stdtypes.html?highlight=strip#str.strip">strip()</a>, et ses acolytes <code>lstrip()</code> et <code>rstrip()</code>, ne retirent pas la chaîne de caractères aux extrémités d&#8217;une autre chaîne de caractères.</p>
<p>Elles retirent des extrémités toutes lettres qui sont dans la chaînes passée en paramètre. La nuance est subtile, mais c&#8217;est la différence entre ça:</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: #483d8b;">&quot;# ##  # test &quot;</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'# '</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># comportement attendu mais faux</span>
<span style="color: #483d8b;">'##  # test '</span></pre></div></div>

<p>Et ça:</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: #483d8b;">&quot;# ##  # test &quot;</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'# '</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># comportement réel</span>
<span style="color: #483d8b;">'test'</span></pre></div></div>


feed_id: http://sametmax.com/?p=2416
title: Comment utiliser yield et les générateurs en Python ?
uri: Comment-utiliser-yield-et-les-générateurs-en-Python
url: http://sametmax.com/comment-utiliser-yield-et-les-generateurs-en-python/
content:
<p>Les générateurs sont une fonctionalité fabuleuse de Python, et une étape indispensable dans la maîtrise du langage. Une fois compris, <a href="http://sametmax.com/parcourir-un-iterable-par-morceaux-en-python/">vous ne pourrez plus vous en passer</a>.</p>
<h2>Rappel sur les itérables</h2>
<p>Quand vous lisez des éléments un par un d&#8217;une liste, on appelle cela l&#8217;itération:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">lst = <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: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> lst :
...     <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">1</span>
<span style="color: #ff4500;">2</span>
<span style="color: #ff4500;">3</span></pre></div></div>

<p>Et quand on utilise une liste en intention, on créé une liste, donc un itérable. Encore une fois, avec une boucle <code>for</code>, on prend ses éléments un par un, donc on <em>itère</em> dessus:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">lst = <span style="color: black;">&#91;</span>x<span style="color: #66cc66;">*</span>x <span style="color: #ff7700;font-weight:bold;">for</span> x <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;">3</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> lst :
...     <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0</span>
<span style="color: #ff4500;">1</span>
<span style="color: #ff4500;">4</span></pre></div></div>

<p>À chaque fois qu&#8217;on peut utiliser &#8220;<code>for</code>… <code>in</code>…&#8221; sur quelque chose, c&#8217;est un itérable : lists, strings, files…</p>
<p>Ces itérables sont pratiques car on peut les lire autant qu&#8217;on veut, mais ce n&#8217;est pas toujours idéal car on doit stocker tous les éléments en mémoire. </p>
<h2>Les générateurs</h2>
<p>Si vous vous souvenez de l&#8217;article sur <a href="http://sametmax.com/python-love-les-listes-en-intention-partie/">les comprehension lists</a>, on peut également créer des expressions génératrices:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">generateur = <span style="color: black;">&#40;</span>x<span style="color: #66cc66;">*</span>x <span style="color: #ff7700;font-weight:bold;">for</span> x <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;">3</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> generateur :
...     <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0</span>
<span style="color: #ff4500;">1</span>
<span style="color: #ff4500;">4</span></pre></div></div>

<p>La seule différence avec précédement, c&#8217;est qu&#8217;on utilise <code>()</code> au lieu de <code>[]</code>. Mais on ne peut pas lire <code>generateur</code> une seconde fois car le principe des générateurs, c&#8217;est justement qu&#8217;ils génèrent tout à la volée: ici il calcule <code>0</code>, puis l&#8217;oublie, puis calcule <code>1</code>, et l&#8217;oublie, et calcule <code>4</code>. Tout ça un par un.</p>
<h2>Le mot clé yield</h2>
<p><code>yield</code> est un mot clé utilisé en lieu et place de <code>return</code>, à la différence prêt qu&#8217;on va récupérer un générateur.</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;">def</span> creerGenerateur<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> :
...     <span style="color: black;">mylist</span> = <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">3</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> mylist:
...         <span style="color: #ff7700;font-weight:bold;">yield</span> i<span style="color: #66cc66;">*</span>i
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> generateur = creerGenerateur<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># crée un générateur</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>generateur<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># generateur est un objet !</span>
<span style="color: #66cc66;">&lt;</span> generator <span style="color: #008000;">object</span> creerGenerateur at 0x2b484b9addc0<span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> generateur:
...     <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0</span>
<span style="color: #ff4500;">1</span>
<span style="color: #ff4500;">4</span></pre></div></div>

<p>Ici c&#8217;est un exemple inutile, mais dans la vraie vie vivante, c&#8217;est pratique quand on sait que la fonction va retourner de nombreuses valeurs qu&#8217;on ne souhaite lire qu&#8217;une seule fois.</p>
<p>Le secret des maîtres Zen qui ont aquis la comprenhension transcendentale de <code>yield</code>, c&#8217;est de savoir que <strong>quand on appelle la fonction, le code de la fonction n&#8217;est pas éxécuté</strong>. A la place, la fonction va retourner un objet générateur.</p>
<p>C&#8217;est pas évident à comprendre, alors relisez plusieurs fois cette partie.</p>
<p><code>creerGenerateur()</code> n&#8217;éxécute pas le code de <code>creerGenerateur</code>. <code>creerGenerateur()</code> retourne un objet générateur.</p>
<p>En fait, <strong>tant qu&#8217;on ne touche pas au générateur, il ne se passe rien</strong>. Puis, <strong>dès qu&#8217;on commence à itérer sur le générateur, le code de la fonction s&#8217;éxécuter</strong>.</p>
<p>La première fois que le code s&#8217;éxécute, il va partir du début de la fonction, arriver jusqu&#8217;à <code>yield</code>, et retourner la première valeur. Ensuite, à chaque nouveau tour de boucle, le code va reprendre de la où il s&#8217;est arrêté (oui, Python sauvegarde l&#8217;état du code du générateur entre chaque appel), et éxécuter le code à nouveau jusqu&#8217;à ce qu&#8217;il rencontre <code>yield</code>. Donc dans notre cas, il va faire un tour de boucle. </p>
<p>Il va continuer comme ça jusqu&#8217;à ce que le code ne rencontre plus <code>yield</code>, et donc qu&#8217;il n&#8217;y a plus de valeur à retourner. Le générateur est alors considéré comme définitivement vide. Il ne peut pas être &#8220;rembobiné&#8221;, il faut en créer un autre.</p>
<p>La raison pour laquelle le code ne rencontre plus yield est celle de votre choix: condition <code>if</code>/<code>else</code>, boucle, recursion&#8230; Vous pouvez même yielder à l&#8217;infini.</p>
<h2>Un exemple concret et un café, plz</h2>
<p><code>yield</code> permet non seulement d&#8217;économiser de la mémoire, mais surtout de masquer la complexité d&#8217;un algo derrière une API classique d&#8217;itération.</p>
<p>Supposez que vous ayez une fonction qui &#8211; tada ! &#8211; extrait les mots de plus de 3 caractères de tous les fichiers d&#8217;un dossier.</p>
<p>Elle pourrait ressembler à ça:</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;">os</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> extraire_mots<span style="color: black;">&#40;</span>dossier<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> fichier <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span>dossier<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>dossier, fichier<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
            <span style="color: #ff7700;font-weight:bold;">for</span> ligne <span style="color: #ff7700;font-weight:bold;">in</span> f:
                <span style="color: #ff7700;font-weight:bold;">for</span> mot <span style="color: #ff7700;font-weight:bold;">in</span> ligne.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
                    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>mot<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">3</span>:
                        <span style="color: #ff7700;font-weight:bold;">yield</span> mot</pre></div></div>

<p>Vous avez là un algo dont on masque complètement la complexité, car du point de vue de l&#8217;utilisateur, il fait juste ça:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> mot <span style="color: #ff7700;font-weight:bold;">in</span> extraire_mots<span style="color: black;">&#40;</span>dossier<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> mot</pre></div></div>

<p>Et pour lui c&#8217;est transparent. En plus, il peut utiliser tous les outils qu&#8217;on utilise sur les itérables d&#8217;habitude. Toutes les fonctions qui acceptent les itérables acceptent donc le résultat de la fonction en paramètre grâce à la magie du duck typing. On créé ainsi une merveilleuse toolbox.</p>
<h2>Controller yield</h2>

<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;">class</span> DistributeurDeCapote<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    stock = <span style="color: #008000;">True</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> allumer<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">self</span>.<span style="color: black;">stock</span>:
            <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #483d8b;">&quot;capote&quot;</span>
...</pre></div></div>

<p>Tant qu&#8217;il y a du stock, on peut récupérer autant de capotes que l&#8217;on veut.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> distributeur_en_bas_de_la_rue = DistributeurDeCapote<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> distribuer = distributeur_en_bas_de_la_rue.<span style="color: black;">allumer</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> distribuer.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
capote
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> distribuer.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
capote
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>distribuer.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> c <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;">4</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #483d8b;">'capote'</span>, <span style="color: #483d8b;">'capote'</span>, <span style="color: #483d8b;">'capote'</span>, <span style="color: #483d8b;">'capote'</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Dès qu&#8217;il n&#8217;y a plus de stock&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> distributeur_en_bas_de_la_rue.<span style="color: black;">stock</span> = <span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> distribuer.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-22-389e61418395&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    distribuer.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">StopIteration</span>
<span style="color: #66cc66;">&lt;</span> <span style="color: #008000;">type</span> <span style="color: #483d8b;">'exceptions.StopIteration'</span><span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Et c&#8217;est vrai pour tout nouveau générateur:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> distribuer = distributeur_en_bas_de_la_rue.<span style="color: black;">allumer</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> distribuer.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-24-389e61418395&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    distribuer.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">StopIteration</span></pre></div></div>

<p>Allumer une machine vide n&#8217;a jamais permis de remplir le stock ;-) Mais il suffit de remplir le stock pour repartir comme en 40:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> distributeur_en_bas_de_la_rue.<span style="color: black;">stock</span> = <span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> distribuer = distributeur_en_bas_de_la_rue.<span style="color: black;">allumer</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> c <span style="color: #ff7700;font-weight:bold;">in</span> distribuer :
...     <span style="color: #ff7700;font-weight:bold;">print</span> c
capote
capote
capote
capote
capote
capote
capote
capote
capote
capote
capote
capote
...</pre></div></div>

<h2><code>itertools</code>: votre nouveau module favori</h2>
<p>Le truc avec les générateurs, c&#8217;est qu&#8217;il faut les manipuler en prenant en compte leur nature: on ne peut les lire qu&#8217;une fois, et on ne peut pas déterminer leur longeur à l&#8217;avance. <code>itertools</code> est un module spécialisé la dedans: <code>map</code>, <code>zip</code>, <code>slice</code>&#8230; Il contient des fonctions qui marchent sur tous les itérables, y compris les générateurs.</p>
<p>Et rappelez-vous, les strings, les listes, les sets et même les fichiers sont itérables.</p>
<p>Chaîner deux itérables, et prendre les 10 premiers caractères ? Piece of cake !</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;">import</span> <span style="color: #dc143c;">itertools</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d = DistributeurDeCapote<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">allumer</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> generateur = <span style="color: #dc143c;">itertools</span>.<span style="color: black;">chain</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;12345&quot;</span>, d<span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> generateur = <span style="color: #dc143c;">itertools</span>.<span style="color: black;">islice</span><span style="color: black;">&#40;</span>generateur, <span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> generateur:
...     <span style="color: #ff7700;font-weight:bold;">print</span> x
...     
<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>
capote
capote
capote
capote
capote</pre></div></div>

<h2>Les dessous de l&#8217;itération</h2>
<p>Sous le capôt, tous les itérables utilisent un générateur appelé &#8220;itérateur&#8221;. On peut récupérer l&#8217;itérateur en utiliser la fonction <code>iter()</code> sur un itérable:</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: #008000;">iter</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</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span> listiterator <span style="color: #008000;">object</span> at 0x7f58b9735dd0<span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">iter</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span> tupleiterator <span style="color: #008000;">object</span> at 0x7f58b9735e10<span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">iter</span><span style="color: black;">&#40;</span>x<span style="color: #66cc66;">*</span>x <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span> generator <span style="color: #008000;">object</span>  at 0x7f58b9723820<span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Les itérateurs ont une méthode next() qui retourne une valeur pour chaque appel de la méthode. Quand il n&#8217;y a plus de valeur, ils lèvent l&#8217;exception <code>StopIteration</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> gen = <span style="color: #008000;">iter</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</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> gen.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> gen.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">2</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> gen.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">3</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> gen.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt; stdin&gt;&quot;</span>, line <span style="color: #ff4500;">1</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: #008000;">StopIteration</span></pre></div></div>

<p>Message à tous ceux qui pensent que je fabule quand je dis qu&#8217;en Python on utilise les exceptions pour contrôler le flux d&#8217;un programme (sacrilège !): ceci est le mécanisme des boucles interne en Python. Les boucles <code>for</code> utilisent <strong>iter()</strong> pour créer un générateur, puis attrappent une exception pour s&#8217;arrêter. <strong>À chaque boucle <code>for</code>, vous levez une exception sans le savoir</strong>.</p>
<p>Pour la petite histoire, l&#8217;implémentation actuelle est que <strong>iter()</strong> appelle la méthode <strong>__iter__()</strong> sur l&#8217;objet passé en paramètre. Donc ça veut dire que vous pouvez créer vos propres itérables:</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;">class</span> MonIterableRienQuaMoi<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__iter__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
...         <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #483d8b;">'Python'</span>
...         <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #483d8b;">&quot;ça&quot;</span>
...         <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #483d8b;">'déchire'</span>
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> gen = <span style="color: #008000;">iter</span><span style="color: black;">&#40;</span>MonIterableRienQuaMoi<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> gen.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'Python'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> gen.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'ça'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> gen.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'déchire'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> gen.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt; stdin&gt;&quot;</span>, line <span style="color: #ff4500;">1</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: #008000;">StopIteration</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> MonIterableRienQuaMoi<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">print</span> x
...
<span style="color: black;">Python</span>
ça
déchire</pre></div></div>


feed_id: http://sametmax.com/?p=2237
title: Une petite compilation de trucs de cul bien fun
uri: Une-petite-compilation-de-trucs-de-cul-bien-fun
url: http://sametmax.com/une-petite-compilation-de-trucs-de-cul-bien-fun/
content:
<p>On croise des trucs pas croyable, et je me dis qu&#8217;il serait dommage de ne pas partager.</p>
<p>Si vous croyez que le porno c&#8217;est hard, dites vous que certaines videos youtubes peuvent être beaucoup plus perturbantes</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="http://www.youtube.com/embed/fS1uDnIPTvo" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>En voici <a href="http://www.worldsex.com/videos/weirdest-sex-ever-23213.html">une autre qui parait normale</a> jusqu&#8217;à ce que vous remarquiez une premier détail. Puis vous vous dites que ce n&#8217;est pas si rare sur la toile, jusqu&#8217;à ce que vous remarquiez un second détail.</p>
<p>Ensuite, celle-là, c&#8217;est une vidéo éducative (Oui, oui&#8230;): </p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/LRogmcixV_M" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Pour les non anglophones:</p>
<p>&#8220;Oh mon fils, tu te branlais ? C&#8217;était bon ? Et bien contente que tu le fasses en privé dans ta chambre.&#8221; (et je vais continuer à rentrer dans ta chambre sans frapper avec un air de serial killer jusqu&#8217;à ce que tu te suicide).</p>
<p>Et juste <a href="sametmax.com/message-subliminal/">pour le SEO</a>, encore un truc de cul japonais complètement barge:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="510" height="400" src="http://sextvx.com/embed/130067" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Le sexe sur la plage, c&#8217;est un fantasme surévalué, le sexe avec la plage par contre:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="510" height="400" src="http://xhamster.com/xembed.php?video=1413408" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Le SM est un grand classique, mais j&#8217;avoue que les vacuum beds et les tits pumps ne me blasent jamais:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://www.youjizz.com/videos/embed/183275" frameborder="0" width="704" height="550" scrolling="no" allowtransparency="true" class="iframe-class"></iframe>
<p>Et pour finir, qui n&#8217;a jamais eu envie de se taper catwoman ?</p>
<p><object height="344" width="434"><param name="allowfullscreen" value="true"><param name="AllowScriptAccess" value="always"><param name="movie" value="http://embed.redtube.com/player/"><param name="FlashVars" value="id=75246&#038;style=redtube&#038;autostart=false"><embed src="http://embed.redtube.com/player/?id=75246&#038;style=redtube" allowfullscreen="true" AllowScriptAccess="always" flashvars="autostart=false" pluginspage="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash" type="application/x-shockwave-flash" height="344" width="434" /></object></p>


feed_id: http://sametmax.com/?p=2461
title: Réponse à l’article “Ruby -vs- Python” de Bodo Tasche
uri: Réponse-à-l-article-Ruby-vs-Python-de-Bodo-Tasche
url: http://sametmax.com/reponse-a-larticle-ruby-vs-python-de-bodo-tasche/
content:
<p>C&#8217;est pas encore vendredi, mais je ne  <a href="http://xkcd.com/386/">pouvais pas</a> laisser passer <a href="http://bitboxer.de/2012/10/03/ruby-vs-python/">ça</a>. Petite réponse à Bodo Tasche, affûtez votre english car j&#8217;ai la flemme de traduire sa prose (si quelqu&#8217;un se propose, il aura droit à un tampon :-p).</p>
<blockquote><p>Ruby and Python. Two languages. Two communities. Both have a similar target: to make software development better. Better than Java, better than PHP and better for everyone. But where is the difference? And what language is “better”? For the last question I can say: none is better. Both camps are awesome and do tons of great stuff. But for the first question the answer is longer. And I hope to provide that in this little article</p>
<p>Is the difference in the toolset around the language? No, I don’t think so. Both have good package managers, tons of libraries for all kind of stuff and a few decent web frameworks.</p></blockquote>
<p>Heu&#8230; si. Il y a une énorme différence.</p>
<p><strong>Ruby a RVM, un truc enorme et très difficile à mettre en oeuvre</strong>. Python a virtualenv, un truc léger et très simple à faire passer. Conséquence ? Une grande partie des rubistes n&#8217;utilisent pas RVM et leurs projets souffrent de problèmes constant de compatibilité. Combien de fois j&#8217;ai vu des <code>gems install</code> planter à cause de ça&#8230;</p>
<p>Et <strong>combien y a-t-il de RAD pour faire des applications en Ruby ?</strong> Ca influe sur le nombre d&#8217;applications desktop écrites en Ruby.</p>
<p><strong>Combien y a-t-il d&#8217;outils pour facilement interfacer Ruby avec d&#8217;autres technologies ?</strong> Python est utilisé massivement comme langage d&#8217;extensions à cause de ça (Sublime Text, Blender, Nautilus, Inscape, etc).</p>
<p>Quant aux libs. <strong>On utilise Ruby pour quoi en dehors du Web ?</strong> Développement de jeu ? Sur tablette tactile ? Simulation scientifique ? Application desktop ? Très peu. Alors que Python <a href="http://sametmax.com/quest-ce-quon-peut-faire-avec-python/">est utilisé pour tout ça</a>. La raison est justement le large panel de libs. Python a beaucoup, beaucoup, beaucoup plus de libs que Ruby.</p>
<p>Youhou ! Pour accéder à Internet, on utilise un ordinateur plein de trucs qui ne sont pas sur Internet ! Pour servir un site Web aussi !</p>
<p><strong>L&#8217;écosystème, c&#8217;est la moitié de l’intérêt d&#8217;un langage</strong>. Je ne retire pas à Ruby le mérite de la qualité du sien: il est innovant, dynamique, sa communauté est fantastique. Mais on est loin d&#8217;avoir dans Ruby le dixième des outils et libs qu&#8217;on a en Python. C&#8217;est pour ça que Mac <del datetime="2012-10-04T09:44:47+00:00">embarque</del> embarquait Python par défaut et pas Ruby. C&#8217;est pour ça qu&#8217;Ubuntu est massivement codé en Python et pas en Ruby. Ca fait toute la différence.</p>
<blockquote><p>I think there is something else that is way more important. The culture.</p></blockquote>
<p>+ 1. Et Ruby en a une excellente. Faites un bisou aux gars de 37 signals.</p>
<blockquote><p>Okay, now what is the difference in the culture? It is pretty easy. Python folks are really conservative and afraid of change, Ruby folks love the new shiny stuff even if it breaks older things. It’s that simple. But it has huge consequences.</p></blockquote>
<p>Ce n&#8217;est pas la seule différence, mec. Les rubistes sont vachement plus sympa, d&#8217;une manière générale. Les pythonistes que je connais sont généralement assez blafards. Compétents, mais pas funny fun. Et les rubistes sont plus actifs socialement, du coup: plus d&#8217;events, plus d&#8217;articles de blog, plus de vidéos&#8230; Et ça, c&#8217;est un gros plus pour Ruby.</p>
<p>Mais d&#8217;un autre côté, Python a la culture des comptable: du code lisible, et de la documentation. Et comme c&#8217;est un peu mon job de lire le code 500 fois par jour et de fouiller dans la doc, c&#8217;est très important pour moi. <strong>Les docs Ruby, parfois, c&#8217;est vraiment une grosse blague</strong>. Regarder dans le code source n&#8217;est pas un bon palliatif. Une doc indique une manière officielle de faire, une manière figée, stable, qu&#8217;on va pouvoir utiliser et supporter sur des années. C&#8217;est important.</p>
<blockquote><p>One you can see for example in the adaption of Ruby 1.9 vs Python 3. Both new versions did tons of breaking changes. A lot of code needed changes to run on the new plattform. In the Ruby world the transition went pretty quick. In the Python world it is very troublesome. Some Python people even say that Python 3 is broken and all energy should be focused on the 2.x-branch of the language. The Ruby community saw the opportunities. The Python community only saw the update problems. Yes, there have been update problems in the Ruby world, but we found an easy way to fix this: isitruby19.com. A simple plattform that showed if the gem is ready for 1.9. And if it wasn’t and the gem was important, it got fixed with pull requests or something similar. And the problems went away fast.</p></blockquote>
<p>Ouai mais tu vois (tu me permet de te tutoyer ? en anglais on s&#8217;en fou de toute façon&#8230;), c&#8217;est vachement plus facile de tout péter quand on a pas deux OS majeurs qui se basent dessus. Je sais pas si tu as déjà essayé de faire upgrader un repo complet de milliers d&#8217;apps open sources, mais ça prend du temps.</p>
<p>Oh, et <strong>Python est là depuis vachement plus longtemps que Ruby</strong>. Python était même là avant Java. Chaque corps de métier à un sacret paquet de code à faire migrer, et ils sont pas tous en lean management super agile mega scrum mode, eux. Les biologistes qui utilisent Python pour faire leurs simulations depuis 10 ans, ils ont pas que ça à foutre d&#8217;upgrader leur code. Pour eux la prog, c&#8217;est pas &#8220;Fuck yeah, new features, I&#8217;m going to touch myself on Vx and migrate&#8221;. Pour eux c&#8217;est 7 ans de scripts d&#8217;analyse de génome à se retaper alors que ce n&#8217;est qu&#8217;un outil ennuyeux à leurs yeux.</p>
<blockquote><p>Both models of thinking have pros and cons. The Python world is more stable, you can update your django installation without much troubles. But that also means new technology is only added very slowly. The Ruby world loves changes.</p></blockquote>
<p>La différence majeur entre Rails et Django ? Rails: chaque version stable possède des gros trous qu&#8217;ils bouchent au fur et à mesure, parce que c&#8217;est pas grâve, on est flexible et adaptif mec, on release early et often. Django, en version 0.96, tout le monde l&#8217;utilisait déjà en production car le truc était rock solide.</p>
<p>Alors oui, y a moins de features. Mais ma plateforme ne m&#8217;explose pas à la gueule. Et<a href="http://sametmax.com/je-voulais-juste-installer-une-gem/"> pip installe fonctionne</a>.</p>
<blockquote><p>So much that most of the “new stuff” in the Python world was tested in the Ruby world first.</p></blockquote>
<p>Ca c&#8217;est vrai. Merci d&#8217;ailleurs. Mais encore une fois, on parle d&#8217;une catégorie de libs qui se limitent au dev Web. C&#8217;est le même débat que &#8220;Mac est innovant&#8221;. C&#8217;est certain, quand on a une archi et 3 modèles à supporter, c&#8217;est plus facile de faire un truc innovant: on a pas à supporter de compatibilité.</p>
<blockquote><p>We love changes so much that the Rails core is build around that idea. You can easily change nearly everything and extend everything. Most of the new stuff the Rails Core Team is testing right now for version 4 is available as plugin for Rails 3. This is pretty interesting if you love new things, love change, and love playing around with stuff. If you don’t and hate the idea of breaking changes, you maybe are better suited with the Python way. But don’t be afraid of breaking changes. They are all pretty well documented in the release guides. It’s not voodoo.</p></blockquote>
<p>Si. <strong>C&#8217;est carrément du voodoo</strong>. Le monkey patching des objets built-in, c&#8217;est la porte ouverte à toutes les fenêtres, et quand deux libs le font en même temps, BOUM.</p>
<p>Et le nouveau, c&#8217;est marrant. Je suis pour le nouveau. Max m&#8217;engueule tout le temps car je veux essayer les trucs nouveaux. Mais pas instable. L&#8217;écosystème de Ruby est instable. Si les langages étaient des OS, Java serait Debian, Python serait Ubuntu LTS, Ruby serait Ubuntu RC. J&#8217;utilise la dernière Ubuntu pour mon desktop, parce qu&#8217;avoir Unity qui plante une fois par jour ne me dérange pas. Mais sur le serveur, je prends la version la plus stable, parce que j&#8217;ai pas besoin de &lt;blink&gt;, j&#8217;ai besoin de &lt;strong&gt;.</p>
<blockquote><p>I for myself love the Ruby mindset. Something like Rails or Asset Pipelines or all the other things would not be possible if we are stuck with “no, don’t change that, it works pretty well that way”. Someone has to be the leader. Someone has to play around with new ideas. Yes, some ideas won’t fly, some are removed pretty quickly. But at least we tried them. Yes, I know that some people prefer the conservative way. If you consider yourself to be like that, you should at least try Python. I stay with Ruby.</p></blockquote>
<p>C&#8217;est vrai qu&#8217;on ne fait rien d&#8217;innovant en Python: <a href="http://www.raspberrypi.org/faqs">programmation du rasberry py</a>, <a href="http://pythonneuro.sciencesconf.org/">simulation neurale</a>, <a href="http://pypi.python.org/pypi/clize/1.0b">facilitation du parsing d&#8217;arguments</a>, <a href="http://www.bittorrent.com/intl/fr/">création du meilleur protocole d&#8217;échange en P2P au monde</a>&#8230; Ah, par innovation tu veux dire une énième lib Web ? Pardon, je croyais qu&#8217;on parlait de programmation au sens large du terme.</p>
<p>Dans ce cas: Twisted était là bien avant event-machine (ou même NodeJs). Wep.py était là avant Sinatra. Virtualenv était là avant RVM. Zope était là 6 ans avant ROR avec son ORM et son langage de template.</p>
<p><strong>Et oui, vous avez bien amélioré tout ça. Et c&#8217;est génial.</strong> C&#8217;est comme ça que ce doit être. Mais arrêtez de vous prendre pour l&#8217;élément indispensable de l&#8217;innonvation de la programmation Web moderne. Vous n&#8217;êtes pas tous des <a href="https://en.wikipedia.org/wiki/Jason_Fried"> Jason Fried</a>. Et là plupart des choses que l&#8217;on fait aujourd&#8217;hui on été inventé par les mecs de Lisp, Haskel et Smalltalk de toute façon, qui eux même se sont inspirés de l&#8217;amont. On giant shoulders, tout ça, tout ça&#8230;</p>


feed_id: http://sametmax.com/?p=2452
title: Les listes en intention VS map() en Python
uri: Les-listes-en-intention-VS-map()-en-Python
url: http://sametmax.com/les-listes-en-intentions-vs-map-en-python/
content:
<p>Les adeptes de la programmation fonctionnelle connaissent bien le principe de la fonction <a href="http://docs.python.org/library/functions.html#map">map()</a> et sont souvent plus à l&#8217;aise avec elle qu&#8217;avec les listes en intention en Python.</p>
<p>Les deux font pourtant la même chose, <del datetime="2012-10-04T08:33:03+00:00">tant et si bien que Python 3 voit <code>map()</code> retiré de ses built-in</del>. Ouuuups. Dérapage un-con-trollé de Sam.</p>
<p>C&#8217;est plutôt une nouvelle chose car dans un language orienté objet comme Python, il y a une subtile différence entre <code>map()</code> et les <a href="http://sametmax.com/python-love-les-listes-en-intention-partie/">comprehension lists</a>. Quand on utilise une méthode plutôt qu&#8217;une fonction, <code>map()</code> tue le duck tuping:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> l = <span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'      Le choix dans la date     '</span>, <span style="color: #483d8b;">'     Les nouilles cuisent au jus de canne     '</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span>.<span style="color: black;">strip</span>, l<span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-14-41df8a735feb&gt;&quot;</span>, line <span style="color: #ff4500;">1</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: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span>.<span style="color: black;">strip</span>, l<span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: descriptor <span style="color: #483d8b;">'strip'</span> requires a <span style="color: #483d8b;">'str'</span> <span style="color: #008000;">object</span> but received a <span style="color: #483d8b;">'unicode'</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #008000;">unicode</span>.<span style="color: black;">strip</span>, l<span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-15-fc0fc8fef32d&gt;&quot;</span>, line <span style="color: #ff4500;">1</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: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #008000;">unicode</span>.<span style="color: black;">strip</span>, l<span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: descriptor <span style="color: #483d8b;">'strip'</span> requires a <span style="color: #483d8b;">'unicode'</span> <span style="color: #008000;">object</span> but received a <span style="color: #483d8b;">'str'</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: black;">&#91;</span>x.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> l<span style="color: black;">&#93;</span>
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'Le choix dans la date'</span>, <span style="color: #483d8b;">'Les nouilles cuisent au jus de canne'</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Notez que je vous recomande d&#8217;éviter à tout prix de mélanger des chaînes encodées, et des chaînes unicode, de toute façon. J&#8217;utilise ceci uniquement parce que c&#8217;est un cas simple à comprendre.</p>
<p>Mais ici, le problème peut être résumé ainsi: nous avons une collection hétérogène d&#8217;objets (qui pourraient être de n&#8217;importe quels autres types, il y a des cas beaucoup plus légitimes), et nous appliquons la méthode de l&#8217;objet. Qui ne correspond pas forcément à son type.</p>
<p>Avoir des types différents avec la même interface est courant en Python pour profiter du duck typing, donc ce genre de chose n&#8217;est pas un edge case.</p>
<p>La solution est bien entendu de wrapper l&#8217;appel dans une <a href="http://sametmax.com/fonctions-anonymes-en-python-ou-lambda/">fonction anonyme</a>:</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: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: x.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, l<span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'Le choix dans la date'</span>, <span style="color: #483d8b;">'Les nouilles cuisent au jus de canne'</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Mais à ce stade, <code>[x.strip() for x in l]</code> est beaucoup plus lisible et rapide. Sans compter qu&#8217;il peut être transformé en générateur juste en changeant les <code>[]</code> en <code>()</code>.</p>


feed_id: http://sametmax.com/?p=2400
title: 10 excellentes séries peu connues
uri: 10-excellentes-séries-peu-connues
url: http://sametmax.com/10-excellentes-series-peu-connues/
content:
<p>La <a href="https://fr.wikipedia.org/wiki/24_heures_chrono">gestion de crise à l&#8217;américaine</a>, des <a href="https://fr.wikipedia.org/wiki/Desperate_Housewives">femmes au foyer à la répartie et la libido surhumaine</a>, des <a href="https://fr.wikipedia.org/wiki/Lost_:_Les_Disparus">délires télévisuels sous LSD</a> et des <a href="https://fr.wikipedia.org/wiki/Dexter">psychopathes adorables</a>, &#8230; Il y a une vie après les block busters.</p>
<h2>Better off Ted</h2>
<p>Hilarant de cynisme léger, ses deux saisons mettent en scène le département de recherche et développement de la société Veridian Dynamics, monstre tentaculaire qui congèle ses collaborateurs, fait travailler les enfants de la garderies des employés et fabrique de la viande de bœuf sans vache, entre autre choses.</p>
<p>C&#8217;est drôle, pas sérieux pour deux sous, et aucun personnage n&#8217;est à jeté durant les courtes 20 minutes de chaque épisodes.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe frameborder="0" width="480" height="360" src="http://www.dailymotion.com/embed/video/xk2baa_veridian-dynamics-ad-friendship_shortfilms" scrolling="no" class="iframe-class"></iframe>
<h2>Psychoville</h2>
<p>5 fous reçoivent une lettre avec écrit: &#8220;&#8221;Je sais ce que vous avez fait&#8221;. Un clown dégueulasse qui ne quitte jamais sont déguisement, un nain qui croit qu&#8217;il est télékinésique, un fils et sa mère débiles et violents, une infirmière qui nourrit une poupée avec du sang pour lui donner vie, et un collectionneur qui a vendu ses yeux pour poursuivre son hobby.</p>
<p>Cette flaque d&#8217;humour noir glauque et glissante prouve une fois de plus que les rosbifs sont toujours au top créativement parlant.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe frameborder="0" width="480" height="400" src="http://www.dailymotion.com/embed/video/x9mpnn_psychoville-1x01-friday-19th-of-jun_shortfilms" scrolling="no" class="iframe-class"></iframe>
<h2>Dead like me</h2>
<p>Belle, blonde et blasée: une peu morte à l’intérieur. La mauvaise nouvelle, c&#8217;est que Georgia va passer le reste de sa vie dans une cave à trier des papiers avec son air morose. La bonne, c&#8217;est que la fin de sa vie est à peu prêt dans 5 minutes. Tuée par des lunettes de WC tombant de la station Mir, elle devient une morte-vivante SDF suivant des ordres sur posts it. Si, si.</p>
<p>C&#8217;est lent. C&#8217;est tronqué à la saison 2. C&#8217;est très mystérieux. Mais qu&#8217;est-ce que c&#8217;est bon.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="http://www.youtube.com/embed/xh2_Pe1jV2w#t=166s" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Sherlock</h2>
<p>A part la très inattendue bonne surprise des films avec Robert Downey Jr, les adaptations à l&#8217;écran de Sherlock Holmes ont toujours été coup-ci coup-ça. Dites bonjour à un jeune Sherlock, méprisant, insupportable, détesté de tous, et parfaitement génial, qui s&#8217;est très bien adapté aux SMS.</p>
<p>On connaît l&#8217;histoire, mais la réa impeccable et l&#8217;excellent Benedict Cumberbatch font très vite accrocher à ces saisons de 3 épisodes d&#8217;une heure trente. Les personnages secondaires sont magistraux, avec une mention spéciale pour l&#8217;attaque des bijoux de la couronnes par Moriarty et son lecteur MP3 et l&#8217;introduction de The Woman à oulpé.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="http://www.youtube.com/embed/4ebHOsr8sjA" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Pushing Daisies</h2>
<p>Un pouvoir: deux règles. Ned peut ressusciter les morts en les touchant, mais si la résurrection dure plus d&#8217;une minute, une autre personne meurt au hasard. Et si il les retouche, ils retournent pour toujours à leur éternel repos. Ned doit maintenant caresser son chien avec une cuillère en bois et embrasser sa petite amie à travers un papier cellophane.</p>
<p>Si vous avez aimé Amélie Poulain, vous allez crier au chef d’œuvre. Petit bijoux d&#8217;esthétisme, chaque épisode peut être regardé plusieurs fois pour y trouver des centaines de détails. En prime, les personnages féminins ont des répliques fabuleuses.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/IsPqWKT005A" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Red Dwarf</h2>
<p>Le vaisseau le Red Dwarf embarque l&#8217;équipage le plus nul du monde. C&#8217;est cheap, et pas forcément bien joué. Mais c&#8217;est sooooooooooooo Monthy Python. Et geek.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="http://www.youtube.com/embed/KUFkb0d1kbU" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Firefly</h2>
<p>Après Stargate, le monde de la série SciFi s&#8217;est écroulé. Battle Star Galactica a laissé quelques espoirs, mais le syndrome de Lost l&#8217;a très vite gagné. Puis j&#8217;ai découvert Firefly, ses personnages stéréotypés et son mélange science fiction / western. Et ça a pris. Je ne sais pas pourquoi. Mais ça a pris.</p>
<p>Difficile pour moi de vendre cette série. Elle n&#8217;a rien d&#8217;extraordinnaire. Mais elle m&#8217;a permit de me remettre de la déception de Farescape.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="http://www.youtube.com/embed/7EcyhneTXiY" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Oui, ils ont fait un film&#8230;</p>
<h2>Misfits</h2>
<p>Prenez 6 ados racailles condamnés aux travaux d’intérêt général. Donnez leur des pouvoirs arbitrairement, soudainement, sans leur ajouter ni morale, ni but dans la vie. Laissez mijotez dans un gettho britanique. Seule série de super héros sans aucun héros ou même personnage maîtrisant ses pouvoirs, Misfits brille par son ambiance unique, ainsi qu&#8217;une forte cohérence du scénario.</p>
<p>Combien de séries peuvent se venter de faire revenir un personnage dans le temps pour tuer Hitler, le laisser se faire mettre un coup de boule par Adolf, puis montrer comment l&#8217;Allemagne gagne la guerre grâce au téléphone portable du pauvre mec ?</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/TlqOuzkgIy0" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Community</h2>
<p>Il n&#8217;y a pas de scénario. Il n&#8217;y a pas de cohérence. Il n&#8217;y a pas de budget. Community est une série dans la lignée de Scrubs: des personnages caricaturaux dans un décors simple, des situations géniales et la volonté de donner un style à chaque morceau de saison. Un épisode est une partie de poker / paintball, un autre est entièrement en animation, un troisième est un huit-clos dans un simulateur spatial&#8230;</p>
<p>A prendre à dose régulière pour traiter la déprime, chaque prise vous apportera l&#8217;effervescence d&#8217;un sourir et la bonne humeur pour le reste de la journée. Six seasons and a movie !</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="http://www.youtube.com/embed/dlz8S4t0HUY" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Awake</h2>
<p>Sam award de l&#8217;idée la plus cool. Le agent Michael Britten se plante en voiture avec son môme et sa femme. Il se réveille, son mioche est mort, sa femme est en vie, il va résoudre une enquête. Il se couche, sont fils est vivant, sa femme est dead, et il travaille sur une affaire différent mais étrangement liée. Dans chaque réalité, alternant un réveil sur deux, il va voir un psy qui lui assure que &#8220;ceci n&#8217;est pas un rêve&#8221;.</p>
<p>Le protagoniste le plus important est aussi le plus classe, et il vous entraîne dans son monde au rythme brumeux, mais tellement convainquant. Cette fois je suis sûr, c&#8217;est celle là la vraie vie. Ah non, merde, attend&#8230;</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="http://www.youtube.com/embed/Uk06mR-yt9w" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>V.O required</h2>
<p>Regarder ces séries en français n&#8217;est pas toujours possible, mais même dans le cas où ça l&#8217;est, je vais invite à l&#8217;éviter à tout prix. Certaines séries ne sont pas justes moins bonne une fois doublée, elles sont mauvaises. Mon pire souvenir ayant été, après avoir vécu en Angletterre, de retourner en France recommander Scrubs à mes amis pour m&#8217;entendre répondre que c&#8217;était affligeant. Et ils avaient raisons, Scrubs en français est une sombre merde qui ne mérite pas le temps de qui que ce soit.</p>
<p>Donc si vous ne pouvez pas les voir en V.O (au moins sous-titré), ne perdez pas votre temps, allez sur youporn.</p>


feed_id: http://sametmax.com/?p=2482
title: Après on dit que je troll sur le monde de Ruby et de NodeJs
uri: Après-on-dit-que-je-troll-sur-le-monde-de-Ruby-et-de-NodeJs
url: http://sametmax.com/apres-on-dit-que-je-troll-sur-le-monde-de-ruby-et-de-nodejs/
content:
<p>Je sais, je sais, tous les programmes ont des bugs. Je sais, ces outils sont super cool. Je sais, il faut se soutenir entre communautés et pas se tirer dans les pattes.</p>
<p>Mais merde, je voulais juste lancer la génération de mon fichier <em>less</em> pour le fabuleux bootstrap (juste publié par la plus grosse boîte qui utilise Ruby au monde, à savoir Twitter):<br />
<code><br />
make<br />
jshint: command not found</code></p>
<p>Ah ? <a href="http://bootstrap.lesscss.ru/less.html#compiling">C&#8217;est pas sur le site ça</a>.</p>
<p>Ah nan c&#8217;est <a href="https://github.com/twitter/bootstrap/pull/3228">un bug</a>, mais comme expliqué sur <a href="https://github.com/twitter/bootstrap">README</a>, il faut juste installer jshint:<br />
<code><br />
sudo npm install jshint -g<br />
npm http 304 http://registry.npmjs.org/jshint<br />
</code></p>
<p>Ah, non. Ah mais c&#8217;est <a href="https://github.com/isaacs/npm/issues/2825">un bug de nodejs</a>. C&#8217;est rien, il a été corrigé ! Il faut juste installer la dernière version.</p>
<p><code>sudo apt-get upgrade<br />
</code><br />
Ah nan, aucune mise à jour.</p>
<p>Solution recommandée par les dev: compiler les sources. Youhou !</p>
<p><a href="http://sametmax.com/je-voulais-juste-installer-une-gem/">Je voulais juste</a>&#8230; </p>
<p>:-(</p>


feed_id: http://sametmax.com/?p=989
title: Où trouver un Job ou une mission Python / Django ?
uri: Où-trouver-un-Job-ou-une-mission-Python-Django
url: http://sametmax.com/ou-trouver-un-job-ou-une-mission-python-django/
content:
<p>Je vois ici et là encore des gens qui se posent la question, et ça m&#8217;étonne, car <a href="http://learnpython.wordpress.com/2012/05/27/how-not-to-get-a-python-job-a-rant/">il y a pénurie de devs</a>, donc du besoin partout.</p>
<h2>Les annonces françaises</h2>
<p>Si vous cherchez en France, il y a de bonnes annonces sur des sites spécialisés comme <a href="http://emploi.trovit.fr/offres-emploi/python">lesjeudis</a>,<a href="http://emploi.trovit.fr/index.php/cod.rss_jobs/what_d.python/">trovit</a>, l&#8217;<a href="http://www.afpy.org/jobs">afpy</a> et <a href="http://jobs.humancoders.com/python">human coders</a>, et nous agrégeons les 4 sur le <a href="http://multiboards.net/">multiboards</a>. Dans ceux qu&#8217;on agrège pas, il y a <a href="http://emploi.alsacreations.com/index.php?q=python&amp;action=q&amp;table=tout">alsacreations</a>, <a href="http://www.indeed.fr/emplois?q=python&amp;l=">indeed</a>, <a href="http://www.jobintree.com/emploi/?keywords=python">jobintree</a>, <a href="http://www.keljob.com/recherche/python/_/N-6qc/Ntk-SI_What/Ntt-python?nbJobPage=15">keljob</a>, <a href="http://offres.monster.fr/offres-d-emploi/?q=python&amp;cy=fr">monster</a>, <a href="http://www.optioncarriere.com/emploi-developpeur-python.html">option carriere</a>, <a href="http://www.wanajob.com/emploi?search=python&amp;fpc=">wanajob</a> et bien entendu Google&#8230; <strong>Ne perdez pas de temps sur les sites officiels type Apec, Anpe, Pôle emploi, etc</strong>. C&#8217;est beaucoup de temps pour un très mauvais retour.</p>
<p>(Et c&#8217;est là que je me dis que faire un méta moteur de recherche pour des annonces uniquement sur Python, ça pourrait être trop cool)</p>
<p>Si vous êtes freelance, vous devriez quand même utiliser ces sites car les offres y sont pèles mêle, et il y a des missions dans le lot. De plus, <strong>si vous voyez écrit quelque chose dans une annonce, ça ne veut pas dire qu&#8217;on ne peut pas proposer autre chose</strong>. Offrez vos talents en tant que freelance à quelqu&#8217;un qui cherche à embaucher en CDD, et même parfois en CDI, peut parfaitement marcher. Ca ne coûte rien, et au pire les gens ont votre CV et vous avez leurs contacts, et rien que pour ça, ça vaut la peine.</p>
<p>Parfois les sites ne proposent pas les contacts. Soyez créatifs: vous êtes informaticien, utilisez les outils informatiques à votre disposition pour retrouver la société à travers une annonce sur un site concurrent, un dossier de presse qui parle du projet sur lequel on embauche, la localisation géographique, le nombre d&#8217;employés, les technos utilisées, le nom du contact&#8230; <strong>On augmente drastiquement ses chances quand on contacte les gens en direct</strong>, pas à travers un site, donc n&#8217;hésitez pas à passer quelques heures pour trouver la source d&#8217;une annonce. Dans le cas où il y a trop peu d&#8217;infos pour lancer une recherche, laissez tomber. Un employer qui met 3 lignes dans sont annonce hors de Twitter, ça sent le job pourri.</p>
<h2>Les annonces anglaises</h2>
<p>Les meilleurs jobs (les projets les plus cools et les mieux payés), impliquent presque tous un environnement de travail anglophone. Si vous ne parlez pas anglais, commencez dès maintenant à chercher des cours, c&#8217;est un investissement sur votre vie à très haut rendement.</p>
<p>Attention, ça ne veut pas dire que vous aurez à aller travailler à l&#8217;étranger. Il y a des boîtes qui communiquent en anglais basées en France, et d&#8217;autres qui acceptent le télétravail. J&#8217;ai déjà travaillé pour Paris depuis Madrid, Baltimore depuis Bangkok, New York depuis Bamako, etc.</p>
<p>On trouve des annonces sympa sur:</p>
<ul>
<li><a href="http://www.python.org/community/jobs/">Le job board officiel Python</a></li>
<li><a href="http://careers.stackoverflow.com/jobs?searchTerm=python&amp;location=france">SO career</a></li>
<li><a href="http://www.simplyhired.com/a/jobs/list/q-python">Simply hired</a></li>
</ul>
<p>Et pour Django uniquement:</p>
<ul>
<li><a href="http://www.djangojobs.org/">Django jobs</a></li>
<li><a href="http://djangogigs.com/">Django gigs</a></li>
<li><a href="https://www.djangoproject.com/community/jobs/">Job board Django officiel</a></li>
</ul>
<h2>Hors annonces</h2>
<p>Certains sites non destinés à l&#8217;emploi sont excellents pour ça malgré tout. Passez du temps sur les forum spécialisés de votre métier, par exemple <a href="http://forum.django-fr.org/viewtopic.php?id=623">django-fr</a>. Enregistrez-vous comme expert sur les listings spécialisés comme <a href="http://djangogigs.com/developers/add/">django gigs</a> et la <a href="https://people.djangoproject.com">map officielle des dev Django</a>. Inscrivez-vous aux mailling lists. Si vous avez un compte sur <a href="http://stackoverflow.com/">Stackoverflow</a>, mettez votre email dedans et spécifiez que vous cherchez du travail.</p>
<p>Faites une veille informationnelles régulière: les blogs et les journaux publient souvent des annonces. Il n&#8217;y a pas une semaine sans que <a href="https://twitter.com/i/#!/search/?q=%28python+OR+django+OR+git+OR+%23python+OR+%23django+OR+%23git%29+lang%3Afr&amp;src=savs">cette recherche</a> sur Twitter ne contienne une offre de travail Python. Nous même on retweet des offres régulièrement. Oui, ça prend du temps, la veille informationnelle. Ça me prend environ une heure par jour, depuis 15 ans. Ça fait parti du job. Comment vous croyez qu&#8217;on obtient la connaissance pour écrire ces articles ?</p>
<p>Enfin il faut mettre le nez dehors. Allez dans les lieux où il y à d&#8217;autres geek: espaces de co-working, hacker spaces, fab labs, etc. Mais aussi aux événements réguliers: afpyros, open coffee, hack-a-thon, pycon, pyconfr, django cong, django breizh&#8230; Il y a souvent quelqu&#8217;un qui cherche un dev, ou connaît quelqu&#8217;un qui cherche un dev.</p>
<h2>Quelques petits conseils pour maximiser vos chances</h2>
<p>Je vous dis ça car j&#8217;ai été apprenti, employé, freelance, et chef d&#8217;entreprise, donc j&#8217;ai eu pas mal de points de vue sur la question.</p>
<ul>
<li><strong>Designer votre CV avec un logiciel de dessin</strong>, pas un traitement de texte: un beau CV ne pallie pas sa pauvreté, mais c&#8217;est comme mettre un joli cadre sur un tableau, ça donne envie de l&#8217;accrocher.</li>
<li><strong>Ne parlez pas aux ressources humaines</strong> si vous le pouvez. Essayez à tout prix (quitte à vous faire passer pour l&#8217;employer des postes), d&#8217;obtenir le contact d&#8217;un mec de l&#8217;équipe technique ou du patron. Les RH ne pigent rien à la technique et pourront vous rembarrer pour tout un tas de mauvaises raisons. A l&#8217;inverse, on a jamais vu les RH dire non à un CV apporté par un patron où l&#8217;équipe technique.</li>
<li><strong>Mentez</strong>. Ce n&#8217;est pas une blague. L&#8217;entreprise ment. Tout le temps. Elle ne va pas vous parler de ce qui ne va pas, du projet merdique que vous allez devoir reprendre, du collègue insupportable qui sera là, etc. L&#8217;entreprise fait comme vous, elle se montre sous son meilleur jour. Vous voulez un bon job ? Mentez. La boîte ne prendra pas de risque pour vous, vous devez lui forcer la main si vous n&#8217;avez pas l&#8217;expérience, car elle essaye toujours de la jouer safe et d&#8217;embaucher un profile improbable alors que vous pourriez très bien faire l&#8217;affaire.</li>
<li><strong>Demandez</strong>. On obtient rien si on ne demande pas. On est parfois ridicule, mais c&#8217;est une question d&#8217;habitude. L&#8217;humiliation, c&#8217;est le prix à payer si vous tentez des choses que les autres ne font pas, et donc qui ont de grandes chances de foirer. Rappel de Cocteau: &#8220;Le tact dans l&#8217;audace c&#8217;est de savoir jusqu&#8217;où on peut aller trop loin&#8221;</li>
</ul>
<p>Peut-être qu&#8217;il faudrait que je fasse un article complet sur réussir son entretien et son CV un de ces quatres.</p>


feed_id: http://sametmax.com/?p=1674
title: Qu’est ce qu’un middleware Django ?
uri: Qu-est-ce-qu-un-middleware-Django
url: http://sametmax.com/quest-ce-quun-middleware-django/
content:
<p>Vous savez qu&#8217;il y a un settings qui ressemble à ça:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">MIDDLEWARE_CLASSES = <span style="color: black;">&#40;</span>
    <span style="color: #483d8b;">'django.middleware.common.CommonMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.sessions.middleware.SessionMiddleware'</span>,
    <span style="color: #483d8b;">'django.middleware.csrf.CsrfViewMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.auth.middleware.AuthenticationMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.messages.middleware.MessageMiddleware'</span>,
<span style="color: black;">&#41;</span></pre></div></div>

<p>Vous savez qu&#8217;il est important. Vous ne savez pas vraiment pourquoi.</p>
<h2>WaT iZ a MideulWaire ?</h2>
<p>Un <a href="https://docs.djangoproject.com/en/1.4/ref/middleware/">middleware</a> est un moyen d&#8217;éxécuter du code à toutes requêtes et/ou à toutes les réponses reçues et envoyées par Django. Si vous ne voyez pas comment fonctionne le cyle de requêtes/réponses, faites un petit saut sur notre <a href="http://sametmax.com/schema-de-fonctionnement-general-de-django/">schéma de fonctionnement général de Django</a>.</p>
<p>Un middleware, c&#8217;est <strong>une classe Python ordinaire</strong>, avec deux méthodes: une appelée pour les requêtes, une appelée pour les réponses.</p>
<h2>L&#8217;exemple bidon habituel</h2>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> MideulWaireForEverReturnsTheRevenge3<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># cette méthode sera appelée automatiquement pour chaque requête</span>
    <span style="color: #808080; font-style: italic;"># et Django lui passera la requête en cours</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> process_request<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, request<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Hey, une requête est arrivée !&quot;</span>
        <span style="color: #808080; font-style: italic;"># on est pas obligé de retourner quoi que ce soit</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># cette méthode sera appelée automatiquement pour chaque réponse</span>
    <span style="color: #808080; font-style: italic;"># et Django lui passera la reponse en cours et la requete</span>
    <span style="color: #808080; font-style: italic;"># à laquelle on répond</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> process_response<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, request, response<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Hey, on a répondu a une requête !&quot;</span>
        <span style="color: #808080; font-style: italic;"># on DOIT retourner une réponse</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> response</pre></div></div>

<p>On met tout ça dans un fichier <em>mon_projet/mon_app/middlewares.py</em>, et on active le middleware en le rajoutant dans les settings:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">MIDDLEWARE_CLASSES = <span style="color: black;">&#40;</span>
    <span style="color: #483d8b;">'django.middleware.common.CommonMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.sessions.middleware.SessionMiddleware'</span>,
    <span style="color: #483d8b;">'django.middleware.csrf.CsrfViewMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.auth.middleware.AuthenticationMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.messages.middleware.MessageMiddleware'</span>,
    <span style="color: #483d8b;">'mon_projet.mon_app.middlewares.MideulWaireForEverReturnsTheRevenge3'</span>
<span style="color: black;">&#41;</span></pre></div></div>

<p>Et à chaque reload de page, dans l&#8217;affichage du terminal de dev, on a ça:</p>
<div id="attachment_2527" class="wp-caption aligncenter" style="width: 520px"><a href="http://sametmax.com/wp-content/uploads/2012/10/Espace-de-travail-1_013.jpg"?9d7bd4"><img class=" wp-image-2527 " title="./manage.py runserver" src="http://sametmax.com/wp-content/uploads/2012/10/Espace-de-travail-1_013.jpg"?9d7bd4" alt="Capture d'écran de l'output terminal de ./mange.py runserver avec un middleware qui print sur stdout" width="510" height="328" /></a><p class="wp-caption-text">./manage.py runserver</p></div>
<p>Et voici ce qui se passe dans le fonctionnement de Django: il trouve la liste des classes de middlewares, et pour chaque requête et réponse, il appelle les méthodes <code>process_response</code> et <code>process_request</code> de chaque middleware.</p>
<div id="attachment_2514" class="wp-caption aligncenter" style="width: 479px"><a href="http://sametmax.com/wp-content/uploads/2012/10/middleware_django2.png"?9d7bd4"><img class=" wp-image-2514 " title="C'est l'histoire de la viiiiiiiiiiiiiie. C'est le cycle éterneeeeeleuuuuuuuuuuuu" src="http://sametmax.com/wp-content/uploads/2012/10/middleware_django2.png"?9d7bd4" alt="Schéma de fonctionnement des middlewares en Django" width="469" height="454" /></a><p class="wp-caption-text">C&#39;est l&#39;histoire de la viiiiiiiiiiiiiie. C&#39;est le cycle éterneeeeeleuuuuuuuuuuuu</p></div>
<h2>Les points les plus importants</h2>
<p>Aucune méthode n&#8217;est obligatoire, vous pouvez créer un middleware avec uniquement l&#8217;une ou l&#8217;autre.</p>
<p>Si <code>process_request</code> renvoit une réponse, tout s&#8217;arrête. Les <code>process_request</code> des autres middlewares ne sont pas appelés, vos vues ne sont pas appelées, et c&#8217;est le cycle de réponse qui commence directement. Très utile si par exemple vous voulez faire une redirection brutale pour toutes les requêtes qui correspondent à un certain critère (par exemple rediriger vers un site mobile).</p>
<p>Les middlewares sont appelés dans leur ordre de déclaration dans <code>MIDDLEWARE_CLASSES</code> pour chaque requête, et dans l&#8217;odre inverse pour chaque réponse. Mettez donc votre middleware au bon endroit dans la file: inutile de mettre un middleware qui vérifie si un user a des droits avant le middleware d&#8217;authentification, puisque l&#8217;utilisateur n&#8217;est pas encore authentifié.</p>
<p>Un middleware peut posséder 3 autres méthodes également facultatives: <code>process_view</code> (appelée juste avant l&#8217;appel de chaque vue, et et permettant de modifier l&#8217;instance de la vue elle-même), <code>process_template_response</code> (appelée sur chaque instance implémentant une méthode render, et surtout utilisée pour injecter des données dans TemplateResponse) et <code>process_exception</code> (appelée quand une vue lève une exception).</p>
<h2>Pour quoi utiliser les middleware ?</h2>
<p>Exemples de quelques middlewares qui viennent d&#8217;office avec Django:</p>
<ul>
<li><strong>UpdateCacheMiddleware, FetchFromCacheMiddleware</strong>: ils cachent l&#8217;intégralité des pages.</li>
<li><strong>GZipMiddleware</strong>: retourne une réponse compressée si le browser le gère.</li>
<li><strong>LocaleMiddleware</strong>: set la langue que Djando doit utiliser, en fonction du navigateur.</li>
<li><strong>MessageMiddleware</strong>: gestion des &#8220;flash-messages&#8221;.</li>
<li><strong>SessionMiddleware</strong>: gestion des sessions.</li>
<li><strong>AuthenticationMiddleware</strong>: authentifier un utilisateur.</li>
</ul>
<p>Il y en a beaucoup d&#8217;autres, et il y en a plein qui trainent sur internet. Mais bien entendu le plus chouette, c&#8217;est d&#8217;en faire un soi-même.</p>
<p>Par exemple, quand je développe (pas en prod, hien !), j&#8217;utilise souvent ce petit middleware que j&#8217;ai fait avec amour:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> ForceSuperUserMiddleWare<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> process_request<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, request<span style="color: black;">&#41;</span>:
        request.<span style="color: #dc143c;">user</span> = User.<span style="color: black;">objects</span>.<span style="color: #008000;">filter</span><span style="color: black;">&#40;</span>is_superuser=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Comme ça je suis toujours connecté en tant que super user, même sur les projets avec des timeout courts pour la session, des doubles authentifications super relous et tout le toutim des clients paranos (traduction: des américains).</p>


feed_id: http://sametmax.com/?p=2498
title: Do’s and dont’s du français abordant l’indigène anglophone
uri: Do-s-and-dont-s-du-français-abordant-l-indigène-anglophone
url: http://sametmax.com/dos-and-donts-du-francais-abordant-lindigene-anglophone/
content:
<p>Parler une langue, ce n&#8217;est pas juste se faire comprendre, c&#8217;est aussi éviter de dire des conneries. Dans le doute, fermez-là.</p>
<h2>Pratiquer les séries de mots à sonorités similaires</h2>
<p>Certains son, par exemple les différentes forment de <strong>i</strong>, nous sont peu familiers dans notre langue. Il est tentant de faire l&#8217;impasse dessus en se disant qu&#8217;un mauvaise accent n&#8217;est pas la fin du monde, mais malheureusement la mise en contexte sur laquelle vous compter pour être compris ne va pas forcément jouer en votre faveur :</p>
<ul>
<li><strong>sheep / ship</strong>: &#8220;<em>My friend is jacking off the ship</em>&#8220;</li>
<li><strong>shit / sheet / cheat</strong>: &#8220;<em>I think he is cheating on his wife</em>&#8221; ou &#8220;<em>I&#8217;d like to work with you, but I need to take a sheet firs</em>t&#8221;</li>
<li><strong>bitch / beach</strong>: &#8220;<em>I know you&#8217;ve been ridding on a beach all night</em>&#8220;</li>
</ul>
<h2>Apprendre les exceptions de prononciation et les jeux de mots graveleux</h2>
<p>Le &#8216;a&#8217; se prononce &#8216;ai&#8217;, sauf dans certains cas arbitraires (parfois pour mettre l&#8217;emphase sur l&#8217;origine française). &#8220;Massage&#8221; se prononce à la pseudo-française (sinon ils comprendront &#8220;message&#8221;), tout comme rap (sinon &#8220;I love rap&#8221; va être compris comme &#8220;I love rape&#8221;, avec tout le potentielle de LOLatoire que ça implique). Bref, évitez le jeu de mot involontaire.</p>
<p>Dans le même ordre d&#8217;idée, regardez quelques séries débile, pour y apprendre des trucs dangereux à dire nonchalamment comme:</p>
<ul>
<li>I love Uranus.</li>
<li>I&#8217;m John, he&#8217;s Dick.</li>
</ul>
<h2>Apprendre les mots qui ont changé de significations</h2>
<p>Il y a 30 ans, gay était un mot parfaitement anodin. Celui-ci est évident, mais sachez qu&#8217;il y en a beaucoup d&#8217;autres. Par exemple:</p>
<ul>
<li><strong>Willy</strong>: ce n&#8217;est pas juste un prénom. C&#8217;est aussi une bite.</li>
<li><strong>Johnny</strong>: ce n&#8217;est pas juste un prénom. C&#8217;est aussi une bite.</li>
<li><strong>Johson</strong>: ce n&#8217;est pas juste un prénom. C&#8217;est aussi une bite.</li>
</ul>
<p>Vous avez compris le principe&#8230;</p>
<p>Ici, une série pour jeunes ados peut vous aider à vous mettre à jour.</p>
<p>Et bien entendu, assurez-vous que le mot que vous voulez utiliser soit le bon. Voici ce que donne <a href="http://www.bash.org/?111338">Harry Potter</a> quand on remplace le mot &#8220;wand&#8221; (baguette) par &#8220;wang&#8221; (bite):</p>
<blockquote><p>&#8220;You have your mother&#8217;s eyes. It seems only yesterday she was in here herself, buying her first wang. Ten and a quarter inches long, swishy, made of willow. Nice wang for charm work.&#8221;<br />
&#8220;Your father, on the other hand, favored a mahogany wang. Eleven inches. &#8221;</p>
<p>[...]</p>
<p>Harry took the wang. He felt a sudden warmth in his fingers. He raised the wang above his head, brought it swishing down through the dusty air and a stream of red and gold sparks shot from the end like a firework, throwing dancing spots of light on to the walls</p>
<p>[...]</p>
<p>&#8220;Oh, move over,&#8221; Hermione snarled. She grabbed Harry&#8217;s wang, tapped the lock, and whispered, &#8216;Alohomora!&#8221;</p>
<p>[...]</p>
<p>He bent down and pulled his wang out of the troll&#8217;s nose. It was covered in what looked like lumpy gray glue.</p>
<p>[...]</p>
<p>He ran onto the field as you fell, waved his wang, and you sort of slowed down before you hit the ground. Then he whirled his wang at the dementors. Shot silver stuff at them.</p>
<p>[...]</p>
<p>Something silver-white, something enormous, erupted from the end of his wang</p>
<p>Then, with a sigh, he raised his wang and prodded the silvery substance with its tip.</p></blockquote>


feed_id: http://sametmax.com/?p=2537
title: Django-quicky: l’abolition des préliminaires, par Sam et Max
uri: Django-quicky-l-abolition-des-préliminaires-par-Sam-et-Max
url: http://sametmax.com/django-quicky-labolition-des-preliminaires-par-sam-et-max/
content:
<p>Max aime <a href="http://sametmax.com/creer-un-site-avec-bottle-en-5-minutes-parceque-7-cest-impossible-voyons/">Bottle</a> pour sa simplicité. J&#8217;aime Django pour sa puissance. Nous aimons tous les deux les jeux de mots graveleux à connotations sexuelles.</p>
<p>Ainsi est né <a href="https://github.com/sametmax/django-quicky">django-quicky</a>, une petite app qui permet de faire du routing et du rendering déclaratif en Django.</p>
<p><code><a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a> install django-quicky</code></p>
<h2>Par toutes les routes</h2>
<p>Vous avez envie d&#8217;un site, maintenant, tout de suite. Mais il faut créer l&#8217;<em>urls.py</em>, et les vues, et les mapper. Et jongler entre les deux fichiers.</p>
<p>Ou alors vous pouvez juste faire:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> django_quicky <span style="color: #ff7700;font-weight:bold;">import</span> routing
&nbsp;
url, urlpatterns = routing<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
@url<span style="color: black;">&#40;</span><span style="color: #483d8b;">'/une/regex/que/django/comprends'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> une_vue<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:
    ...
&nbsp;
&nbsp;
@url<span style="color: black;">&#40;</span><span style="color: #483d8b;">'/on/peut/cummuler/les/routes'</span><span style="color: black;">&#41;</span>
@url<span style="color: black;">&#40;</span><span style="color: #483d8b;">'/une/regex/que/django/comprends'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> une_vue<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:
    ...</pre></div></div>

<p>Le résultat est parfaitement compatible (et mélangeable) avec le routing habituel de Django. Il suffit juste d&#8217;utiliser <em>views.py</em> à la place d&#8217;<em>urls.py</em>, par exemple dans <code>URL_ROOT</code> ou dans <code>include()</code>.</p>
<h2>Rien ne vaut une bonne renderette</h2>
<p>Declarer sa vue, c&#8217;est comme les jupes, c&#8217;est de plus en plus court avec le temps qui passe (et la méthode <code>render()</code>). Mais on peut faire encore plus court, genre limite tanga:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> django_quicky <span style="color: #ff7700;font-weight:bold;">import</span> view
&nbsp;
@view<span style="color: black;">&#40;</span>render_to=<span style="color: #483d8b;">'template.html'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> une_vue<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">'truc'</span>: truc<span style="color: black;">&#125;</span>
&nbsp;
&nbsp;
@view<span style="color: black;">&#40;</span>render_to=<span style="color: #483d8b;">'json'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> une_vue_json<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">'truc'</span>: truc<span style="color: black;">&#125;</span></pre></div></div>

<p>Dans la première vue, le dico est utilisé comme contexte pour faire le rendu du template. Dans la seconde vue, le dico est retourné sérialisé en JSON.</p>
<h2>On change de position ?</h2>
<p>Des fois vous êtes sur une bonne lancée, mais vous voudriez changer juste un truc. Et garder le code précédent bien sûr. C&#8217;est d&#8217;ailleurs pour ça qu&#8217;on nous vend les <a href="http://sametmax.com/des-vues-normales-aux-vues-generiques-django/">CBV</a>, c&#8217;est tellement plus flexible !</p>
<p>Vous aimez la souplesse ? Voici de quoi mettre les chevilles très près des oreilles:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> django_quicky <span style="color: #ff7700;font-weight:bold;">import</span> view
&nbsp;
@view<span style="color: black;">&#40;</span>render_to=<span style="color: #483d8b;">'template.html'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> vue_commune<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">'stuff'</span>: stuff<span style="color: black;">&#125;</span>
&nbsp;
@vue_commune.<span style="color: black;">post</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> vue_POST<span style="color: black;">&#40;</span>request, context<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># do more stuff</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> context
&nbsp;
@vue_commune.<span style="color: black;">ajax</span><span style="color: black;">&#40;</span>render_to=<span style="color: #483d8b;">'json'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> vue_AJAX<span style="color: black;">&#40;</span>request, context<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> context</pre></div></div>

<p>On a ici une seule et même vue. La première partie est rendue sous forme de template si on y arrive par une requête GET ordinaire. La seconde si c&#8217;est une requête POST. La troisième si c&#8217;est une requête en AJAX, avec rendering JSON en prime. Et les deux dernières récupèrent toujours le résultat de la première avant de s&#8217;exécuter, ce qui permet d&#8217;avoir le code en commun dans la première.</p>
<p>C&#8217;est sous licence <a href="http://www.zlib.net/zlib_license.html">zlib</a>.</p>


feed_id: http://sametmax.com/?p=2544
title: Un alias bash pour Django + virtualenv dont je ne peux plus me passer
uri: Un-alias-bash-pour-Django-virtualenv-dont-je-ne-peux-plus-me-passer
url: http://sametmax.com/un-alias-bash-pour-django-virtualenv-dont-je-ne-peux-plus-me-passer/
content:
<p>Ce n&#8217;est pas subtil, ça veut dire que pour chaque projet on rajoute cette patate dans son <code>.bashrc</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> nom_du_projet <span style="color: #7a0874; font-weight: bold;">&#123;</span>
    workon nom_du_virtualenv;
    <span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #000000; font-weight: bold;">/</span>chemin<span style="color: #000000; font-weight: bold;">/</span>vers<span style="color: #000000; font-weight: bold;">/</span>le<span style="color: #000000; font-weight: bold;">/</span>projet<span style="color: #000000; font-weight: bold;">/</span>django<span style="color: #000000; font-weight: bold;">/</span>;
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$#</span> <span style="color: #660033;">-ne</span> <span style="color: #000000;">0</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
        .<span style="color: #000000; font-weight: bold;">/</span>manage.py $<span style="color: #000000; font-weight: bold;">@</span>
    <span style="color: #000000; font-weight: bold;">fi</span>
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></div></div>

<p>Mais du coup:</p>
<p>Aller dans le dossier du projet et activer le virtualenv:</p>
<p><code>nom_du_projet</code></p>
<p>Aller dans le dossier du projet et activer le virtualenv, et éxécuter une commande de <em>manage.py</em>:</p>
<p><code>nom_du_projet schemamigration app --auto</code></p>
<p>Et bien sur on peut toujours revenir dans le dossier précédent avec:</p>
<p><code>cd -</code></p>


feed_id: http://sametmax.com/?p=2553
title: Arf, on avait laissé l’ancien formulaire de contact
uri: Arf-on-avait-laissé-l-ancien-formulaire-de-contact
url: http://sametmax.com/arf-on-avait-laisse-lancien-formulaire-de-contact/
content:
<p>Le lien vers l&#8217;ancien formulaire de contact était toujours accessible, et du coup on a reçu un mail depuis celui-ci, alors qu&#8217;<a href="http://sametmax.com/qui-nont-pas-eu-de-reponse-via-le-formulaire-de-contact-desole/">on ne peut pas y répondre</a>.</p>
<p>C&#8217;est bon, on l&#8217;a viré.</p>
<p>En attendant, voici le mail, et la réponse (je strip l&#8217;intro et la conclusion.):</p>
<blockquote><p>Je viens de lire le post sur virtualenv+django et je me disais qu&#8217;il existe un moyen différent, oserais-je dire plus propre (pas sur la tête pitié &#8230;),  de faire quasiment la même chose.</p>
<p>Je m&#8217;explique : je vois dans le script l&#8217;utilisation de workon, je ne me rappelle plus trop mais je crois que cette commande est amenée par virtualenvwrapper. Dans ce cas là, je voulais vous faire partager le contenu de quelques fichiers contenu dans mon dossier .virtualenvs.</p>
<p>Tout d&#8217;abord le fichier postactivate (hook fourni par virtualenvwrapper s&#8217;insérant après l&#8217;initialisation de l&#8217;environnement) :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #007800;">PROJECT_PATH</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$PROJECT_HOME</span>&quot;</span><span style="color: #000000; font-weight: bold;">/</span><span style="color: #ff0000;">&quot;<span style="color: #007800;">$env_name</span>&quot;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-a</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$PROJECT_PATH</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span> ;<span style="color: #000000; font-weight: bold;">then</span>
    <span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$PROJECT_PATH</span>&quot;</span>
<span style="color: #000000; font-weight: bold;">fi</span></pre></div></div>

<p>ce petit script permet de faire ce que tu décris dans le post, si jamais ton dossier contenant le projet ne se trouve pas à l&#8217;endroit défini par la variable d&#8217;environnement <code>$PROJECT_HOME</code>, il est possible d&#8217;overrider son comportement en modifiant <code>PROJECT_PATH</code> par le chemin que tu souhaite dans le fichier <em>.virtualenvs/nom_de_l&#8217;environnement/bin/postactivate</em></p>
<p>Voili voilou et sinon pour encore me faire mousser (mais pas trop hein), je voulais juste vous faire partager un autre script que je place dans postmkproject :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Create a django project y/n ?&quot;</span>
<span style="color: #000000; font-weight: bold;">while</span> <span style="color: #c20cb9; font-weight: bold;">true</span>
<span style="color: #000000; font-weight: bold;">do</span>
    <span style="color: #c20cb9; font-weight: bold;">read</span> INPUT
    <span style="color: #000000; font-weight: bold;">case</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$INPUT</span>&quot;</span> <span style="color: #000000; font-weight: bold;">in</span>
        <span style="color: #ff0000;">&quot;y&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#41;</span>
            <span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$PROJECT_HOME</span>&quot;</span>
            <span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-r</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$envname</span>&quot;</span>
            pip <span style="color: #c20cb9; font-weight: bold;">install</span> django
            django-admin.py startproject <span style="color: #ff0000;">&quot;<span style="color: #007800;">$envname</span>&quot;</span>
            <span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$envname</span>&quot;</span>
            <span style="color: #7a0874; font-weight: bold;">break</span>
            <span style="color: #000000; font-weight: bold;">;;</span>
        <span style="color: #ff0000;">&quot;n&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#41;</span>
            <span style="color: #7a0874; font-weight: bold;">break</span>
            <span style="color: #000000; font-weight: bold;">;;</span>
    <span style="color: #000000; font-weight: bold;">esac</span>
<span style="color: #000000; font-weight: bold;">done</span></pre></div></div>

<p>En clair, ça demande à l&#8217;utilisateur si son projet sera un projet django, ça télécharge le framework via pip et cela créé directement le projet dans notre dossier <code>PROJECT_HOME</code>, en évitant d&#8217;avoir à créer un autre sous-dossier rien que pour notre application django.</p>
</blockquote>
<p>Bonjour l&#8217;ami,</p>
<p>Merci de l&#8217;info. Comme tu vois, on l&#8217;a fait passer. Quand tu as un truc comme ça à mettre, utilise les commentaires, ça en fait profiter tout le monde !</p>
<p>@+</p>


feed_id: http://sametmax.com/?p=2697
title: Démasquer les fakes profils sur les réseaux sociaux et sites de rencontres
uri: Démasquer-les-fakes-profils-sur-les-réseaux-sociaux-et-sites-de-renc
url: http://sametmax.com/demasquer-les-fakes-profils-sur-les-reseaux-sociaux-et-sites-de-rencontres/
content:
<p>Haaaa c&#8217;est bientôt l&#8217;hiver, on a envie de trouver une poule pour être au chaud alors on va sur <a href="http://badoo.com">Badoo</a> et on sélectionne les petites les plus chaudes pour commencer, on se dit qu&#8217;après quelques rateaux on tapera dans les monstres.<br />
Mais voilà c&#8217;est plein de faux profils qui vont tenter de vous vendre un compte en banque rempli de millions de dollars sous condition d&#8217;envoyer un Western Union pour débloquer l&#8217;avocat enfermé au Congo chargé de valider la transaction&#8230; Et bing un trou mais pas au bon endroit&#8230;Plutôt dans le compte en banque&#8230; Retour case branlette&#8230;</p>
<p>Certains profils comme sur Bado sont super bien foutu, il y a même écrit &#8220;vérifié&#8221; en medaillon histoire de bien noyer le poisson dans la choucroute.</p>
<div id="attachment_2699" class="wp-caption aligncenter" style="width: 335px"><a href="http://sametmax.com/wp-content/uploads/2012/10/badoo_fake.png"?9d7bd4"><img src="http://sametmax.com/wp-content/uploads/2012/10/badoo_fake.png"?9d7bd4" alt="" title="Très bonne la petite au passage..." width="325" height="489" class="size-full wp-image-2699" /></a><p class="wp-caption-text">Houuu la bonne petite, tout juste majeure en plus, ça doit craquer...</p></div>
<p>Un meuf comme ça sur Badoo qui cherche à se faire réalaiser le tuyaux on pourrait se dire que c&#8217;est trop beau, mais souvent on tente le coup quand même et le piège se referme sur la proie que vous êtes. Préparez la CB&#8230;</p>
<p>Tout ça c&#8217;est du passé, grace à tonton Max vous allez pouvoir arrêter de vous faire pigeonner par ces belles poulettes derrière qui se cache certainement un Somalien à qui vous auriez du envoyer DES MILLIERS DE $$$.<br />
<strong><br />
Google image est ton ami:</strong></p>
<p>1. Sauvegardez l&#8217;image sur votre disque de cette charmante jeune fille (bouton droit, &#8220;Enregistrer l&#8217;image sous&#8230;&#8221;)<br />
2. Allez sur <a href="https://www.google.fr/imghp?hl=fr&#038;tab=wi">Google image</a> et cliquez sur le petit appareil photo, uploadez l&#8217;image de la belle et Ho surprise !!!</p>
<p>Notre chère petite &#8220;BelleCoeur&#8221; de Badoo est en fait la ravissante actrice de boule <strong>&#8220;ann angel&#8221;</strong></p>
<div id="attachment_2700" class="wp-caption aligncenter" style="width: 666px"><a href="http://sametmax.com/wp-content/uploads/2012/10/anne_angel.png"?9d7bd4"><img src="http://sametmax.com/wp-content/uploads/2012/10/anne_angel.png"?9d7bd4" alt="" title="Toujour vérifier ses sources !" width="656" height="668" class="size-full wp-image-2700" /></a><p class="wp-caption-text">Bellecoeur de chez Bado n&#039;est autre que &quot;Ann Angel&quot; , une actrice XXX</p></div>
<p>Ca ne marche pas à tous les coups mais on a facilement une idée de l&#8217;authenticité du profil 4 fois sur 5.</p>
<p><strong>Conclusion:</strong><br />
Ne chauffez que les tromblons, là peut de chance d&#8217;avoir de faux profils et elles ont faim ! Faites un bon geste pour la planète que diable !.</p>


feed_id: http://sametmax.com/?p=2338
title: On va tous les niquer !
uri: On-va-tous-les-niquer
url: http://sametmax.com/on-va-tous-les-niquer/
content:
<p>Je suis ravis qu&#8217;il y ait pas trop de réactions comme <a href="http://sametmax.com/la-theorie-de-la-salle-de-bain-et-un-tout-petit-peu-de-python/#comment-2154">celle-ci</a> sur ce blog. Mais il faut bien avouer que le politiquement correcte continue de pourrir la journée. Notre cher <a href="http://www.sebsauvage.net/">sebsauvage</a> publie régulièrement des <a href="http://sebsauvage.net/links/?6Mhydg">petites piques</a> à destination des peignent cul, et j&#8217;avoue que l&#8217;article &#8220;<a href="http://www.telegraph.co.uk/news/uknews/law-and-order/9616750/Rowan-Atkinson-we-must-be-allowed-to-insult-each-other.html">Nous devons nous autoriser à nous insulter les uns les autre</a>&#8221; m&#8217;a clairement fait tilté, tellement il est significatif de l&#8217;état d&#8217;esprit de l&#8217;ambiance qui certains veulent nous installer.</p>
<p>Moi je veux vivre dans un monde où on peut publier aussi bien ceci:</p>
<div id="attachment_2682" class="wp-caption aligncenter" style="width: 391px"><a href="http://sametmax.com/wp-content/uploads/2012/10/635.jpg"?9d7bd4"><img class=" wp-image-2682 " title="Personne n'est mort pour la publication de cette image" src="http://sametmax.com/wp-content/uploads/2012/10/635.jpg"?9d7bd4" alt="Orgie de divinités" width="381" height="214" /></a><p class="wp-caption-text">Personne n&#39;est mort pour la publication de cette image</p></div>
<p>&nbsp;</p>
<p>Que cela:</p>
<p>&nbsp;</p>
<div id="attachment_2683" class="wp-caption aligncenter" style="width: 442px"><a href="http://sametmax.com/wp-content/uploads/2012/10/I6HTg.jpg"?9d7bd4"><img class=" wp-image-2683  " title="Par contre y a un film récent qui a fait quelques morts" src="http://sametmax.com/wp-content/uploads/2012/10/I6HTg.jpg"?9d7bd4" alt="Caricature de Mahomet par Charlie Hebdo" width="432" height="533" /></a><p class="wp-caption-text">Par contre y a un film récent qui a fait quelques morts</p></div>
<p>&nbsp;</p>
<p>Mais si on se fait chahuter en France, j&#8217;ai visité beaucoup de pays où on est très loin de pouvoir ne serait-ce qu&#8217;en parler tout bas. J&#8217;ai vu le résultat, et ça ne me donne pas du tout envie de me retrouver dans cette situation.</p>
<h2>Alors petite piqûre de rappel</h2>
<p>Arabes, asiatiques et racistes:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/kOlhv7s2-mE" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Juifs, chinois et allemands:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/zp7U8uEd8T4#t=34s" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Flics:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/6Cvj6NRpTXo" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Paranos, sursécuriataires et racistes:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/ejVrbqEUnec" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Gay, homophones et metrosexuels:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://stansdad.ch/episode.php?epid=104" noresize="noresize" bordercolor="#333333" marginheight="0" marginwidth="0" frameborder="no" height="406" scrolling="no" width="520" class="iframe-class"></iframe>
<p>Noirs:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/8DT8SK34fRA" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Et parce qu&#8217;il faut bien donner l&#8217;exemple par l&#8217;auto dérision:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/rlarCLhzfoU" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Et on peut continuer sur les gros, les handicapés, les cancereux, les orphelins, etc.</p>
<blockquote><p>Je hais vos idées, mais je me ferai tuer pour que vous ayez le droit de les exprimer.</p></blockquote>
<p><em>Voltaire<br />
</em></p>


feed_id: http://sametmax.com/?p=2660
title: Les environnements virtuels Python : virtualenv et virtualenvwrapper
uri: Les-environnements-virtuels-Python-virtualenv-et-virtualenvwrapper
url: http://sametmax.com/les-environnement-virtuels-python-virtualenv-et-virtualenvwrapper/
content:
<p>Quand on commence à beaucoup programmer, on accumule rapidement plusieurs projets en cours de développement sur sa machine. Certains vieux, certains récents, qui utilisent tous des bibliothèques similaires, mais pas forcément de mêmes versions. Ou parfois des bibliothèques incompatibles. Parfois même, des version différentes de Python: Python 2.6, 2.7, 3.2 ? Et c&#8217;est sans compter les mises à jour de l&#8217;OS, qui a ses propres besoins en terme de libs et de versions.</p>
<p>Le jour où ça casse, c&#8217;est le chaos.</p>
<p>Dans le monde de Python, la solution à ce problème est d&#8217;utiliser des environnements virtuels. Ca à l&#8217;air d&#8217;un gros mot, mais derrière ce terme se cache la notion simple d&#8217;avoir des installations de Python isolées de l&#8217;OS, et séparées les unes des autres pour chaque projet.</p>
<p>Il existe plusieurs écoles: certains utilisent <a href="http://www.buildout.org/">buildout</a>. C&#8217;est une solution puissante, et très compliquée. Python 3.3 vient avec <a href="http://docs.python.org/dev/library/venv.html">venv</a>, un outil intégré pour gérer les environnements virtuels. Pour les gens comme moi qui veulent quelque chose qui marche partout, tout le temps et facilement, il y a <a href="http://pypi.python.org/pypi/virtualenv">virtualenv</a>.</p>
<h2>Installation et usage</h2>
<p>Première chose à faire, installer <code>virtualenv</code>:</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> <span style="color: #660033;">--user</span> virtualenv</pre></div></div>

<p>Si vous avez besoin d&#8217;un <a href="http://sametmax.com/votre-python-aime-les-pip/">rappel sur pip, c&#8217;est par là</a>.</p>
<p>Ensuite, pour chacun de vos projets, créez un environnement virtuel:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">virtualenv <span style="color: #000000; font-weight: bold;">/</span>path<span style="color: #000000; font-weight: bold;">/</span>vers<span style="color: #000000; font-weight: bold;">/</span>projet<span style="color: #000000; font-weight: bold;">/</span>env_nom_du_projet</pre></div></div>

<p>Virtualenv va créer un dossier avec un environnement complet dedans: l&#8217;interpreteur Python, les libs, des commandes, etc. C&#8217;est votre installation isolée.</p>
<p>Pour travailler dans votre installation isolée:</p>
<ul>
<li>sous Unix, il faut faire <code>source /path/vers/projet/env_nom_du_projet/bin/activate</code>.</li>
<li>sous Windows, il faut faire <code>C:\\path\vers\projet\env_nom_du_projet\Scripts\activate.bat</code>.</li>
</ul>
<p>Votre prompt de ligne de commande va changer pour indiquer que vous êtes dans un environnement virtuel:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span>env_nom_du_projet<span style="color: #7a0874; font-weight: bold;">&#41;</span> sam $</pre></div></div>

<p>Si vous installez une bibliothèque avec <code>pip</code>, il l&#8217;installera dans cet environnement virtuel, et elle ne sera pas accessible ailleurs. Si vous lancez la commande <code>python</code>, le shell Python aura accès à toutes les libs de cet environnement virtuel.</p>
<p>Vous pouvez sortir de l&#8217;environnement virtuel avec la commande <code>deactivate</code>.</p>
<p>Creez autant de virtualenv que vous voulez: un par projet, un pour les tests de nouvelles libs, un pour le plaisir, un pour la route&#8230; Ca prend juste de la place, et ce n&#8217;est pas ce qui manque sur nos disques durs de nos jours.</p>
<h2>Quelques astuces avec virtualenv</h2>
<h3>Isolation par rapport à l&#8217;OS</h3>
<p>Vous pouvez choisir que votre env hérite des libs de l&#8217;OS, ou non, mais uniquement à la création. Il faut spécifier une option:</p>
<ul>
<li><code>--no-site-packages</code>: votre environnement est vierge, il n&#8217;hérite pas des libs du système et a seulement accès aux libs standards de Python (<code>os</code>, <code>sys</code>, <code>itertools</code>, <code>json</code>, etc).</li>
<li><code>--system-site-packages</code>: tout ce qui est installé sur l&#8217;OS est disponible dans installé dans l&#8217;env (et sera installé à l&#8217;avenir). Par exemple sous Ubuntu, vous pourrez importer toutes les libs d&#8217;UbuntuOne, le système de synchronisation Cloud d&#8217;Ubuntu écrit en Python.</li>
</ul>
<p>Les anciennes versions ont la valeur <code>--system-site-packages</code> activée par défaut, les nouvelles versions de virtualenv ont la valeur <code>--no-site-packages</code> activée par défaut.</p>
<p>Si vous utilisez <code>--system-site-packages</code>, vous pouvez quand même demander à <code>pip freeze</code> de lister uniquement les libs de l&#8217;env avec l&#8217;option <code>--local</code>.</p>
<h3>Choisir une version de Python</h3>
<p>Parfois vous voudrez utiliser une version spécifique de Python. Vous pouvez tout à fait créer un env dédié à Python 3.2 et un autre à Python 2.6, il faut juste que les deux versions soient installées sur votre système. </p>
<p>Je ne vais pas détailler commen installer deux versions de Python en parallèle sur chaque OS car je n&#8217;ai aucune idée de comment on fait sous Mac ou Windows, mais sous Ubuntu c&#8217;est très simple: par défaut on est en Python 2.7, et pour installer Python 3, on fait <code>sudo apt-get install python3</code>. Pour installer Python 2.6, on fait <code>sudo apt-get python2.6</code>. </p>
<p>On a alors 3 executables: <em>/usr/bin/python</em> va déclencher Python 2.7, <em>/usr/bin/python2.6</em> va appeler Python 2.6, etc. Aucun conflit système, c&#8217;est merveilleux.</p>
<p>Il ne reste qu&#8217;à construire son environnement virtuel en lui passant en paramètre le chemin vers le Python à utiliser:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">virtualenv mon_env -p /usr/bin/python2.6</pre></div></div>

<p>Et voilà, si on active &#8220;mon_env&#8221;, la commande <code>python</code> ouvre un shell en Python 2.6, et toutes les libs de l&#8217;env sont en 2.6.</p>
<p>Attention: on ne peut pas reconvertir facilement un env d&#8217;une version de Python à l&#8217;autre. Une fois que c&#8217;est créé, c&#8217;est fait. Si vous changez d&#8217;avis, faite un <code>pip freeze</code>, supprimez l&#8217;env, recréé l&#8217;env, et faites un <code>pip install -r</code>.</p>
<h3>Virtualenv depuis un script extérieur</h3>
<p>Si vous êtes dans un script extérieur et que vous voulez appeler un de vos scripts avec ce virtualenv, vous n&#8217;avez pas besoin de l&#8217;activer pour que ça marche. Il suffit d&#8217;appeler le script en le passant en paramètre à l&#8217;interpréteur de l&#8217;env. Par exemple:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">/path/vers/projet/env_nom_du_projet/bin/python mon_script.<span style="color: black;">py</span></pre></div></div>

<p>Le script sera alors exécuté dans le cadre du virtualenv.</p>
<h2>virtualenvwrapper: ou comment ne pas se faire chier pour passer d&#8217;un env à l&#8217;autre</h2>
<p>Si vous êtes sous Windows, vous pouvez aller boire une bière à la cuisine, ça ne marche pas sous votre OS.</p>
<p>Pour les chanceux qui ont accès à un Unix, il existe un merveilleux logiciel qui va vous éviter le yoyo entre les envs:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">pip install --<span style="color: #dc143c;">user</span> virtualenvwrapper</pre></div></div>

<p>Ensuite il faut rajouter quelques lignes dans votre script d&#8217;init de shell, par exemple dans <em>~/.bashrc</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">WORKON_HOME</span>=~<span style="color: #000000; font-weight: bold;">/</span>.virtualenvs
<span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #660033;">-p</span> <span style="color: #007800;">$WORKON_HOME</span>
<span style="color: #7a0874; font-weight: bold;">source</span> ~<span style="color: #000000; font-weight: bold;">/</span>.local<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>virtualenvwrapper.sh</pre></div></div>

<p>Selon où vous avez installé virtualenvwrapper, la dernière ligne peut changer. Moi, mon virtualenv est installé au niveau du système dont le chemin est plutôt <em>/usr/local/bin/virtualenvwrapper.sh</em>.</p>
<p>Ces lignes vont lancer virtualenvwrapper en permanence dans le shell. Relancez le terminal pour l&#8217;activer. Le premier lancement va vous afficher un tas de lignes, rassurez-vous, ça n&#8217;arrive qu&#8217;une fois.</p>
<p>Ensuite, vous avez accès à de nouvelles commandes:</p>
<ul>
<li><code>mkvirtualenv nom_env</code> va créer un virtualenv dans le dossier <em>~/.virtualenvs</em>, où que vous soyez.</li>
<li><code>workon nom_env</code> va automatiquement activer un env, où que vous soyez.</li>
<li><code>rmvirtualenv nom_env</code> va surpprimer l&#8217;env du même nom.</li>
</ul>
<p>Les options de <code>mkvirtualenv</code> sont les mêmes que pour la commande <code>virtualenv</code>, vous n&#8217;avez juste plus à vous souciez de où sont vos envs, ni de où vous êtes.</p>


feed_id: http://sametmax.com/?p=2642
title: Ajouter un chemin à la variable d’environnement PATH sous Windows
uri: Ajouter-un-chemin-à-la-variable-d-environnement-PATH-sous-Windows
url: http://sametmax.com/ajouter-un-chemin-a-la-variable-denvironnement-path-sous-windows/
content:
<p>Il y a beaucoup de tutos qui demandent de simplement &#8220;ajouter le résultat au PATH&#8221;, mais assez peu expliquent pourquoi et comment le faire.</p>
<p>Comme on aime bien faire les choses à l&#8217;envers chez Sam et Max, on va d&#8217;abord expliquer comment, et ensuite pourquoi.</p>
<h2>Modifier le PATH sous Windows 7 et XP</h2>
<p>Il faut d&#8217;abord ouvrir l&#8217;outil d&#8217;édition des variables d&#8217;environnement.</p>
<h3>Sous Windows XP, c&#8217;est: </h3>
<ul>
<li>Clic droit sur l&#8217;icône &#8220;Ordinateur&#8221; de votre Bureau (ou dans le panel de gauche de l&#8217;explorateur de fichiers) et dans le menu-contextuel, allez sur &#8220;Propriétés&#8221;.</li>
<li>Dans la fenêtre &#8220;Propriétés système&#8221; qui vient de s&#8217;ouvrir, allez dans l&#8217;onglet &#8220;Avancé&#8221;</li>
<li>Enfin, cliquez sur le bouton &#8220;Variables d&#8217;environnement&#8230;&#8221;</li>
</ul>
<h3>Sous Windows 7, c&#8217;est presque pareil:</h3>
<ul>
<li>Clic droit sur l&#8217;icône &#8220;Ordinateur&#8221; de votre Bureau (ou dans le panel de gauche de l&#8217;explorateur de fichiers) et dans le menu-contextuel, allez sur &#8220;Propriétés&#8221;.</li>
<li>Dans la grande fenêtre qui s&#8217;ouvre, cliquez sur le lien &#8220;Paramètres système avancés&#8221; dans la liste de gauche.</li>
<li>Dans la nouvelle fenêtre ainsi ouverte, cliquez sur le bouton &#8220;Variables d&#8217;environnement&#8230;&#8221;</li>
</ul>
<p>Dans les deux cas, vous allez vous retrouver avec la fenêtre le plus détestée du monde de Windows, la fameuse fenêtre &#8220;Variables d&#8217;envionnement&#8221;. Toute petite, illisible, est pas redimensionable. Vous ne l&#8217;oublierez plus jamais:</p>
<div id="attachment_2650" class="wp-caption aligncenter" style="width: 401px"><a href="http://sametmax.com/wp-content/uploads/2012/10/modifier_le_system_path_de_windows1.png"?9d7bd4"><img src="http://sametmax.com/wp-content/uploads/2012/10/modifier_le_system_path_de_windows1.png"?9d7bd4" alt="Capture d&#039;écran de la fenêtre des variables d&#039;environnement de Windows" title="Oh mon dieu, il nous fonce dessus !" width="391" height="432" class="size-full wp-image-2650" /></a><p class="wp-caption-text">Oh mon dieu, il nous fonce dessus !</p></div>
<p>Dans cette fenêtre, dans la partie &#8220;Variables systèmes&#8221; (la liste du bas), il faut cliquer sur la ligne qui contient &#8216;Path&#8217;, de telle sorte qu&#8217;elle soit sélectionnée (en couleur alors que les autres items de la listes ne le sont pas). Il vous faudra sûrement scroller un peu pour la trouver.</p>
<p>Ensuite il faut cliquer sur le bouton &#8220;Modifier&#8230;&#8221;.</p>
<p>Là s&#8217;ouvre une fenêtre avec deux champs, le deuxième, &#8220;Valeur de la variable&#8221;, est celui qui nous intéresse.<strong> Il est absolument chiant à modifier, alors faites plutôt un copier/coller dans un éditeur de texte à part</strong>: <kbd>Ctrl + A</kbd> pour tout selectioner, <kbd>Ctrl + C</kbd> pour tout copier, puis <kbd>Ctrl + V</kbd> pour tout coller ailleurs, car je ne suis pas sûr que le clic droit fonctionne dans cette grosse bouse.</p>
<p>Vous devriez avoir un texte qui ressemble à ceci (pas exactement le même, mais proche):</p>
<p><code>%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;</code></p>
<p>Ne retirez rien de cette valeur si vous ne savez pas ce que vous faites. </p>
<p>Pour ajouter quelque chose au PATH de Windows, il suffit de le mettre <strong>tout collé à la fin, suivit d&#8217;un &#8216;;&#8217;</strong></p>
<p>Par exemple, pour rajouter le chemin vers l&#8217;installation de Python dans le PATH de Windows:</p>
<p><code>%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;<strong>C:\Python27;</strong></code></p>
<p>Attention, si vous avez copié/collé le contenu ailleurs, supprimez bien l&#8217;ancien contenu en le remplaçant complètement par le nouveau (<kbd>Ctrl + A</kbd>, <kbd>Ctrl + V</kbd>) sinon vous allez tout péter.</p>
<h2>A quoi servent les variables d&#8217;environnement et le PATH ?</h2>
<p>Sous tous les OS, il y a des variables qui déterminent le fonctionnement de celui-ci (ou plutôt du shell, mais ce n&#8217;est pas important). Elles permettent à l&#8217;utilisateur, en changeant la variable, de choisir certains comportement primitifs du système.</p>
<p>Par exemple, quand vous tapez une commande dans un terminal, le système va utiliser la variable d&#8217;environnement PATH. Il va prendre chaque dossier listé dans PATH, et regarder si il trouve la commande dedans. Si il trouve cette commande, il la lance, et arrête la recherche. Si il ne trouve pas la commande, il va vous dire que la commande n&#8217;existe pas.</p>
<p>Ainsi, si vous avez installé Python mais que le shell Python ne se lance pas quand vous entrez la commande <code>python</code> dans un terminal, ajouter <code>C:\Python27;</code> au PATH peut résoudre le problème: Windows va maintenant chercher dans ce dossier également pour voir si la commande existe.</p>


feed_id: http://sametmax.com/?p=545
title: Rechercher dans l’historique de Git
uri: Rechercher-dans-l-historique-de-Git
url: http://sametmax.com/rechercher-dans-lhistorique-de-git/
content:
<p>Si vous voulez trouver tous les commits dont les messages contiennent une chaîne de caractères:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> log <span style="color: #660033;">--grep</span>=<span style="color: #ff0000;">&quot;le truc a chercher&quot;</span></pre></div></div>

<p>Comme grep, on peut y adjoindre <code>-i</code> pour le rendre insensible à la casse, et <code>-E</code> pour utiliser des regex PCRE.</p>
<p>Si vous voulez trouver tous les commits dans lequel une chaîne a été retirée ou introduite dans un des fichiers:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> log <span style="color: #660033;">-S</span><span style="color: #ff0000;">&quot;le truc a chercher&quot;</span></pre></div></div>

<p>Et dans ce cas vous voudrez probablement passer aussi <code>-p --color=auto</code> qui va vous permettre d&#8217;avoir un diff coloré et mis en contexte pour savoir ce qui a été modifié.</p>
<p>On peut limiter sa recherche dans le temps en utilisant <code>--before</code> et <code>--after</code>. Par exemple, pour chercher dans tous les commits créés après le 1er juillet et jusqu&#8217;à il y a 2 semaines:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> log <span style="color: #660033;">--before</span>=<span style="color: #ff0000;">&quot;2 weeks ago&quot;</span> <span style="color: #660033;">--after</span>=<span style="color: #ff0000;">&quot;2012-07-01&quot;</span></pre></div></div>

<p>Ou alors choisir deux commits et chercher entre ces deux commits:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> log 710f0f..8a5cbc</pre></div></div>

<p>Ce qui va limiter la recherche à la branche en cours. En parlant de branche, on peut voir les commits qui sont sur une branche et pas l&#8217;autre:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> log master..develop</pre></div></div>

<p>Ici on aura tout ce qui est sur <code>develop</code> qui n&#8217;est pas encore mergé dans <code>master</code>. L&#8217;inverse est bien sur possible.</p>
<p>Parfois on a besoin de savoir <a href="http://sametmax.com/quel-est-labruti-qui-a-fait-ca/">qui est le connard qui a fait ça</a>, et on peut lister les commits d&#8217;un utilisateur:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> log <span style="color: #660033;">--author</span> sam</pre></div></div>

<p>Ou</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> log <span style="color: #660033;">--author</span> lesametlemax<span style="color: #000000; font-weight: bold;">@</span>notremail.com</pre></div></div>

<p>En fait ça marche même avec une partie du nom.</p>
<p>Les critères ci-dessus peuvent être utilisés en même temps, et les résultats obtenus seront ceux correspondant à au moins un des critères (OU). Mais si vous voulez les commits qui correspondent à tous ces critères (ET), utilisez <code>--all-match</code>.</p>
<p>Tout ça cherche dans l&#8217;historique entier, mais si vous êtes plutôt intéressé par certains fichiers en particulier, vous pouvez préciser des paths après <code>--</code>.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> log <span style="color: #660033;">--author</span> max <span style="color: #660033;">--before</span>=<span style="color: #ff0000;">&quot;1 day ago&quot;</span> <span style="color: #660033;">--</span> project<span style="color: #000000; font-weight: bold;">/</span>settings.py project<span style="color: #000000; font-weight: bold;">/</span>settings_local.py</pre></div></div>

<p>Et oui, ça marche récursivement sur les dossiers.</p>
<p>La plupart du temps les commits juste après les merges ne vous intéresse pas. On peut les ignorer avec <code>–-no-merges</code>.</p>
<p>Enfin si vous avez merdé et que vous pensez avoir perdu quelque chose dans Git, vous pouvez chercher dans le reflog avec <code>--walk-reflogs</code>. Cela vous donnera accès à tous les commits qui ne sont pas sur des branches ou plus accessibles facilement pour une raison ou une autre.</p>


feed_id: http://sametmax.com/?p=2621
title: Générateur de nom d’heroic fantasy en Python
uri: Générateur-de-nom-d-heroic-fantasy-en-Python
url: http://sametmax.com/generateur-de-nom-dheroic-fantasy-en-python/
content:
<p>Les <a href="http://www.kleimo.com/random/name.cfm">générateurs de noms d&#8217;heroic fantasy</a> sont légions sur internet. Mais autant j&#8217;ai trouvé des <a href="https://github.com/amnong/namegen">générateurs de noms normaux en Python</a> (dont je me sers d&#8217;ailleurs pour créer des comptes bidons automatiquement pour les démos), autant je n&#8217;ai rien trouvé pour pythonement printer l&#8217;en-tête d&#8217;une feuille de personnage de DDA.</p>
<p>Et comme c&#8217;est fun, voilà le nonos du Sam du jour:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">random</span> <span style="color: #ff7700;font-weight:bold;">import</span> randint, choice
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> FantasyNameGenerator<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
        Random fantasy name generator
    &quot;&quot;&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># on déclare les lettres, leurs positions voulues dans le nom</span>
    <span style="color: #808080; font-style: italic;"># et un poids de fréquence d'apparition</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># voyelles</span>
    VOWELS = <span style="color: black;">&#40;</span>
        <span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'start'</span>, <span style="color: #483d8b;">'middle'</span>, <span style="color: #483d8b;">'end'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>
                <span style="color: black;">&#40;</span><span style="color: #ff4500;">5</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;a&quot;</span>, <span style="color: #483d8b;">&quot;e&quot;</span>, <span style="color: #483d8b;">&quot;i&quot;</span>, <span style="color: #483d8b;">&quot;o&quot;</span>, <span style="color: #483d8b;">&quot;u&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
                <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;ae&quot;</span>, <span style="color: #483d8b;">&quot;ai&quot;</span>, <span style="color: #483d8b;">&quot;ao&quot;</span>, <span style="color: #483d8b;">&quot;au&quot;</span>, <span style="color: #483d8b;">&quot;aa&quot;</span>, <span style="color: #483d8b;">&quot;ea&quot;</span>, <span style="color: #483d8b;">&quot;eo&quot;</span>, <span style="color: #483d8b;">&quot;eu&quot;</span>, <span style="color: #483d8b;">&quot;ee&quot;</span>, <span style="color: #483d8b;">&quot;ia&quot;</span>,
                     <span style="color: #483d8b;">&quot;io&quot;</span>, <span style="color: #483d8b;">&quot;iu&quot;</span>, <span style="color: #483d8b;">&quot;ii&quot;</span>, <span style="color: #483d8b;">&quot;oa&quot;</span>, <span style="color: #483d8b;">&quot;oe&quot;</span>, <span style="color: #483d8b;">&quot;oi&quot;</span>, <span style="color: #483d8b;">&quot;ou&quot;</span>, <span style="color: #483d8b;">&quot;oo&quot;</span>, <span style="color: #483d8b;">&quot;eau&quot;</span>, <span style="color: #483d8b;">&quot;y&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
        <span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'middle'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>
            <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;'&quot;</span>,<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
        <span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># consonnes</span>
    CONSONANTS = <span style="color: black;">&#40;</span>
        <span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'start'</span>, <span style="color: #483d8b;">'middle'</span>, <span style="color: #483d8b;">'end'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>
                <span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;b&quot;</span>, <span style="color: #483d8b;">&quot;c&quot;</span>, <span style="color: #483d8b;">&quot;d&quot;</span>, <span style="color: #483d8b;">&quot;f&quot;</span>, <span style="color: #483d8b;">&quot;g&quot;</span>, <span style="color: #483d8b;">&quot;h&quot;</span>, <span style="color: #483d8b;">&quot;j&quot;</span>, <span style="color: #483d8b;">&quot;k&quot;</span>, <span style="color: #483d8b;">&quot;l&quot;</span>, <span style="color: #483d8b;">&quot;m&quot;</span>, <span style="color: #483d8b;">&quot;n&quot;</span>, <span style="color: #483d8b;">&quot;p&quot;</span>,
                     <span style="color: #483d8b;">&quot;r&quot;</span>, <span style="color: #483d8b;">&quot;s&quot;</span>, <span style="color: #483d8b;">&quot;t&quot;</span>, <span style="color: #483d8b;">&quot;v&quot;</span>, <span style="color: #483d8b;">&quot;w&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
                <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;x&quot;</span>, <span style="color: #483d8b;">&quot;y&quot;</span>, <span style="color: #483d8b;">&quot;z&quot;</span>, <span style="color: #483d8b;">&quot;sc&quot;</span>, <span style="color: #483d8b;">&quot;ch&quot;</span>, <span style="color: #483d8b;">&quot;gh&quot;</span>, <span style="color: #483d8b;">&quot;ph&quot;</span>, <span style="color: #483d8b;">&quot;sh&quot;</span>, <span style="color: #483d8b;">&quot;th&quot;</span>, <span style="color: #483d8b;">&quot;sk&quot;</span>, <span style="color: #483d8b;">&quot;wk&quot;</span>, <span style="color: #483d8b;">&quot;st&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
        <span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'middle'</span>, <span style="color: #483d8b;">'end'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>
                <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;ck&quot;</span>, <span style="color: #483d8b;">&quot;nk&quot;</span>, <span style="color: #483d8b;">&quot;rk&quot;</span>, <span style="color: #483d8b;">&quot;ss&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
        <span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
        <span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'start'</span>, <span style="color: #483d8b;">'middle'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>
                <span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;br&quot;</span>, <span style="color: #483d8b;">&quot;dr&quot;</span>, <span style="color: #483d8b;">&quot;fr&quot;</span>, <span style="color: #483d8b;">&quot;gr&quot;</span>, <span style="color: #483d8b;">&quot;kr&quot;</span>, <span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
                <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;cr&quot;</span>, <span style="color: #483d8b;">&quot;pr&quot;</span>, <span style="color: #483d8b;">&quot;sr&quot;</span>, <span style="color: #483d8b;">&quot;tr&quot;</span>, <span style="color: #483d8b;">&quot;qu&quot;</span>, <span style="color: #483d8b;">&quot;wh&quot;</span>, <span style="color: #483d8b;">&quot;cl&quot;</span>, <span style="color: #483d8b;">&quot;fl&quot;</span>, <span style="color: #483d8b;">&quot;gl&quot;</span>, <span style="color: #483d8b;">&quot;kl&quot;</span>,
                     <span style="color: #483d8b;">&quot;ll&quot;</span>, <span style="color: #483d8b;">&quot;pl&quot;</span>, <span style="color: #483d8b;">&quot;sl&quot;</span>, <span style="color: #483d8b;">&quot;str&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># on génère deux listes de type ((lettre, position), (lettre, position)...)</span>
    <span style="color: #808080; font-style: italic;"># pour pouvoir piocher au hasard dedans</span>
    SYLLABLES_POOL = <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> i, group <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>VOWELS, CONSONANTS<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
        pool = SYLLABLES_POOL<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> place, pack <span style="color: #ff7700;font-weight:bold;">in</span> group:
            <span style="color: #ff7700;font-weight:bold;">for</span> frequency, letters <span style="color: #ff7700;font-weight:bold;">in</span> pack:
                <span style="color: #ff7700;font-weight:bold;">for</span> letter <span style="color: #ff7700;font-weight:bold;">in</span> letters:
                    pool.<span style="color: black;">extend</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>letter, <span style="color: #008000;">set</span><span style="color: black;">&#40;</span>place<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#41;</span> <span style="color: #66cc66;">*</span> frequency<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <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>, min_syllable=<span style="color: #ff4500;">2</span>, max_syllable=<span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">min_syllable</span> = min_syllable
        <span style="color: #008000;">self</span>.<span style="color: black;">max_syllable</span> = max_syllable <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: black;">&#40;</span>min_syllable + <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__iter__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># juste pour le plaisir d'avoir le générateur itérable</span>
        <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
            <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #008000;">self</span>.<span style="color: black;">get_new_name</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># générer un nom avec les réglages de l'instance</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> get_new_name<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">generate_name</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">min_syllable</span>, <span style="color: #008000;">self</span>.<span style="color: black;">max_syllable</span><span style="color: black;">&#41;</span>
&nbsp;
    @<span style="color: #008000;">classmethod</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> generate_name<span style="color: black;">&#40;</span>cls, min_syllable, max_syllable, base=<span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #808080; font-style: italic;"># méthode pour générer un nom à indépendament de l'instance</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># on génère aléatoirement la taille du mot et le son de départ</span>
        length, pool = randint<span style="color: black;">&#40;</span>min_syllable, max_syllable<span style="color: black;">&#41;</span>, randint<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># pour chaque syllabe, on en choppe une au hasard et on change de pool</span>
        <span style="color: #808080; font-style: italic;"># si la syllable n'est pas à la bonne place, on tire à nouveau</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, length + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
&nbsp;
            <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
&nbsp;
                letter, place = choice<span style="color: black;">&#40;</span>cls.<span style="color: black;">SYLLABLES_POOL</span><span style="color: black;">&#91;</span>pool<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
                <span style="color: #ff7700;font-weight:bold;">if</span> i == <span style="color: #ff4500;">1</span>:
                    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'start'</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> place:
                        <span style="color: #ff7700;font-weight:bold;">continue</span>
                <span style="color: #ff7700;font-weight:bold;">elif</span> i == length:
                    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'end'</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> place:
                        <span style="color: #ff7700;font-weight:bold;">continue</span>
                <span style="color: #ff7700;font-weight:bold;">else</span>:
                    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'middle'</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> place:
                        <span style="color: #ff7700;font-weight:bold;">continue</span>
&nbsp;
                base += letter
                pool = <span style="color: #008000;">abs</span><span style="color: black;">&#40;</span>pool - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
                <span style="color: #ff7700;font-weight:bold;">break</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">return</span> base.<span style="color: black;">title</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et ça s&#8217;utilise comme ça:</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;">itertools</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> name <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">itertools</span>.<span style="color: black;">islice</span><span style="color: black;">&#40;</span>FantasyNameGenerator<span style="color: black;">&#40;</span>max_syllable=<span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>, <span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> name</pre></div></div>

<p>Et ça affiche ça:</p>
<p><code>Oislaex<br />
Feasroap<br />
Kab<br />
Uthi<br />
Iin</code></p>
<p>Ok, ok, ça sert à rien. Mais c&#8217;est marrant !</p>


feed_id: http://sametmax.com/?p=2612
title: Nos tweets sans Twitter
uri: Nos-tweets-sans-Twitter
url: http://sametmax.com/nos-tweets-sans-twitters/
content:
<p>On met pas mal de choses sur le <a href="https://twitter.com/sam_et_max">flux Twitter</a>, mais tout le monde n&#8217;a pas envie d&#8217;y aller (ni même de s&#8217;inscrire) pour les consulter.</p>
<p>Du coup on a mis directement sur le site <a href="http://sametmax.com/nos-tweets/">le contenu de notre feed @sam_et_max</a> avec en plus un lien vers le <a href="http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=sam_et_max">flux RSS des tweets</a>. Comme ça, pas besoin de compte pour les suivre. </p>
<p>On poste la plupart de nos articles dessus, donc c&#8217;est un peu redondant avec le flux des articles. Mais parfois il y a des choses sur l&#8217;un et pas sur l&#8217;autre. Les liens en vrac sont sur Twitter par exemple, mais le flux des articles contient les articles en entier, donc pas besoin d&#8217;aller sur le site, on peut même les lire dans l&#8217;avion.</p>
<p>Au passage, on a reçu notre premier don <a href="https://flattr.com/profile/sam_et_max">flattr</a> par Twitter. Merci <a href="https://twitter.com/Chassegnouf">@Chassegnouf</a>, ça fait super plaisir.</p>


feed_id: http://sametmax.com/?p=2575
title: MySQL: créer un utilisateur avec une base de données à son nom sur laquelle il a tous les droits
uri: MySQL-créer-un-utilisateur-avec-une-base-de-données-à-son-nom-sur
url:
http://sametmax.com/mysql-creer-un-utilisateur-avec-une-table-a-son-nom-sur-laquelle-il-a-tous-les-droits/

content:
<p>Le truc classique, qu&#8217;on fait tout le temps, et qu&#8217;on oublie toujours comment on a fait la dernière fois.</p>
<p>Vu qu&#8217;on a pas toujours PhpMyAdmin installé&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">DATABASE</span> nom_db;
<span style="color: #993333; font-weight: bold;">GRANT</span> <span style="color: #993333; font-weight: bold;">ALL</span> PRIVILEGES <span style="color: #993333; font-weight: bold;">ON</span> nom_db<span style="color: #66cc66;">.*</span> <span style="color: #993333; font-weight: bold;">TO</span> <span style="color: #ff0000;">&quot;nom_utilisateur&quot;</span>@<span style="color: #ff0000;">&quot;localhost&quot;</span> <span style="color: #993333; font-weight: bold;">IDENTIFIED</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">'mot_de_passe'</span>;
<span style="color: #993333; font-weight: bold;">FLUSH</span> PRIVILEGES;</pre></div></div>


feed_id: http://sametmax.com/?p=2591
title: Le pattern observer en utilisant des décorateurs
uri: Le-pattern-observer-en-utilisant-des-décorateurs
url: http://sametmax.com/le-pattern-observer-en-utilisant-des-decorateurs/
content:
<p>Nous avons vu précédemment que les <a href="http://sametmax.com/comprendre-les-decorateurs-python-pas-a-pas-partie-1/">décorateurs</a> permettaient d’exécuter du code avant et après une fonction, sans modifier la fonction. La plupart du temps on retourne ainsi une nouvelle fonction avec un comportement différent.</p>
<p>Mais il existe d&#8217;autres usages pour les décorateurs, et notamment un qui est au cœur du fonctionnement de <a href="http://sametmax.com/django-quicky-labolition-des-preliminaires-par-sam-et-max/">django-quicky</a>: l&#8217;abonnement.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> evenement<span style="color: black;">&#40;</span>nom<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># on assure que la liste des events et callabcks est initialisae</span>
    evenement.<span style="color: black;">abonnements</span> = <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span>evenement, <span style="color: #483d8b;">'abonnements'</span>, <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># on ajoute un moyen d'appeler tous les callbacks pour un event</span>
    evenement.<span style="color: black;">trigger</span> = <span style="color: #ff7700;font-weight:bold;">lambda</span> e: <span style="color: black;">&#91;</span>f<span style="color: black;">&#40;</span>e<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> f <span style="color: #ff7700;font-weight:bold;">in</span> evenement.<span style="color: black;">abonnements</span><span style="color: black;">&#91;</span>e<span style="color: black;">&#93;</span><span style="color: black;">&#93;</span> 
&nbsp;
    <span style="color: #808080; font-style: italic;"># définition du décorateur lui-même</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> decorateur<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #808080; font-style: italic;"># on ajoute la fonction comme callback pour cet event</span>
        evenement.<span style="color: black;">abonnements</span>.<span style="color: black;">setdefault</span><span style="color: black;">&#40;</span>nom, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># et on retourne la fonction telle qu'elle, sans la modifier</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> func
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> decorateur</pre></div></div>

<p>Ce morceaux de code s&#8217;utilise ainsi:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># a chaque fois qu'on met le decorateur</span>
<span style="color: #808080; font-style: italic;"># la fonction est liae à un événement</span>
@evenement<span style="color: black;">&#40;</span><span style="color: #483d8b;">'evenement1'</span><span style="color: black;">&#41;</span>
@evenement<span style="color: black;">&#40;</span><span style="color: #483d8b;">'evenement2'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> reagir_a_evenement<span style="color: black;">&#40;</span>evenement<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># la fonction doit acccepter l'evenement en paramètre</span>
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Oh, evenement '%s' a eu lieu&quot;</span> <span style="color: #66cc66;">%</span> evenement
&nbsp;
@evenement<span style="color: black;">&#40;</span><span style="color: #483d8b;">'evenement1'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> moi_aussi<span style="color: black;">&#40;</span>evenement<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Cool, moi aussi j'ai reagit a l'evenement '%s'&quot;</span> <span style="color: #66cc66;">%</span> evenement
&nbsp;
<span style="color: #808080; font-style: italic;"># ici on déclenche l'événement sans raison</span>
<span style="color: #808080; font-style: italic;"># mais dans du vrai code on le déclenche à la suite</span>
<span style="color: #808080; font-style: italic;"># d'une action réelle</span>
evenement.<span style="color: black;">trigger</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'evenement1'</span><span style="color: black;">&#41;</span>
evenement.<span style="color: black;">trigger</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'evenement2'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Ici c&#8217;est un exemple simplifié, mais le principe y est: chaque fois qu&#8217;on utilise un décorateur, on associe la fonction décorée à un nom (ici le nom de notre événement, mais dans django-quicky, c&#8217;est l&#8217;url). Et quand l&#8217;événement se produit, on appelle toutes les fonctions enregistrées, en leur passant l&#8217;objet événement (ici une simple string) en paramètres.</p>
<p>Avec ce design pattern appelé &#8216;observer&#8217;, on découple complètement le code qui déclenche un événement (la lecture d&#8217;un fichier, une erreur, un entrée utilisateur, etc) et le code qui réagit à cet événement (qui peut très bien être celui d&#8217;une lib complètement séparée).</p>
<p>Le décorateur Python est un moyen particulièrement pratique de déclarer un abonnement d&#8217;une fonction à un événement, et ne demande quasiment aucun effort de la part du développeur qui l&#8217;utilise à part d&#8217;avoir une fonction qui accepte les bons paramètres pour réagir à tous les événements que peuvent produire votre library. </p>


feed_id: http://sametmax.com/?p=2569
title: Django cache illimité sur filesystem – Overrider FileBasedCache
uri: Django-cache-illimité-sur-filesystem-Overrider-FileBasedCache
url: http://sametmax.com/django-cache-illimite-sur-filesystem-overrider-filebasedcache/
content:
<p>Django propose plusieurs façons de mettre de son <a href="https://docs.djangoproject.com/en/1.4/topics/cache/">site en <em>cache</em></a>.<br />
Un de nos site gourmant en pages commencait à saturer le cache en mémoire alors il a fallut le basculer sur le filesystem, oui mais Django et son backend filesystem par défaut autorise 300 entrées dans le cache, ensuite il va effacer les anciennes pour les remplacer par les nouvelles, etc&#8230;</p>
<p>On peut régler le nombre d&#8217;entrées avec l&#8217;option MAX_ENTRIES dans les settings mais que fait django derrière ?<br />
Il va scanner votre répertoire de <em>cache</em> et <strong>compter tous les fichiers !</strong> Niveau performance on a vu mieux !</p>
<p>Voici un petit patch qui consiste à bypasser le comptage des fichiers dans le cas où l&#8217;ont veut un cache &#8220;infini&#8221;, ce qui soulève un autre problème, ça va <em>cacher</em> jusqu&#8217;à qu&#8217;il n&#8217;y ait plus de pages à cacher ou que le disque sature :)</p>
<p>dans un fichier cache.py que vous mettez où vous voulez (moi dans libs par ex):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;
    Override FileBasedCache to extend entries cache count.
    avoid scanning all cache dir to count entries.
&nbsp;
&quot;&quot;&quot;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">core</span>.<span style="color: black;">cache</span>.<span style="color: black;">backends</span>.<span style="color: black;">filebased</span> <span style="color: #ff7700;font-weight:bold;">import</span> FileBasedCache
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> CustomFileBasedCache<span style="color: black;">&#40;</span>FileBasedCache<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _get_num_entries<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
       count = <span style="color: #ff4500;">0</span>
       <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>._max_entries == <span style="color: #ff4500;">9999</span>: <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">0</span>
       <span style="color: #ff7700;font-weight:bold;">for</span> _,_,files <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">walk</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._dir<span style="color: black;">&#41;</span>:
           count += <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>files<span style="color: black;">&#41;</span>
       <span style="color: #ff7700;font-weight:bold;">return</span> count
    _num_entries = <span style="color: #008000;">property</span><span style="color: black;">&#40;</span>_get_num_entries<span style="color: black;">&#41;</span></pre></div></div>

<p>dans les settings rajoutez à votre backend filesystem le backend customisé &#8220;libs.cache.CustomFileBasedCache&#8221; et l&#8217;option MAX_ENTRIES à -1:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">CACHE_DEFAULT_SECONDS = <span style="color: #ff4500;">3600</span>
CACHES = <span style="color: black;">&#123;</span>
   <span style="color: #483d8b;">'default'</span>: <span style="color: black;">&#123;</span>
       <span style="color: #483d8b;">'BACKEND'</span>: <span style="color: #483d8b;">'redis_cache.RedisCache'</span>,
       <span style="color: #483d8b;">'LOCATION'</span>: <span style="color: #483d8b;">'localhost:6379'</span>,
       <span style="color: #483d8b;">'TIMEOUT'</span>: CACHE_DEFAULT_SECONDS,
   <span style="color: black;">&#125;</span>,
   <span style="color: #483d8b;">'filesystem'</span>: <span style="color: black;">&#123;</span>
       <span style="color: #483d8b;">'BACKEND'</span>: <span style="color: #483d8b;">'libs.cache.CustomFileBasedCache'</span>,
       <span style="color: #483d8b;">'LOCATION'</span>: <span style="color: #483d8b;">'/var/tmp/django'</span>,
       <span style="color: #483d8b;">'TIMEOUT'</span>: CACHE_DEFAULT_SECONDS,
       <span style="color: #483d8b;">'OPTIONS'</span>: <span style="color: black;">&#123;</span>
            <span style="color: #483d8b;">'MAX_ENTRIES'</span>: <span style="color: #ff4500;">9999</span> <span style="color: #808080; font-style: italic;"># Set 9999 for unlimited cache</span>
       <span style="color: black;">&#125;</span>
   <span style="color: black;">&#125;</span>
<span style="color: black;">&#125;</span></pre></div></div>

<p>On évite du coup le os.walk de la méthode _get_num_entries qui dans le cas d&#8217;un grand nombre de fichiers en cache pourrait faire du mal à votre serveur.</p>
<p>A utiliser avec précaution car ça cache, ça cache, ça cache&#8230; :)</p>


feed_id: http://sametmax.com/?p=2717
title: Nous avons mis puis enlevé Piwik sur 0bin
uri: Nous-avons-mis-puis-enlevé-Piwik-sur-0bin
url: http://sametmax.com/nous-avons-mis-puis-enleve-piwik-sur-0bin/
content:
<p>Par curiosité nous voulions savoir combien de personnes allaient sur <a href="0bin.net/">0bin</a>. C&#8217;était une mauvaise idée.</p>
<p>On ne pouvait pas utiliser Google Analytics car ça aurait émoussé la confiance des utilisateurs, alors on a installé notre propre instance de <a href="http://piwik.com/">Piwik</a>: une solution open source sur laquelle du coup nous avions la main du code en passant par le serveur.</p>
<p>Malheureusement, en regardant les stats détaillées, j&#8217;ai remarqué que Piwik sauvegardait chaque URL avec l&#8217;ancre, donc avec la clé de chiffrement. J&#8217;avais dans ma base de données une liste d&#8217;URLs menant à des pastes dont je pouvais lire le contenu.</p>
<p>Cela pose plusieurs problèmes:</p>
<ul>
<li>si vous êtes hébergeurs de 0bin, vous voulez éviter ça à tout prix. <a href="http://sametmax.com/0bin-implementation-python-de-zerobin-pastebin-chiffre-cote-client/">Le but est justement ne pas pouvoir faire ça</a>, car on parie sur le fait que ce qu&#8217;on ne peut pas être légalement tenu de modérer ce qu&#8217;on ne peut pas lire.</li>
<li>si vous êtes utilisateurs, tout l’intérêt de ce qui fait 0bin autre chose qu&#8217;un simple pastebin s&#8217;écroule</li>
</ul>
<p>J&#8217;ai tout supprimé, mais c&#8217;est vraiment un coup de bol que je m&#8217;en sois aperçu, car je n&#8217;avais même pas imaginé que juste pour des stats on pourrait enregistrer jusqu&#8217;à l&#8217;ancre d&#8217;une URL. Et je n&#8217;ai certainement pas cherché ces URLs, qui n&#8217;étaient pas mises en avant dans ma configuration du tableau de bord.</p>
<p>Moralité:</p>
<ul>
<li>si vous êtes hébergeurs, n&#8217;installez rien sur 0bin. Rien du tout. On ne peut jamais être parfaitement certain de ce que fait un outil tierce partie, fut-il open source. Si je n&#8217;avais pas ouvert par hasard ce sous-sous-sous-menu, je n&#8217;aurais pas vu le problème, et aurait pu accumuler ces URLs pendant des mois.</li>
<li>si vous êtes utilisateurs, faites bien attention à ce que l&#8217;outil ne comporte rien en plus. Un petit view source est de rigueur. Si quelqu&#8217;un peut nous pondre une extension pour vérifier le JS, encore mieux&#8230;</li>
</ul>


feed_id: http://sametmax.com/?p=2706
title: Comment servir les fichiers statiques avec Django en dev et en prod
uri: Comment-servir-les-fichiers-statiques-avec-Django-en-dev-et-en-prod
url: http://sametmax.com/comment-servir-les-fichiers-statiques-avec-django-en-dev-et-en-prod/
content:
<p>Servir les fichiers CSS, javascript et les images avec Django a toujours été la plus grande source de confusion (heureusement ça s&#8217;est bien amélioré avec la 1.4, donc upgradez si vous pouvez). C&#8217;est d&#8217;autant plus déroutant que la manière de faire est différente selon la version de Django, et selon que l&#8217;on est en production ou en développement.</p>
<p>Donc, pour profiter de cet article:</p>
<ul>
<li>Lisez les parties qui vous concernent uniquement.</li>
<li>Ne lisez pas en diagonale.</li>
<li>Si ça ne marche pas, partez de zéro (avec un projet tout neuf), et une fois que ça marche, essayez sur le votre.</li>
</ul>
<p>C&#8217;est typiquement le cas où <strong>il faut comprendre ce qui se passe et pas juste copier/coller du code</strong> (ceci est une petite pique à Max qui est en train de décuver comme une loque sur le canap pendant que j&#8217;écris cette partie de l&#8217;article).</p>
<h2>Préparation</h2>
<p>Les fichiers statiques se gèrent à base de chemins absolus. Afin de faciliter celà, vous devriez donc toujours avoir ceci tout en haut de votre fichier settings.py:</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;">os</span>
PROJECT_DIR = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">abspath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Si votre fichier de settings n&#8217;est pas à la racine du projet (typiquement dans un projet Django 1.4), faites:</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;">os</span>
SETTINGS_DIR = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">abspath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
PROJECT_DIR = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span>SETTINGS_DIR<span style="color: black;">&#41;</span></pre></div></div>

<p>Le fichiers de settings étant un fichier Python, on peut mettre tout le code que l&#8217;on souhaite dedans, et ce code nous permet d&#8217;obtenir de manière dynamique le chemin absolu vers votre dossier de projet. Il servira de base pour tous les chemins vers les fichiers statiques.</p>
<p><code>__file__</code> contient le chemin vers le fichier en cours. <code>abspath()</code> permet d&#8217;obtenir le chemin absolu. <code>dirname()</code> permet d&#8217;obtenir le nom du dossier contenant le fichier.</p>
<p>Notez aussi l&#8217;emplacement des fichiers statiques de la Django admin dans un coin (dans la doc de votre site par exemple). Ces fichiers se trouvent dans <em>django/contrib/admin/media</em>, mais si vous galerez pour les trouver, vous pouvez toujours lancer la commande:</p>

<div class="wp_syntax"><div class="code"><pre class="base" style="font-family:monospace;">python -c &quot;import django, os; print os.path.join(os.path.dirname(django.__file__), 'contrib/admin/media')&quot;</pre></div></div>

<p>Moi ça donne un truc comme ça:</p>
<p><em>/home/sam/.virtualenvs/project_env/local/lib/python2.7/site-packages/django/contrib/admin/media</em></p>
<h2>En phase de développement, de la version 1.0 à la version 1.2</h2>
<p>Vous êtes sur votre machine, et vous utilisez la commande <code>runserver</code>. C&#8217;est donc Django qui va servir vos fichier statiques, et nous allons voir comment, pour chaque version de Django, on peut lui demander de le faire.</p>
<p>C&#8217;est une vieille version, servir les fichiers statiques est assez relou, alors on va gruger pour vous faciliter la vie. Non, ce n&#8217;est pas la meilleur manière de faire, mais c&#8217;est la manière de faire qui vous évitera de retourner sur un forum pour demander pourquoi ça ne marche pas.</p>
<p>Créez un dossier nommé &#8220;static&#8221; <strong>à la racine de votre projet</strong>. Mettez tous vos fichiers statiques dedans: js, css, images&#8230; Organisez ça en sous-dossier si vous voulez, mais <strong>mettez tout dedans, y compris les fichiers statiques des autres apps Django que vous avez installé</strong> (et qu&#8217;il va falloir copier/coller ou alors faire un lien symbolique). La seule exception est l&#8217;admin.</p>
<p>Ce n&#8217;est pas particulièrement propre ni pratique, mais ça va marcher. Le surcoût en maintenant sera largement compensé par le fait que ce sera très simple à comprendre et à servir.</p>
<p>Dans votre fichier de settings, pointez <code>MEDIA_ROOT</code> sur ce dossier:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">MEDIA_ROOT = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>PROJECT_DIR, <span style="color: #483d8b;">'static'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et choissisez un chemin explicite pour <code>MEDIA_URL</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">MEDIA_URL = <span style="color: #483d8b;">'/static/'</span></pre></div></div>

<p>Ne touchez pas à <code>ADMIN_MEDIA_PREFIX</code>. Ne mettez pas <code>MEDIA_URL</code> égale à <code>ADMIN_MEDIA_PREFIX</code>.</p>
<p>Dans le fichier urls.py principal, c&#8217;est à dire ce lui est généralement à la racine de votre projet, faites:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># on importe ici tout les trucs nécessaires à urls.py</span>
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
<span style="color: #808080; font-style: italic;"># on va récupérer MEDIA_ROOT depuis le fichier de settngs</span>
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span> <span style="color: #ff7700;font-weight:bold;">import</span> settings
&nbsp;
<span style="color: #808080; font-style: italic;"># on active l'admin</span>
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">contrib</span> <span style="color: #ff7700;font-weight:bold;">import</span> admin
admin.<span style="color: black;">autodiscover</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># on créé un pattern vide. Cela va nous permettre d'insérer le service</span>
<span style="color: #808080; font-style: italic;"># des fichiers statiques en premier</span>
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On active maintenant le service des fichiers statiques par Django</span>
<span style="color: #808080; font-style: italic;"># mais uniquement en mode DEBUG (pour éviter de l'oublier en prod)</span>
<span style="color: #ff7700;font-weight:bold;">if</span> settings.<span style="color: black;">DEBUG</span>:
    urlpatterns += patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,
        <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'%s/(?P&lt;path&gt;.*)$'</span> <span style="color: #66cc66;">%</span> settings.<span style="color: black;">MEDIA_URL</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/'</span><span style="color: black;">&#41;</span>,
         <span style="color: #483d8b;">'django.views.static.serve'</span>,
         <span style="color: black;">&#123;</span><span style="color: #483d8b;">'document_root'</span>: settings.<span style="color: black;">MEDIA_ROOT</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Ensuite on déclare nos patterns normalement</span>
<span style="color: #808080; font-style: italic;"># ATTENTION, le signe doit-être &quot;+=&quot;, pas &quot;=&quot;, sinon vous allez tout écraser</span>
urlpatterns += patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,
    <span style="color: #808080; font-style: italic;"># Example:</span>
    <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^'</span>, include<span style="color: black;">&#40;</span><span style="color: #483d8b;">'app.urls'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># Uncomment the admin/doc line below and add 'django.contrib.admindocs'</span>
    <span style="color: #808080; font-style: italic;"># to INSTALLED_APPS to enable admin documentation:</span>
    <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^admin/doc/'</span>, include<span style="color: black;">&#40;</span><span style="color: #483d8b;">'django.contrib.admindocs.urls'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># Uncomment the next line to enable the admin:</span>
    <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^admin/(.*)'</span>, admin.<span style="color: #dc143c;">site</span>.<span style="color: black;">root</span><span style="color: black;">&#41;</span>,
<span style="color: black;">&#41;</span></pre></div></div>

<p>Vous notez que contrairement à ce qu&#8217;on voit la doc officielle, on met l&#8217;url pour les fichiers statiques en premier. Cela donne une forme étrange à la déclation des urls car on a un <code>urlpatterns</code> vide au début, mais c&#8217;est très important: à un moment vous allez déclarer une URl attrape-tout qui court-circuitera tout ce qu&#8217;il y a après, et ce jour là vous passerez des heures à chercher pourquoi vos fichiers statiques ne sont pas déclarés.</p>
<p>Le <code>strip()</code> n&#8217;est pas obligatoire si vous mettez les slashes correctement partout. Mais ce n&#8217;est jamais le cas.</p>
<p>Maintenant, dans votre html, vous pouvez faire ceci:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;link href=&quot;/static/chemin/du/fichier/a/relatif/au/dossier/static.css&quot;  rel=&quot;stylesheet&quot; /&gt;</pre></div></div>

<p>Et pareil pour le js, les images, etc.</p>
<p>Le chemin est bel et bien écrit en dur dans le templates HTML. Encore une fois, ce n&#8217;est pas la meilleure manière de faire, c&#8217;est juste celle qui vous garanti que ça marche. Si vous vous sentez à l&#8217;aise avec le processus, vous pouvez changer celà en utilisant un context_processor pour ajouter <code>MEDIA_URL</code> à chaque template et remplacer <code>/static/</code> par <code>{{ MEDIA_URL }}</code>.</p>
<p><a href="http://sametmax.com/wp-content/uploads/2012/10/servir_fichiers_statiques_django_1.0_a_1.2.zip?9d7bd4">Télécharger le projet complet d&#8217;exemple</a></p>
<h2>En phase de développement, pour la version 1.3 et 1.4</h2>
<p>C&#8217;est globalement beaucoup plus facile. Il suffit de mettre tous vos fichiers statiques dans un dossier nommé &#8220;static&#8221; dans le dossier d&#8217;une de vos app pour qu&#8217;ils soient trouvés automatiquement quand vous lancerez <code>manage.py runserver</code>.</p>
<p>Voici à quoi ressemblera votre settings.py:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># plus rien à voir avec avant, MEDIA_ROOT et MEDIA_URL designent</span>
<span style="color: #808080; font-style: italic;"># l'endroit où vous voulez que vos utilisateur upload et download des fichiers</span>
<span style="color: #808080; font-style: italic;"># Ce n'est donc plus un paramètre primordial</span>
MEDIA_ROOT = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>PROJECT_DIR, <span style="color: #483d8b;">'media'</span><span style="color: black;">&#41;</span>
MEDIA_URL = <span style="color: #483d8b;">'/media/'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Ce qui s'appelait avant MEDIA_ROOT s'appelle maintenant STATIC_ROOT</span>
<span style="color: #808080; font-style: italic;"># mais il n'est utile pour la prod</span>
<span style="color: #808080; font-style: italic;"># On le met quand même pour plus tard</span>
STATIC_ROOT = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>PROJECT_DIR, <span style="color: #483d8b;">'static'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Le settings le plus important: à quelle adresse servir les fichiers statiques</span>
<span style="color: #808080; font-style: italic;"># Utile en dev afin de pouvoir bénéficier des templates tags</span>
STATIC_URL = <span style="color: #483d8b;">'/static/'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Les medias de l'admin sont enfin une URL comme une autre qu'on peut</span>
<span style="color: #808080; font-style: italic;"># mettre sous notre propre arborescence</span>
ADMIN_MEDIA_PREFIX = <span style="color: #483d8b;">'/static/admin/'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Vous pouvez OPTIONNELLEMENT rajouter ici une liste de chemin vers</span>
<span style="color: #808080; font-style: italic;"># des dossiers de fichiers statiques qui seront ainsi aussi servit automatiquement</span>
<span style="color: #808080; font-style: italic;"># pendant le développement. Par exemple un dossier à la racine</span>
STATICFILES_DIRS = <span style="color: black;">&#40;</span>
    <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>PROJECT_DIR, <span style="color: #483d8b;">'more_static'</span><span style="color: black;">&#41;</span>,
<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># N'utilisez PAS le même dossier que STATIC_ROOT</span></pre></div></div>

<p>Il n&#8217;y a rien à faire de plus, vos fichiers seront servis automatiquement en dev, pas besoin de toucher aux urls.</p>
<p>Maintenant il faut juste les déclarer vos URLs dans le template.</p>
<p>Pour Django 1.3, vous pouvez ajouter un fichiers statiques ainsi pour éviter d&#8217;écrire l&#8217;URL en dur:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">{% load static %}
{% get_static_prefix as STATIC_PREFIX %}
&nbsp;
&lt;link href=&quot;{{ STATIC_PREFIX }}app/css/style.css&quot;  rel=&quot;stylesheet&quot; /&gt;</pre></div></div>

<p>Pour django 1.4, c&#8217;est encore plus simple:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">{% load staticfiles %}
&lt;img src=&quot;{% static &quot;app/css/style.css&quot; %}&quot; /&gt;</pre></div></div>

<p>Encore un détail, si vous n&#8217;utilisez pas le serveur de dev Django mais un autre serveur de dev (ex: werkzeug), vos fichiers statiques ne seront pas servis automatiquement, mais il est facile d&#8217;y remédier. Ajoutez à votre urls.py:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">contrib</span>.<span style="color: black;">staticfiles</span>.<span style="color: black;">urls</span> <span style="color: #ff7700;font-weight:bold;">import</span> staticfiles_urlpatterns
&nbsp;
urlpatterns += staticfiles_urlpatterns<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p><a href="http://sametmax.com/wp-content/uploads/2012/10/servir_fichiers_statiques_django_1.3_et_1.4.zip?9d7bd4">Télécharger le projet complet d&#8217;exemple</a></p>
<h2>Migration de 1.2 ou moins vers 1.3 ou 1.4</h2>
<p>Bouger vos fichiers statiques du répertoire à la racine vers le répertoire nommé &#8220;static&#8221; d&#8217;une de vos apps (ou de plusieurs).</p>
<p>Ajoutez ceci dans votre fichier de config:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">STATICFILES_DIRS = <span style="color: black;">&#40;</span>
<span style="color: black;">&#41;</span>
&nbsp;
STATICFILES_FINDERS = <span style="color: black;">&#40;</span>
    <span style="color: #483d8b;">'django.contrib.staticfiles.finders.FileSystemFinder'</span>,
    <span style="color: #483d8b;">'django.contrib.staticfiles.finders.AppDirectoriesFinder'</span>,
<span style="color: black;">&#41;</span></pre></div></div>

<p>Et ajoutez <code>django.contrib.sites</code> à vos <code>INSTALLED_APPS</code>.</p>
<p>Remplacez toutes les URls en dur dans le HTML par une version avec les templates tags (voir partie précédente).</p>
<p>Attention, ça ne couvre que la partie pour la gestion des fichiers statiques, il y a d&#8217;autres choses à migrer.</p>
<h2>En production: toutes versions</h2>
<p>Je ne vais pas expliquer ici comment mettre Django en production (c&#8217;est un article à lui tout seul, peut être même plusieurs). Ici je vais me concentrer sur comment servir les fichiers statiques, et présupposer <code>DEBUG = False</code>.</p>
<p>Si vous utilisez Djagno 1.2 ou moins, vous n&#8217;avez rien à faire côté Django. Si vous utilisez Django 1.3 ou 1.4, vous devez maintenant appeler la commande <code>pyhon manage.py collectstatic</code>. Celle-ci va prendre tous les fichiers statiques de tous les dossiers &#8220;static&#8221; des apps et ceux listés dans <code>STATICFILES_DIRS</code> et va les copier dans <code>STATIC_ROOT</code>.</p>
<p>Dans tous les cas, vous n&#8217;aurez qu&#8217;un seul dossier pour le js, le css et les images à servir avec Nginx ou Apache.</p>
<h4>Nginx</h4>
<p>Si vous avez votre propre serveur, je vous conseil Nginx plutôt qu&#8217;Apache pour mettre votre site en prod.</p>
<p>L&#8217;idée est de dire dans le fichier de configuration nginx que toutes les URLs qui concernent les fichiers statiques sont servies directement par Nginx, et les autres sont passées à Django:</p>

<div class="wp_syntax"><div class="code"><pre class="json" style="font-family:monospace;">server {
        listen      8080;
&nbsp;
        ############################################################
        # la partie qui concerne les fichiers statiques commence ici
        ############################################################
&nbsp;
        location /favicon.ico {
            # favicon.ico doit être à la racine du dossier img
            root  /chemin/absolu/vers/dossier/img;
        }
&nbsp;
        # on sert nos fichiers statiques
        # l'url doit correspondre à MEDIA_URL
        location ~* ^/static/ {
            root  /chemin/absolu/vers/dossier/PARENT/du/dossier/statique;
            # on active gzip pour tous les petits fichiers qui contiennent du texte
            # si le navigateur le supporte
            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;
            # petite astuce gzip pour les gros fichier
            # voir http://blog.leetsoft.com/2007/7/25/nginx-gzip-ssl
            gzip_buffers 16 8k;
&nbsp;
            # on desactive gzip pour les vieux navigateurs
            gzip_disable ~@~\MSIE [1-6].(?!.*SV1)~@~];
        }
&nbsp;
       # on fait pareil mais pour l'admin Django
       # l'url doit corresponde à ADMIN_MEDIA_PREFIX
       location ~* ^/media/ {
            root  /chemin/absolu/du/dossier/PARENT/du/dossier/media/de/django;
            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)~@~];
        }
&nbsp;
        ##############################################################
        # la partie qui concerne les fichiers statiques se termine ici
        ##############################################################
&nbsp;
        location / {
            proxy_pass http://127.0.0.1:8000;
        }
}</pre></div></div>

<p>Notez bien que la directive <code>root</code> suppose que vous mettiez le dossier parent du dossier que vous voulez servir, et que le dossier servi a le même nom que le chemin dans l&#8217;url.</p>
<p>Par exemple, si vos fichiers statiques sont dans <em>/home/sam/project/static</em>, alors l&#8217;url devra être <code>^/static/</code> et on passera à l&#8217;instruction <code>root</code> le chemin <em>/sam/project</em>.</p>
<h4>Apache</h4>
<p>Si vous êtes chez un hébergeur qui n&#8217;a qu&#8217;Apache, voici un manière de servir les fichiers statiques. Je ne connais pas Apache aussi bien que Nginx, donc je ne peux pas m&#8217;engager sur la gestion de Gzip.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"># TOUS les chemins doivent être accessible pour le user apache (www-data le plus souvent)
# N'oubliez pas les slashes finaux, ils sont importants
&nbsp;
WSGIPythonPath /chemin/absolu/vers/project/:/chemin/absolu/vers/dossier/parent/du/project/:/chemin/vers/site/package/du/virtualenv/
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;VirtualHost</span> *:80<span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
    WSGIScriptAlias / &quot;/chemin/absolu/vers/fichier/project.wsgi&quot;
&nbsp;
    ########################################################
    # Début de la partie qui concerne les fichiers statiques
    ########################################################
&nbsp;
    # on sert les fichiers statiques du site
    Alias /static/ &quot;/chemin/absolu/vers/dossier/static/&quot;
    Alias /favicon.ico &quot;/chemin/absolu/vers/dossier/static/img/favicon.ico&quot;
&nbsp;
    # on donne l'autorisation à tous de les lire
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Directory</span> <span style="color: #ff0000;">&quot;/chemin/absolu/vers/dossier/static/&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        Order allow,deny
        Allow from all
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Directory<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
    # on sert les fichiers statiques de l'admin
    Alias /media/ &quot;/chemin/absolu/vers/dossier/django/contrib/admin/media/&quot;
    # on donne l'autorisation à tous de les lire
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Directory</span> <span style="color: #ff0000;">&quot;/chemin/absolu/vers/dossier/django/contrib/admin/media/&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        Order allow,deny
        Allow from all
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Directory<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
    ######################################################
    # Fin de la partie qui concerne les fichiers statiques
    ######################################################
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/VirtualHost<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Si vous faites bien gaffe aux droits d&#8217;accès des dossiers (récursivement) et que vous avec pas oublié de &#8220;/&#8221; à la fin d&#8217;un chemin, tout ira bien.</p>
<p>Pour Apache, servir les fichiers statiques est généralement la partie facile, c&#8217;est faire marcher Django et mod_wsgi qui est difficile: problèmes de droits, mauvaise configuration, Python path qui foine&#8230; Mais je m&#8217;en branle, puisque c&#8217;est pas l&#8217;objet de l&#8217;article, donc démerdez-vous.</p>
<h2>Notes de fin</h2>
<p>Jusqu&#8217;à la version 1.2, <code>MEDIA_ROOT</code> et <code>MEDIA_URL</code> ne sont que des conventions qui ne servent pas à grand chose à part à être utilisées par des contexts managers et à vous éviter les chemins en durs dans les templates et urls.py.</p>
<p>A partir de Django 1.3, <code>STATIC_ROOT</code> et <code>STATIC_URL</code> sont vraiment utilisées: <code>STATIC_ROOT</code> est là où Django va mettre le resultat de la commande <code>collecstatic</code> et <code>STATIC_URL</code> et l&#8217;url que va utiliser la vue <code>staticfiles_urlpatterns</code>.</p>
<p><code>MEDIA_ROOT</code> et <code>MEDIA_URL</code> existent toujours, mais sont utilisés pour designer le dossier et l&#8217;url qui pointent vers les contenus uploadés et downlodés par les utilisateurs. Si vous voulez les servir, il faut faire exactement la même chose à l&#8217;époque de Django 1.2 et avant: mettre la route à la main dans urls.py (mais cette fois, il y a un <a href="https://docs.djangoproject.com/en/1.3/howto/static-files/#django.conf.urls.static.static">raccourcis</a> pour ça), et rajouter une entrée supplémentaire dans le fichier de conf Nginx ou Apache.</p>
<p>Sinon, vous pouvez aussi vous éviter tout ce merdier en utilisant le middleware qui sert automatiquement tous les fichiers statiques de <a href="https://github.com/sametmax/django-quicky">django_quicky</a>.</p>
<p>Enfin, je n&#8217;ai pas abordé les storage backends, tout simplement parce que je n&#8217;en utilise pas, donc je ne peux pas vous donner de bons conseils sur la question.</p>


