Bouil.org2011-08-01T17:46ZBouilurn:md5:b7372a1dbe3e7c27be318211c2db1fc5Home madeBloc notesurn:md5:02f78145becfd9ab1d775e1b7af4c4df2011-08-01T17:46ZBouil<ul class="star"> <li><a href="http://www.txt2pic.com">http://www.txt2pic.com</a></li> </ul> Accueilurn:md5:74fe31b598483c373e2921603105e05c2011-06-23T22:22ZBouil<p>Vous trouverez sur ce site des pages sur la programmation, sur d'autres sujets comme l'espéranto, et aussi d'autres choses inclassables.</p> <p><a href="Contact">Pour me contacter</a>.</p> <h3>Programmation</h3> <ul> <li><a href="SOAP-avec-PHP-et-Python">SOAP avec PHP et Python</a></li> <li><a href="Python-et-XML">Python et XML</a></li> <li><a href="Parsing-de-fichier-XML-avec-Castor">Parsing de fichier XML avec Castor</a></li> <li><a href="ResultSetTableModel">ResultSetTableModel (Java)</a></li> <li><a href="R%C3%A9utiliser-les-mots-de-passe-SPIP">Réutiliser les mots de passe SPIP (PHP)</a></li> <li><a href="R%C3%A9utiliser-les-mots-de-passe-MediaWiki">Réutiliser les mots de passe MediaWiki (PHP)</a></li> <li><a href="Ant">Quelques trucs pour Ant</a></li> <li><a href="Cr%C3%A9ation-d%27un-environnement-de-test-JUnit-avec-JNDI">Création d'un environnement de test JUnit avec JNDI</a></li> </ul> <h3>Configuration</h3> <p>À propos de la configuration ou de l'installation de divers trucs sous GNU/Linux :</p> <ul> <li><a href="Clavier-fran%C3%A7ais-sous-GRUB">Clavier français sous GRUB</a></li> <li><a href="Installer-un-serveur-IMAP-avec-Dovecot%2C-Postfix-et-Fetchmail">Installer un serveur IMAP avec Dovecot, Postfix et Fetchmail</a></li> <li><a href="Configuration-du-Touchpad-Synaptics">Configuration du Touchpad Synaptics</a></li> <li><a href="Configuration-en-vrac-Windows">En vrac Windows</a></li> <li><a href="HAProxy-:-SSH-et-HTTPS-sur-le-même-port">HAProxy : SSH et HTTPS sur le même port</a></li> </ul> <h3>Esperanto</h3> <p>?i sube pa?oj en esperanto a? franclingve pri esperanto.</p> <ul> <li>Esperanto <ul> <li><a href="Pri-mi">Pri mi</a></li> <li><a href="ReVo">Instali la retan vortaron</a></li> </ul> </li> <li>Français <ul> <li><a href="Taper-les-caract%C3%A8res-Esp%C3%A9ranto-sous-Linux">Taper les caractères Espéranto sous Linux</a></li> <li><a href="ReVo">Installer le dictionnaire espéranto ReVo</a></li> </ul> </li> </ul> <h3>Divers</h3> <ul> <li><a href="Adjectifs">Saurez vous trouver, sans tricher, l'adjectif qui correspond au nom ?</a></li> <li><a href="Bloc-notes">Bloc notes</a></li> </ul> Ne pas installer les paquets recommandés avec Apt ou Aptitudeurn:md5:bdd7a25c4033444a896e05bd3fb150212010-06-02T15:26ZBouil<p>Pour installer <a href="http://ant.apache.org/">ant</a> ou <a href="http://www.eclipse.org/">Eclipse</a> sous Ubuntu ou Debian, apt (ou aptitude) impose souvent d'installer GCJ et d'autres bibliothèques que l'on ne veut pas installer si on a déjà la JDK de Sun.</p> <p>Pour éviter cette installation, il suffit de creer le fichier <tt>/etc/apt/apt.conf.d/90NoRecommends</tt> contenant la ligne suivante :</p> <pre> Apt::Install-Recommends "false";</pre>Contacturn:md5:bbaff12800505b22a853e8b7f4eb6a222010-05-15T20:43ZBouil<p><a href="http://nicolas.bouillon.tel">http://nicolas.bouillon.tel</a></p> <iframe src="http://nicolas.bouillon.tel" style="width: 90%; height: 600px"></iframe> WebServices SOAP avec Apache CXFurn:md5:404a40723d80f02a71fca8a823f08d632009-12-11T20:57ZBouil<h3>Introduction</h3> <p>De manière simplifiée, SOAP permet de faire de l'appel de procédure à distance au dessus du protocole HTTP. Les données échangées sont au format XML.</p> <p>Apache CXF est un framwork Java qui permet de simplifier la creation de Webservices SOAP</p> <h3>Architechture</h3> <p>L'idée est de faire un package pour le client (un jar), un package pour le serveur (un war), et un package commun (jar) aux deux qui contiendra les interfaces et les POJO échangés entre les deux services.</p> <p>Cela simplifie la création d'un client en Java, mais cela n'empêche pas de créer un webservice simplement à partir du WSDL qui sera généré à la demande par CXF.</p> <h3>Dépendances Maven pour CXF</h3> <pre class="brush: xml"> &lt;dependency&gt; &lt;groupId&gt;javax.servlet&lt;/groupId&gt; &lt;artifactId&gt;servlet-api&lt;/artifactId&gt; &lt;version&gt;2.5&lt;/version&gt; &lt;scope&gt;provided&lt;/scope&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.apache.cxf&lt;/groupId&gt; &lt;artifactId&gt;cxf-rt-frontend-jaxws&lt;/artifactId&gt; &lt;version&gt;2.1.3&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.apache.cxf&lt;/groupId&gt; &lt;artifactId&gt;cxf-rt-transports-http&lt;/artifactId&gt; &lt;version&gt;2.1.3&lt;/version&gt; &lt;/dependency&gt; </pre> <h3>Package Commun</h3> <p>Tout d'abord l'interface du service</p> <pre class="brush: java"> package org.bouil.example; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; @WebService public interface MonService { @WebResult(name = "helloresponse") Hello sayHello(@WebParam(name = "name") String name); } </pre> <p>Puis une classe POJO simple pour le retour. Ce n'est pas obligatoire, on aurait pu faire un return String tout simple pour notre méthode sayHello.</p> <pre class="brush: java"> package org.bouil.example; import java.util.Date; public class Hello { private Date when; private String hello; public Date getWhen() { return when; } public void setWhen(Date when) { this.when = when; } public String getHello() { return hello; } public void setHello(String hello) { this.hello = hello; } } </pre> <h3>Package serveur</h3> <h4>Implémentation du service</h4> <pre class="brush: java"> package org.bouil.example; public class MonServiceImpl implements MonService { public Hello sayHello(String name) { Hello response = new Hello(); response.setHello("Hello " + name); return response; } } </pre> <h4>WEB-INF/web.xml</h4> <pre class="brush: xml"> &lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"&gt; &lt;web-app&gt; &lt;context-param&gt; &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt; &lt;param-value&gt;WEB-INF/beans.xml&lt;/param-value&gt; &lt;/context-param&gt; &lt;listener&gt; &lt;listener-class&gt; org.springframework.web.context.ContextLoaderListener &lt;/listener-class&gt; &lt;/listener&gt; &lt;servlet&gt; &lt;servlet-name&gt;CXFServlet&lt;/servlet-name&gt; &lt;display-name&gt;CXF Servlet&lt;/display-name&gt; &lt;servlet-class&gt; org.apache.cxf.transport.servlet.CXFServlet &lt;/servlet-class&gt; &lt;load-on-startup&gt;1&lt;/load-on-startup&gt; &lt;/servlet&gt; &lt;servlet-mapping&gt; &lt;servlet-name&gt;CXFServlet&lt;/servlet-name&gt; &lt;url-pattern&gt;/services/*&lt;/url-pattern&gt; &lt;/servlet-mapping&gt; &lt;/web-app&gt; </pre> <h4>WEB-INF/beans.xml</h4> <p>Ce fichier va être chargé automatiquement par Spring (dont dépend CXF), afin de déclarer nos services.</p> <pre class="brush: xml"> &lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"&gt; &lt;import resource="classpath:META-INF/cxf/cxf.xml" /&gt; &lt;import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /&gt; &lt;import resource="classpath:META-INF/cxf/cxf-servlet.xml" /&gt; &lt;jaxws:endpoint id="MonService" implementor="org.bouil.example.MonServiceImpl" address="/MonService" /&gt; &lt;/beans&gt; </pre> <h4>Execution</h4> <p>Un fois le package déployé, le WSDL du service sera disponible par exemple à l'URL http://localhost:8080/service.server/services/MonService?wsdl</p> <h3>Package Client</h3> <p>Le client aura besoin d'importer le package commun, qui contient la déclaration de l'interface et les pojo partagés. Bien sur, il est possible de générer ces pojo et cette interface à partir du WSDL, mais ce n'est pas l'objet de cet article.</p> <p>Le client est alors aussi simple que cela:</p> <pre class="brush: java"> package org.bouil.example; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; public class TestService { public static String address = "http://localhost:8080/service.server/services/MonService"; public static MonService getMonService() { JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean(); factoryBean.setServiceClass(MonService.class); factoryBean.setAddress(address); MonService monService = (MonService) factoryBean.create(); return monService; } public static void main(String[] args) { Hello response = getMonService().sayHello("bouil"); System.out.println(response.getHello()); } } </pre> UTFConverturn:md5:e183fa0252cde5a1260fa5f9e0f420032009-12-11T20:57ZBouil<p>Les distributions Linux sont maintenant par défaut en UTF-8.</p> <p>Si vous aviez des fichiers avec des accents, il ne sont plus affichés correctement. Ci dessous un petit script Python qui permet de renomer les fichiers en UTF-8.</p> <ul> <li><a href="http://ccomb.free.fr/wiki/wakka.php?wiki=UtfConvert">http://ccomb.free.fr/wiki/wakka.php?wiki=UtfConvert</a></li> <li><a href="http://ccomb.free.fr/utfconvert/utfconvert.py">http://ccomb.free.fr/utfconvert/utfconvert.py</a></li> </ul> Téléphoner pas cher avec un mobile prépayé et Asteriskurn:md5:5eb7365c5534ae7bc360c22ea02565f22009-12-11T20:57ZBouil<p>L'un des avantages d'un mobile prépayé, c'est de ne payer que pour ce que l'on consomme. Chez <a href="http://www.leclercmobile.fr" hreflang="fr">Leclerc Mobile</a> c'est d'ailleurs assez intéressant car le crédit à une durée de validité de 12 mois. Le défaut c'est que le coût à la minute est assez élevé pour un consommateur occasionnel de téléphone comme moi&nbsp;: 0,39€/min pour qui consomme moins de 30 minutes par mois. Et comme je travaille au Luxembourg désormais, c'est encore pire&nbsp;: 0,58€/min l'appel émis, 0,28€/min l'appel reçu.</p> <p>Mais c'est là qu'intervient les services de <a href="http://fr.wikipedia.org/wiki/Voix_sur_r%C3%A9seau_IP" hreflang="fr">VoIP</a> basés sur <a href="http://fr.wikipedia.org/wiki/Session_Initiation_Protocol" hreflang="fr">SIP</a>, et le logiciel libre de <a href="http://fr.wikipedia.org/wiki/IPBX" hreflang="fr">IPBX</a> <a href="http://fr.wikipedia.org/wiki/Asterisk_%28logiciel%29" hreflang="fr">Asterisk</a>.</p> <h3>VoIP</h3> <p><a href="http://www.betamax.com" hreflang="fr">Betamax</a> propose une foule de <a href="http://progx.ch/home-voip-prixbetamax-5-1-2.html" hreflang="fr">sites clones de VoIP</a>, comme par exemple <a href="http://www.nonoh.net" hreflang="en">Nonoh</a>. Il permet la mise en relation de deux numéros de téléphones à partir d'un formulaire sur le site. Les tarifs sont assez intéressants. Par exemple, pour mettre en relation un téléphone portable français et un téléphone fixe, cela coûte 0,071€/min (tarif mobile fr) + 0€/min (tarif fixe fr).</p> <p>En bref, si je suis en France, un appel vers un fixe me coutera alors 0,071€/min, et un appel vers un mobile 0,142€/min. Au lieu de 0,39€/min. Cependant, via Nonoh la minute facturée est indivisible&nbsp;: c'est donc rentable qu'à partir de 30 sec d'appel vers un mobile.</p> <p>Si je suis au Luxembourg, un appel vers un fixe francais me coutera alors 0,28€/min (prix reception) + 0,071€/min (prix appel mobile) soit 0,351€/min. Au lieu de 0,58€/min. VIa Nonoh la minute facturée est indivisible, et via Leclerc Mobile la première minute est indivisible.</p> <p>Seul hic&nbsp;: l'appel s'initie depuis une page web. Pas toujours très pratique&nbsp;: je ne suis pas toujours devant un PC connecté au net.</p> <h3>Asterisk, SIP et DID</h3> <p>Asterisk est un PABX&nbsp;: un central d'appel qui permet de router des appels dans tous les sens. SIP est un protocole de communication. Nonoh permet de passer les appels via ce protocole. Asterisk peut se connecter à un compte SIP pour passer des appels. Le but est de demander à Asterisk d'appeler mon mobile d'un coté et mon correspondant de l'autre, et de nous connecter ensemble.</p> <p>Tout ça c'est bien beau, mais comment faire pour dire à Asterisk de faire cela&nbsp;? Il faut utiliser un numéro de téléphone qui dirige vers Asterisk. On utilisera pour cela un <a href="http://en.wikipedia.org/wiki/Direct_Inward_Dialing" hreflang="en">DID</a> associé à un compte SIP. Le scénario d'utilisation est le suivant&nbsp;:</p> <ol> <li>je téléphone avec mon mobile à Asterisk via le numéro DID.</li> <li>asterisk detecte l'appel et constate que c'est mon numéro de mobile qui l'appelle. Mais il ne prends pas l'appel.</li> <li>mon mobile se prends une erreur réseau ou un message comme quoi le numéro n'est pas disponible. Je ne paie rien.</li> <li>asterisk m'appelle via Nonoh (7,1cts/min)</li> <li>je tape mon mot de passe</li> <li>j'obtiens une tonalité pour taper le numéro de mon correspondant via Nonoh ou Freephonie, en fonction du préfixe tapé (comme au temps de la préselection via Tele2 / LeNeuf)</li> </ol> <h3>Freephonie</h3> <p>Vous vous demandez peut être pourquoi se tracasser avec un numéro DID et un fournisseur SIP distinct alors que Free propose un compte SIP correspondant à la ligne téléphonique (nommé freephonie). Tout d'abord, les tarifs vers les mobiles de Free sont moins intéressants que ceux de Nonoh. Ensuite, Freephonie ne permet de passer qu'un seul appel à la fois. Difficile donc de s'appeler et d'appeler le correspondant en même temps. De plus je ne veux pas que lorsque j'appelle chez moi avec mon mobile, je me fasse systématiquement rappeler.</p> <p>Je permettrai tout de même de choisir Freephonie pour composer le numéro en sortie.</p> <h3>En pratique</h3> <p>Installation d'asterisk (ubuntu)&nbsp;: apt-get install asterisk asterisk-config asterisk-prompt-fr-proformatique</p> <p>Création d'un compte chez Nonoh (ou ailleurs), et ajout d'un peu de crédit pour pouvoir passer des appels.</p> <p>Création d'un compte SIP sur ekiga.net&nbsp;: sip:user@ekiga.net</p> <p>Création d'un compte sur <a href="http://www.pimpmynumber.co.uk/" hreflang="en">PimpMyNumber</a> pour obtenir un DID gratuitement. Créer un numéro d'appel en (+44)(0)703..... Attention, ce numéro est au Royaume Uni et surtaxé, mais on s'en fiche, puisque Asterisk ne décroche jamais. A noter par ailleurs que je n'arrive pas à jointe ce numéro avec le téléphone de la freebox&nbsp;: il est refusé car surtaxé. Il est possible d'obtenir d'autres DID localisés dans d'autres pays chez d'autres prestataires moyennant finances, comme par exemple chez <a href="http://www.voipgate.com" hreflang="en">voipGate</a>, qui propose un compte SIP prépayé pour de la VoIP et en option un numéro d'appel, par exemple un numéro français géographique (en 03 54 ... pour Nancy) à pour 5€ par mois, ou un numéro allemand pour 3€ par mois).</p> <p>Faire rediriger le numéro DID sur le compte SIP crée chez ekiga&nbsp;: sip:user@ekiga.net.</p> <p>Renommer les fichiers existant de configuration d'Asterisk. mv /etc/asterisk/sip.conf /etc/asterisk/sip.conf.sample mv /etc/asterisk/extensions.conf /etc/asterisk/extensions.conf.sample</p> <p>Créer le fichier /etc/asterisk/sip.conf, qui contient les informations sur les comptes SIP entrant et sortant</p> <pre class="brush: plain">[general] defaultexpiry=1800 ; necessaire dans le cas d'une connexion SIP vers freephonie dtmfmode=auto qualify=yes language=fr ; pour les messages lus par asterisk disallow=all allow=ulaw allow=alaw allow=speex ; pour les appels sortants via free register =&gt; 0954xxxxxx:PASSWORD@freephonie.net ; pour les appels sortants via nonoh register =&gt; USERNAME:PASSWORD@sip.nonoh.net ; pour les appels entrant via le DID de chez www.pimpmynumber.co.uk register =&gt; USER:PASS@ekiga.net [freephonieout] ; on déclare le point d'accès SIP pour les appels sortants type=peer host=freephonie.net username=0954xxxxxx fromuser=0954xxxxxx fromdomain=freephonie.net qualify=yes secret=PASSWORD nat=yes ;; freephonie-in desactivé dans la console FREE ;[freephoniein] ; Et pour les appels entrants ;type=peer ;context=freephoniein ;host=freephonie.net [nonohout] ; on declare le point d acces SIP nonoh pour les appels sortants type=peer host=sip.nonoh.net username=USERNAME fromuser=USERNAME fromdomain=sip.nonoh.net qualify=yes secret=PASSWORD nat=yes [ekigain] ; appels entrant via le DID qui pointe sur ekiga type=peer context=ekigain host=ekiga.net [moi] ; on déclare un client SIP (par exemple pour connecter un softphone sur le PBX) type=friend username=moi secret=PASSWD host=dynamic context=maison nat=yes ; je peux me connecter sur mon PBX depuis d'autres réseaux "nattés"</pre> <p>Puis créer le fichier /etc/asterisk/extensions.conf, qui contient les sénarios d'appel</p> <pre class="brush: plain">[maison] ; on déclare le contexte local qu'on a spécifié dans le sip.conf ; numéros "locaux" ou rapides exten =&gt; 6,1,Dial(SIP/moi) ; quand on compose le 6, le softphone branché sur le lien "moi" sonnera exten =&gt; 1,1,Dial(SIP/nonohout/00336xxxxxxxx) ; portable madame exten =&gt; 2,1,Dial(SIP/freephonieout/03xxxxxxxx) ; parents ; numéros externes via free ; quand on compose un numero qui commence par 01, on utilise le lien "freephonieout" et on passe le numero au peer en ôtant le premier digit (0) et en ajoutant au debut 0033. exten =&gt; _01.,1,Dial(SIP/freephonieout/0033${EXTEN:1}) exten =&gt; _02.,1,Dial(SIP/freephonieout/0033${EXTEN:1}) exten =&gt; _03.,1,Dial(SIP/freephonieout/0033${EXTEN:1}) exten =&gt; _04.,1,Dial(SIP/freephonieout/0033${EXTEN:1}) exten =&gt; _05.,1,Dial(SIP/freephonieout/0033${EXTEN:1}) exten =&gt; _06.,1,Dial(SIP/freephonieout/0033${EXTEN:1}) exten =&gt; _09.,1,Dial(SIP/freephonieout/0033${EXTEN:1}) exten =&gt; _00.,1,Dial(SIP/freephonieout/${EXTEN}) ; numero externes via nonoh prefixe 9 ; quand on compose un numero qui commence par 91, on utilise le lien "nonohout" et on passe le numero au peer en ôtant le premier digit (9) et en ajoutant au debut 0033. exten =&gt; _91.,1,Dial(SIP/nonohout/0033${EXTEN:1}) exten =&gt; _92.,1,Dial(SIP/nonohout/0033${EXTEN:1}) exten =&gt; _93.,1,Dial(SIP/nonohout/0033${EXTEN:1}) exten =&gt; _94.,1,Dial(SIP/nonohout/0033${EXTEN:1}) exten =&gt; _95.,1,Dial(SIP/nonohout/0033${EXTEN:1}) exten =&gt; _96.,1,Dial(SIP/nonohout/0033${EXTEN:1}) exten =&gt; _99.,1,Dial(SIP/nonohout/0033${EXTEN:1}) exten =&gt; _90.,1,Dial(SIP/nonohout/0${EXTEN:1}) [ekigain] exten =&gt; s,1,NoOp(Appel entrant Ekiga) exten =&gt; s,2,NoOp(${CALLERID(num)}) exten =&gt; s,3,GotoIf($["${CALLERID(num)}" = "0033662xxxxxx"]?init-callback,s,1) exten =&gt; s,4,Congestion ; refuse l'appel [init-callback] exten =&gt; s,1,Congestion exten =&gt; s,2,Hangup exten =&gt; h,1,Set(CALLERID(number)=${CALLERID(num)}) exten =&gt; h,2,System(echo channel: SIP/nonohout/${CALLERID(num)} &gt; /tmp/${CALLERID(num)}) exten =&gt; h,3,System(echo context: callback &gt;&gt; /tmp/${CALLERID(num)}) exten =&gt; h,4,System(echo extension: ${CALLERID(num)} &gt;&gt; /tmp/${CALLERID(num)}) exten =&gt; h,5,System(echo priority: 1 &gt;&gt; /tmp/${CALLERID(num)}) exten =&gt; h,6,Sys!!!tem(echo callerid: ${CALLERID(num)} &gt;&gt; /tmp/${CALLERID(num)}) ; exten =&gt; h,7,System(echo sleep 5 &gt; /tmp/${CALLERID(num)}.2) exten =&gt; h,8,System(echo cp /tmp/${CALLERID(num)} /var/spool/asterisk/outgoing &gt;&gt; /tmp/${CALLERID(num)}.2) exten =&gt; h,9,System(chmod 775 /tmp/${CALLERID(num)}.2) exten =&gt; h,10,System(/tmp/${CALLERID(num)}.2) exten =&gt; h,11,Hangup() [callback] exten =&gt; s,1,Background(silence/1) ; lecture du fichier silence d'une seconde exten =&gt; s,2,SIPDtmfMode(inband) ; le touches sont lues sur la bande son, et pas sur les metadata SIP exten =&gt; s,3,Set(TIMEOUT(digit)=5) ; timeout entre deux chiffes. si rien n'est tape, fin d'appel exten =&gt; s,4,Set(TIMEOUT(response)=5) ; timeout avant le premier chiffre tape. si rien fin d'appel exten =&gt; s,5,Authenticate(1234) ; demande du mot de passe 1234 exten =&gt; s,6,DISA(no-password|maison) ; donner une tonalité sur le contexte maison</pre> <p>Et la cerise sur le gateau&nbsp;: modifier le fichier /etc/asterisk/indications.conf pour que les tonalités (invite et sonnerie) soient comme en France&nbsp;:</p> <pre class="brush: plain">[general] country=fr</pre> <p>Lancer asterisk en mode console via asterisk -vvvvc pour afficher ce qui se passe. Un fois que tout est bon, arrêter le serveur et lancer via /etc/init.d/asterisk start</p> <p>Cette démarche a été inspirée par <a href="http://nuxli.wordpress.com/2008/01/18/un-mvno-low-cost-a-utiliser-avec-ou-sans-le-systeme-asterisk/" hreflang="fr">ce blog</a> et une aide technique par <a href="http://toorop.fr/asterisk-callback-telephonez-a-moindre-cout-depuis-votre-mobile/" hreflang="fr">celui ci</a>, qui utilise Ovh comme fournisseur du numéro d'appel et des services SIP VoIP.</p> <h3>Amélioration</h3> <p>Je suppose qu'il devrai être possible de connecter le numéro DID directement sur Asterisk et se passer du compte SIP chez ekiga, mais je n'ai pas approfondi le sujet.</p> Taper les caractères Espéranto sous Linuxurn:md5:d5a4ef19f58d870c383efdc401bb52112009-12-11T20:57ZBouil<p>Sous Linux avec GTK, taper <tt>^ + g</tt> ne donne pas <tt>ĝ</tt>, mais un ''bip'' très pénible. Alors qu'avec les applications QT (KDE), ça fonctionne...</p> <p>La première chose à vérifier, c'est qu'au niveau des ''locales'', c'est bien en UTF-8. Car les caractères de l'espéranto ne sont pas présent dans la table de caractère française&#8230; Donc ici, ma locale est :</p> <pre class="brush: plain">$ locale LANG=fr_FR.UTF-8 LC_CTYPE="fr_FR.UTF-8" LC_NUMERIC="fr_FR.UTF-8" LC_TIME="fr_FR.UTF-8" LC_COLLATE="fr_FR.UTF-8" LC_MONETARY="fr_FR.UTF-8" LC_MESSAGES="fr_FR.UTF-8" LC_PAPER="fr_FR.UTF-8" LC_NAME="fr_FR.UTF-8" LC_ADDRESS="fr_FR.UTF-8" LC_TELEPHONE="fr_FR.UTF-8" LC_MEASUREMENT="fr_FR.UTF-8" LC_IDENTIFICATION="fr_FR.UTF-8" LC_ALL= $</pre> <p>C'est maintenant la configuration par défaut sous Ubuntu. Lorsqu'on a généré les locales adéquates, il est possible de choisir la bonne avec GDM.</p> <p>Revenons donc à nos moutons. En général, être en locale UTF-8 ne suffit pas. En fait, cela semble venir de la <em>méthode de saisie</em> (<em>Input Method</em>), qui est <em>Cedilla</em> par défaut avec GTK et qui ne fonctionne pas bien dans notre cas&#8230; Il faut passer en <em>méthode de saisie X</em> (<em>X Input Method</em>, ou <em>XIM</em>) pour que ça fonctionne.</p> <p>Pour le faire de manière provisoire, on peut cliquer bouton droit et changer à la main la méthode de saisie. Cependant, ça ne marche pas sous Firefox par exemple, parce que ce menu n'est pas présent.</p> <p>Pour le faire de manière automatique, il faut affecter une variable d'environnement :</p> <pre class="brush: plain">export GTK_IM_MODULE=xim</pre> <p>Vous pouvez tapez cette ligne juste avant de lancer vos programmes depuis la console. Mais ce n'est pas pratique, le mieux est de le faire de manière automatique.</p> <p>Si vous utilisez Gnome, il suffit alors de mettre le code précédent dans le fichier <tt>~/.gnomerc</tt>, que vous allez créer s'il n'existe pas. Dans un autre gestionnaire de bureau, un autre fichier devrait avoir le même but. Ou encore dans votre <tt>.Xsession</tt> si vous en utilisez un. Sous Ubuntu, vous pouvez aussi utiliser <tt>/etc/environment</tt> pour affecter des variables pour tout le système.</p> <p>Ainsi, beaucoup de combinaisons de touches auparavant impossibles vont maintenant fonctionner, que ce soit avec la touche morte <tt>^</tt> ou alors avec la touche <tt>Compose</tt> (que vous devez affecter à la touche de votre choix). D'ailleurs, pour saisir la lettre <tt>ŭ</tt>, la combinaison est <tt>Compose + b + u</tt>. (''b'' comme ''brève'').</p> <!-- /usr/lib/X11/locale/fr_FR.UTF-8/Compose --> SOAP avec PHP et Pythonurn:md5:b16cae8fa0160206b8edf5fb0330daf12009-12-11T20:57ZBouil<h3>Introduction</h3> <p>De manière simplifiée, SOAP permet de faire de l'appel de procédure à distance au dessus du protocole HTTP. Les données échangées sont au format XML.</p> <h3>Serveur PHP</h3> <h4>Avec PHP 5</h4> <p>Il va utiliser l'extension SOAP fournie avec <strong>PHP5</strong>, et il va répondre aux requêtes. Le code est alors très simple, que j'enregistre dans un fichier simple_soap.php :</p> <pre class="brush: python">&lt;?php //Définition des fonctions. Cela pourrait être dans un autre fichier inclus. function bonjour($nom) { return "Bonjour " . $nom . " !"; } function additionner($a, $b) { return $a + $b; } //Création du serveur $server = new SoapServer(null, array('uri'=&gt;'http://localhost/~bouil/simple_soap/simple_soap.php', 'encoding'=&gt;'UTF-8')); $server-&gt;addFunction("bonjour"); $server-&gt;addFunction("additionner"); //Et on lance le service en attente des données du client. $server-&gt;handle(); ?&gt;</pre> <p>Et c'est tout. On déclare les fonctions, on crée un nouveau serveur, on liste les fonctions à mettre à disposition, et on lance enfin le service.</p> <h4>Avec PHP 4</h4> <p>Pour <strong>PHP4</strong>, on peut utiliser <a href="http://sourceforge.net/projects/nusoap/">NuSoap</a>.</p> <p>Le code est alors légèrement différent. À noter que l'utilisation de NuSoap est incompatible avec PHP5, à cause de collision dans le nom des classes avec les classes SOAP déjà fournies.</p> <pre class="brush: php">&#60;?php require_once('nusoap.php'); //Définition des fonctions. Cela pourrait être dans un autre fichier inclus. function bonjour($nom) &#123; return "Bonjour " . $nom . " !"; &#125; function additionner($a, $b) &#123; return $a + $b; &#125; //Création du serveur $server = new soap_server; $server-&#62;soap_defencoding = "UTF-8"; $server-&#62;decode_utf8= false; $server-&#62;register('bonjour'); $server-&#62;register('additionner'); //Et on lance le service en attente des données du client. $server-&#62;service($HTTP_RAW_POST_DATA); ?&#62;</pre> <h3>Client Python</h3> <h4>Code</h4> <p>Python va utiliser le module python-soappy, disponible dans votre distribution.</p> <p>Une fois encore, le code du fichier simple_soap.py est simple :</p> <pre class="brush: python">#!/usr/bin/env python # -- coding: utf-8 -- import SOAPpy # création du client SOAP clientSOAP = SOAPpy.SOAPProxy("http://localhost/~bouil/simple_soap/simple_soap.php") clientSOAP.config.dict_encoding = "utf8" clientSOAP.config.debug = 0 clientSOAP.config.dumpSOAPIn = 0 clientSOAP.config.dumpSOAPOut = 0 # exécution des fonctions distantes print clientSOAP.bonjour(u"Bouil") x = 7 y = 35 res = clientSOAP.additionner(7, 35) print "%s + %s = %s" % (x, y, res)</pre> <p>Les lignes concernant le débogage (clientSOAP.config.debug = 0) ou l'affichage des données SOAP envoyées ou reçues (clientSOAP.config.dumpSOAPIn = 0 et clientSOAP.config.dumpSOAPOut = 0) sont bien utiles quand quelque chose va de travers. Il suffit alors de mettre les valeurs à 1.</p> <h4>Exécution</h4> <p>Et voilà, cela donne bien sur l'effet attendu :</p> <pre class="brush: plain">$ ./simple_soap.py Bonjour Bouil ! 7 + 35 = 42</pre> <h3>Conclusion</h3> <p>J'ai fait ici l'impasse sur les aspects plus complexes de SOAP, puisque ce n'était pas ce dont j'avais besoin lorsque j'ai cherché à utilser ces choses là.</p> <p>L'aspect interessant de SOAP, ici servi par PHP, c'est de pouvoir alors fournir les mêmes services, à partir d'une interface Web ou depuis un client dit "lourd" sur le bureau, par exemple en PyGTK, PyQT, &#8230;</p> Réutiliser les mots de passe SPIPurn:md5:e348fb20fb275d687d12ec1136671ef52009-12-11T20:57ZBouil<p>Imaginons que vous ayez un site sous SPIP, et que vous voulez utiliser sa base de donnée d'utilisateurs pour limiter l'accès à une page de votre conception aux seuls personnes ayant un compte SPIP. Voici la fonction PHP que j'ai utilisée dans ce cas de figure :</p> <pre class="brush: php">function identification(&#36;login, &#36;password) &#123; &#36;connexion = mysql_pconnect(&#36;serveur_mysql, &#36;login_mysql, &#36;pass_mysql); @mysql_select_db(&#36;nom_base_mysql); &#36;requete = "SELECT login FROM spip_auteurs WHERE login = '" . &#36;login . "'" . ' AND pass = md5( CONCAT(alea_actuel,"' . &#36;password . '"))'; &#36;results = mysql_query(&#36;requete, &#36;connexion); &#36;nb_results = mysql_num_rows(&#36;results); if(&#36;nb_results == 0) &#123; //ident pas ok mysql_free_result(&#36;results); return "Nom d'utilisateur ou mot de passe incorrect. ( &#36;login , &#36;password )"; &#125; else &#123; //auth ok mysql_free_result(&#36;results); return "ok"; &#125; &#125;</pre> <p>Je suppose qu'il est certainement bien mieux d'envoyer l'aléa actuel dans le formulaire de saisie du mot de passe, et de calculer le MD5 coté client avec Javascript, afin que le mot de passe ne circule pas en clair.</p> Réutiliser les mots de passe MediaWikiurn:md5:9342e7c32376ba5e4ad6045a54ad2d372009-12-11T20:57ZBouil<p>Imaginons que vous ayez un site sous MediaWiki 1.5, et que vous voulez utiliser sa base de donnée d'utilisateurs pour limiter l'accès à une page de votre conception aux seuls personnes ayant un compte sous votre Wiki. Voici la fonction PHP que j'ai utilisée dans ce cas de figure :</p> <pre class="brush: php">&#36;wgPasswordSalt = true; function identification(&#36;login, &#36;password) &#123; &#36;connexion = mysql_pconnect(&#36;serveur_mysql, &#36;login_mysql, &#36;pass_mysql); @mysql_select_db(&#36;nom_base_mysql); &#36;requete = "SELECT user_id, user_password FROM user WHERE user_name = '" . &#36;login . "'"; &#36;results = mysql_query(&#36;requete, &#36;connexion); &#36;nb_results = mysql_num_rows(&#36;results); if(&#36;nb_results == 0) &#123; //auth pas ok mysql_free_result(&#36;results); return "Nom d'utilisateur ou mot de passe incorrect."; &#125; else &#123; &#36;dict = mysql_fetch_assoc(&#36;results); &#36;db_passwd = &#36;dict&#91;"user_password"&#93;; &#36;db_id = &#36;dict&#91;"user_id"&#93;; mysql_free_result(&#36;results); &#36;enc_passwd = wfEncryptPassword(&#36;db_id, &#36;password); if (strcmp(&#36;enc_passwd, &#36;db_passwd) == 0) &#123; //auth ok return "ok"; &#125; else &#123; return "Nom d'utilisateur ou mot de passe incorrect. "; &#125; &#125; &#125; function wfEncryptPassword( &#36;userid, &#36;password ) &#123; global &#36;wgPasswordSalt; &#36;p = md5( &#36;password); if(&#36;wgPasswordSalt) return md5( "&#123;&#36;userid&#125;&#45;&#123;&#36;p&#125;" ); else return &#36;p; &#125;</pre> Récupérer un mail depuis un serveur IMAP avec Javaurn:md5:47fe5868db53f42262da94285dc70a9c2009-12-11T20:57ZBouil<p>Voici un exemple de code qui peut être utilisé pour se connecter à un serveur IMAP et récupérer un message donné par son Message-ID.</p> <pre class="brush: java"> import java.util.Properties; import javax.mail.Folder; import javax.mail.Message; import javax.mail.Session; import javax.mail.Store; import javax.mail.search.MessageIDTerm; public class App { public static void main( String[] args ) throws Exception { Session imapSession = Session.getDefaultInstance(new Properties(), null); imapSession.setDebug(false); Store imapStore = imapSession.getStore("imap"); imapStore.connect("imap.example.com", "john", "monPassword"); Folder imapFolder = imapStore.getDefaultFolder().getFolder("INBOX"); imapFolder.open(Folder.READ_ONLY); Message[] messages = imapFolder.search(new MessageIDTerm("<0KBN00DF4RBKI750@example.com>")); for (Message message : messages) { System.out.println(message.getSubject()); if (message.isMimeType("TEXT/PLAIN")){ System.out.println(message.getContent()); } } imapStore.close(); } } </pre> <p>En utlisant Maven, il faut ajouter la dépendance suivante :</p> <pre class="brush: xml"> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.1</version> </dependency> </pre> ResultSetTableModelurn:md5:eab4c96d5664b3d6e1c345b4c08685ef2009-12-11T20:57ZBouil<p>Ce petit bout de code permet d'afficher dans javax.swing.JTable le résultat d'un requête SQL. Il suffit pour l'utiliser, de placer le code suivant :</p> <pre class="brush: java">monJTable.setModel(new ResultSetTableModel(monResultSet));</pre> <p>Et le code contenant le modèle, à mettre dans un fichier à part, ResultSetTableModel.java :</p> <pre class="brush: java">import java.sql.*; import javax.swing.*; import javax.swing.table.*; import java.util.*; public class ResultSetTableModel extends AbstractTableModel{ private ResultSet rs = null; public ResultSetTableModel(ResultSet _rs){ rs = _rs; } public String getColumnName(int col) { try{ return rs.getMetaData().getColumnName(col + 1); } catch (SQLException e){ return Integer.toString(col); } } public int getColumnCount(){ int i = 0; try{ i = rs.getMetaData().getColumnCount(); } catch(SQLException e){ System.err.println("getColumnCount() : " + e); } return i; } public int getRowCount(){ int i = 0; try{ rs.last(); i = rs.getRow(); } catch(SQLException e){ System.err.println("getRowCount() : " + e); } return i; } public Object getValueAt(int row,int column){ Object o = ""; try{ rs.absolute(row + 1); o = rs.getObject(column + 1); } catch(SQLException e){ System.err.println("getValueAt() : " +e); } return o; } }</pre> ReVourn:md5:ce909c67b37e3de9488b9e15933a86532009-12-11T20:57ZBouil<p>Version française en bas.</p> <h3>Esperanto</h3> <p>Ĉi tiu paĝo klarigas kiel instali la esperantan vortaron <a href="http://reta-vortaro.de/">ReVo</a> en Debian aŭ Ubuntu.</p> <p>Unue, retumi tiun paĝon : <a href="http://reta-vortaro.de/tgz/index.html">http://reta-vortaro.de/tgz/index.html</a></p> <p>Poste, elŝutu la vortaron en la DICT-a formato (DICT-Revo) : revodict_XXXX-XX-XX.tgz</p> <p>Malkunpremu ĉiujn dosieron ekzemple en la dosierujo "/opt/esperanto".</p> <p>Ŝanĝu (kun "sed") la dosieron "/opt/esperanto/dictd.conf" por meti la ĝustajn vojojn kontraŭ la malkunpremitaj dosieroj. Ekzemple :</p> <pre class="brush: plain">database revo_eo &#123; data /opt/esperanto/revo.dat.dz index /opt/esperanto/revo.eo.inx name "Reta Vortaro, esperanta indekso" &#125; &#91;...&#93;</pre> <p>Instalu la pakaĵon "dictd".</p> <p>Ŝanĝu la dosieron "/etc/dictd/dictd.conf" kaj aldonu :</p> <pre class="brush: plain">&#35; Access section here: access &#123; allow localhost allow 127.0.0.1 &#35; this allows access only from local host &#125; &#91;...&#93; &#35; User section here: include /opt/esperanto/dictd.conf</pre> <p>Finfine, la "dictd" servilo devas funkcii kun la lokaĵo "UTF-8", ĉar estas la kodoprezento de la ReVo. Ĉi tiu punkto malfacilas por mi ĉar, sen tio, la servilo ne funkcias, sen erara mesaĝo por helpi. Do, ŝanĝu la dosieron "/etc/default/dictd" por havi la sekvantan linion (aŭ same por via lando) :</p> <pre class="brush: plain">DICTD_ARGS="&#45;&#45;locale=fr_FR.UTF&#45;8"</pre> <p>Restartu la servilon per "/etc/init.d/dictd restart".</p> <p>Poste tio farita, oni povas peti la servilon per la kliento "dict" (en konzolo), per "kdict", "gnome-dictionnary". Pensu diri al via kliento, ke ĝi devas uzi la servilon "localhost".</p> <h3>Français</h3> <p>Cette page explique comment installer le dictionnaire Espéranto <a href="http://reta-vortaro.de/">http://reta-vortaro.de/</a> ReVo sur Debian ou Ubuntu.</p> <p>Aller sur cette page : <a href="http://reta-vortaro.de/tgz/index.html">http://reta-vortaro.de/tgz/index.html</a></p> <p>Télécharger ensuite le dictionnaire au format DICT (DICT-Revo) : revodict_XXXX-XX-XX.tgz</p> <p>Décompresser tous les fichiers dans le repertoire /opt/esperanto/ par exemple.</p> <p>Modifier (un coup de "sed") le fichier /opt/esperanto/dictd.conf afin de mettre les bons chemins vers les fichiers extraits. Par exemple :</p> <pre class="brush: plain">database revo_eo &#123; data /opt/esperanto/revo.dat.dz index /opt/esperanto/revo.eo.inx name "Reta Vortaro, esperanta indekso" &#125; &#91;...&#93; </pre> <p>Installer le paquet 'dictd'.</p> <p>Modifier le fichier /etc/dictd/dictd.conf et ajouter :</p> <pre class="brush: plain"> &#35; Access section here: access &#123; allow localhost allow 127.0.0.1 &#35; this allows access only from local host &#125; &#91;...&#93; &#35; User section here: include /opt/esperanto/dictd.conf</pre> <p>Enfin, le serveur dictd doit être lancé en locale UTF-8, car c'est l'encodage du ReVo. Ce point m'a fait beaucoup galèrer car sans ça, le lancement du serveur dictd échoue sans message d'erreur pouvant aider. Modifier alors le fichier /etc/default/dictd de manière à avoir la ligne suivante (ou assimilée) :</p> <pre class="brush: plain">DICTD_ARGS="&#45;&#45;locale=fr_FR.UTF&#45;8"</pre> <p>Puis redémarrer le serveur avec "/etc/init.d/dictd restart".</p> <p>Un fois ceci effectué, on peut interroger le serveur à l'aide du client "dict" en ligne de commande, de "kdict" (sympa car il sépare bien les entrée lorsque plusieurs résultats sont possibles en configurant un peu les préférences), "gnome-dictionary" (interface trop simple, il ne sait interoger que tous les index d'un coup et ne sépare pas bien les différentes entrée). Il existe aussi d'autres clients DICT pour Emacs, mais je vous laisse trouver celui que vous préférez (apt-cache search dict client). D'ailleurs si vous connaissez un client DICT pour Windows cela m'interesse (c'est pas pour moi, bien entendu...).</p> Python et XMLurn:md5:c262853934af24c95b4e6c0cdd863dd32009-12-11T20:57ZBouil<p>Aide mémoire d'ouverture et d'enregistrement d'un fichier XML avec python-xml.</p> <pre class="brush: python">import xml.dom import xml.dom.ext.reader.Sax2 import xml.dom.ext &#35; Ouverture du fichier XML f = open('fichier.xml'), 'r') reader = xml.dom.ext.reader.Sax2.Reader() dom = reader.fromStream(f) &#35; Manipulation du DOM &#35; ... &#35; Enregistrement xml.dom.ext.Print(dom, open('fichier.xml', 'w')) &#35; Enregistrement indenté xml.dom.ext.PrettyPrint(dom, open('fichier.xml', 'w'))</pre> Parsing de fichier XML avec Castorurn:md5:c4350bfe7813e2e0a42a99a739ef9dbe2009-12-11T20:57ZBouil<p>Dans un programme Java, le chargement de fichiers XML externe est quelque chose de très fréquent. On utilise alors souvent DOM ou SAX, et c'est en général assez fastidieux. En voici <a href="Magnolia to Google Bookmarks">un exemple simple avec l'API DOM</a>.</p> <p>Heureusement, et comme souvent d'ailleurs, des gens ont pensé au problème d'automatiser et de simplifier tout ça. Voici un exemple avec la bibliothèque <a href="http://www.castor.org">Castor</a>.</p> <p>Je pars du principe que la version de Java utilisée est au moins la 1.5 (nécessaire pour les traitements XML sans JAR additionnels).</p> <h3>Fonctionnement de Castor</h3> <p>Castor va générer pour vous les classes métiers correspondantes aux différents éléments de votre fichier XML. Le prérequis pour cette étape est d'avoir un schéma XSD correspondant à vos fichiers XML. C'est plutôt une bonne chose que d'en avoir un, car cela permet d'être certain de ce qui va rentrer dans votre programme, et d'avoir donc moins de cas d'erreur à traiter.</p> <p>Castor propose pour la génération une tâche Ant, qui prendra donc en paramètres un fichier XSD, un ou deux fichiers de configuration si nécessaire, un répertoire de sortie pour les fichiers source Java générés.</p> <h3>Fichiers XML et XSD</h3> <p>Créer un nouveau projet (avec Eclipse par exemple), avec répertoire source (src) et destination (bin) séparés.</p> <p>Dans le répertoire "./src", placer le fichier schéma suivant, nommé "shiporder.xsd" :</p> <pre class="brush: xml">&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt; &lt;!-- http://www.w3schools.com/Schema/schema_example.asp --&gt; &lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt; &lt;xs:simpleType name="stringtype"&gt; &lt;xs:restriction base="xs:string"/&gt; &lt;/xs:simpleType&gt; &lt;xs:simpleType name="inttype"&gt; &lt;xs:restriction base="xs:positiveInteger"/&gt; &lt;/xs:simpleType&gt; &lt;xs:simpleType name="dectype"&gt; &lt;xs:restriction base="xs:decimal"/&gt; &lt;/xs:simpleType&gt; &lt;xs:simpleType name="orderidtype"&gt; &lt;xs:restriction base="xs:string"&gt; &lt;xs:pattern value="[0-9]{6}"/&gt; &lt;/xs:restriction&gt; &lt;/xs:simpleType&gt; &lt;xs:complexType name="shipto"&gt; &lt;xs:sequence&gt; &lt;xs:element name="name" type="stringtype"/&gt; &lt;xs:element name="address" type="stringtype"/&gt; &lt;xs:element name="city" type="stringtype"/&gt; &lt;xs:element name="country" type="stringtype"/&gt; &lt;/xs:sequence&gt; &lt;/xs:complexType&gt; &lt;xs:complexType name="item"&gt; &lt;xs:sequence&gt; &lt;xs:element name="title" type="stringtype"/&gt; &lt;xs:element name="note" type="stringtype" minOccurs="0"/&gt; &lt;xs:element name="quantity" type="inttype"/&gt; &lt;xs:element name="price" type="dectype"/&gt; &lt;/xs:sequence&gt; &lt;/xs:complexType&gt; &lt;xs:complexType name="shiporder"&gt; &lt;xs:sequence&gt; &lt;xs:element name="orderperson" type="stringtype"/&gt; &lt;xs:element name="shipto" type="shipto"/&gt; &lt;xs:element name="item" maxOccurs="unbounded" type="item"/&gt; &lt;/xs:sequence&gt; &lt;xs:attribute name="orderid" type="orderidtype" use="required"/&gt; &lt;/xs:complexType&gt; &lt;xs:element name="shiporder" type="shiporder"/&gt; &lt;/xs:schema&gt;</pre> <p>Créer également dans le répertoire racine un fichier de données exemple "./shiporder.xml" :</p> <pre class="brush: xml">&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt; &lt;shiporder orderid="889923" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="shiporder.xsd"&gt; &lt;orderperson&gt;John Smith&lt;/orderperson&gt; &lt;shipto&gt; &lt;name&gt;Ola Nordmann&lt;/name&gt; &lt;address&gt;Langgt 23&lt;/address&gt; &lt;city&gt;4000 Stavanger&lt;/city&gt; &lt;country&gt;Norway&lt;/country&gt; &lt;/shipto&gt; &lt;item&gt; &lt;title&gt;Empire Burlesque&lt;/title&gt; &lt;note&gt;Special Edition&lt;/note&gt; &lt;quantity&gt;1&lt;/quantity&gt; &lt;price&gt;10.90&lt;/price&gt; &lt;/item&gt; &lt;item&gt; &lt;title&gt;Hide your heart&lt;/title&gt; &lt;quantity&gt;1&lt;/quantity&gt; &lt;price&gt;9.90&lt;/price&gt; &lt;/item&gt; &lt;/shiporder&gt;</pre> <h3>Génération du code</h3> <p>Dans le répertoire "./lib", dans lequel nous allons mettre les JAR nécessaire à l'exécution projet :</p> <p> <ul> <li><span class="wikiexternallink"><a href="http://castor.org/download.html#Castor">castor&#45;1.2.jar</a></span></li> <li><span class="wikiexternallink"><a href="http://castor.org/download.html#Castor">castor&#45;1.2&#45;xml.jar</a></span></li> <li><span class="wikiexternallink"><a href="http://castor.org/download.html#Castor">castor&#45;1.2&#45;xml&#45;schema.jar</a></span></li> <li><span class="wikiexternallink"><a href="http://commons.apache.org/downloads/download_io.cgi">commons&#45;io&#45;1.1.jar</a></span></li> <li><span class="wikiexternallink"><a href="http://commons.apache.org/downloads/download_lang.cgi">commons&#45;lang&#45;2.4.jar</a></span></li> <li><span class="wikiexternallink"><a href="http://commons.apache.org/downloads/download_logging.cgi">commons&#45;logging.jar</a></span></li> <li><span class="wikiexternallink"><a href="http://jakarta.apache.org/site/downloads/downloads_oro.cgi">jakarta&#45;oro&#45;2.0.8.jar</a></span></li> <li><span class="wikiexternallink"><a href="http://logging.apache.org/log4j/1.2/download.html">log4j&#45;1.2.8.jar</a></span></li> </ul> <p>Et dans un répertoire "./lib/extra", placer les JAR nécessaire à la génération du code par Ant :</p> <p> <ul class="star"> <li><span class="wikiexternallink"><a href="http://castor.org/download.html#Castor">castor&#45;1.2&#45;anttasks.jar</a></span></li> <li><span class="wikiexternallink"><a href="http://castor.org/download.html#Castor">castor&#45;1.2&#45;codegen.jar</a></span></li> <li><span class="wikiexternallink"><a href="http://velocity.apache.org/download.cgi">velocity&#45;1.5.jar</a></span></li> </ul> </p> <p>À la racine du projet, créer le fichier build ant "./build.xml" suivant :</p> <pre class="brush: xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;project basedir="." default="build" name="ExempleCastor"&gt; &lt;property name="project.name" value="ExempleCastor" /&gt; &lt;property name="dist.dir" location="dist" /&gt; &lt;property environment="env" /&gt; &lt;property name="debuglevel" value="source,lines,vars" /&gt; &lt;property name="target" value="1.2" /&gt; &lt;property name="source" value="1.3" /&gt; &lt;path id="ExempleCastor.classpath"&gt; &lt;fileset dir="lib/"&gt; &lt;include name="*.jar" /&gt; &lt;/fileset&gt; &lt;/path&gt; &lt;path id="ExempleCastor.extra.classpath"&gt; &lt;fileset dir="lib/extra"&gt; &lt;include name="*.jar" /&gt; &lt;/fileset&gt; &lt;path refid="ExempleCastor.classpath" /&gt; &lt;/path&gt; &lt;target name="clean"&gt; &lt;delete dir="bin" /&gt; &lt;mkdir dir="bin" /&gt; &lt;/target&gt; &lt;!-- VERIFICATION DE LA JVM : pour que CASTOR fonctionne, il faut que la JVM soit au moins 1.5 --&gt; &lt;target name="get-jvm"&gt; &lt;condition property="jvm.ok"&gt; &lt;or&gt; &lt;equals arg1="${ant.java.version}" arg2="1.5" /&gt; &lt;equals arg1="${ant.java.version}" arg2="1.6" /&gt; &lt;/or&gt; &lt;/condition&gt; &lt;/target&gt; &lt;target name="check-jvm" depends="get-jvm" unless="jvm.ok"&gt; &lt;fail message="Wrong JVM - ${ant.java.version}" /&gt; &lt;/target&gt; &lt;target name="test-jvm" depends="check-jvm"&gt; &lt;echo message="JVM OK - ${ant.java.version}" /&gt; &lt;/target&gt; &lt;target name="generate-sources" depends="test-jvm" description="Generate Java source files from XSD."&gt; &lt;taskdef name="castor-srcgen" classname="org.castor.anttask.CastorCodeGenTask" classpathref="ExempleCastor.extra.classpath" /&gt; &lt;delete dir="generated-source" /&gt; &lt;mkdir dir="generated-source" /&gt; &lt;castor-srcgen bindingfile="bindings.xml" casesensitive="on" verbose="yes" file="./src/shiporder.xsd" todir="generated-source" package="org.bouil.exemple.castor.schema.shiporder" types="j2" warnings="true" /&gt; &lt;/target&gt; &lt;target name="compile" depends="generate-sources"&gt; &lt;javac debug="true" destdir="bin" classpathref="ExempleCastor.classpath" source="${source}" target="${target}"&gt; &lt;src path="src" /&gt; &lt;src path="generated-source" /&gt; &lt;/javac&gt; &lt;copy todir="bin"&gt; &lt;fileset dir="src"&gt; &lt;exclude name="**/*.java" /&gt; &lt;/fileset&gt; &lt;/copy&gt; &lt;/target&gt; &lt;target name="jar" depends="compile"&gt; &lt;delete dir="dist" /&gt; &lt;mkdir dir="dist" /&gt; &lt;jar destfile="dist/${project.name}.jar" basedir="bin"&gt; &lt;manifest&gt; &lt;attribute name="Main-Class" value="org.bouil.exemple.castor.Process" /&gt; &lt;/manifest&gt; &lt;/jar&gt; &lt;/target&gt; &lt;target name="build" depends="clean,generate-sources,compile,jar" /&gt; &lt;/project&gt;</pre> <p>Je ne détaille pas tout le script Ant, la tache nommée "generate-sources" est celle mettant en jeu Castor.</p> <p>Le fichier, à la racine du projet, nommé "bindings.xml" est important, car sans celui ci, la génération des sources ne fonctionnerait pas.</p> <p>En effet, j'ai volontairement dans le fichier XSD, nommé les éléments avec le même nom que les types de données. Ceci se voit par exemple ici :</p> <pre class="brush: xml">&lt;s:element name="shiporder" type="shiporder"/&gt;</pre> <p>Castor va générer une classe pour le Bean représentant l'élément "shiporder", et une classe pour le type complexe "shiporder", qui ont le malheur de s'appeler pareil. La génération donnerait un message comme celui ci :</p> <pre class="brush: plain">Warning: A class name generation conflict has occured between complexType '/complexType:shipto' and element '/complexType:shiporder/shipto'. Please use a Binding file to solve this problem.</pre> <p>Le fichier "bindings.xml" permet de résoudre ce problème :</p> <pre class="brush: xml">&lt;binding xmlns="http://www.castor.org/SourceGenerator/Binding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.castor.org/SourceGenerator/Binding C:\\Castor\\xsd\\binding.xsd" defaultBinding="element"&gt; &lt;namingXML&gt; &lt;complexTypeName&gt; &lt;suffix&gt;Type&lt;/suffix&gt; &lt;/complexTypeName&gt; &lt;/namingXML&gt; &lt;!-- &lt;elementBinding name="/complexType:shiptotype"&gt; &lt;java-class name="ShipToType" /&gt; &lt;/elementBinding&gt; --&gt; &lt;/binding&gt;</pre> <p>La partie mise en commentaire permet, si nécessaire, de renommer un élément avec le nom choisi.</p> <p>Lancer maintenant la tâche Ant avec la cible par défaut. Le répertoire "./generated-source" doit maintenant être rempli avec les sources générés par Castor.</p> <h3>Chargement du XML</h3> <p>Avec Eclipse, ajouter le répertoire "./generated-source" à la liste des répertoires contentant des sources Java.</p> <p>La classe permettant de charger le fichier XML est assez simple. J'y ajouté également une validation du fichier XML par rapport au schéma XSD afin d'être certain que le fichier d'entrée est correct.</p> <p>Le fichier XSD est volontairement chargé via le ClassLoader. Je considère en effet que ce fichier fait partie des sources, et n'est pas susceptible d'être modifié sans que les souces générés soit également modifiés.</p> <p>Créer cette classe dans le fichier "./src/org/bouil/exemple/castor/Process.java" :</p> <pre class="brush: java">package org.bouil.exemple.castor; import java.io.File; import java.io.FileInputStream; import javax.xml.XMLConstants; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import org.bouil.exemple.castor.schema.shiporder.Shiporder; import org.exolab.castor.xml.Unmarshaller; import org.xml.sax.InputSource; public class Process { public static void main(String[] args) throws Exception { File fichierXML = new File("shiporder.xml"); validateXML(fichierXML); unmarshal(fichierXML); } /** * Valide le fichier XML par rapport au Schéma * @param fichierXML * @return * @throws Exception */ public static boolean validateXML(File fichierXML) throws Exception { try { System.out.println("Validation XSD du fichier XML..."); long debut = System.currentTimeMillis(); SchemaFactory factory = SchemaFactory .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schemaFile = factory.newSchema(new StreamSource( Process.class.getClassLoader().getResourceAsStream( "shiporder.xsd"))); Validator validator = schemaFile.newValidator(); validator .validate(new StreamSource(new FileInputStream(fichierXML))); long fin = System.currentTimeMillis(); long duree = fin - debut; System.out.println(duree + " ms"); return true; } catch (Exception e) { throw e; } } /** * Charge le fichier XML dans le Bean généré par Castor * @param fichierXML * @throws Exception */ public static void unmarshal(File fichierXML) throws Exception { System.out.println("Lecture du fichier XML en mémoire..."); long debut = System.currentTimeMillis(); InputSource inputSource = new InputSource(new FileInputStream( fichierXML)); Shiporder shipOrder = (Shiporder) Unmarshaller.unmarshal( Shiporder.class, inputSource); long fin = System.currentTimeMillis(); long duree = fin - debut; System.out.println(duree + " ms"); System.out.println("shipOrder " + shipOrder.getOrderid() + " chargée"); } }</pre> <h3>Exécution</h3> <p>L'exécution donne ceci :</p> <pre class="brush: plain">Validation XSD du fichier XML... 79 ms Lecture du fichier XML en mémoire... 182 ms shipOrder 889923 chargée</pre> Magnolia to Google Bookmarksurn:md5:04140c6c9dfb10233932b11e00a580502009-12-11T20:57ZBouil<p>L'export ma.gnolia.com vers un fichier bookmarks.html compatible firefox ne permet pas un import correct des tags vers Google Bookmarks.</p> <p>En effet, la barre d'outils Google va utiliser le nom du dossier du favori comme tag.</p> <p>Voici un programme Java qui permet d'exporter vos signets ma.gnolia vers un fichier bookmark (affiché dans la console, à copier dans un fichier ensuite) que vous pourrez ensuite importer dans Firefox. Les tags seront donc des dossiers. Un signet qui a plusieurs tags apparaitera du coup plusieurs fois. Mais ceci permet à la barre d'outil Google d'importer les favoris avec tous les tags.</p> <pre class="brush: java">import java.io.InputStream; import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; public class Process { /** * @param args */ public static void main(String[] args) throws Exception { String apiKey = "YOUR_API_KEY"; String person = "YOUR_LOGIN_NAME"; URL url = new URL( "http://ma.gnolia.com/api/rest/1/bookmarks_find?api_key=" + apiKey + "&person=" + person); InputStream content = (InputStream) url.getContent(); Document dom = DocumentBuilderFactory.newInstance() .newDocumentBuilder().parse(content); NodeList bookmarkList = dom.getElementsByTagName("bookmark"); // Store local contenant les bookmarks, associé à leur tag HashMap&lt;String , Set&lt;Bookmark&gt;&gt; liste = new HashMap&lt;String, Set&lt;Bookmark&gt;&gt;(); for (int i = 0; i &lt; bookmarkList.getLength(); i++) { Element bookmarkNode = (Element) bookmarkList.item(i); Element titleNode = (Element) bookmarkNode.getElementsByTagName( "title").item(0); Element urlNode = (Element) bookmarkNode .getElementsByTagName("url").item(0); Element descriptionNode = (Element) bookmarkNode .getElementsByTagName("description").item(0); Bookmark bookmark = new Bookmark(); bookmark.setName(titleNode.getTextContent()); bookmark.setUrl(urlNode.getTextContent()); if (descriptionNode.getTextContent().length() != 0) { bookmark.setDescription(descriptionNode.getTextContent()); } Element tagsNode = (Element) bookmarkNode.getElementsByTagName( "tags").item(0); NodeList tagNodeList = tagsNode.getElementsByTagName("tag"); Set&lt;String&gt; tagSet = new HashSet&lt;String&gt;(); for (int j = 0; j &lt; tagNodeList.getLength(); j++) { Element tagNode = (Element) tagNodeList.item(j); String tag = tagNode.getAttribute("name"); tagSet.add(tagNode.getTextContent()); if (!liste.containsKey(tag)) { liste.put(tag, new HashSet&lt;Bookmark&gt;()); } liste.get(tag).add(bookmark); } bookmark.setTags(tagSet); } // parcours de la liste et print du bookarmks.html System.out.println("&lt;!DOCTYPE NETSCAPE-Bookmark-file-1&gt;"); System.out .println("&lt;META HTTP-EQUIV=\ "Content-Type\" CONTENT=\"text/html; charset=UTF-8\"&gt;"); System.out.println("&lt;TITLE&gt;Bookmarks&lt;/TITLE&gt;"); System.out.println("&lt;H1&gt;Bookmarks&lt;/H1&gt;"); System.out.println("&lt;DL&gt;&lt;p&gt;"); for (Iterator&lt;String&gt; iterator = liste.keySet().iterator(); iterator .hasNext();) { String tag = iterator.next(); System.out.println("&lt;DT&gt;&lt;H3&gt;" + tag + "&lt;/H3&gt;"); System.out.println("&lt;DL&gt;&lt;p&gt;"); Set&lt;Bookmark&gt; bookmarks = liste.get(tag); for (Iterator&lt;Bookmark&gt; iterator2 = bookmarks.iterator(); iterator2 .hasNext();) { Bookmark bookmark = iterator2.next(); System.out.println("&lt;DT&gt;&lt;A HREF=\"" + bookmark.getUrl() + "\"&gt;" + bookmark.getName() + "&lt;/A&gt;"); if (bookmark.getDescription() != null) { System.out.println("&lt;DD&gt;" + bookmark.getDescription()); } } System.out.println("&lt;/DL&gt;&lt;p&gt;"); } System.out.println("&lt;/DL&gt;&lt;p&gt;"); } } class Bookmark { private String name = null; private String url = null; private Set&lt;String&gt; tags = null; private String description = null; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public Set&lt;String&gt; getTags() { return tags; } public void setTags(Set&lt;String&gt; tags) { this.tags = tags; } }</pre> Installer un serveur IMAP avec Dovecot, Postfix et Fetchmailurn:md5:18e81fcd79069dd78f606b43301c58c52009-12-11T20:57ZBouil<p>Installer postfix. Cela fonctionne aussi avec d'autres serveurs de courriel, mais je détaille uniquement pour Postfix.</p> <p>Par choix personnel, je préfère utiliser le format Maildir afin de conserver mes courriels. Chaque courriel sera alors dans un fichier propre, contrairement au format mbox avec lequel chaque dossier (contenant souvent plusieurs centaines de courriels) est un fichier de plusieurs Mo. Pour configurer ainsi Postfix, modifier alors le fichier /etc/postfix/main.cf pour ajouter :</p> <p> <pre class="brush: plain">home_mailbox = Courriel/</pre> </p> <p>Le "/" final indique à Postfix que l'on veut utiliser le format Maildir. Les courriels seront dont mis dans le repertoire personnel de chaque utilisateur, dans le sous répertoire courriel.</p> <p>Redémarrer Postfix. Assurez vous que le répertoire ~/Courriel existe, avec les droits d'écriture pour votre utilisateur. Afin de créer la structure du Maildir, s'envoyer un courriel :</p> <p> <pre class="brush: plain">&#36; mail nom_utilisateur Subject: Creation de la boite &#60;entrée&#62; Voila qui est fait &#60;ctrl+D&#62; Cc: &#60;entree&#62; &#36;</pre> </p> <p>Si on liste le contenu de ~/Courriel, apparait alors :</p> <p> <pre class="brush: plain">&#36; ls &#45;F ~/Courriel/ cur/ new/ tmp/ &#36;</pre> </p> <p>Installer dovecot-imapd. C'est un très bon serveur IMAP, qui est configurable facilement (contrairement à uw-imapd). Il suffit ensuite de modifier la configuration pour indiquer à Dovecot où il doit chercher les courriels. Dans le fichier /etc/dovecot.conf, chercher default_mail_env et indiquer à la suite des exemples donnés :</p> <p> <pre class="brush: plain">default_mail_env = maildir:/home/%u/Courriel/</pre> </p> <p>Si vous avez conservé le format mbox, il suffit d'adapter la configuration à votre cas, dovecot pouvant également accéder à une boite au format mbox.</p> <p>Redémarrez dovecot. Vous pouvez ensuite tester avec Mozilla Thunderbird, KMail ou évolution votre accès au serveur IMAP. Vous pouvez utiliser IMAP/SSL pour plus de sécurité.</p> <p>Il s'agit ensuite de récupérer les courriels distants de votre éventuel fournisseur si vous ne faites pas vous même serveur pour vos courriels. Pour cela, installez fetchmail. Vous pouvez également installer fechtmailconf pour vous aider lors de la configuration de fetchmail. Fetchmail va se charger de récupérer vos courriels par POP3 ou POP3/SSL et va les transférer à Postfix. Créez vous un fichier ~/.fetchmailrc qui va ressembler à ceci :</p> <p> <pre class="brush: plain">&#35; Configuration created Wed Apr 7 23:12:15 2004 by fetchmailconf set postmaster "bouil" set bouncemail set no spambounce set properties "" poll pop.ouvaton.org with proto POP3 and options tracepolls user 'mon_login_POP' there with password 'VOTRE_MOT_DE_PASSE' is 'mon_login_LOCAL' here options fetchall ssl poll mail.altern.org with proto POP3 and options tracepolls user 'mon_login_POP' there with password 'VOTRE_MOT_DE_PASSE' is 'mon_login_LOCAL' here options fetchall</pre> </p> <p>Donc, on relève ici deux boites, la première en SSL (option ssl à la fin de la ligne), l'autre sans SSL. Les courriels seront dans les deux cas transmis dans la boite de l'utilsateur local.</p> <p>Lancez ensuite fetchmail à ma main, et vérifiez ainsi que la configuration de fetchmail est correcte. Creez ensuite une tache planifiée afin de faire executer fetchmail de manière régulière, automatiquement. Éditez pour cela votre fichier crontab personnel :</p> <p> <pre class="brush: plain">&#36; crontab &#45;e</pre> </p> <p>et ajouter une ligne ressemblant à cela :</p> <p> <pre class="brush: plain">&#35; m h dom mon dow user command &#42;/5 &#42; &#42; &#42; &#42; fetchmail &#62;/dev/null 2&#62;&1</pre> </p> <p>Ceci executera fetchmail toutes les 5 minutes. Les erreurs eventuelles de fetchmail (erreur de résolution de noms, connexion perdue, etc...) seront poubellisées, au lieu de vous être envoyées par courriel (mécanisme classique de cron).</p> <p>N'oubliez pas, le cas échéant, d'autoriser IMAP en entrée au niveau de votre pare-feu. <h2>Utilisation de procmail pour filter les mails</h2> <p>Dans le fichier postfix/main.cf, ne pas définir <pre class="brush: plain">home_mailbox = Courriel/</pre> mais ajouter la ligne suivante :</p> <p> <pre class="brush: plain">mailbox_command = procmail -a "$EXTENSION"</pre> </p> Dans votre répertoire personnel, créer un fichier .procmailrc <p> <pre class="brush: plain"> SHELL=/bin/sh PMDIR=$HOME/Procmail LOGFILE=$PMDIR/pm.log MAILDIR=$HOME/Courriel/ DEFAULT=$MAILDIR INCLUDERC=$PMDIR/rc.subscription </pre> </p> <p>Comme on a mis l'option tracepolls à fetchmail plus haut, on va pouvoir mettre les mails dans un répertoire différent en fonction de la boite d'origine. On peut filter par expéditeur, liste de diffusion, etc..</p> <p>Créer donc le fichier <pre>~/Procmail/rc.subscription</pre>.</p> <p> <pre class="brush: plain"> # Les messages du credit mutuel :0: * ^From:.*creditmutuel.fr.* .INBOX.Banque/ # Tapestry Mailing List :0: * ^List-Id: .*tapestry.*$ .INBOX.Tapestry/ :0: * ^X-fetchmailtracepoll: ouvaton$ .INBOX.Ouvaton/ </pre> </p> Graver en ligne de commandeurn:md5:b1e5a9b58e5b64830a53130a824aafea2009-12-11T20:57ZBouil<p>Pour graver rapidement une ISO en ligne de commande, j'utilise le script shell suivant :</p> <pre class="brush: bash">&#35;!/bin/bash if &#91; &#45;z &#36;1 &#93; then echo "Usage &#36;0 Nom_Iso" exit 1 fi cdrecord &#45;v &#45;eject &#45;multi driveropts=burnfree speed=48 dev=/dev/cdrw &#36;1</pre> <p>Pour graver rapidement un répertoire en ligne de commande :</p> <pre class="brush: bash">&#35;!/bin/bash if &#91; &#45;z &#36;1 &#93; then echo "Usage &#36;0 Nom_de_Volume" exit 1 fi mkisofs &#45;v &#45;V "&#36;1" &#45;J &#45;r . | cdrecord &#45;v &#45;eject driveropts=burnfree speed=48 dev=/dev/cdrw &#45;</pre> Création d'un environnement de test JUnit avec JNDIurn:md5:322c64eee3178224dcb9e3d69c6d581b2009-12-11T20:57ZBouil<p>Dans un projet, il est important de pouvoir créer des tests unitaires JUnit. Dans le cas d'un projet Web, la connexion à la base de donnée est réalisée avec JNDI. Dans l'environnement de test, il faut alors disposer d'un environnement JNDI. Pour cela, on peut utiliser <a href="http://www.osjava.org/simple-jndi/">Simple-JNDI</a>.</p> <p>Voici en une capture d'écran toutes les informations pour mettre en place ceci (cliquer sur l'image pour voir en taille réelle):</p> <p><a href='../images/jndi.png'><img src="../images/jndi.png" height="400px" alt="Screenshot Eclipse" title="Screenshot Eclipse" /></a></p> <p>test/JNDITest.java</p> <pre class="brush: java">import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; import org.junit.Assert; import org.junit.Test; public class JNDITest {; @Test public void testJNDI() throws Exception {; // Obtain our environment naming context Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); // Look up our data source DataSource ds = (DataSource) envCtx.lookup("jdbc/myDataSource"); Assert.assertNotNull(ds); } }</pre> <p>test/jndi.properties : doit être à la racine du classpath lors des tests, mais pas lors de l'exécution normale du programme</p> <pre class="brush: plain">java.naming.factory.initial=org.osjava.sj.SimpleContextFactory org.osjava.sj.root=test/resources/simple-jndi/ org.osjava.sj.delimiter=/ org.osjava.sj.space=java:comp/env</pre> <p>test/resources/simple-jndi/jdbc/myDataSource.properties</p> <pre class="brush: plain">type=javax.sql.DataSource driver=org.gjt.mm.mysql.Driver url=jdbc:mysql://localhost/testdb user=testuser password=testing</pre> <p>Consulter <a href="http://www.osjava.org/simple-jndi/manual/index.html">le manuel de simple-jndi</a> pour plus d'informations sur la configuration.</p> Configuration en vrac Windowsurn:md5:c51b9a399a5e187641f763a040ff4e222009-12-11T20:57ZBouil<h3>Rechercher dans tous les fichiers</h3> <p>Lors d'une recherche du contenu d'un fichier, Windows ne cherche pas dans le contenu de tous les fichiers, mais seuls ceux pour lesquels il a envie.</p> <p>Le fichier .reg suivant permet d'activer la recherche de texte quelque soit le type de fichier.</p> <pre class="brush: plain">Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ContentIndex] "FilterFilesWithUnknownExtensions"=dword:00000001</pre> <h3>Virer l'écran « Utiliser le service Web » lors de l'ouverture d'un fichier inconnu</h3> <pre class="brush: plain">Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System] "NoInternetOpenWith"=dword:00000001</pre> Configuration du Touchpad Synapticsurn:md5:c1d08a2fd294b65cf5c4232b8c294dc92009-12-11T20:57ZBouil<p>Pour désactiver le clic lors d'une petite touche sur le Touchpad (histoire de pas cliquer de partout en voiture quand y a des bosses !), il faut mettre ceci dans la section correspondante du fichier <tt>xorg.conf</tt> :</p> <pre class="brush: plain">Option "MaxTapMove" "0"</pre> <p>Par contre, ça ne désactive pas le clic du milieu avec deux doigts et le clic droit avec trois doigts, que l'on peut désactiver avec :</p> <pre class="brush: plain">Option "MaxTapTime" "0"</pre> <p>Plus d'infos sur le driver Synaptics : <a href="http://web.telia.com/~u89404340/touchpad/index.html">http://web.telia.com/~u89404340/touchpad/index.html</a></p> Clavier français sous GRUBurn:md5:50b81ddbcd8f47f6461aabb16bab05d72009-12-11T20:57ZBouil<p>Source : <a href="http://lists.gnu.org/archive/html/bug-grub/2003-10/msg00178.html">Message de Michel Bouissou sur la liste de diffusion GRUB</a></p> <p>Pour avoir un clavier AZERTY français sous GRUB, il suffit de mettre ceci au début du fichier de configuration de GRUB <tt>menu.lst</tt> :</p> <pre class="brush: plain"># Gestion clavier AZERTY francais pour grub # # Lettres correctement transposees # setkey a q setkey A Q setkey z w setkey Z W setkey q a setkey Q A setkey m semicolon setkey M colon setkey w z setkey W Z # # Ponctuation correctement transposee # setkey comma m setkey question M setkey semicolon comma setkey period less setkey colon period setkey slash greater setkey exclam slash # setkey dollar bracketright setkey asterisk backslash setkey percent doublequote # # Chiffres et symboles. Le clavier QWERTY ne gere pas la touche AltGr, ce qui # pose probleme pour la conversion AZERTY. Choix retenu: # - Quand le symbole minuscule est utile (exemple "-"), c'est lui qui sera # obtenu, et le symbole obtenu par AltGr (exemple "|") devra etre transfere # vers une autre touche. # - Quand le symbole minuscule est inutile ou ne peut etre converti (exemple # "e accent aigu"), c'est alors le symbole AltGr (exemple "~") qui sera # directement obtenu. # setkey ampersand 1 setkey 1 exclam setkey tilde 2 setkey 2 at setkey doublequote 3 setkey 3 numbersign setkey quote 4 setkey 4 dollar setkey parenleft 5 setkey 5 percent setkey minus 6 setkey 6 caret setkey backquote 7 setkey 7 ampersand setkey underscore 8 setkey 8 asterisk setkey caret 9 setkey 9 parenleft setkey at 0 setkey 0 parenright # # Symboles correctement transposes # setkey parenright minus # # Symboles demenages vers d'autres touches (vous devrez chercher un peu...) # # Inferieur et superieur => touche "carre / cube" setkey less backquote setkey greater tilde # # "#" ==> la touche "£" setkey numbersign braceright # # "|" ==> touche "mu" (et peut-etre "<"), identique a QWERTY # # "\" ==> touche "paragraphe" setkey backslash question # # "[" et "]" sur touche "circonflexe" / "trema" setkey bracketright braceleft # # "{" ==> touche "u accent grave" setkey braceleft quote # # "}" ==> touche "degre" setkey braceright underscore # # Fin des transpositions</pre> Anturn:md5:938db156ad9b67fa1d4276ac676499402009-12-11T20:57ZBouil<h3>Vérifier la version de la JVM</h3> <p>Repris et adapté depuis <a href="http://www.jguru.com/faq/view.jsp?EID=557952">http://www.jguru.com/faq/view.jsp?EID=557952</a></p> <p>Pour compiler, il se peut qu'il soit nécessaire que la JVM ait une certaine version. Le bout de script Ant suivant permet de faire échouer le build si la version n'est pas correcte.</p> <p> <pre class="brush: xml">&#60;target name="get-jvm"&#62; &#60;condition property="jvm.ok"&#62; &#60;or&#62; &#60;equals arg1="${ant.java.version}" arg2="1.5" /&#62; &#60;equals arg1="${ant.java.version}" arg2="1.6" /&#62; &#60;/or&#62; &#60;/condition&#62; &#60;/target&#62; &#60;target name="check-jvm" depends="get-jvm" unless="jvm.ok"&#62; &#60;fail message="Wrong JVM - ${ant.java.version}" /&#62; &#60;/target&#62; &#60;target name="test-jvm" depends="check-jvm"&#62; &#60;echo message="JVM OK - ${ant.java.version}" /&#62; &#60;/target&#62; &#60;target name="maCible" depends="test-jvm" description="Ma cible qui dépends d'une JVM au moins 1.5"&#62; &#60;/target&#62;</pre> </p> <p>Si la version de Java n'est pas 1.5 ou 1.6, la variable "jvm.ok" aura une valeur à "false" après la cible "get-jvm". Ainsi, le step "check-jvm" sera exectué, et le build échouera.</p> <p>Si la version de Java est correcte, alors "jvm.ok" sera à "true". La cible "check-jvm" ne sera pas executée, et le build pourra donc continuer.</p> <p>On peut imaginer de vérifier aussi le fournisseur ("vendor"). Cela peut être nécessaire par exemple pour Webphère et la compilation des EJB via un build Ant.</p> Adjectifsurn:md5:5e484151c10e7da18cece1f8a409f7e92009-12-11T20:57ZBouil<p>Le but du jeu est de trouver l'adjectif qui correspond au nom, sans bien sûr regarder avant la colone de droite !</p> <p>Dans le tableau de gauche, le français. Dans le tableau de droite, l'espéranto. Vous allez vous rendre compte qu'à partir du nom, vous trouverez toujours (sauf pour les 2 ou 3 premiers, le temps de comprendre comment ça marche) l'adjectif correspondant en espéranto même si vous ne l'avez jamais appris. En français, c'est beaucoup plus difficile, même pour un locuteur natif !</p> <p>Si vous voulez en savoir plus sur l'espéranto :</p> <ul> <li><a href="http://esperanto.net/info/index_fr.html">http://esperanto.net/info/index_fr.html</a></li> <li><a href="http://www.lernu.net">http://www.lernu.net</a></li> <li><a href="http://fr.wikipedia.org/wiki/Esperanto">http://fr.wikipedia.org/wiki/Esperanto</a></li> </ul> <table border="0" style="border: none;"> <tr> <td style="padding: 1em;"> <table border="1" style="border: 1px solid black; border-collapse: collapse"> <caption>Liste de noms et d'adjectifs en français</caption> <tbody> <tr> <td><strong class="strong">nom</strong></td> <td><strong class="strong">adjectif</strong></td> </tr> <tr> <td>frère</td> <td>fraternel</td> </tr> <tr> <td>matin</td> <td>matinal</td> </tr> <tr> <td>ami</td> <td>amical</td> </tr> <tr> <td>cercle</td> <td>circulaire</td> </tr> <tr> <td>soir</td> <td>vespéral</td> </tr> <tr> <td>dimanche</td> <td>dominical</td> </tr> <tr> <td>oncle</td> <td>avunculaire</td> </tr> <tr> <td>chien</td> <td>canin</td> </tr> <tr> <td>chat</td> <td>félin</td> </tr> <tr> <td>mouton</td> <td>ovin</td> </tr> <tr> <td>soleil</td> <td>solaire</td> </tr> <tr> <td>étoile</td> <td>stellaire</td> </tr> <tr> <td>mer</td> <td>maritime, marin</td> </tr> <tr> <td>nuit</td> <td>nocturne</td> </tr> <tr> <td>parole</td> <td>oral</td> </tr> <tr> <td>aide</td> <td>auxiliaire</td> </tr> <tr> <td>main</td> <td>manuel</td> </tr> <tr> <td>oreille</td> <td>auriculaire</td> </tr> <tr> <td>œil</td> <td>oculaire</td> </tr> <tr> <td>évêque</td> <td>épiscopal</td> </tr> <tr> <td>jour</td> <td>diurne</td> </tr> <tr> <td>île</td> <td>insulaire</td> </tr> <tr> <td>ville</td> <td>urbain</td> </tr> <tr> <td>village</td> <td>rural</td> </tr> <tr> <td>hiver</td> <td>hivernal</td> </tr> <tr> <td>automne</td> <td>automnal</td> </tr> <tr> <td>été</td> <td>estival</td> </tr> <tr> <td>printemps</td> <td>printanier, vernal</td> </tr> <tr> <td>feu</td> <td>igné, ardent, incandescent</td> </tr> <tr> <td>armée</td> <td>militaire</td> </tr> <tr> <td>art</td> <td>artistique</td> </tr> <tr> <td>champignon</td> <td>fongique</td> </tr> <tr> <td>cheveux</td> <td>capilaire</td> </tr> <tr> <td>odeur</td> <td>olfactif</td> </tr> <tr> <td>lettre (courrier)</td> <td>épistolaire</td> </tr> <tr> <td>champ</td> <td>agraire, champêtre</td> </tr> <tr> <td>rêve</td> <td>onirique</td> </tr> <tr> <td>cuisine</td> <td>culinaire</td> </tr> <tr> <td>vin</td> <td>vinicole</td> </tr> <tr> <td>or</td> <td>aurifère</td> </tr> <tr> <td>poil</td> <td>pilaire</td> </tr> <tr> <td>école</td> <td>scolaire</td> </tr> <tr> <td>argent</td> <td>pécuniaire</td> </tr> <tr> <td>eau</td> <td>aquatique, hydrique, aqueux</td> </tr> <tr> <td>oiseau</td> <td>aviaire, ornithologique</td> </tr> <tr> <td>vélo</td> <td>cycliste</td> </tr> <tr> <td>nord</td> <td>nordique, septentrional</td> </tr> <tr> <td>ouest</td> <td>occidental</td> </tr> <tr> <td>est</td> <td>oriental</td> </tr> <tr> <td>sud</td> <td>méridional</td> </tr> <tr> <td>sueur</td> <td>sudoral</td> </tr> <tr> <td>prison</td> <td>carcéral</td> </tr> </tbody> </table> </td> <td style="padding: 1em;"> <table border="1" style="border: 1px solid black; border-collapse: collapse"> <caption>espéranto</caption> <tbody> <tr> <td><strong class="strong">nom</strong></td> <td><strong class="strong">adjectif</strong></td> </tr> <tr> <td>frato</td> <td>frata</td> </tr> <tr> <td>mateno</td> <td>matena</td> </tr> <tr> <td>amiko</td> <td>amika</td> </tr> <tr> <td>cirklo</td> <td>cirkla</td> </tr> <tr> <td>vespero</td> <td>vespera</td> </tr> <tr> <td>dimanĉo</td> <td>dimanĉa</td> </tr> <tr> <td>onklo</td> <td>onkla</td> </tr> <tr> <td>hundo</td> <td>hunda</td> </tr> <tr> <td>kato</td> <td>kata</td> </tr> <tr> <td>ŝafo</td> <td>ŝafa</td> </tr> <tr> <td>suno</td> <td>suna</td> </tr> <tr> <td>stelo</td> <td>stela</td> </tr> <tr> <td>maro</td> <td>mara</td> </tr> <tr> <td>nokto</td> <td>nokta</td> </tr> <tr> <td>parolo</td> <td>parola</td> </tr> <tr> <td>helpo</td> <td>helpa</td> </tr> <tr> <td>mano</td> <td>mana</td> </tr> <tr> <td>orelo</td> <td>orela</td> </tr> <tr> <td>okulo</td> <td>okula</td> </tr> <tr> <td>episkopo</td> <td>episkopa</td> </tr> <tr> <td>tago</td> <td>taga</td> </tr> <tr> <td>insulo</td> <td>insula</td> </tr> <tr> <td>urbo</td> <td>urba</td> </tr> <tr> <td>vilaĝo</td> <td>vilaĝa</td> </tr> <tr> <td>vintro</td> <td>vintra</td> </tr> <tr> <td>aŭtuno</td> <td>aŭtuna</td> </tr> <tr> <td>somero</td> <td>somera</td> </tr> <tr> <td>printempo</td> <td>printempa</td> </tr> <tr> <td>fajro</td> <td>fajra</td> </tr> <tr> <td>armeo</td> <td>armea</td> </tr> <tr> <td>arto</td> <td>arta</td> </tr> <tr> <td>fungo</td> <td>funga</td> </tr> <tr> <td>haro</td> <td>hara</td> </tr> <tr> <td>odoro</td> <td>odora</td> </tr> <tr> <td>letero</td> <td>letera</td> </tr> <tr> <td>kampo</td> <td>kampa</td> </tr> <tr> <td>revo</td> <td>reva</td> </tr> <tr> <td>kuirejo</td> <td>kuireja</td> </tr> <tr> <td>vino</td> <td>vina</td> </tr> <tr> <td>oro</td> <td>ora</td> </tr> <tr> <td>haro</td> <td>hara</td> </tr> <tr> <td>lernejo</td> <td>lerneja</td> </tr> <tr> <td>mono</td> <td>mona</td> </tr> <tr> <td>akvo</td> <td>akva</td> </tr> <tr> <td>birdo</td> <td>birda</td> </tr> <tr> <td>biciklo</td> <td>bicikla</td> </tr> <tr> <td>nordo</td> <td>norda</td> </tr> <tr> <td>okcidento</td> <td>okcidenta</td> </tr> <tr> <td>oriento</td> <td>orienta</td> </tr> <tr> <td>sudo</td> <td>suda</td> </tr> <tr> <td>ŝvito</td> <td>ŝvita</td> </tr> <tr> <td>malliberejo</td> <td>mallibereja</td> </tr> </tbody> </table> </td> </tr> </table> Pri miurn:md5:fd60f885fdfd875c47439a23e57cf7362009-06-23T17:12ZBouil<p>Mi nun loĝas en Thionville (Francio), meza urbo inter Metz kaj Luksemburgo. Mi naskiĝis en 1981.</p> <p>Mi eklernis Esperanton je la februaro 2004. Mi legis en la aŭtobuso la kurson <a href="http://ikurso.esperanto-jeunes.org/doc/DLEK.pdf">DLEK</a> (DekLeciona Kurso), dum mi veturis al la laborejo. Mi miris pri lingvo lernebla tiel rapida ! Mi interesiĝis pri ĉi tiu lingvo, ĉar kiel Linuksito, mi vidas rilaton inter la idealo de Esperanto kaj tiu de Libera Programaro. Poste 6 montoj de sola lernado, mi ekpartoprenis al la esperanta kurso en Quetigny, apud Dijon.</p> <p>Ja, mi lernis la germanan lingvon dum 7 jaroj, sed nun mi preskaŭ ne povas paroli ĝin. Lerni la anglan lingvon necesis por min ĉirkaŭ 10 jaroj, sed hodiaŭ, mi ne povas paroli ĝin senerare. Kiel sciencisto, mi malŝatas esceptojn kaj lerni iojn ajn sen logiko, kiel vortlisto de anglaj aŭ germanaj verboj. Estas kalvario por mi !</p> <p>Hodiaŭ, mi certe multe eraras en esperanto, kiam mi skribas aŭ parolas la esperantan lingvon, erarante kun akuzativo aŭ io ajn. Multa da vortoj mankas al mia propra terminaro, kaj mi skribas certe pli facila la angla ol esperanto. Sed iom post iom, mia terminaro kreskas.</p> <p>Se vi deziras paroli kun mi, aŭ kun aliaj esperantistoj, vi povas eniri la jabber-an babilejon "esperanto" en la servilo conference.jabber.org. Vi povas eniri tie per via Jabber-a kliento, aŭ per <a href="http://www.startu.net/babilejo.">http://www.startu.net/babilejo</a>.</p> CVurn:md5:a5c8c3544bc49ebacde4ffe04bf34de02008-11-12T13:33ZBouil<p>CV hors-ligne : je ne suis pas actuellement en recherche d'emploi.</p> <!-- <p class="paragraph" /> <p class="paragraph" />Téléchargement en PDF : <a href="http://bouil.org/xwiki/download/Main/CV/CVNicolasBouillonDetaille.pdf">CV Nicolas Bouillon</a> <p class="paragraph" /><strong class="strong">Nicolas Bouillon</strong><br /> Né le 27/09/1981<br /> Nationalité Française<br /> <p class="paragraph" />96 rue des romains<br /> F-57970 Yutz<br /> 09 54 95 53 48<br /> 06 62 55 91 39<br /> nicolas -@- bouil.org <p class="paragraph" /> <h2 class="heading-1" id="HIngC3A9nieurNouvellesTechnologies"><span>Ingénieur Nouvelles Technologies</span></h2> <span class='edit_section'>&#91;<a style='text-decoration: none;' title='Edit section: Ingénieur Nouvelles Technologies' href='http://bouil.org/xwiki/edit/Main/CV?section=33'>edit</a>&#93;</span> <p class="paragraph" /> <h3 class="heading-1-1" id="HExpC3A9riencesprofessionnelles"><span>Expériences professionnelles</span></h3> <span class='edit_section'>&#91;<a style='text-decoration: none;' title='Edit section: Expériences professionnelles' href='http://bouil.org/xwiki/edit/Main/CV?section=34'>edit</a>&#93;</span> <p class="paragraph" /> <h4 class="heading-1-1-1" id="HAvril2008E28093PrC3A9sent"><span>Avril 2008 – Présent</span></h4> <p class="paragraph" /> <h5 class="heading-1-1-1-1" id="HAltranEst2CenmissionC3A0CoraInformatique2857Metz29"><span>Altran Est, en mission à Cora Informatique (57 - Metz)</span></h5> <p class="paragraph" />Développeur <p class="paragraph" />Maitenance et développement dans l'environnement décisionel. <p class="paragraph" /><strong class="strong">Technologies</strong> : Java, Struts 1, Sunopsis, BO XI SDK <p class="paragraph" /> <h4 class="heading-1-1-1" id="HOct2007E28093Mars2008"><span>Oct 2007 – Mars 2008</span></h4> <p class="paragraph" /> <h5 class="heading-1-1-1-1" id="HAltranEst2CenmissionauRecoratNancy2FMetz2854Nancy29"><span>Altran Est, en mission au Recorat Nancy/Metz (54 - Nancy)</span></h5> <p class="paragraph" />Développeur <p class="paragraph" />Assurer l'évolution de l'application suite aux retours des utilisateurs durant la première campagne d'utilisation par les primo-utilisateurs <p class="paragraph" /> <ul class="star"> <li>Architecture et développement <ul class="star"> <li>Analyse des besoins</li> <li>Analyse technique, étude d'impacts, chiffrage des réalisations</li> </ul> </li> <li>Réalisation des développements : nouveaux modules (Struts et Hibernate), optimisations de traitements</li> <li>Optimisation de la vie courante du projet <ul class="star"> <li>Mise en place d'un outil de suivi de projet : gestion des demandes, planification, pointage</li> <li>Installation et configuration de BIRT (Business Intelligence and Reporting Tool)</li> <li>Création de tableau de bord de suivi du projet avec BIRT</li> </ul> </li> <li>Migration de la gestion des sources depuis CVS vers Subversion</li> <li>Création de l'environnement de tests unitaires</li> <li>Tests de montée en charge</li> <li>Conseiller technique Java, Javascript et architecture auprès des équipes en place</li> </ul> <strong class="strong">Technologies</strong> : Java, Struts 1.2.8, Hibernate 3.2.5, JSP, Tiles, Servlets, MS SQL Server, MySQL, HTML, CSS, Javascript (Prototype.js, Scriptaculous, DWR), Eclipse, Ant, Tomcat, CVS, Subversion <p class="paragraph" /> <h4 class="heading-1-1-1" id="HMai2006E28093Sept2007"><span>Mai 2006 – Sept 2007</span></h4> <p class="paragraph" /> <h5 class="heading-1-1-1-1" id="HEnmissionchezArcelorSystems2857Florange29"><span>En mission chez Arcelor Systems (57 - Florange)</span></h5> <p class="paragraph" />Développeur <p class="paragraph" />TMA : application Web de prise de commande d'acier par les clients d'Arcelor. Intégrations de flux XML et de documents. <p class="paragraph" /> <ul class="star"> <li>Analyse des besoins</li> <li>Études d'impacts</li> <li>Chiffrage des réalisations</li> <li>Réalisation des développements <ul class="star"> <li>Java/J2EE</li> <li>Coldfusion</li> <li>En environnement Weblogic, Websphere et JRun</li> <li>Webservices, couches d'accès aux données, développement d'IHM</li> </ul> </li> <li>MS SQL Server <ul class="star"> <li>Réalisation de procédures stockées</li> <li>analyse des plans d'exécution</li> <li>amélioration des performances</li> </ul> </li> <li>Infocentre <ul class="star"> <li>modification des univers Business Object</li> <li>mise à jour des scripts SQL de chargement de l'infocentre</li> </ul> </li> <li>Assitance aux passages en production</li> <li>Réalisation des documentations de spécification, d'implémentation et des procédures d'installation</li> <li>Prototype de migration de l'environnement JRun/Coldfusion vers Websphere/Coldfusion</li> <li>Réalisation de scripts CVS de packaging automatique des changements et de vérification de la qualité du code</li> </ul> <strong class="strong">Technologies</strong> : Coldfusion MX 7, MS SQL Server 2000, Java, J2EE, Web Services, Axis, CMMI, Business Objects, CVS <p class="paragraph" /> <h4 class="heading-1-1-1" id="HNov2005E28093Avril2006"><span>Nov 2005 – Avril 2006</span></h4> <p class="paragraph" /> <h5 class="heading-1-1-1-1" id="HCMVInformatics2821Dijon29"><span>CMV Informatics (21 - Dijon)</span></h5> <p class="paragraph" />Analyste – Programmeur <p class="paragraph" />Support et maintenance de l'application de gestion de point de vente (grandes surfaces).. <ul class="star"> <li>Hotline téléphonique : réactivité requise dans l'environnement de la grande distribution <ul class="star"> <li>Analyse des incidents de production et correctif par le biais de requêtes SQL</li> </ul> </li> <li>Développement d'application d'assistance au service support : <ul class="star"> <li>Gestion des tickets d'appels</li> <li>Gestion de la base des incidents</li> </ul> </li> <li>Création, administration et gestion d'une base de connaissance de type Wiki</li> </ul> <strong class="strong">Technologies</strong> : Delphi 6, Python, PHP, XML, MS SQL Server, MySQL <p class="paragraph" /> <h3 class="heading-1-1" id="HStages2CJobsC3A9tudiants"><span>Stages, Jobs étudiants</span></h3> <span class='edit_section'>&#91;<a style='text-decoration: none;' title='Edit section: Stages, Jobs étudiants' href='http://bouil.org/xwiki/edit/Main/CV?section=35'>edit</a>&#93;</span> <p class="paragraph" /> <ul class="star"> <li>Printemps 2004 <ul class="star"> <li>Laboratoire LE2I (21000 Dijon)</li> <li>Stage, 6 mois</li> <li>Étude d'un modèle de connaissance, dans le domaine de la CAO, et représentation de ce modèle en XML</li> </ul> </li> <li>Printemps 2004 <ul class="star"> <li>UFR STAPS (21000 Dijon)</li> <li>Vacataire, 10h/sem, 5 mois</li> <li>Réactualisation du site internet. Maintenance du parc informatique</li> </ul> </li> <li>Automne 2003 <ul class="star"> <li>Bibliothèque de l'UTBM (90000 Sévenans)</li> <li>Vacataire, 10h/sem, 4 mois</li> <li>Accueil des lecteurs (renseignements, prêts et retours), équipement des ouvrages</li> </ul> </li> <li>Août 2003 <ul class="star"> <li>Usine Spindler (70290 Plancher Bas)</li> <li>Intérim, 1 mois</li> <li>Agent d'entretien et de maintenance</li> </ul> </li> <li>Automne Hiver 2002 <ul class="star"> <li>Contigo (59100 Roubaix)</li> <li>CDD ponctuels</li> <li>Animateur/démonstrateur en magasin de produits informatiques</li> </ul> </li> <li>Août 2002 <ul class="star"> <li>CTAA (90000 Belfort)</li> <li>Intérim, 15 jours</li> <li>Agent de production en injection plastique</li> </ul> </li> <li>Printemps 2002 <ul class="star"> <li>LGS France (90000 Belfort)</li> <li>Stage, 6 mois</li> <li>Développement d'un outil de gestion de configuration (Visual Basic, MsAccess)</li> </ul> </li> <li>Automne Hiver 2001 <ul class="star"> <li>Contigo (59100 Roubaix)</li> <li>CDD ponctuels</li> <li>Animateur/démonstrateur en magasin (produits informatiques)</li> </ul> </li> <li>Août 2001 <ul class="star"> <li>Trajectoire Formation (25200 Montbéliard)</li> <li>Bénévolat, 1 mois</li> <li>Développement d'un outil logiciel de gestion du fond documentaire (MsAccess, HTML/ASP)</li> </ul> </li> <li>Juillet 2001 <ul class="star"> <li>Domaine de Chalain (39130 Fontenu)</li> <li>CDD, 1 mois</li> <li>Caissier d'entrée dans le secteur touristique</li> </ul> </li> <li>Eté 2000 <ul class="star"> <li>Fromageries Bel (39000 Lons le Saunier)</li> <li>Intérim, 6 semaines</li> <li>Agent de conditionnement</li> </ul> </li> </ul> <h3 class="heading-1-1" id="HFormation"><span>Formation</span></h3> <span class='edit_section'>&#91;<a style='text-decoration: none;' title='Edit section: Formation' href='http://bouil.org/xwiki/edit/Main/CV?section=36'>edit</a>&#93;</span> <p class="paragraph" /> <ul class="star"> <li>11/2004 - 10/2005 : Doctorant en Informatique à l'Université de Bourgogne. <em class="italic">Peer-to-peer et Web Sémantique</em></li> <li>2004 : Diplôme d'Études Approfondies en <em class="italic">Informatique Automatique et Productique</em> à l'UFR des Sciences et Techniques de l'Université de Franche Comté. Mention Bien.</li> <li>2004 : Diplôme d'Ingénieur, branche <em class="italic">Génie Informatique - Ingénierie des Logiciels et de la Connaissance</em>, à l'Université de Technologie de Belfort Montbéliard.</li> <li>2001 : Diplôme d'Études Universitaires de Technologie (DEUTEC) à l'UTBM.</li> <li>1999 : Obtention du Baccalauréat scientifique. Mention Assez Bien.</li> </ul> <h3 class="heading-1-1" id="HLangues"><span>Langues</span></h3> <span class='edit_section'>&#91;<a style='text-decoration: none;' title='Edit section: Langues' href='http://bouil.org/xwiki/edit/Main/CV?section=37'>edit</a>&#93;</span> <p class="paragraph" /> <ul class="star"> <li>Anglais <ul class="star"> <li>Lu, écrit, parlé</li> </ul> </li> <li>Espéranto <ul class="star"> <li>Lu, écrit, parlé</li> </ul> </li> <li>Allemand <ul class="star"> <li>Notions</li> </ul> </li> <li>Français <ul class="star"> <li>Natif</li> </ul> </li> </ul> -->