JESUISUNGEEK.COM2022-10-15T08:24:27+02:00urn:md5:80fcbbbeeb78d335e0ba1eaeec99fb37DotclearModules Pythonurn:md5:c36e62a3e78f46851403448d7232854b2017-03-29T16:49:00+02:002017-03-29T16:49:00+02:00Jean-Baptiste LangloisProjets<p>Interface de communications liés à mon travail actuel</p> <p>Tel un ours, me voilà qui ressort de ma tanière pour poster mon message annuel. Bon, OK, pour le coup, je ne vais pas <strong>encore</strong> promettre de davantage poster, sachant que j'ignore quand j'aurai l'opportunité (le temps libre ? <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /> ) de poster à nouveau ici.<br />
Juste pour vous faire partager deux de mes modules développés récemment et que j'utilise au quotidien dans mon travail. Du coup, je me suis dit : <q>Hey, mais... Si ça m'est utile, ça peut l'être pour d'autres, pas vrai ?</q>. D'où ce post (c'est bien foutu, non ? <img src="/dotclear/themes/chestnut/smilies/smile.gif" alt=":-)" class="smiley" /> )<br />
<br />
Ces deux modules suivent le même process d'écriture et utilisent <code>setuptools</code> avec tout ce que ça implique de <code>test</code>, <code>install</code> et autres <code>bdist</code><br />
<br /></p>
<h3><a href="https://github.com/Mithweth/python-servicenow" title="python-servicenow">python-servicenow</a></h3>
<p><img src="http://www.jesuisungeek.com/public/pictures/real/.ServiceNow-logo-300x200_m.jpg" alt="ServiceNow-logo-300x200.jpg" title="ServiceNow-logo-300x200.jpg, mar. 2017" /><br />
Il faut d'un bête module encapsulant <code>urllib2</code> simplifiant les appels à <a href="http://www.service-now.com" hreflang="en" title="ServiceNow">ServiceNow</a> mais permet ainsi de communiquer avec son serveur ServiceNow sans trop se trimballer toute la syntaxe <code>urllib2</code>.
<br /></p>
<h3><a href="https://github.com/Mithweth/python-ansible" title="pyansible">pyansible</a></h3>
<p>OK, on me dira que l'API Python fournit avec ansible permet DEJA un moyen d'appeler Ansible via Python (ce qui fait également <strong>pyansible</strong>). Mais honnêtement... DataLoader ? VariableManager ? Inventory ? Sérieux, qui a déjà utilisé cette API sans utiliser la doc ? Alors que là... un petit :</p>
<pre>
import pyansible
pb = pyansible.Playbook('test.yml', inventory='/etc/ansible/hosts')
if pb.run():
print "SUCCESS!"
</pre>
<p>Et c'est tout <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /> Et de surcroît, ce module gère aussi l'execution de Task et Role ainsi que les clés SSH et l'usage de Vault. C'est pas beau ? <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" /></p>http://www.jesuisungeek.com/index.php?post/2017/03/29/Modules-Python#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/252Ansible Extended Modulesurn:md5:dde08d2b8704e053cca929e32e748b6d2016-07-07T13:54:00+02:002016-07-07T13:54:00+02:00Jean-Baptiste LangloisProjets<p>Modules Ansible pour Amazon EC2, écrit en Python<a href="https://github.com/Mithweth/ansible-extended-modules" title="GitHub"></a></p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/aws_logo.png" alt="Amazon Web Services" style="float:left; margin: 0 1em 1em 0;" title="Amazon Web Services, juil. 2016" /> Dans mon boulot actuel, je travaille sur <a href="http://aws.amazon.com/">Amazon Web Services</a> où je dois provisionner et décommissionner de nouvelles machines EC2 à la demande. Pour cela, j'utilise <a href="https://www.ansible.com/">Ansible</a> qui fonctionne comme un charme pour ce type de tâches. Toutefois, il arrive qu'un utilisateur ait besoin de nouvelles ressources et on doit pouvoir, alors, modifier la taille du disque dur, celle de la RAM ou le nombre de CPU. Et à ces demandes, Ansible s'avère plutôt mauvais. C'est pour cela que j'ai développé deux modules :</p>
<ul>
<li><strong>ec2_modify</strong> qui modifie le nombre de CPU ou la taille de la RAM (en langage Amazon, on parle <q>type d'instances</q>), la position géographique ainsi que le VLAN à utiliser</li>
<li><strong>ec2_vol_resize</strong> qui crée un snapshot d'un volume existant pour en créer un plus gros qu'on attachera à l'instance, permet ainsi l'agrandissement du disque dur.</li>
</ul>
<p>Ces modules étaient destinés à grossir et à s'étoffer, je les ai placé sur mon <a href="https://github.com/Mithweth/ansible-extended-modules" title="GitHub">GitHub</a> ; toute la documentation et les pré-requis s'y trouvent également.</p>http://www.jesuisungeek.com/index.php?post/2016/07/07/Enlarge-your-hard-disk#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/251Connexion en LDAPS avec Icingaurn:md5:09ce0dac9aabf317caf6b181d701f1342016-05-24T12:30:00+02:002016-05-24T12:56:26+02:00Jean-Baptiste LangloisBidouillesicingaldaplinux<p>Authentification sur Icinga via un serveur LDAP nécessitant un certificat</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/.icinga-ssl_s.png" alt="Icinga avec LDAPS" style="float:left; margin: 0 1em 1em 0;" title="Icinga avec LDAPS, mai 2016" /> Ce problème m'a été posé au bureau, et comme je n'ai pas trouvé de page traitant de ce problème, j'en détaille la configuration.<br />
Le serveur LDAPS utilisé dans ma société est permissif et autorise les connexions sans certificats. Il est être remplacer par un serveur forçant la connexion via un certificat en SHA-256. Quant à moi, je suis chargé de m'occuper de la migration correcte pour le serveur <a href="https://www.icinga.org/" hreflang="fr">Icinga</a>. La plupart des applicatifs dans ma société étant basé sur Java, plus qu'un certificat, il s'agit d'un TrustKeyStore (JKS) qui est fourni pour réaliser la migration.<br />
Dans Icinga, l'authentification LDAP s'effectue à travers Icinga-Web. A savoir dans les fichiers suivants (dans le cas d'une installation par défaut) :</p>
<ul>
<li><strong>/usr/share/icinga-web/app/modules/AppKit/config/auth.xml</strong></li>
<li><strong>/etc/icinga-web/conf.d/auth.xml</strong></li>
</ul>
<p>On y trouve la partie suivante :</p>
<pre class="brush: xml">
<setting name="provider">
<ae:parameter name="openldap-ldap1">
<ae:parameter name="auth_module">AppKit</ae:parameter>
<ae:parameter name="auth_provider">Auth.Provider.LDAP</ae:parameter>
<ae:parameter name="auth_enable">true</ae:parameter>
<ae:parameter name="auth_authoritative">true</ae:parameter>
<ae:parameter name="auth_create">true</ae:parameter>
<ae:parameter name="auth_update">true</ae:parameter>
<ae:parameter name="auth_map">
<ae:parameter name="user_firstname">givenName</ae:parameter>
<ae:parameter name="user_lastname">sn</ae:parameter>
<ae:parameter name="user_email">email</ae:parameter>
</ae:parameter>
<ae:parameter name="ldap_allow_anonymous">false</ae:parameter>
<ae:parameter name="ldap_dsn">ldaps://serveur1:636</ae:parameter>
<ae:parameter name="ldap_start_tls">false</ae:parameter>
<ae:parameter name="ldap_basedn">ou=people,dc=societe</ae:parameter>
<ae:parameter name="ldap_binddn">uid=userdn,ou=Applis,dc=societe</ae:parameter>
<ae:parameter name="ldap_bindpw"><![CDATA[mot_de_passe_userdn]]></ae:parameter>
<ae:parameter name="ldap_filter_user"><![CDATA[(&(uid=__USERNAME__))]]></ae:parameter>
</ae:parameter>
</setting>
</pre>
<p>Le paramètre <code>ldap_start_tls</code> semble attirant mais malheureusement ne correspond pas à mon cas où le serveur s'attend à trouver un certificat client sur la machine interrogeant l'annuaire.<br />
En fait, après plusieurs recherches, j'ai réalisé que Icinga-Web délègue l'intégralité du processus de connexion LDAP à PHP, en se basant sur les fonctions <a href="http://php.net/manual/fr/function.ldap-connect.php" hreflang="en">ldap_connect()</a> et <a href="http://php.net/manual/fr/function.ldap-search.php" hreflang="en">ldap_search()</a>, elles-mêmes s'appuyant sur la configuration locale.<br /></p>
<h3>Récupération du certificat</h3>
<p>Comme indiqué, je pars d'un <a href="https://en.wikipedia.org/wiki/Keystore" hreflang="en">Keystore</a> duquel je dois extraire le certificat nécessaire. Tout d'abord, je récupère l'alias du certificat que je compte extraire :</p>
<pre>
[root@icinga]# keytool -list -keystore mon_keystore.jks -storepass mot_de_passe_keystore
</pre>
<p>Ensuite, j'extrais le certificat (au format PEM) du Keystore (j'ai choisi le répertoire par défaut pour y stocker le certificat) :</p>
<pre>
[root@icinga]# keytool -exportcert -keystore mon_keystore.jks -storepass mot_de_passe_keystore -rfc -alias alias_du_certificat > /etc/openldap/cacerts/alias_du_certificat.pem
[root@icinga]# chmod 644 /etc/openldap/cacerts/alias_du_certificat.pem
</pre>
<p>Et je vérifie si l'algorithme de ce certificat est bien, comme demandé du SHA-256.</p>
<pre>
[root@icinga]# openssl x509 -text -noout -in /etc/openldap/cacerts/alias_du_certificat.pem | grep Algorithm
Signature Algorithm: sha256WithRSAEncryption
Public Key Algorithm: rsaEncryption
Signature Algorithm: sha256WithRSAEncryption
</pre>
<h3>Configuration du client LDAP</h3>
<p>Comme je l'ai dit plus haut, Icinga-Web se base, à travers PHP, sur la configuration locale, à savoir, <ins>l'environnement de l'utilisateur exécutant Apache</ins> (généralement <strong>www</strong>) :</p>
<pre>
[www@icinga]$ cat > ~/.ldaprc << EOF
TLS_REQCERT never
TLS_CACERT /etc/openldap/cacerts/alias_du_certificat.pem
EOF
</pre>
<p>On peut alors tester le bon fonctionnement de cette configuration :</p>
<pre>
[www@icinga]$ ldapsearch -H ldaps://serveur2:636 -d 1 2>&1 | grep TLS
TLS: loaded CA certificate file /etc/openldap/cacerts/alias_du_certificat.pem.
TLS: certificate [CN=server2,OU=0002,O=SOCIETE,C=TEST] is valid
...
</pre>
<p>Si le résultat est concluant, ne pas oublier de <ins>redémarrer Apache</ins>.</p>
<h3>Reconfiguration de Icinga-Web</h3>
<p>Finalement, je modifie le fichier auth.xml de Icinga-Web, et je vide le cache.</p>
<pre>
[icinga@icinga]$ sed -i.bak 's/serveur1/serveur2/1' /etc/icinga-web/conf.d/auth.xml
[icinga@icinga]$ /usr/share/icinga-web/bin/clearcache.sh
Cachedir: /usr/share/icinga-web/cache
Deleting cache from config (69 files) ... ok
Deleting cache from Squished (4 files) ... ok
</pre>
<p>Si aucune erreur n'a été faite, on devrait pouvoir se connecter avec ses <em>credentials</em> LDAP sur l'interface graphique de Icinga-Web <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /></p>http://www.jesuisungeek.com/index.php?post/2016/05/24/Connexion-en-LDAPS-avec-Icinga#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/250Liens pour s'occuper quand on s'ennuieurn:md5:b83e000280301aaa284ca4e3bc46c0392016-05-05T17:01:00+02:002016-05-05T17:36:16+02:00Jean-Baptiste LangloisGeekeries<p>On la sent bien, là, le jour férié à glander devant son PC <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /></p> <p>Depuis un certain temps, quand je tombe sur un site amusant (même si parfois pas forcément utile), je le note afin de le poster ici ultérieurement. Mais, organisé comme je suis, je perds mes Post-It et du coup, l'adresse des sites que je voulais poster. Du coup, avant que j'oublie ceux-là, voici que j'ai pu voir aujourd'hui et qui méritent le détour :<br /><br />
<ins><em>Star Wars</em> en telnet :</ins><br />
<img src="http://www.jesuisungeek.com/public/pictures/divers/star_wars_telnet.png" alt="Star Wars Episode IV en Telnet" style="display:block; margin:0 auto;" title="Star Wars Episode IV en Telnet, mai 2016" />
Après la VHS, le DVD et le Blu-Ray, voici la version Telnet ! connectez-vous sur <a href="telnet://towel.blinkenlights.nl">towel.blinkenlights.nl</a> en <strong>telnet</strong> (donc sur le port 23, bonne chance si vous êtes en entreprise <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" /> ), et c'est parti pour 1H30 d'un <em>Episode IV</em> en <a href="https://fr.wikipedia.org/wiki/Art_ASCII">Ascii Art</a> <img src="/dotclear/themes/chestnut/smilies/smile.gif" alt=":-)" class="smiley" /><br /><br />
<ins>Overkill :</ins><br />
<img src="http://www.jesuisungeek.com/public/pictures/divers/.grab4-overkill_m.png" alt="Overkill" style="display:block; margin:0 auto;" title="Overkill, mai 2016" /><br />
Continuons dans l'<a href="https://fr.wikipedia.org/wiki/Art_ASCII">Ascii Art</a> avec <a href="http://artax.karlin.mff.cuni.cz/~brain/0verkill/" hreflang="en">Overkill</a> qui se présente comme un Doom-like en 2D et... en ASCII <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /> Tout y est, même la couleur. Alors, certes, la procédure d'installation est un poil complexe, mais une fois compilé, on redécouvre les FPS (euh, pardon, les TPS (<q>Third Person Shooter</q>) <img src="/dotclear/themes/chestnut/smilies/smile.gif" alt=":-)" class="smiley" /><br /><br />
<ins>JS/Linux :</ins><br />
<img src="http://www.jesuisungeek.com/public/pictures/divers/jslinux.png" alt="JS/Linux" style="display:block; margin:0 auto;" title="JS/Linux, mai 2016" /><br />
Alors, ça, j'adore !! <a href="http://bellard.org/jslinux/">JS/Linux</a> est, comme son nom l'indique, une implémentation de GNU/Linux en... JavaScript !! Du coup, on a un mini système Linux (avec Presse-papier intégré !) directement accessible via une page Web ! Si le temps vous en dit, vous pouvez également jeter un oeil aux sources pour voir un peu le travail qui a été abattu pour en arriver à ce résultat.<br /><br />
<ins>Mosh :</ins><br />
<a href="https://mosh.mit.edu/" hreflang="en">Mosh</a> est une petite application qui monte et qui, à mon sens, va bientôt devenir incontournable !! En effet, pour un peu qu'on ait pour habitude de contrôler ces petits serveurs persos de l'extérieur, il peut arriver qu'on ait besoin de s'y connecter dans les transports en commun... Avec... le <strong>réseau-qui-fait-peur !!!</strong> C'est là tout le génie de Mosh qui est un client SSH en... UDP !! Ainsi, peu importe la qualité du réseau, Mosh trouvera toujours un moyen de se connecter au serveur pour y faire executer les commandes en attente.</p>http://www.jesuisungeek.com/index.php?post/2016/05/05/Liens-pour-s-occuper-quand-on-s-ennuie#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/249Remonter les checks Icinga grâce à Rubyurn:md5:4c15f6d766824a599be4ed6a9d0930442016-02-15T11:51:00+01:002016-02-15T14:21:17+01:00Jean-Baptiste LangloisBidouillesdashingicingaruby<p><img src="http://www.jesuisungeek.com/public/pictures/divers/icinga-api-2.PNG" alt="icinga-api-2.PNG" style="display:block; margin:0 auto;" title="icinga-api-2.PNG, fév. 2016" />Classe Ruby permettant de remonter des informations grâce à l'interface REST de Icinga-Web</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/icinga-icon.png" alt="Logo Icinga" style="float:left; margin: 0 1em 1em 0;" title="Logo Icinga, fév. 2016" />Actuellement en plein développement de modules pour <a href="http://dashing.io/" hreflang="en" title="Dashing">Dashing</a>,on m'a demandé de créer un <em>widget</em> remontant le nombre de checks réalisés en recette et passant en orange ou rouge en fonction des erreurs pouvant être remontés par <a href="https://www.icinga.org/icinga/icinga-2/" hreflang="en" title="Icinga2">Icinga2</a>. Plus que créer un <em>widget</em>, le problème qui se pose à moi est la remonté d'informations à partir d'<a href="https://www.icinga.org/icinga/icinga-2/" hreflang="en" title="Icinga2">Icinga2</a>. Certes, il existe une API REST qui gère cela mais la versin d'<a href="https://www.icinga.org/icinga/icinga-2/" hreflang="en" title="Icinga2">Icinga2</a> dont je dispose est trop ancienne pour en bénéficier. Plutôt que de partir sur une mise à jour du système (On est en RedHat 5 <img src="/dotclear/themes/chestnut/smilies/hmm.gif" alt=":-/" class="smiley" /> ), j'ai préféré tabler sur l'existant et utiliser l'API disponible avec <a href="https://www.icinga.org/icinga/screenshots/icinga-web/" hreflang="en" title="Icinga-Web">Icinga-Web</a>.<br />
Néanmoins, même si l'usage de cette API est (moins ou plus) documenté, rien n'existe pour la récupération des données à partir de <a href="http://dashing.io/" hreflang="en" title="Dashing">Dashing</a>, <a href="http://rubyonrails.org/" hreflang="en" title="Ruby on Rails">Rails</a> ou tout autre application issue de Ruby (à l'opposé une fois encore, de l'API de <a href="https://www.icinga.org/icinga/icinga-2/" hreflang="en" title="Icinga2">Icinga2</a> <img src="/dotclear/themes/chestnut/smilies/sad.gif" alt=":-(" class="smiley" /> ). Du coup, j'ai décidé de développer moi-même ce type d'interface via une classe Ruby : <strong>IcingaWebParser.rb</strong> <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" />
<div class="dcnote noteclassic">
<p>L'usage de cette classe ne se limite bien sûr pas à <a href="http://dashing.io/" hreflang="en" title="Dashing">Dashing</a> et peut être utilisé dans n'importe quel programme Ruby. On peut, par exemple, imaginer un script calculant un pourcentage de disponibilité hebdomadaire en fonction de l'état renvoyé par Icinga.</p>
</div>
</p>
<h3>INSTALLATION</h3>
<p>Tout d'abord, il faut créer une clé d'authentification permettant d'accéder à l'API REST dirrectement via une URL. Pour ce faire, se connecter à l'interface d'administration d'Icinga Web et créer un nouvel utilisateur.<br />
<img src="http://www.jesuisungeek.com/public/pictures/divers/icinga-api-1.PNG" alt="icinga-api-1.PNG" style="display:block; margin:0 auto;" title="icinga-api-1.PNG, fév. 2016" /><br /></p>
<ul>
<li><ins>User name :</ins> Remplir avec un <em>username</em> sans espace ni caractères spéciaux</li>
<li><ins>Auth via :</ins> Choisir <strong>auth_key</strong></li>
<li><ins>Authkey for API :</ins> Cliquer sur l'icône de flèches bleues pour générer une clé. Cette clé (<em>Authkey</em>) sera nécessaire lors de la connexion avec la classe Ruby.</li>
</ul>
<p><img src="http://www.jesuisungeek.com/public/pictures/divers/icinga-api-2.PNG" alt="icinga-api-2.PNG" style="display:block; margin:0 auto;" title="icinga-api-2.PNG, fév. 2016" /><br /></p>
<ul>
<li><ins>Credentials :</ins> cocher l'identifiant <strong>appkit.api.access</strong></li>
<li>Cliquer sur <strong>Save</strong> pour créer l'utilisateur.<br /></li>
</ul>
<h3>UTILISATION</h3>
<p>Avant tout, ne pas oublier d'installer la Gem <q>rest-client</q>, utilisé par <strong>IcingaWebParser.rb</strong> pour se connecter à l'API d'<a href="https://www.icinga.org/icinga/screenshots/icinga-web/" hreflang="en" title="Icinga-Web">Icinga-Web</a>. L'exemple suivant récupérera le nom de services et d'hôtes dont l'état est <strong>CRITICAL</strong>.</p>
<pre>
irb(main):001:0> require './lib/icingawebparser.rb'
=> true
irb(main):002:0> i = IcingaWebParser.new "icinga_url", "auth_key"
=> #<IcingaWebParser:0x007fa3629ec548 @url="icinga_url", @authkey="auth_key">
irb(main):003:0> i.query("service", "AND(SERVICE_CURRENT_STATE|=|2;0)", ["SERVICE_NAME", "HOST_NAME"])
=> [{:SERVICE_NAME=>"Oracle Process", :HOST_NAME=>"server1"}, {:SERVICE_NAME=>"Logs JVM", :HOST_NAME=>"server2"}]
</pre>
<p><div class="dcnote noteclassic">
<p>Les arguments pour créer une nouvelle instance sont :</p>
<ul>
<li>L'URL du serveur Icinga Web</li>
<li>La <em>Auth key</em> précédemment créée</li>
</ul>
<p></p>
</div>
La classe est attachée à ce post. La documentation complète de la classe est ici : <a href="http://www.jesuisungeek.com/public/files/etc/icingawebparser/IcingaWebParser.html">IcingaWebParser.html</a><br /><br />
<ins>Icinga utilisé :</ins> <strong>2.3.4</strong><br />
<ins>Icinga-Web utilisé :</ins> <strong>1.13.0</strong><br />
<ins>Pour en savoir plus :</ins> <strong><a href="https://wiki.icinga.org/display/Dev/Icinga-Web+REST+API">Icinga Wiki</a></strong></p>http://www.jesuisungeek.com/index.php?post/2016/02/15/Remonter-les-checks-Icinga-gr%C3%A2ce-%C3%A0-Ruby#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/248Partage si tu aimes çaurn:md5:b6e83c83179b24f73cf778a87bd1df2e2016-02-14T07:56:00+01:002016-02-15T14:23:34+01:00Jean-Baptiste LangloisBidouillesblogdotclear<p>Le retour de la vengeance du geek en retard !</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/dotclear-2-b6c7a.png" alt="Logo dotClear" style="float:left; margin: 0 1em 1em 0;" title="Logo dotClear, fév. 2016" /> Salut à tous !<br /><br />
Ca fait un bail, pas vrai ? Ca fait genre une siècle que j'ai pas posté ici, mais ça ne m'a pas empêché de bien travailler <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" /> Du coup, j'ai genre une tonne de messages en attente à poster, ici... J'ai la motivation ; gageons qu'elle ne m'abandonne pas en chemin <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /><br />
A ce titre, je souhaitais depuis un certain temps rajouter des icônes de partage en bas des posts comme en possède la majorité des blogs ou sites de news et n'ayant pas trouvé de plugins équivalent sur dotClear, j'avais en projet de développer mon propre plugin. Or, dehors mon hibernation, je me suis aperçu q'un plugin qui faisait <strong>exactement</strong> ce que je cherchais, était sorti : <em><a href="http://open-time.net/post/2015/07/22/Plugin-socialShare-033-pour-Dotclear" hreflang="fr" title="socialShare">socialShare</a></em>. Très simple d'usage, peu gourmand, il était parfait... sauf que je voulais ajouter un lien de partage vers <a href="https://www.linkedin.com/in/jean-baptiste-langlois-9398b12" hreflang="fr" title="LinkedIn">LinkedIn</a>. Du coup, j'ai modifié ce plugin afin qu'il permette ce partage également.<br />
Vous trouverez, ainsi, le patch pour ajouter la possibilité de partage vers LinkedIn attaché à ce post (valable pour la version 0.3.3 de <a href="http://open-time.net/post/2015/07/22/Plugin-socialShare-033-pour-Dotclear" hreflang="fr" title="socialShare">socialShare</a>).<br />
Pour l'appliquer, c'est simple : Déposer le fichier <em>plugin-socialShare-0.3.3-linked.patch</em> au même niveau que le répertoire <em>socialShare/</em> (de l'archive ZIP du plugin socialShare) et tapez la commande :</p>
<pre>
patch -p0 < plugin-socialShare-0.3.3-linkedin.patch
</pre>http://www.jesuisungeek.com/index.php?post/2016/02/14/Partage-si-tu-aimes-%C3%A7a#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/247Pourcentage d'avancementurn:md5:67816720986a6b18bdd5400e9b398c482015-01-19T14:51:00+01:002015-01-19T14:53:25+01:00Jean-Baptiste LangloisGeekeries<p>Pour ceux qui ont dû mal à estimer leur avancement dans le travail</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/.progress_bars_s.png" alt="Barres de progression" style="float:left; margin: 0 1em 1em 0;" title="Barres de progression, janv. 2015" /> Qui n'a jamais été chargé de donner son "degré d'avancement" dans les charges quotidiennement effectué dans le travail ? Bien, je cromprends qu'il est vital de pouvoir ressentir, à travers un indicateur simple, l'avancée d'un projet, mais pour l'exécutant... 30%? 35%? 37%? C'est difficile à dire, non ? D'autant que, les réunions d'avancement s'enchaînant, on a parfois du mal à se rappeler du dernier pourcentage donné et qu'on risque donc les foudres du supérieur hiérachique, si on doit un pourcentage d'avancement inférieur à la précédente réunion.<br />
C'est donc pour cela que j'ai créé ce petit formulaire qui à partir de différents indicateurs, peut générer un <strong>pourcentage d'avancement</strong> aléatoire mais crédible et ménageant le chef d'équipe <img src="/dotclear/themes/chestnut/smilies/cool.gif" alt="8-)" class="smiley" /> Enjoy <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" /> <br /></p>
<script type="text/javascript">
function calculate() {
var miniv = document.forms["planning"].elements["miniVal"].value;
var maxiv = document.forms["planning"].elements["maxiVal"].value;
var previousv = document.forms["planning"].elements["previousVal"].value;
miniv = Math.max(previousv, miniv);
if (maxiv > 100) {
maxiv = 100;
}
if (miniv < 0) {
miniv = 0;
}
var presentv = Math.floor((Math.random() * ( maxiv - miniv )) + miniv);
document.forms["planning"].elements["miniVal"].value = miniv;
document.forms["planning"].elements["maxiVal"].value = maxiv;
document.forms["planning"].elements["previousVal"].value = presentv;
document.forms["planning"].elements["presentVal"].value = presentv;
}
</script>
<form id="planning">
<table>
<tr>
<td>Pct en deça duquel le boss sera furieux : </td>
<td><input type="text" name="miniVal" value="0" size="2" />%</td>
</tr>
<tr>
<td>Pct au dela duquel le boss sera soupçonneux : </td>
<td><input type="text" name="maxiVal" value="100" size="2" />%</td>
</tr>
<tr>
<td>Pct d'avancement à la dernière réunion : </td>
<td><input type="text" name="previousVal" value="0" size="2" />%</td>
</tr>
<tr>
<td><b>Pct d'avancement actuel :</b> </td>
<td><input type="text" name="presentVal" value="" size="2" readonly="true" />%</td>
</tr>
</table>
<input type="button" onclick="calculate();" value="Calculer" />
</form>
http://www.jesuisungeek.com/index.php?post/2015/01/19/Pourcentage-d-avancement#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/246Bonne Année 2015 !urn:md5:3fafc6b994eb310cda7fdccdc59a23bd2015-01-05T16:44:00+01:002016-02-15T14:20:07+01:00Jean-Baptiste Langlois3615 Ma viechiyokodessinlinux<p>Ah ah! Il ne sera pas dit que ce blog n'hébergerai pas, au moins une fois, mes voeux du nouvel An !</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/mini-chiyoko.png" alt="mini-chiyoko.png" style="float:left; margin: 0 1em 1em 0;" title="mini-chiyoko.png, janv. 2015" />Ah ah! Il ne sera pas dit que ce blog n'hébergera pas, au moins une fois, mes voeux du nouvel An ! Non, mais ! Mais bon, voilà qui est fait ! Il ne faudra dès lors plus s'attendre à ce que je me livre à ce genre d'exercices. Non, mais, c'est vrai, quoi ? Annoncer des résolutions qu'on ne tiendra pas ? Se baffrer à en être malade le lendemain ? Picoler ? (Ah, quoique, sur ce dernier argument, ça vaut peut-être le coup <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> ).<br />
Bref, je souhaite, je souhaite. D'où acte. Bonne année. Voilà qui est dit...<br />
Mais à vrai dire, si je poste ce message sur mes voeux en cette belle journée du 5 janvier (Oui, pas la fête non plus, j'avais la flemme de faire ça le 1er...), c'est surtout pour partager le dernier dessin de ma femme qui est justement de saison, avec un petit plus geek (Bah oui, sinon je l'aurai pas posté ici <img src="/dotclear/themes/chestnut/smilies/tongue.gif" alt=":-P" class="smiley" /> ).<br />
<a href="http://www.chiyoko-langlois.com" hreflang="fr" title="Bonne année 2015, les pingouins !!"><img src="http://www.jesuisungeek.com/public/pictures/divers/.bonne-anne-2015-linux_m.png" alt="Bonne Année 2015" style="display:block; margin:0 auto;" title="Bonne Année 2015, janv. 2015" /></a><br />
Et une plus qui a succombé au libre, c'est pas mignon ? <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" />
Si vous voulez davantage de jolis dessins de ce genre, je vous invite à vous rendre ici : <a href="http://www.chiyoko-langlois.com" hreflang="ja" title="Promenade avec Taro">Promenade avec Taro</a>.</p>http://www.jesuisungeek.com/index.php?post/2015/01/05/Bonne-Ann%C3%A9e-2015-%21#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/245Comprendre les micro-contrôleurs - EPFLurn:md5:4f9c1c31d4444c17a960887f56d251e12014-11-08T07:10:00+01:002014-11-08T07:12:13+01:00Jean-Baptiste Langlois3615 Ma vie<p>Formation à distance et gratuitement via l'Ecole Polytechnique Fédérale de Lausanne</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/logo-epfl-front.png" alt="logo-epfl-front.png" style="float:left; margin: 0 1em 1em 0;" title="logo-epfl-front.png, nov. 2014" /> Salut à tous, ça fait longtemps, pas vrai ? En fait, je n'occupais durant tout ce temps du blog de ma femme (ouverture prochaine, j'en reparlerai) et comme j'ai fait mes tests de layout comem un kéké, j'ai à moitié pourrie mon installation de Dotclear (ce qui fait que ce site a été, un temps, inaccessible).<br />
J'aimerai parler aujourd'hui du cours que je suis via <a href="http://www.coursera.org" hreflang="fr" title="Coursera">Coursera</a> qui regroupe tous les cours proposés par des universités en ligne à travers le monde ; du coup, y'a à boire et à manger avec des cours s'étalant aussi bien de <em>Chinese for beginners</em> à <em>Plannification urbaine des villes africaines</em> ou encore <em>Ce que sait une plante</em>. C'est vaste et bien que la grande majorité de ces cours sont en anglais, il n'est pas difficile de trouver un cours intéressant dans sa langue.<br />
C'est le cas du cours auquel je me suis inscrit <em><a href="https://www.coursera.org/course/microcontroleurs" hreflang="fr" title="Comprendre les microcontrôleurs">Comprendre les microcontrôleurs</a></em>. Ce cours, très bien fait, présente le fonctionnement bas-niveau de nos ordinateurs avec une bonne part aux travaux pratiques via l'acquisition d'un microcontrôleur (je ne présente pas l'<a href="http://www.arduino.cc/" hreflang="en" title="Arduino">Arduino</a>, on est d'accord, hein) permettant d'appliquer pratiquement les notions enseignées dans les cours. C'est un cours très accessible (trop, peut-être ?) au départ, mais ça accélère vite, par la suite. En plus :</p>
<ul>
<li>Pour 70% de réussite aux examens (eux aussi gratuit), on obtient une attestation de réussite</li>
<li>Pour 70% de réussite , on obtient une mention !!</li>
</ul>
<p>Et ça, c'est cool sur le CV <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /></p>http://www.jesuisungeek.com/index.php?post/2014/11/08/Comprendre-les-micro-contr%C3%B4leurs-EPFL#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/244Temporisation des sous-titresurn:md5:47d328f93c7d05ac5820f8fce7aeca292014-05-09T13:56:00+02:002014-05-09T14:02:25+02:00Jean-Baptiste LangloisBidouillesbashlinuxmacsous-titre<p>Pour les amateurs non-anglophones de séries américaines...</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/Gnome_Subtitles_Icon.png" alt="Gnome_Subtitles_Icon.png" style="float:left; margin: 0 1em 1em 0;" title="Gnome_Subtitles_Icon.png, mai 2014" />Récemment, ma femme m'a demandé quels étaient les séries à la mode en Occident. Comme elle est fan de tout ce qui est fantastique, je lui ai proposé de regarder <em><a href="http://en.wikipedia.org/wiki/Game_of_Thrones" hreflang="fr" title="Game of Thrones">Game Of Thrones</a></em> (Bon, alors, j'avoue, elle n'a que moyennement apprécié les viols et autres décapitations <img src="/dotclear/themes/chestnut/smilies/tongue.gif" alt=":-P" class="smiley" /> ). Toutefois, afin que ce soit plus facile à comprendre pour elle, j'ai décidé de chercher des sous-titres en japonais (<strong>N.B.</strong>: Monsieur Hadopi, si tu me lis, je parle ici des épisodes de <em>Game Of Thrones</em> en DVD que j'ai acheté <img src="/dotclear/themes/chestnut/smilies/whistle.gif" alt=":siffle:" class="smiley" /> Tu peux toujours venir vérifier, mais n'oublie pas d'apporter le pop-corn <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> ). J'ai finalement pu trouver mon bonheur sur <a href="http://www.podnapisi.net/fr/ppodnapisi/search?sJ=11" hreflang="en" title="Podnapisi">Podnapisi</a>. A propos, il y a assez peu de sites proposant des sous-titres en japonais donc je vais rajouter cette page en lien.<br />
Toutefois, tous les sous-titres télécharger sont décalés par rapport aux épisodes que je regarde (la faute au fait que je n'ai pas les <em>Previously on Game of Thrones</em> sur ma version DVD... Du coup, c'est bien gentil mais... Strictement inutilisable !<br />
Du coup, plus que de tous réencoder à la main, j'ai décidé de créer un script qui modifie la temporisation des sous-titres ; ce script est très simple dans son fonctionnement : il a pour but de modifier toutes les données de l'entrée standard (au format <a href="http://fr.wikipedia.org/wiki/SubRip" hreflang="fr" title="SRT">SRT</a>) en les augmentant ou les diminuant d'une certaine valeur. Ainsi l'invocation est très simple :</p>
<pre>
[mithweth@himiko ~]$ retime_sub.sh -1:20 < sous_titres.srt
</pre>
<p><em>Diminue le moment d'apparition des sous-titres de 1 minute et 20 secondes (ainsi, un sous-titre devant apparaître à 3 minutes 30 seondes, apparaîtra à 2 minutes 10)</em></p>
<pre>
[mithweth@himiko ~]$ retime_sub.sh +1:0:5 < sous_titres.srt
</pre>
<p><em>Augmente le moment d'apparition des sous-titres de 1 heure et 5 secondes</em></p>
<pre>
[mithweth@himiko ~]$ retime_sub.sh -12 < sous_titres.srt
</pre>
<p><em>Diminue le moment d'apparition des sous-titres de 12 secondes</em></p>http://www.jesuisungeek.com/index.php?post/2014/05/09/Temporisation-des-sous-titres#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/239DOT Generatorurn:md5:dfabf9bedc16f86eac58f211667e67f82014-04-27T15:30:00+02:002014-05-09T14:22:06+02:00Jean-Baptiste LangloisProjetsbashcontrolmgraphviz<p>Petit script permettant de créer des graphes plus lisibles que le champ des conditions de Control-M</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/.graphviz_s.jpg" alt="Graphviz - Exemple de graphe" style="float:left; margin: 0 1em 1em 0;" title="Graphviz - Exemple de graphe, avr. 2014" />Ma tâche actuelle au boulot consiste à mettre à jour une chaîne de jobs Control-M en fonction des mises à jour de l'applicatif maison. Toutefois, n'ayant pas accès à Control-M, je dois mettre à jour le fichier d'exportation Control-M qui sera, par la suite, réinjecter dans le serveur. Je n'ai donc aucune autre interface qu'un document austère listant tous les groupe de jobs possibles et ce sur plus de 800 lignes. Bien sûr, les chaînes de dépendances sont telles que si je me plante, c'est tout le système qui part à vau-l'eau. Donc, plutôt que de passer trois heures par lignes pour vérifier toutes les dépendances, j'ai préféré créer des graphes de dépendances. Pour aller plus vite. Mais comme il y avait encore un gain à faire, j'ai automatisé cette tâche. C'est là où intervient le script dont je parle aujourd'hui : à partir d'un export de la chaîne Control-M au format CSV, ce script crée tous les graphes de dépendances des différents groupes de jobs.<br />
Ce que je sous-entend par là, c'est que ce script prend en entrée un fichier CSV généré par Control-M pour produire autant de fichiers de groupes de job que nécessaires et ces fichiers au <a href="http://fr.wikipedia.org/wiki/DOT_%28langage%29" hreflang="fr" title="format DOT">format DOT</a> pourront être utilisé par des ressources comprenant ce type de fichiers (au hasard, <a href="http://www.graphviz.org/" hreflang="en" title="Graphviz">Graphviz</a> <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> ). De plus, si Graphviz est déjà installé sur la machine où est exécuté ce script (<code>dot_gen.sh</code> de son petit nom), il est possible de générer directement un fichier PNG ou JPEG.<br />
Par exemple, prenons cette chaîne-ci :<br />
<a href="http://www.jesuisungeek.com/public/pictures/real/excel-controlm.png" title="Fichier d'import Excel - Control-M"><img src="http://www.jesuisungeek.com/public/pictures/real/.excel-controlm_m.jpg" alt="Fichier d'import Excel - Control-M" title="Fichier d'import Excel - Control-M, avr. 2014" /></a><br />
Bien que courte, c'est déjà compliqué à lire alors, il faut imaginer des groupes de 300 jobs et pleurer <img src="/dotclear/themes/chestnut/smilies/ouch.gif" alt=":-s" class="smiley" /> Bref, à l'aide de <code>dot_gen.sh</code> et des arguments qui vont bien :</p>
<pre class="brush: bash">
dot_gen.sh --label 4 1 5 < fichier_entree.csv
</pre>
<p>Où <code>--label</code> indique la colonne des intitulés et où 1 et 5 sont respectivement les colonnes des noms de jobs et des conditions à leur exécution, on obtient le fichier suivant :</p>
<pre class="brush">
digraph JDEMA {
JDEMA000 [label="Début du démarrage"]
JDEMA999 [label="Fin du démarrage"]
JDEMAAA [label="Application A"]
JDEMAAB [label="Application B"]
JDEMAAC [label="Application C"]
JDEMAAD [label="Application D"]
JDEMATA [label="Test Appli A"]
JDEMATB [label="Test Appli B"]
JDEMATC [label="Test Appli C"]
JDEMATD [label="Test Appli D"]
JDEMA000 -> JDEMA999
JDEMATD -> JDEMA999
JDEMA000 -> JDEMAAA
JDEMA000 -> JDEMAAB
JDEMATA -> JDEMAAC
JDEMATB -> JDEMAAC
JDEMATC -> JDEMAAD
JDEMAAA -> JDEMATA
JDEMAAB -> JDEMATB
JDEMAAC -> JDEMATC
JDEMAAD -> JDEMATD
}
</pre>
<p>Celui-ci peur-être directement géré en PNG via l'option <code>--png</code> à <code>dot_gen.sh</code> où alors, <em>a posteriori</em>, en utilisant Graphviz :</p>
<pre class="brush: bash">
dot -Tpng JDEMA.dot -o JDEMA.png
</pre>
<p>On obtient le graphe suivant :<br />
<a href="http://www.jesuisungeek.com/public/pictures/real/JDEMA.png" title="Graph de dépendance - ControlM"><img src="http://www.jesuisungeek.com/public/pictures/real/.JDEMA_m.jpg" alt="Graph de dépendance - ControlM" title="Graph de dépendance - ControlM, avr. 2014" /></a><br />
Avouez que c'est quand bien beaucoup plus facile à lire que l'original au format Excel <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> <br />
<br />
<strong>N.B. :</strong> Pour avoir accès à toutes les options de <code>dot_gen.sh</code>, lancer le script sans aucun argument pour faire apparaitre l'aide en ligne.</p>http://www.jesuisungeek.com/index.php?post/2014/04/27/Grapher-comme-un-pro-sur-Control-M#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/235Retrouver la version de son ESXurn:md5:a521c3480d6313f398cdba0179c9f38b2014-04-07T14:29:00+02:002014-04-07T14:29:00+02:00Jean-Baptiste LangloisBidouillesperlpuppetRed Hatrubyvmware<p>Comment connaitre la version de son ESX pour déterminer la version des vmware-ools SANS installer les vmware-tools ?</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/vmware-workstation.png" alt="WMWare Workstation - Logo" style="float:left; margin: 0 1em 1em 0;" title="WMWare Workstation - Logo, fév. 2013" />VMWare, c'est bien! Avec cela, on peut tester diverses situations ou projets (comme par exemple, <a href="https://www.reactos.org/fr" hreflang="fr" title="ReactOS">ReactOS</a> <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> ) sans forcément flinguer son système. Par contre, la maintenace de ce type de système tend à devenir assez laborieux pour peu que l'on doive gérer les mises à jour système (ne serait-ce pour conserver le support constructeur). C'est pour cela qu'on utilise les <q>vmware-tools</q>, ces outils bien pratiques qui permettent la gestion de l'ESX à partir d'une machine cliente. Seulement voilà ; ces outils étant très spécifiques, il est <strong>nécessaire</strong> d'installer les <q>vmware-tools</q> qui correspondent bien à la version de son ESX installé (si vous avez du temps et du pop-corn à portée de main, installer donc les <q>vmware-tools</q> d'un ESX 4.0 sur une machine géré par un ESX 5.1, c'est fendard ! <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /> ). Là où ça devient franchement folklo, c'est lors d'un déploiement automatisé. En effet : plus votre parc est grand, plus il est probable d'avoir des versions différentes d'ESX. Dans ce cas, on arrive au paradoxe de l'oeuf et de la poule : une fois la VM <em>guest</em> installée, pour connaitre la version des <q>vmware-tools</q> à installer, il faudrait connaître la version de l'ESX mais cette information n'est accessible qu'à traverser les <q>vmware-tools</q>... Du coup, comment faire ?<br />
Par chance, à travers, les dizaines d'informations que nous fournis <q>dmidecode</q>, il y en a une qui va nous sauver :<br />
En effet, si on regarde attentivement le champ <em>Address</em> de la commande <q>dmidecode -t 0</q> sur une VM, on s'aperçoit que l'adresse est toujours identique, <strong>en fonction de la version de l'ESX hôte !</strong> C'est donc par cette information qu'on va pouvoir passer. On obtient donc le script ci-dessous (j'ai testé différentes VM sur différents ESX pour obtenir les valeurs indiquées) :</p>
<pre class="brush: shell">
#!/bin/sh
case $( dmidecode | grep -A4 "BIOS Information" | grep Address | awk '{ print $2 }' ) in
"0xE8480" ) echo "ESX 2.5" ;;
"0xE7C70" ) echo "ESX 3.0" ;;
"0xE7910" ) echo "ESX 3.5" ;;
"0xEA550" ) echo "ESX 4U1" ;;
"0xEA2E0" ) echo "ESX 4.1" ;;
"0xE72C0" ) echo "ESX 5" ;;
"0xEA0C0" ) echo "ESX 5.1" ;;
*) echo "Unknown version: "; dmidecode | grep -A4 "BIOS Information";;
esac
</pre>
<p>Et voilà <img src="/dotclear/themes/chestnut/smilies/cool.gif" alt="8-)" class="smiley" /> Bon, bien sûr , même si c'est fonctionnel, ce n'est pas le top d'utiliser ce type de script durant la <em>post-install</em> (sans parler que c'est difficile de le réutiliser). C'est pour cela que je fournis également la version <strong>facter</strong> afin de pouvoir l'utiliser au sein d'une installation automatisé avec Puppet et son copain Foreman</p>
<pre class="brush: ruby">
# /usr/lib/ruby/site_ruby/1.8/facter/esxversion.rb
Facter.add("esxversion") do
confine :kernel => :Linux
setcode do
case Facter::Util::Resolution.exec('dmidecode | grep -A4 "BIOS Information" | grep Address | cut -d x -f 2')
when "E8480"
"ESX 2.5"
when "E7C70"
"ESX 3.0"
when "E7910"
"ESX 3.5"
when "EA550"
"ESX 4U1"
when "EA2E0"
"ESX 4.1"
when "E72C0"
"ESX 5"
when "EA0C0"
"ESX 5.1"
else
"Unknown"
end
end
end
</pre>
<p>Une fois copié dans le répertoire qui va bien (ou <a href="http://docs.puppetlabs.com/guides/custom_facts.html" hreflang="en">déployé par puppet</a>, en placant le <em>fact</em> ci-dessus dans le répertoire <q>facter</q> du projet), le script devrait renvoyer la version correcte de l'ESX hôte s'il est appelé par un : <strong>facter esxversion</strong></p>http://www.jesuisungeek.com/index.php?post/2014/04/07/Retrouver-la-version-de-son-ESX#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/234暗記は意味?urn:md5:8a9c1adfcea3bf84356f3c11ae8cae572013-07-22T11:50:00+02:002014-05-09T06:05:36+02:00Jean-Baptiste LangloisBidouillesankidictionnaireimiwajaponaistraduction<p>Le premier billet polyglotte dans l'Histoire de ce blog ! Santé !</p> <p>L'apprentissage des langues étrangères repose avant tout sur les bons outils. Dans le cas de l'apprentissage du Japonais à partir du Français (ou du Français à partir du Japonais), ces outils sont au nombre de deux :</p>
<ul>
<li><a href="http://imiwa.pierrephi.net/" hreflang="fr" title="IMIWA?">IMIWA?</a> qui est un dictionnaire franco-japonais pour iOS</li>
<li><a href="https://ankiweb.net" hreflang="en" title="Anki">Anki</a> qui permet l'édition et la création de <em>Flashcards</em> pour potasser son vocabulaire</li>
</ul>
<p>Sans plus détaillé les qualités intrinsèques de chaque de ces deux programmes (il y a les liens ci-dessus pour cela), notons que <strong>IMIWA?</strong> est un outil de référence complet, et que <strong>Anki</strong> permet d'apprendre vite un vocabulaire... une fois qu'il est bien configuré. Car voilà le problème : comme d'habitude, le plus grand point faible de ce type de logiciels se situe entre la chaise et le clavier. En effet, même si <strong>Anki</strong> permet d'étudier à peu près n'importe quoi, il faut tout d'abord saisir ses propres <em>Flashcards</em>. Certes, il y a des <em>decks</em> de <em>Flashcards</em> déjà prêt à l'emploi sur le site officiel mais, d'expérience, pour 1000 étudiants, il y aura 1000 decks différents.<br />
Là, où le lien peut se faire avec <strong>IMIWA?</strong>, c'est que celui-ci, via des favoris et un historique référence les dernières consultations ainsi que les mots les plus consultés... ceux précisément qu'on aimerait bien étudier !<br />
Or, et, c'est tout le point de ce post, j'ai créé un moyen d'exporter la liste des favoris et d'histoirique de <strong>IMIWA?</strong> pour créer un nouveau <em>deck</em> pour <strong>Anki</strong> et ainsi obtenir le <em>deck</em> le plus pertinent possible !!<br />
<br /></p>
<ul>
<li>Dans <strong>IMIWA?</strong>, choisir l'onglet <em>Historique</em> ou <em>Signets</em></li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa1.PNG" title="imiwa1.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa1_s.jpg" alt="imiwa1.PNG" title="imiwa1.PNG, juil. 2013" /></a></p>
<ul>
<li>Cliquer sur la flèche <em>Partager</em> et sélectionner <em>Exporter</em></li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa2.PNG" title="imiwa2.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa2_s.jpg" alt="imiwa2.PNG" title="imiwa2.PNG, juil. 2013" /></a>
<a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa3.PNG" title="imiwa3.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa3_s.jpg" alt="imiwa3.PNG" title="imiwa3.PNG, juil. 2013" /></a></p>
<ul>
<li>Sélectionner l'option <q>Champs séparés par tabulations</q>. Une fenêtre s'ouvre alors pour envoyer un mail avec un fichier attaché. S'envoyer ce mail à soi-même pour récupérer ce fichier attaché.</li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa4.PNG" title="imiwa4.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa4_s.jpg" alt="imiwa4.PNG" title="imiwa4.PNG, juil. 2013" /></a></p>
<ul>
<li>A partir d'un navigateur Web, charger le fichier attaché au mail sur cette page, puis cliquer sur <em>Export</em>. Le navigateur propose de télécharger un fichier CSV.</li>
<li>Importer le fichier CSV dans l'application Anki sur votre ordinateur de bureau et synchroniser vers <strong>Ankiweb</strong>.</li>
</ul>
<p><br />C'est tout ! Vous pouvez dès à présent synchroniser <strong>Anki Mobile</strong> avec les nouvelles données présentes sur <strong>Ankiweb</strong>. Bien sûr, il aurait été plus simple de l'importer directement à partir du script ci-dessous mais, comme le dit le site officiel : <q>At this time, it is not possible to add shared decks directly to your AnkiWeb account.</q><br />
<br />
ちゃんと外国語を勉強するのに、正しい道具が必要なんですけど、日本語を勉強したいフランス人(または、フランス語を勉強したい日本人)には二つあります:</p>
<ul>
<li>iOSに<a href="http://imiwa.pierrephi.net/" hreflang="fr" title="IMIWA?">IMIWA?</a>と言う日仏辞典</li>
<li>語彙を習えるようにフラッシュカードが作れる<a href="https://ankiweb.net" hreflang="en" title="Anki">Anki</a>と言うソフト</li>
</ul>
<p>その二つのソフトの使い方を言わずに(そのためにリンクがあるんだ)、両方強いソフトだけど、設定しておきます。そうです。相変わらず、そういうソフトの不利はソフトじゃなくて、席からキーボードの間にいる。確か、Ankiで何を勉強してもいいけど、自分のフラッシュカードを入れておきなければいけません。もちろん、ホームページにフラッシュカード練習リストがあるけど、みんなの習い方が違います。<br />
IMIWA?に関係があるポイントはブックマークとヒストリーで、最後の調べた言葉と一番探してる言葉は知っています。ぴったり勉強したい言葉なんです!<br />
それで、Ankiにフラッシュカード練習リストを作れるように、IMIWA?のブックマークとヒストリーのリストを輸出仕方を発明した。<br />
<br /></p>
<ul>
<li>IMIWA?で、<em>Bookmarks</em>か<em>History</em>と言うタッブを選んで下さい</li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa1.PNG" title="imiwa1.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa1_s.jpg" alt="imiwa1.PNG" title="imiwa1.PNG, juil. 2013" /></a></p>
<ul>
<li><em>Share</em>と言う矢印にクリックして、<em>Export</em>を選んで下さい。</li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa2.PNG" title="imiwa2.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa2_s.jpg" alt="imiwa2.PNG" title="imiwa2.PNG, juil. 2013" /></a>
<a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa3.PNG" title="imiwa3.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa3_s.jpg" alt="imiwa3.PNG" title="imiwa3.PNG, juil. 2013" /></a></p>
<ul>
<li>「Tab separated values」と言うオプションを選んで。加え付けるファイルがあるメールを送るのに、新しいウインドーが開いています。自分に送って下さい。</li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa4.PNG" title="imiwa4.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa4_s.jpg" alt="imiwa4.PNG" title="imiwa4.PNG, juil. 2013" /></a></p>
<ul>
<li>ブローザーで、そのページに加え付けたファイルを載せて、<em>Export</em>と言うボタンにクリックして。ブローザーはCSVファイルをダウンロードするのを頼みます。</li>
<li>Ankiと言うデスクトップアプリでCSVファイルを輸入して、Ankiwebにシンクロして下さい。</li>
</ul>
<p><br />それだけです!今から、Ankiwebのある新しいデータでAnki Mobileにシンクロ出来ます。確かに、直接にしたのプログラムで輸入するのが一番簡単ですけど、ホームページは言うとおりに:<q>At this time, it is not possible to add shared decks directly to your AnkiWeb account.</q><br /></p>
<hr />
<form action="http://www.jesuisungeek.com/public/files/etc/imiwa_export.php" enctype="multipart/form-data" method="post">
<table style="width:490px;">
<tr><td>Fichier à import/File to import/乗せるファイル</td><td><input type="file" name="imiwa_import" /></td></tr>
<tr><td>Insérer les kana/Insert kana/仮名を加える</td><td><input type="checkbox" name="kana" /></td></tr>
</table>
<input type="submit" name="submit" value=" Export " />
</form>
http://www.jesuisungeek.com/index.php?post/2013/07/22/anki-wa-imi#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/233Mots de japonaisurn:md5:e98ec2f13fbbca0951d5cbf6df0fd4922013-07-12T15:27:00+02:002013-07-12T15:27:00+02:00Jean-Baptiste Langlois3615 Ma viehumourjapon<p>Les petits mots gentils avec lesquels ma copine décrit sa vie en France</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/.400px-Japop_s.jpg" alt="Le Japon" style="float:left; margin: 0 1em 1em 0;" title="Le Japon, juil. 2013" /><ins>Les petits mots gentils de ma copine</ins><br /><br />Depuis qu'elle vit en France, j'ai remarqué que ma copine faisait usage parfois de très bons traits d'esprit que je partage ici. Comme la plupart font appel à un jeu de mots avec le japonais, j'essayerai de l'expliquer au mieux. <br />
Maintenant, même si je fais de mon mieux pour m'en souvenir, je ne suis pas exhaustif, ce qui est triste car ça fuse <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" /> <br /><br />
J'ai rangé les messages par thèmes ; peut-être diffuserais-je une liste de <em>fortune</em> quand j'en aurais assez <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> <br />
<br /><br />
<strong>Technologie :</strong><br /></p>
<ul>
<li><q>C'est normal que notre technologie vous fasse rêver. Regarde le cinéma, par exemple : Nous avons des explosions, du faux sang, des combats spatiaux alors que le film français le plus avancé technologiquement, c'est <em>The Artist</em>...</q></li>
</ul>
<p><br />
<strong>Politique :</strong><br /></p>
<ul>
<li><q>Pauvre Nicolas, il me fait penser à un singe orphelin</q> En Japonais, <em>singe</em> se dit <q>sar</q>(猿), et <em>orphelin</em> se dit <q>koji</q>(孤児) : <strong>sarkoji</strong></li>
</ul>http://www.jesuisungeek.com/index.php?post/2013/07/12/Mots-de-japonais#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/232ASS2SRTurn:md5:ab57c2a0cc183bf12bb0919a7ddc875a2013-07-11T13:23:00+02:002013-07-12T14:28:43+02:00Jean-Baptiste LangloisBidouillesconversionperlscriptsous-titre<p>Conversions de sous-titres du format SubStation Alpha vers le format SRT</p> <p>Recement j'ai converti ma copine à <a href="http://fr.wikipedia.org/wiki/Doctor_Who" hreflang="fr" title="Doctor Who">Doctor Who</a> <img src="/dotclear/themes/chestnut/smilies/cool.gif" alt="8-)" class="smiley" /> <br />
Alors, certes, c'est une bonne série, mais c'est quand même plus simple de la regarder dans le texte. Je me suis donc mis à la recherche de sous-titres japonais à appliquer sur le rip de mon DVD VF. Et j'ai trouvé... au format <a href="http://fr.wikipedia.org/wiki/SubStation_Alpha" hreflang="fr" title="SubStation Alpha">ASS</a> <img src="/dotclear/themes/chestnut/smilies/ouch.gif" alt=":-s" class="smiley" /> Alors, certes, le <strong>ASS</strong> propose des options sympas, des couleurs, la possibilité d'avoir une position absolue des sous-titres... Sauf que... C'est très très mal supporté, notamment par ma <a href="http://adsl.sfr.fr/internet/" hreflang="fr">NeufBox Evolution</a>, qui ne gère que le <a href="http://fr.wikipedia.org/wiki/SubRip" hreflang="fr" title="SubRip">SRT</a>. Du coup, j'ai pas vraiment eu le choix et j'ai écrit un converteur de fichiers ASS vers SRT (ce qui est bien plus rapide que de réécrire tous les sous-titres à la main, n'est-ce pas ? <img src="/dotclear/themes/chestnut/smilies/whistle.gif" alt=":siffle:" class="smiley" /> ).<br />
Je partage donc mon script ici en espérant qu'il serve à d'autres personnes qui, comme moi, se trouvent bloqués avec un format ASS qu'ils ne peuvent pas lire (le fichier est joint à ce post).<br />
L'usage est relativement simple :</p>
<pre>
# ass2srt.pl <fichier_a_convertir.ass> <fichier_converti.srt>
</pre>
<p>Et comme le format ASS est une évolution du format SSA et bien, ça arche aussi !! Que demande le peuple <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /></p>http://www.jesuisungeek.com/index.php?post/2013/07/11/ASS2SRT#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/231Localisation de projets Ruby on Railsurn:md5:418f517cb44c83e9bdcbd3baa1c687172013-07-05T16:01:00+02:002013-07-12T14:29:59+02:00Jean-Baptiste LangloisBidouillesbashi18nrailsrubyscripttraduction<p>Petit script pour simplifier l'écriture de ses fichiers de localisation</p> <p>Toujours la tête plongée dans mon projet Ruby On Rails actuel (<em>stay tuned !</em> <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" /> ), j'imagine parfois l'avenir où mon application sera <strong>tellement</strong> connues qu'il faudra la localiser en <em>angliche</em> et en <em>日本語</em> (et puis pleins d'autres, au programme: Quenya, Vulcain, Klingon, ...) et pour gagner du temps, j'effectue la localisation en parallèle. Pour cela j'utilise Rails <a href="http://guides.rubyonrails.org/i18n.html" hreflang="en" title="i18n">i18n</a> qui est très simple à utiliser et à configurer. Rien que la fonction !! C'est tout simplement <strong>t</strong>. Donc à la taper, on ne perd pas de temps, c'est juste <ins>UNE</ins> lettre !!<br />
Pour l'aspect fonctionnel, c'est simple, s'il ne trouve pas la chaîne correspondante dans le fichier de localisation, il <q>railise</q> sa chaîne de caractères (comprendre : il remplace les <em>underscores</em> par des espaces et il met une majuscule à la première ligne.<br />
Prenons l'exemple de la fonction suivante : <strong>t(:je_fais_un_prout)</strong> dans un contexte de traduction anglaise.</p>
<ul>
<li>Rails va chercher dans le fichier en.yml, la chaîne correspndante ; s'il la trouve, il affichera <q>I make a prout</q></li>
<li>Sinon, il affichera <q>Je fais un prout</q></li>
</ul>
<p>C'est tellement simple que je place ces fonctions <strong>t</strong> un peu partout en me disant que je remplirais le fichier de localisation <code>fr.yml</code> plus tard... Sauf que voilà... <q>Plus tard</q>, en informatique signifie souvent, comme partout ailleurs, d'ailleurs,... <q>à la saint glin-glin</q>.<br />
Pourquoi ?<br />
Parce que, comme moi, tout bon développeur est une grosse feignasse qui a une flemme de maladie quand il s'agit de rechercher tous les chaines de localisation qu'il a éparpillé un peu partout dans tous ses fichiers (dans mon cas 110 fichiers et 6160 lignes de code <img src="/dotclear/themes/chestnut/smilies/sad.gif" alt=":-(" class="smiley" /> ) et que surtout : <q>traduire, c'est pas du dév!</q><br />
C'est là où le petit programme que je viens de développer vient à point nommé. En effet, ce script se charge de chercher dans une arborescence <em>Ruby On Rails</em>, les fichiers susceptibles d'accueillir des chaines de localisation de les extraire et de chercher un squelette de fichier de localisation avec. Dès lors que tous les chaînes ont été extraites, il ne reste plus qu'à traduire le fichier de la langue désirée. Pas mal, non ? <img src="/dotclear/themes/chestnut/smilies/smile.gif" alt=":-)" class="smiley" /></p>
<pre class="brush: bash">
#!/bin/sh
# by Jean-Baptiste LANGLOIS
# Tested under RoR 3.2.3
DIRECTORY=`pwd`
APPEND=0
usage()
{
cat << _EOF_
Usage: `basename $0` [-a] [-d <directory>] <language>
where:
<language> localized language on two digits (en, fr, etc.)
Options:
-d <directory> RoR application directory (default: current directory)
-a appending localization file if exists
-h this help page
_EOF_
}
while getopts "d:ah" opt; do
case $opt in
d) DIRECTORY=$OPTARG;;
a) APPEND=1;;
h) usage && exit 1 ;;
esac
done
shift $(($OPTIND - 1))
if [ $# -eq 0 ]; then
usage
exit 1
fi
LANGUAGE=$1
FICHIER=$DIRECTORY/config/locales/$LANGUAGE.yml
[ $APPEND -eq 0 ] && echo "$LANGUAGE:" > $FICHIER
find $DIRECTORY -name "*.rb" -o -name "*.erb" | \
xargs grep -h "t(:" | \
sed 's/^.*t(:\([^), ]*\).*$/ \1:/g' | \
sort -u >> $FICHIER
</pre>
<p>Le programme prend en argument obligatoire la variable de langage (<strong>fr</strong> <em>pour Français</em>, par exemple ; cette variable créera aussi le fichier <strong>fr</strong>.yml) et en argument facultatif le répertoire où se trouve le projet Rails (par défaut, le répertoire en cours) et la possibilité d'écraser un fichier précédemment créé.
<div class="dcnote noteclassic">
<p><strong>TODO</strong><br />En plus d'extraire les chaînes de caractères, la prochaine évolution de ce script serait de <q>railiser</q> les chaines de localisation et d'initialiser les variables avec. Ainsi, si les chaines sont bien créés, il n'y aurait alors même pas besoin de modifier le fichier de localisation.
</p>
</div>
</p>http://www.jesuisungeek.com/index.php?post/2013/07/05/Localisation-de-projets-Ruby-on-Rails#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/230Liens utiles pour faire du développement Weburn:md5:5689b6892d3ba3f6b3f442c29328b0572013-05-29T14:03:00+02:002016-02-14T11:53:40+01:00Jean-Baptiste LangloisGeekeriesrailsruby <p>Actuellement sur un tout nouveau projet (donc je parlerai quand je le pourrai) utilisant massivement <a href="http://fr.wikipedia.org/wiki/Ruby_on_Rails" hreflang="fr" title="Ruby On Rails">Ruby On Rails</a>, jQuery et Ajax, je passe mes journées à lire des tutos et faire un référencement des liens intéressants. Malheureusement, n'ayant pas le temps de tout lire, j'en mets un peu de coté, en me disant que je les lirais quand je le pourrai. Sauf que, je perds ces bouts de papier/e-mails et je n'arrive plus du tout à remettre la main sur <ins>LE</ins> site dont j'ai besoin <ins>QUAND</ins> j'en ai besoin. <br />
En fait, il me faudrait un site Web d'enregistrements de bookmarks, mais les solutions type <em>Reddit</em> et/ou <em>Delicious</em> sont trop <q>Web 2.0</q> pour moi... Du coup, comme je ne trouve pas de site correspondant à mes attentes, je les colle ici, en me disant que je les remettrai en forme quand j'aurai développé le site de <em>bookmarking</em> que je cherche (Promis, je vais le faire !!)... L'avantage, c'est que tout le monde pourra en profiter <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" />
<br />
<ins><strong>Resources pour Ajax :</strong></ins><br /></p>
<ul>
<li><a href="http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html" hreflang="en">RoR - Ajax</a> : Utilisation d'Ajax avec Ruby On Rails</li>
<li><a href="http://ajaxload.info/" hreflang="en">Ajaxload</a> : Pour simuler un chargement</li>
<li><a href="http://jqueryfordesigners.com/using-ajax-to-validate-forms/" hreflang="en">jQuery for Designers</a> : Validation Formulaire en Ajax</li>
<li><a href="http://fancybox.net/" hreflang="en">Fancybox</a> : Popup en Ajax</li>
<li><a href="http://api.jquery.com/category/ajax/" hreflang="en">jQuery API</a></li>
</ul>
<p><ins><strong>Resources pour Ruby on Rails :</strong></ins><br /></p>
<ul>
<li><a href="http://railscasts.com/episodes/archive" hreflang="en">RailsCasts</a> : Videos d'apprentissage</li>
<li><a href="http://guides.rubyonrails.org/testing.html" hreflang="en">Rails Guides - Testing</a> : Tests fonctionnels</li>
<li><a href="http://railsdebutant.org/french_guides" hreflang="fr">Rails Guides - FR</a> : Traduction française des Rails Guides</li>
<li><a href="http://french.railstutorial.org/chapters/beginning" hreflang="fr">RailsTutorial</a> : Excellent tutoriel en français</li>
<li><a href="http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-column">Définitions des tables</a> : Options et arguments pour la création des modèles de données</li>
</ul>
<p><ins><strong>Gestion des images avec Ruby on Rails :</strong></ins><br /></p>
<ul>
<li><a href="http://github.com/thoughtbot/paperclip">Paperclip</a> : GEM de gestion des images (<a href="http://railscasts.com/episodes/134-paperclip" hreflang="en" title="vidéo">vidéo</a>)</li>
<li><a href="https://github.com/carrierwaveuploader/carrierwave">CarrierWave</a> (<a href="http://railscasts.com/episodes/253-carrierwave-file-uploads" hreflang="en" title="vidéo">vidéo</a>)</li>
</ul>
<p><ins><strong>Liste des routes du contrôleur Rails :</strong></ins><br />
<img src="http://www.jesuisungeek.com/public/pictures/divers/rails_controller.PNG" alt="Routes RESTful du Controlleur Rails" style="display:block; margin:0 auto;" title="Routes RESTful du Controlleur Rails, juin 2013" /></p>http://www.jesuisungeek.com/index.php?post/2013/05/29/Liens-utiles-pour-faire-du-d%C3%A9veloppement-Web#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/229Installation et configuration d'un clusterurn:md5:c78d41a47ae2b126195d7564a42166872013-05-09T16:12:00+02:002016-07-07T12:57:30+02:00Jean-Baptiste LangloisBidouillesclustergpllinuxredhat<p>Depuis un certain temps, je m'intéresse à la Haute Disponibilité et jusqu'à présent, je n'ai jamais eu le loisir d'installer mon propre cluster. Je comble donc ici ma propre ignorance.</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/.lvs4p-200_t.jpg" alt="LVS Project Logo" style="float:left; margin: 0 1em 1em 0;" title="LVS Project Logo, mai 2013" /><strong>Cluster</strong> ! Le mot est lancé et il fait peur !! Mot compliqué et lié à des termes abscons comme <q>Node</q> ou <q>Concentrateur</q>. Et puis, sur le marché, ça fait sérieux et ça coute cher, donc c'est clairement pas le truc à refiler à des débutants !!<br />
... Enfin, c'est l'idée que j'en avais, car au final, c'est pas si compliqué que ça ; tout ce qu'il faut, ce sont des bonnes connaissances en réseau.<br />
<br />
<ins>Qu'est-ce que j'appelle ici <em>Cluster</em> ?</ins><br />
Il s'agit d'un mécanisme double, permettant l'accès à une information quel que soit l'état de mes ressources. Ainsi, je veux pouvoir être en état d'accéder à ce que je souhaite même si la moitié de mon infra est morte. Pour cela, trois notions sont habitellement associés :</p>
<ul>
<li>Le <ins>cluster failover</ins> qui permet de basculer sur une ressource secondaire si le serveur primaire en <em>down</em></li>
<li>Le <ins>load balancer</ins> qui permet de répartir équitablement l'usage des ressources pour ne pas laisser tout s'executer sur la même (ce qui permet d'une part, de ne pas la faire flancher trop rapidement et, d'autre part, d'avoir de meilleures perfs)</li>
<li>La <ins>redondance</ins> d'information entre les ressources constituant le cluster afin de ne pas perdre de données en cas de bascule (légérement hors-sujet, je dois l'avouer, mais fortement lié à l'architecture désirée)<br /></li>
</ul>
<p><br />
<ins>Un peu de vocabulaire</ins><br /></p>
<ul>
<li>On appelle <em>node</em>, le serveur effectuant la tâche demandé par le client. C'est sur ce serveur que l'applicatif désiré par le client se trouve.<ins>Un peu de vocabulaire</ins><br /></li>
<li>On appelle <em>node</em>, le serveur effectuant la tâche demandé par le client. C'est sur ce serveur que l'applicatif désiré par le client se trouve.</li>
<li>On appelle <em>concentrateur</em> (on voit aussi le terme de <em>directeur</em>, parfois), le serveur prenant en charge la requête du client et la répartie en fonction de la charge (<em>load balancer</em>) ou de l'état des <em>Nodes</em> (<em>failover</em>).</li>
</ul>
<p>On le voit ici (et également dans le schéma ci-dessous), le concentrateur ne fait juste office de <q>passerelle intelligente</q> se s'occupe que de router les paquets sur les nodes les plus adaptés. Pour l'utilisateur, c'est transparent (car il se connecte toujours via la même IP) mais il est fort probable que les divers traitements demandés soient gérés par des serveurs différents.<br /></p>
<ul>
<li>On appelle <em>concentrateur</em> (on voit aussi le terme de <em>directeur</em>, parfois), le serveur prenant en charge la requête du client et la répartie en fonction de la charge (<em>load balancer</em>) ou de l'état des <em>Nodes</em> (<em>failover</em>).</li>
</ul>
<p>On le voit ici (et également dans le schéma ci-dessous), le concentrateur ne fait juste office de <q>passerelle intelligente</q> se s'occupe que de router les paquets sur les nodes les plus adaptés.<br /></p>
<p><ins><strong>0. Présentation de l'infrastructure</strong></ins><br />
<a href="http://www.jesuisungeek.com/public/pictures/real/cluster-apache.png" title="Infrastructure Cluster"><img src="http://www.jesuisungeek.com/public/pictures/real/.cluster-apache_m.jpg" alt="Infrastructure Cluster" style="display:table; margin:0 auto;" title="Infrastructure Cluster, mai 2013" /></a>
Ce que je souhaite réaliser ici est l'un des usages les plus communs pour un cluster : un serveur Web doit être <em>up</em> 100% du temps. Pour ce faire, on monte un cluster avec 2 nodes strictement identiques dans leur configuration : même serveur Apache, même version, et même SGBDR (Car dès lors que l'on a un petit site Web, on a forcément besoin d'une base de données). La difficulté ici, est que si un node tombe,comment se passera le stockage dans le base de données ? Même question pour quand le node remontera ? Ici, on a beaucoup de chances, car MySQL gère un type de connexion Maître/Maître qui permet la mise-à-jour du cluster quel que soit le node sur lequel les données ont été écrites.<br />
Au regard du schéma, je sens poindre une question : <q>Oui, mais si le concentrateur tombe, comment qu'on fait ?</q> Question très judicieuse mais qui ne sera pas abordé ici (sachez toutefois que des solutions existent). Dans le cas présent, j'ai postulé que le Concentrateur, c'est le petit frère de Rambo, il a fait le Viet-Nam, la Thailande, la Corée du Nord, alors merde, c'est pas une petit coupure de courant qui va le faire chier !!<br />
<br />
N'ayant pas des masses de matos, j'ai cloné 2 fois la même VM sur <a href="https://www.virtualbox.org" hreflang="fr" title="Virtual Box">VirtualBox</a> de façon à avoir des machines strictement identiques. Tout juste ai-je rajouté MySQL et Apache sur les deux nodes.<br />
<br />
<strong><ins>1. Autoriser le transfert des paquets sur Concentrateur</ins></strong><br />
Pour ceux qui ont déjà monté des <em>gateway</em>, cette opération devrait déjà être réalisé <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /> Il s'agit juste d'autoriser le transfert des paquets du sous-réseau des nodes, vers le réseau global. En effet, comme le montre le schéma au-dessus, le concentrateur a deux interfaces pour permettre le NAT entre les deux réseaux. Du coup, il suffit d'autoriser le transfert de paquet et de rajouter une règle de NAT à iptables :</p>
<pre>
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
</pre>
<p>A noter que, dans mon cas, l'interface vers le réseau public étant <q>eth0</q>, ma règle <em>iptables</em> route les paquets vers cette interface.<br />
<br />
<ins><strong>2. Préparation des nodes</strong></ins><br />
Dès lors que le <em>forwarding</em> des paquets a été autorisés, on peut tenter d'accéder au réseau global à partir des nodes (en reconfigurant <strong>/etc/resolv.conf</strong>, vous pouvez même faire vos mises à jour <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> ).</p>
<pre>
ping 192.168.1.1
</pre>
<p>Si le ping répond comme il faut, il ne reste plus qu'à bloquer le transfert de paquets <ins><strong>SUR</strong></ins> cette machine, puis créer une page bidon pour tester Apache (j'ai utilisé <code>ip addr show</code> car l'IP apparaît bien, mais n'importe quoi fera l'affaire)</p>
<pre>
echo 0 > /proc/sys/net/ipv4/ip_forward
ip addr show > /var/www/html/index.html
service httpd restart
</pre>
<p><ins><strong>3. Installation load balancer</strong></ins><br />
Pour la mise en place de ma solution de <em>load balancing</em>, comme souvent, de nombreuses possibilités s'offraient à moi. Dans le cas présent, j'ai décidé d'utiliser <a href="http://www.linuxvirtualserver.org" hreflang="en" title="Linux Virtual Server">LVS</a> car c'est un projet récent, sympa et bien supporté. En plus, les RPMs existent et sont déjà diffusés par Red Hat <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /></p>
<pre>
[root@localhost ~]# yum install ipvsadm
</pre>
<p>Une fois LVS, installé, il faut charger ses modules dnas le noyau mais <ins>attention !</ins> Des modules supplémentaires doivent être défini. En effet, ce qui rend un Concentrateur spécial et qui fait de lui plus qu'une gateway est sa capacité à définir sur quel node doit être envoyé les informations transmises. Pour cela, plusieurs algorithmes de décisions existent tels que le <em>Round Robin</em> (RR, accès séquentiel) ou le <em>Weighted Round Robin</em> (WRR, accès séquentiel ou une node de poids double est deux fois plus sollicité que les autres). Dans mon cas, j'ai décidé de rester sur du <em>Round Robin</em> classique.</p>
<pre>
[root@localhost ~]# modprobe ip_vs
[root@localhost ~]# modprobe ip_vs_rr
[root@localhost ~]# ipvsadm -A -t 192.168.1.35:80 -s rr
[root@localhost ~]# ipvsadm -a -t 192.168.1.35:80 -r 192.168.0.2:80 -m -w 1
[root@localhost ~]# ipvsadm -a -t 192.168.1.35:80 -r 192.168.0.3:80 -m -w 1
</pre>
<p>Je charge donc les modules nécessaires et précise à <strong>ipvsadm</strong> que l'algorithme de décision sur le port 80 (puisqu'on tente de faire un cluster avec un serveur Web) se fera sur la base de <em>Round Robin</em>. Ensuite, j'ajoute des serveurs à cette règle de clusters en faisant du NAT vers les ports 80 de mes deux nodes avec un poids de 1.<br />
<div class="dcnote noteclassic">
<p>Comme on ne fait que du <em>Round Robin</em>, on n'a, <em>a priori</em>, pas besoin de spécifier un poids quelconque. Toutefois, par défault, LVS ne prendra pas en compte un node de poids 0 (ce qui, d'ailleurs, se tient)</p>
</div>
Voilà, la configuration du <em>load balancer</em> est terminée !! Facile, non ?<br />
<br />
<ins><strong>4. Test avec le poste client</strong></ins><br />
Il ne reste donc plus qu'à tester le fonctionnement. Pour cela, à partir du poste client (une machine hors du cluster), je lance plusieurs <strong>curl 192.168.1.35</strong> vers le concentrateur qui redirige tout ça vers les différents nodes. Un résultat équivalent à celui ci-dessous devraient confirmer le bon fonctionnement du cluster :</p>
<pre>
iMac-de-Jean-Baptiste-Langlois:~ mithweth$ curl 192.168.1.35
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 08:00:27:d3:5b:e9 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.2/24 brd 192.168.0.255 scope global eth0
inet6 fe80::a00:27ff:fed3:5be9/64 scope link
valid_lft forever preferred_lft forever
iMac-de-Jean-Baptiste-Langlois:~ mithweth$ curl 192.168.1.35
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 08:00:27:6c:73:0a brd ff:ff:ff:ff:ff:ff
inet 192.168.0.3/24 brd 192.168.0.255 scope global eth0
inet6 fe80::a00:27ff:fe6c:730a/64 scope link
valid_lft forever preferred_lft forever
</pre>
<p>On voit bien que, alors qu'on effectue le même appel, la valeur affichée est différente.<br />
<br />
<ins><strong>5. Haute disponibilité</strong></ins><br />
<div class="dcnote noteimportant">
<p>A faire APRES conf du load balancer : En effet, l'idée est d'ajouter ou supprimer des enresgistrements à ipvsadm en fonction de l'état des serveurs, donc il faut qu'auparavant <strong>ipvsadm</strong> soit correctement configuré.</p>
</div>
Dans le cas de mise en Haute Disponibilité d'un cluster, la plupart du temps, c'est <a href="http://www.linux-ha.org/wiki/Heartbeat" hreflang="en" title="Heartbeat">Heartbeat</a> qui est la solution recommandée. Toutefois, bien que connu et supporté, Heartbeat gère surtout l'état d'un node (<em>up</em> ou <em>down</em>) mais pas l'état d'un <em>daemon</em> installé sur ce node. Or, dans mon cas, je me moque de savoir si mon serveur tombe, dès lors que Apache fonctionne correctement. Pour superviser l'état de service et déclencher des scripts sous certaines conditons, j'ai pris le parti d'utiliser plutôt <a href="https://mon.wiki.kernel.org/index.php/Main_Page" hreflang="en" title="Mon">Mon</a>. Celui-ci peut vérifier l'état de plusieurs <em>daemons</em> ou l'état de certains flux réseaux, et le signaler ou bien exécuter un script pour, par exemple, le relancer. Dans notre cas présent, il faudrait que si Apache ne répond pas, le node inhérent soit retiré de la liste de <strong>ipvsadm</strong>.<br />
Pour installer MON, on peut très bien télécharger et recompiler les sources, mais j'ai trouvé des packages RPM de la dernière version (mon-1.2.0-8.el6.i686.rpm ou mon-1.2.0-8.el6.x86_64.rpm) que j'ai attaché à ce post. Toutefois, comme les RPMs semblent avoir été compilé avec les pieds, voici comment installer le RPM qui va bien sur votre RedHat de vos rêves ; Ne vous inquiétez pas, ça marche !! (Au moins avec ma CentOS 6.4 <img src="/dotclear/themes/chestnut/smilies/cool.gif" alt="8-)" class="smiley" /> ).</p>
<pre>
yum -y install perl-CPAN make gcc pam-devel # Installe pkg de dev
perl -MCPAN -e 'install "Time::HiRes"; install "Time::Period"; install "Convert::BER"; install "Authen::PAM"'
rpm -ivh --nodeps mon-1.2.0-8.el6.x86_64.rpm # ne pas oublier le --nodeps
yum -y remove make gcc pam-devel # desInstalle pkg de dev
</pre>
<p><strong>Mon</strong> est désormais bien installé. Il ne reste plus qu'à configurer le fichier de configuration de Mon <code>/etc/mon/mon.cf</code>. Copier ainsi le fichier ci-dessous, en changeant l'IP des ondes à la ligne <q>hostgroup</q></p>
<pre>
cfbasedir = /etc/mon
pidfile = /var/run/mon.pid
statedir = /var/lib/mon/state.d
logdir = /var/lib/mon/log.d
dtlogfile = /var/lib/mon/log.d/downtime.log
alertdir = /usr/lib64/mon/alert.d
mondir = /usr/lib64/mon/mon.d
maxprocs = 20
histlength = 100
randstart = 60s
authtype = pam
userfile = /etc/mon/userfile
hostgroup servers 192.168.0.2 192.168.0.3
watch servers
service http
interval 5s
monitor http.monitor
period wd {Sun-Sat}
upalert ha.alert
alert ha.alert
</pre>
<p>En fait, la partie importante est situé dans <code>watch <hostgroup_name></code>. Ici, la configuration précise de faire le test d'état du port 80 toutes les 5 secondes du Dimanche à Samedi sur les serveurs du <em>hostgroup</em> et qu'en cas d'erreur lancer le script <q>ha.alert</q>. En cas de rétablissement après une panne, il faudra relancer le script <q>ha.alert</q>.
<div class="dcnote noteclassic">
<p>En fait, en cas de rétablissement d'un service, le script indiqué est toujours exécuté avec le paramètre <code>-u</code>, ce qui permet de différencier les actions à effectuer dans un seul et même script.</p>
</div>
Ce script <q>ha.alert</q> n'apparait toutefois pas dans le répertoire <code>/usr/lib64/mon/alert.d</code> pour la simple et bonne réponse que c'est un script que j'ai fait moi-même : si un des <em>daemons</em> générant une réponse sur le port 80 (Apache) le script désactive l'enregistrement de <strong>ipvsadm</strong> permettant le routage vers le mode concerné. Cette désactivation consiste à changer le poids de ce routage de 1 à 0 et vice versa en cas de rétablissement du <em>daemon</em>.</p>
<pre class="brush: bash">
#!/bin/sh
read SERVER
WEIGHT=0
while getopts "s:g:h:t:l:u" opt; do
case $opt in
u) WEIGHT=1;;
s) SERVICE=$OPTARG;;
*) ;;
esac
done
GW=`grep GATEWAY /etc/sysconfig/network | cut -d = -f 2`
IFACE=`netstat -rn | grep $GW | awk '{print $NF;}'`
DFTIP=`grep IPADDR /etc/sysconfig/network-scripts/ifcfg-$IFACE | cut -d = -f 2`
logger -i -p local3.info -t mon "node $SERVER weight is now $WEIGHT"
ipvsadm -e -t $DFTIP:$SERVICE -r $SERVER:$SERVICE -m -w $WEIGHT
</pre>
<p>Il faut donc copier le script ci-dessus, le nommer <q>ha.alert</q>, lui donner les droits d'exécution et redémarrer <strong>mon</strong>.</p>
<pre>
chmod a+x /usr/lib64/mon/alert.d/ha.alert
service mon restart
</pre>
<p><br />
<strong><ins>6. Réplication de MySQL</ins></strong><br />
Comme indiqué plus haut, peu importe le serveur Apache avec lequel on communique, il faut que les données échangées avec la base de données soient les mêmes pour donner l'illusion qu'un unique serveur est à l'oeuvre. Pour cela, la réplication de Maitre à Maitre de MySQL va nous aider. Tout comme Apache, il faut que la configuration des nodes concernés soit strictement la même, ainsi la configuration suivante est à reporter sur chacun des nodes.<br />
<br /><ins>Node 1</ins><br />
<br />
Ajouter la ligne suivante dans <code>/etc/sysconfig/iptables</code></p>
<pre>
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT
</pre>
<p>Ajouter les lignes suivantes dans le fichier <code>/etc/my.cnf</code> (Configuration MySQL)</p>
<pre>
server-id=2
log-bin=mysql-bin
</pre>
<p>On redémarre alors <strong>iptables</strong>, <strong>mysqld</strong> et on se connecte au serveur MySQL où on va créer un utilisateur spécifiquement pour la réplication (changer le <code><mot de passe></code> par le mot de passe de votre choix)</p>
<pre>
mysql> grant replication slave on *.* to 'replication'@'%' identified by '<mot de passe>';
mysql> change master to master_host='192.168.0.2', master_port=3306, master_user='replication', master_password='<mot de passe>';
mysql> slave start;
</pre>
<p><br />
<br /><ins>Node 2</ins><br />
<br />
Ajouter la ligne suivante dans <code>/etc/sysconfig/iptables</code></p>
<pre>
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT
</pre>
<p>Ajouter les lignes suivantes dans le fichier <code>/etc/my.cnf</code> (Configuration MySQL)</p>
<pre>
server-id=3
log-bin=mysql-bin
</pre>
<p>On redémarre alors <strong>iptables</strong>, <strong>mysqld</strong> et on se connecte au serveur MySQL où on va créer un utilisateur spécifiquement pour la réplication (changer le <code><mot de passe></code> par le mot de passe de votre choix)</p>
<pre>
mysql> grant replication slave on *.* to 'replication'@'%' identified by '<mot de passe>';
mysql> change master to master_host='192.168.0.3', master_port=3306, master_user='replication', master_password='<mot de passe>';
mysql> slave start;
</pre>
<p><br />La réplication est enfin configurée ! Pour le vérifier il suffit de taper, dans la console MySQL, la commande suivante :</p>
<pre>
mysql> show slave status\G
</pre>
<p>Si, parmi les instructions retournés, les deux lignes suivantes apparaissent, c'est que la réplication est fonctionnelle.</p>
<pre>
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
</pre>http://www.jesuisungeek.com/index.php?post/2013/05/09/Installation-et-configuration-d-un-cluster#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/228C.V. Interactifurn:md5:c59b41cf41876cd9e35031731ca2cfff2013-03-15T21:24:00+01:002015-01-05T16:45:38+01:00Jean-Baptiste LangloisProjetshtml5javascriptjeurpg<p>Jeu en HTML5 faisant office de présentation technique avec, en bonus, le téléchargement de mon CV <img src="/dotclear/themes/chestnut/smilies/smile.gif" alt=":-)" class="smiley" /></p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/rirekisho.jpg" alt="CV Interactif - Logo" style="float:left; margin: 0 1em 1em 0;" title="CV Interactif - Logo, mar. 2013" />Il y a quelques années, j'étais tombé par hasard sur <a href="http://www.flashcv.com/Site/Site/Home/Home.html" hreflang="fr" title="CV en Flash">ce site</a> et cela m'a beaucoup plu. Ce CV en Flash est une présentation originale des compétences d'une personne et j'ai toujours souhaité faire quelque chose dans le genre ; bien sûr, j'ai voulu faire quelque chose relatif à mes compétences (je dessine très mal, et je suis une tanche en Flash <img src="/dotclear/themes/chestnut/smilies/sad.gif" alt=":-(" class="smiley" /> ), donc j'ai eu l'idée de développer un petit Jeu de Rôle qui, en outre, aurait été un hommage aux jeux auxquels je jouais sur Super Nintendo (Aaaah, souvenir, souvenir !). J'ai donc commencé à développer ce jeu en Java (à l'époque où la balise <code><applet></code> n'était pas un gros mot), puis je suis passé en Flash. Toutefois, avec la mauvaise presse du plugin Flash ces derniers temps, il est devenu probable que le recruteur qui tombe sur mon CV ne l'ait pas installé...<br />
Or, avec l'émergence du HTML5 (dont le draft est sur le point d'être conclu), je me suis dit que j'avais là l'opportunité de développer un jeu accessible de n'importe quel navigateur Web récent... J'ai donc repris le code de zéro, et suis parvenu à un résultat satisfaisant (ça marche même sur iPhone <img src="/dotclear/themes/chestnut/smilies/cool.gif" alt="8-)" class="smiley" /> ).<br />
Merci à tous d'accueillir mon nouveau <a href="http://www.jesuisungeek.com/index.php?post/2013/03/15/index.php?pages/C.V.-Interactif" hreflang="fr" title="CV Interactif">CV Interactif</a> !!</p>http://www.jesuisungeek.com/index.php?post/2013/03/15/C.V.-Interactif#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/227Pixel-Arturn:md5:c6743b8e95e153ad95e46467d8f49ce82013-03-07T06:27:00+01:002013-03-15T19:22:38+01:00Jean-Baptiste LangloisBidouilleshtml5javascript<p>Petit moyen d'obtenir de jolis pixel-art avec la fonction getImageData de HTML5</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/.pixelme_s.jpg" alt="JB pixelisé" style="float:left; margin: 0 1em 1em 0;" title="JB pixelisé, mar. 2013" />Un style graphique que j'adore, c'est vraiment le Pixel-Art ! Avec la mode du <strong>8 bits</strong>, plus une image devient pixelisée et carrée, plus elle est <q>cool</q>. C'est pour cela que j'ai souhaité me faire un avatar en pixel-art sauf que j'avais oublié une chose : je suis une vraiment tanche en dessin ! Et bien entendu, n'ayant pas la patience de colorier pixel par pixel une image, j'étais un peu bloqué.<br />
Toutefois, ces temps-ci, développant un peu en <a href="http://fr.wikipedia.org/wiki/HTML5" hreflang="fr" title="HTML5">HTML5</a> (<code>canvas</code>, ça tue !!), j'ai découvert tout un ensemble de possibilités graphiques plutôt pratique.<br />
Plus que tout, l'élément que j'utilise actuellement massivement pour mon projet perso (<em>Stay tuned!</em> J'en dirai davantage plus tard) m'a permit à lui tout seul de développer la fonction que je présente aujourd'hui : <code>data</code><br />
<code>data</code> est en fait une propriété de l'objet <code>getImageData</code>. <code>getImageData</code> a pour particularité de récupérer les informations d'une portion rectangulaire du canvas. La propriété <code>data</code> retourne un tableau unidimensionnel de taille <code>largeur * longueur * 4</code>. Pour un multiplicateur 4 ? Parce que, et c'est là tout l'intérêt, chaque pixel est divisé en quatre éléments :</p>
<ul>
<li>Rouge</li>
<li>Vert</li>
<li>Bleu</li>
<li>Alpha</li>
</ul>
<p>Ainsi, pixeliser une image consiste à prendre la couleur du pixel à une position <em>(x,y)</em> et dessiner à part de cet axe un carré dont l'arête <em>a</em> correspond à la pixelisation attendue puis recommencer l'opération aux positions <em>(x+a,y)</em> et <em>(x,y+a)</em>. Simple, non ? <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> <br />
Pour ceux pour qui les cours de géometrie datent de Mathusalem, il suffit d'utiliser la fonction suivante :</p>
<pre class="brush: js">
function pixelate(canvas, square_size) {
var ctx = canvas.getContext("2d");
var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = img_data.data;
for (var y = 0; y < canvas.height; y += square_size) {
for (var x = 0; x < canvas.width; x += square_size) {
var pos = 4 * (y * canvas.width + x);
var i0 = data[pos];
var i1 = data[pos + 1];
var i2 = data[pos + 2];
ctx.fillStyle="rgb(" + i0 + "," + i1 + "," + i2 + ")";
ctx.fillRect(x, y, square_size, square_size);
}
}
}
</pre>
<p>La fonction prend deux arguments, le canvas où opérer la pixelisation, et la taille de la pixelisation attendue. Afin de montrer la fonction en action, je l'ai couplé à un <em>timer</em> <q>setInterval</q> qui double la taille de pixelisation toutes les 200 millisecondes. Pour voir le résultat, cliquez juste sur <q>Pixeliser</q>.</p>
<script language="javascript">
function init() {
var picture = document.getElementById("picture");
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var size = 1;
ctx.drawImage(picture, 0, 0, canvas.width, canvas.height);
var timer = window.setInterval(function() {
size *= 2;
if (size<canvas.width/4) {
pixelate(canvas,size);
} else {
window.clearInterval(timer);
}
},200);
}
function pixelate(canvas, square_size) {
var ctx = canvas.getContext("2d");
var img_data = ctx.getImageData(0,0,canvas.width, canvas.height);
var data = img_data.data;
for (var y = 0; y < canvas.height; y+=square_size) {
for (var x = 0; x < canvas.width; x+=square_size) {
var pos = 4*(y * canvas.width + x);
var i0 = data[pos];
var i1 = data[pos + 1];
var i2 = data[pos + 2];
ctx.fillStyle="rgb("+i0+","+i1+","+i2+")";
ctx.fillRect(x,y,square_size,square_size);
}
}
}
</script>
</head>
<body>
<img id="picture" src="http://www.jesuisungeek.com/index.php?post/2013/03/07/public/pictures/divers/dragonemeraude5.jpg" height="512" width="640" />
<br />
<button onclick="init()">Pixeliser</button>
<br />
<canvas id="canvas" height="512" width="640">
</canvas>
http://www.jesuisungeek.com/index.php?post/2013/03/07/Pixel-Art#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/225