Month: April 2008

Page Web : enlever les caractères indésirables (les puces) de Word

Posted by – April 30, 2008

Lors de saisies de formulaires, il arrive assez fréquemment que l’utilisateur copie / colle à partir de Word son texte. Malheureusement, ce dernier est souvent formaté, notamment avec des puces dessinés.

Ces puces ne seront pas lisibles par le navigateur, malgré l’UTF-8 de la page Web. Aussi, autant que faire se peut, il faut les retirer pour l’affichage sinon on encourt le risque d’avoir ce type de caracères sous FF ou IE ou Safari (disponible en version 3.11, apparemment plus stable sous Windows) :

puces Word FF

puces Word IE

Alors comment faire ?

Grâce à ce site qui nous permettra de rechercher le code UTF du ou des caractères indésirables, par exemple les puces de l’exemple, on recherchera (copier/coller directement du symbole affiché) le symbole qui donnera le code F0E0 :

Une fonction utilitaire avec une regexp suffira pour remplacer les puces par le caractère -, avec un fichier Resource.resx qui contiendra tous les codes UTF des puces à substituer. Pour dire au Replace d’interpréter un code UTF, il faudra préfixer le code par \\u, pour F0E0, cela donnera

  1. Regex.Replace("\\uF0E0","-");

La méthode utilitaire :

  1. public static String CleanWord(String chaine)
  2. {
  3. string mystr = chaine;
  4.  
  5. string[] paras = Resource.RegexSubstituteUTF8.Split(';');
  6. mystr = Regex.Replace(mystr, paras[0], paras[1]); // puce Word , ...
  7.  
  8. return mystr;
  9. }

avec comme Resource.resx :

Resource.resx

on aura alors le résultat escompté

Puces

A propos – Olivier DUVAL

Posted by – April 29, 2008

Développeur Web [+objet, +2.0], administrateur de plateformes Web et de messagerie, chargé de projets, je suis actuellement en poste en tant que coordinateur technique dans une organisation para-publique.

Passionné d’informatique et plus particuliérement par les nouvelles technologies depuis de longues années, je m’intéresse à divers sujets sur plusieurs domaines :

  • à la conduite de projets, au développement logiciel et aux méthodes agiles,
  • les technologies .NET (C#, ASP.NET, services Web), au développement objet (design patterns, architecture) et à l’intégration de briques logicielles,
  • l’Opensource, avec linux que je pratique depuis longtemps, et récemment avec une orientation Debian, avec tous les avantages (et inconvénients) que cette distribution GNU/Linux apporte,
  • l’ergonomie et le design et plus généralement, les techniques liées au Web [2.0] : XHTML, CSS, Ajax,
  • l’Opensource du côté des langages, Perl, PHP, ou Ruby

Ce blog a pour vocation principale de discuter de technologies et technique, opensources ou propriétaires. Certains billets peuvent s’écarter de ce cadre, pour aborder des sujets sur l’environnement, la photo, ou le sport. Mon CV qui résume mon parcours professionnel.

Séquence Julien LEPERS : je suis marié, j’aime la photographie, sportif, je pratique depuis longtemps les arts martiaux et sports de combat (Aïkido, grappling, boxes pieds poings, et depuis 3 ans le Kajukenbo), skieur à mes heures, et aussi un peu de voile (dériveur). J’aime écouter les musiques afro caribéennes, je suis danseur de Salsa depuis de nombreuses années. Lecteur assidu, j’aime les livres qui font voyager, je concilie l’utile à l’agréable au travers d’ouvrages d’Histoire (civilisations [[extrêmes-]orientales]) ou de Géopolitique. J’aime les pays d’ailleurs avec de nombreux voyages effectués afin de découvrir d’autres façons de vivre que notre cher pays la France :

  • Comments Closed

Blog : 1 an, “I have a dream”, ma vie, mon oeuvre

Posted by – April 24, 2008

Cela fait environ 1 an que le blog est ouvert (ie: actif et pérenne), quelques retours.

Pourquoi un blog ? tout simplement que je suis dans un sens redevable envers les nombreux blogs et sites qui m’ont aidé dans ma vie professionnelle, sans Internet, que serions-nous, la vie serait tellement plus difficile, à se demander comment nous faisions avant pour résoudre un problème ? (bouquins, newsgroups, …). Aussi si je peux apporter une maigre pierre à l’édifice, pourquoi pas, en y relatant des solutions concrétes.

L’objectif principal est atteint, avoir une majorité des visites qui viennent des moteurs de recherche (Google notamment…), et un bon SEO aide bien. D’ailleurs, j’ai enfin réussi à battre mes nombreux homonymes (5 ou 6 sur la toile), afin de me retrouver en 1er lien de Google, à charge de revanche :-)

Pour cela, les mots clés du billets doivent être réfléchis, notamment pour le titre, et les tags associés. Ce qui peut influer aussi, c’est d’être membre de réseaux dits sociaux, et d’être référencé sur d’autres blogs ou sites.

J’ai changé de moteur récemment, dotclear 2 (qui passera en RC1 le 1mai d’ailleurs !). Dotclear parait être bien mieux indexé que le précédent Typo. Ce dernier souffrait jusqu’à sa version 4 d’un défaut pour l’indexation des moteurs, corrigé dans sa version 5, mais ayant été confronté à la migration, je n’ai pas eu le temps de vérifier ça, communauté trop restreinte. Typo souffrait également d’un déficit de performances : ressources mémoires et CPU élevés, malgré avoir tenté plusieurs alternatives : mongrel, lightTPD en fastcgi. Etant utilisateur et non plus développeur d’une solution, il faut que le moteur soit user friendly : mise à jour simplifié, évolutif (ajout simple de fonctionnalités sous forme de Widgets), respect des standards, et rapide.

Egalement, Google Analytics aide à corriger le tire, en analysant les recherches et les billets les plus consultés. En y ajoutant Google Analytics AIR, cela en devient d’autant plus simple.

En termes de chiffres, qui restent modestes : environ 1 000 visites par mois, mais cela devrait vite augmenter, ~37 abonnés au flux FeedBurner, abonnés que je remercie bien volontiers.

La ligne éditoriale reste la même : technologique et technique, s’articulant autour du thème du Web selon 2 axes : développement au sens large (.NET ou autre, bonnes pratiques, standards, génie logiciel et méthodes), et système (plateforme Web, messagerie), ainsi que quelques sujets anexes off topic.

Le blog est hébergé à la maison, sur un serveur Debian virtualisé (via vserver), mais à termes, je pense le passer sur mon nouveau NAS. En ce qui concerne la messagerie (domaine @olivier-duval.info), elle était hébergée également sur un serveur virtuel (sendmail et quelques milter anti-spams, SYMPA), mais j’ai décidé de passer à GMail, qui permet d’héberger votre messagerie : moins de perte temps pour régler les problèmes de spams surtout, faisons lui confiance.

To be continued…

“programmateur”

Posted by – April 23, 2008

Je n’ai pas l’habitude de relayer des liens, mais celui-ci m’a trop fait penser à notre quotidien et une certaine incompréhension de la part des béotiens ou pas du domaine de l’ingénierie logicielle – notre : nous, ingénieurs en informatique, et plus spécifiquement en développement logiciel.

Oui, toi, visiteur qui est dans le domaine, ne te sens-tu pas incompris par moment, par des phrases à l’emporte pièce et /ou/xor péremptoires du type : ça ne doit pas être trop dur à faire, mon beau frère, lui, il développe son site Oueb dans le métro, nombre de fois que j’ai entendu ça :-)

C’est la contre-partie de la domestication de l’informatique dans les foyers, à nous d’expliquer et de communiquer sur nos métiers, même si ce n’est pas toujours évident. Babozor a écrit un billet sur ce sujet : “comment expliquer son travail aux non initiés”

Dans tous les cas, avec quelques années d’expérience, on peut partir du constat que :

Développer un logiciel est compliqué, très compliqué, quoiqu’en disent certains – faire et maintenir un système reste un défi de tous les jours, l’entropie qui nous guette nous rappelle à l’ordre sur quelques principes de base : refactoring, bonnes pratiques, simplicité, une conception objet reste primordiale.

Je pensais que dans les pays anglo-saxons, et notamment aux USA, les développeurs ou plus généralement les métiers techniques, étaient un peu plus considérés qu’en France, à y réfléchir, peut-être pas forcément.

Le titre programmateur est issu d’un réelle anecdote, lorsqu’une personne m’a demandé ce que je faisais dans la vie professionnelle, et qu’entre autre chose, je développais, terme non parlant, qui eût pour seule réponse : “mais tu es un programmateur, c’est ça ?” :-) , et là, l’analogie avec le programmateur d’une machine à laver m’a bien fait sourire.

Les Hooks ou l’extensibilité d’un objet / programme

Posted by – April 23, 2008

Dans un précédent billet, j’exposais un cas particulier à traiter sur certaines pages.

Rappel des faits : un contrôle se charge d’aller chercher un flux RSS ou Atom afin d’afficher chaque élément sur une page Web afin d’obtenir à peu près ce résultat :

flux Atom

Les pages du site sont pour la plupart en UTF-8 (ou du moins le devraient), mais certaines (en raison d’un lourd existant), présentent un cas particulier : elles sont encodées en ISO-8859-1 (voire Windows-1252). La conséquence de cet encodage est un défaut d’affichage pour certains caractères issus du flux et encodés en UTF; ce qui donne ce mauvais résultat (remarquez les ?) :

bad flux Atom

Solution simple et rapide qui vient à l’esprit : convertir les caractères dans leur équivalent ISO dans le contrôle.

Cette solution ne satisfait pas le cas commun des pages en UTF, il faudra ajouter au contrôle une propriété qui précisera si on veut ou non la conversion en ISO le cas échéant. Ce qui est gênant dans cette rustine, c’est que pour traiter un cas particulier, nous sommes obligés d’apposer une propriété au contrôle, et ce potentiellement pour chaque cas spécifique : à force, on va se retrouver à gérer pleins de cas, donc faire pleins de si(propriete_A) alors faire traitement particulier, ce qui n’est pas forcément le rôle du contrôle (qui devrait traiter le cas général uniquement), la solution n’est pas élégante dira-t-on.

Alors comment rendre extensible mon contrôle sans pour autant qu’il devienne illisible : en donnant la possibilité d’appliquer un hook au moment de l’affichage des éléments du flux.

Alors, qu’est qu’ un hook, selon cette définition :

(…) fonction permettant une plus grande facilité dans l’adjonction de fonctionnalités nouvelles au programme

C’est juste ce qu’il nous faut, une technique simple à mettre en oeuvre, et qui conserve le principe du ouvert-fermé en conception objet.

En C#, les événements (voire les délégués associés) répondent notamment à ce besoin et sont nos amis : autoriser des clients à s’enregistrer sur un objet afin de déclencher des méthodes pour du traitement spécifique. Les événements pourraient aussi être utilisés pour établir une communication inter-objets : qu’un objet serveur puisse donner de l’information à ses clients abonnés, par exemple, sur l’état d’avancement d’un processus.

Notre classe contrôle offre alors un événement sur lequel s’abonner, le contrôle déclenchera alors l’événement au moment opportun, ici lors de l’affichage des données, et une méthode pour déclencher manuellement l’événement si besoin de la part des clients de l’objet :

  1. event EventHandler<EventArgs> Displaying;
  2. void OnDisplaying(Item it, EventArgs arg);

Par défaut, on utilise EvenHandler, car peu d’informations sont à échanger, on pourrait bien entendu implémenter une classe qui dérive d’EventHandler si l’on souhaitait y mettre plus d’informations non directement liées à l’objet à traiter (ici l’élément du flux, la classe Item) : un état, un contexte d’utilisation, …

Il suffit alors de s’abonner à l’événement du contrôle à partir de ma page aspx (cliente de l’objet moncontrole), et de mettre le traitement ad-hoc souhaité, ici, la conversion des caractères :

  1. private void InitializeComponent()
  2. {
  3. moncontrole.Displaying += new EventHandler<EventArgs>(_default_Displaying);
  4. }
  5.  
  6. void _default_Displaying(object sender, EventArgs e)
  7. {
  8. if (sender != null &&
  9. sender is Item)
  10. {
  11. ((Item)sender).Title = UTFtoWin1252(((Item)sender).Title);
  12. ((Item)sender).Description = UTFtoWin1252(((Item)sender).Description);
  13. }
  14. }

dans le contrôle on déclenchera l’événement à chaque affichage d’une élément du flux, dans le CodeFile/CodeBehind du contrôle :

  1. // on expose la possibilité d'un branchement à l'événément Displaying
  2. public event EventHandler<EventArgs> Displaying;
  3.  
  4. // pour le déclenchement manuel de l'événément
  5. public void OnDisplaying(Item it)
  6. {
  7. if (Displaying != null)
  8. Displaying(it, EventArgs.Empty);
  9. }
  10.  
  11. protected void Page_Load(object sender, EventArgs e)
  12. {
  13. this.PreRender += new EventHandler(RssToolBoxWUC_PreRender);
  14. rpRss.ItemCreated += new RepeaterItemEventHandler(rpRss_ItemCreated);
  15. }
  16.  
  17. // appel du hook lors du ItemCreated
  18. void rpRss_ItemCreated(object sender, RepeaterItemEventArgs e)
  19. {
  20. if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
  21. {
  22. Item it = (Item)e.Item.DataItem;
  23. OnDisplaying(it);
  24. }
  25. }

et dans l’ascx du contrôle, on pourrait avoir le code suivant du repeater chargé d’afficher les éléments du flux (l’événement ItemCreated du Repeater déclenche notre hook chargé de nettoyer les caractères indésirables) :

  1. <div id="flux">
  2. <asp:Repeater ID="rpRss" runat="server">
  3. <HeaderTemplate><ul class="item"></HeaderTemplate>
  4. <ItemTemplate>
  5. <li class="itemelt">
  6. <p>
  7. <span class="itemtitle">
  8. <a class="itemlink""
  9. href="<%# ((Item)Container.DataItem).Link %>"><%# ((Item)Container.DataItem).Title)%></a>
  10. </span>
  11. <span class="itemdate">(<%# string.Format("{0:dd/MM/yyyy}", ((Item)Container.DataItem).DatePublication%>)</span>
  12. </p>
  13. <p>
  14. <span class="itemdescription">
  15. <%# ((Item)Container.DataItem).Description%>
  16. </span>
  17. </p>
  18. </li>
  19. </ItemTemplate>
  20. <FooterTemplate></ul></FooterTemplate>
  21. </asp:Repeater>
  22. </div>

Les avantages de cette solution :

  • le contrôle n’est pas pollué de cas particuliers à traiter, on rend la responsabilité au(x) client(s) du contrôle de traiter le cas.
  • va avec le 1er point, on évite pleins de if et donc plein de code à maintenir
  • on étend le comportement de la classe du contrôle sans la modifier
  • on peut décider de créer autant de hooks que l’on souhaite – on pourrait imaginer par exemple, un hook avant d’aller chercher le flux, après recherche du flux, etc…

Inconvénients :

  • les clients doivent connaitre un minimum quand est-ce que le hook sera déclenché, doit donc être documenté
  • coder des hooks inappopriés ou inutiles (en faire trop sans que cela serve forcément)
  • de donner la possibilité aux clients de l’objet de faire tout et surtout n’importe quoi

En génie logiciel, le plus difficile bien souvent c’est la maintenabilité du système, quelques bonnes pratiques permettent d’en réduire (un peu) la difficulté de la réaliser, encore faut-il y penser :-)

NAS : Synology 207+

Posted by – April 22, 2008

Acquisition du nas synology 207+ avec 2 disques Seagate Barracuda 500 Go qui permettra d’avoir un NAS en RAID-1 : stockage ET sauvegarde.

Après installation et configuration des disques pour du RAID-1, mise à jour des logiciels accessibles sur le site de Synology. Le firmware vous donnera accès à cette très belle interface Ajax :

synology interface web

Le Synology est bien plus qu’un simple NAS, c’est un véritable système embarqué. Une mise à jour pour les accès telnet, mais surtout SSH disponible sur cette page permet d’avoir la main sur la distribution et d’y ajouter des modules supplémentaires.

On accéde ensuite au NAS grâce à PuTTY.

  • les informations du CPU :
 DiskStation> cat /proc/cpuinfo Processor       : ARM926EJ-Sid(wb) rev 0 (v5l) BogoMIPS        : 499.71 Features        : swp half thumb fastmult vfp edsp CPU implementer : 0x41 CPU architecture: 5TEJ CPU variant     : 0x0 CPU part        : 0x926 CPU revision    : 0 Cache type      : write-back Cache clean     : cp15 c7 ops Cache lockdown  : format C Cache format    : Harvard I size          : 32768 I assoc         : 1 I line length   : 32 I sets          : 1024 D size          : 32768 D assoc         : 4 D line length   : 32 D sets          : 256 Hardware        : MV-88fxx81 Revision        : 0000 Serial          : 0000000000000000 
  • quelle version du système :
 DiskStation> uname -a Linux DiskStation 2.6.15 #598 Sat Apr 12 22:16:49 CST 2008 armv5tejl unknown 

Le choix de Synology s’est principalement fait en raison de sa communauté, sa bonne réputation et du système hackable installé dessus (ie : packages installables et prise en main de celui-ci) : installer ipkg, un apt-get like qui donnera accès à un ensemble de paquets pour enrichir le NAS.

Installons quelques utilisataires grâce à ipkg (ipkg update; ipkg install package) :

  • htop : on a 123 Mo de RAM, quelques processus utilisés par les modules Synology : postgresql pour le module photo + blog, mysql, apache, smb pour les échanges CIFS, …je m’étonne également qu’il n’y aiy que 30 à 50 Mo RAM consommées malgré l’ensemble des services lancés, système optimisé !

synology htop

  • phpmyadmin

Le Synology peut faire office de serveur de musique pour diffuser des MP3, soit vers un DMA, soit les lire sous réserve d’avoir des HP USB branchés sur le NAS, soit de diffuser les fichiers via iTunes, ou tout simplement écouter quelques radios du Net.

Parmi les logiciels du pack, on trouvera Synology Data Replicator 3 qui permet 3 modes de sauvegarde :

  • immédiate : sauvegarde sur le NAS les répertoires sélectionnés
  • programmé : ajoute dans les tâches planifiées une sauvegarde quotidienne par exemple
  • Sync : détectera automatiquement tous les fichiers modifiés dans votre liste à écouter et les sauvegardera en temps réel dès modifications vers le NAS, le top :-)

Conversions : ISO-8859-1/ Windows-1252 et UTF-8

Posted by – April 21, 2008

Imaginons que nous ayons une page encodée en ISO-8859-1 (ou Windows-1252), soit le code page 28591. Si, si, cela peut arriver d’avoir un existant qui balade encore des pages avec cet encodage obsolète, parfois, le choix est limité de tout passer en UTF-8 (code page 65001, la norme actuelle pour l’encodage), car il faut bien souvent le faire en une seule passe, et ce n’est pas toujours simple lorsqu’il existe beaucoup de pages.

Donc, nous avons une page en ISO, dans celle-ci existe un contrôle (au sens UserControl d’ASP.NET) qui permet de consommer un flux (Atom) et de l’afficher : ce flux est encodé en UTF-8 (ce qui est bien…sauf dans notre cas). Certains caractères n’apparaitront pas bien à l’affichage (apparaitront des ? à la place des “ ou —)

page ISO-8859-1

dans une page ISO

config ISO ko

au lieu d’obtenir cette page bien formée :

flux UTF

pour corriger cela, il faudra les convertir en ISO (car page en ISO…)

Une table de correspondance de 27 caractères qui posent souci (prendre le code Hexa pour l’ISO/Win-1252, et le code xml pour l’UTF ) sur ce site

Pour chaque caractère, on va remplacer le code UTF-8 par celui en ISO/Win-1252, un replace suffit , on pourra avoir une méthode utilitaire de ce type, le faire pour les 27 caractères, autrement dit, pas comme dans l’exemple ;-)  :

  1. public static String UTFtoWin1252(String laChaine)
  2. {
  3. string mystr = laChaine;
  4.  
  5. mystr = mystr.Replace((char)0x2022,(char)0x95); // •
  6. mystr = mystr.Replace((char)0x20AC,(char)0x80); // €
  7. mystr = mystr.Replace((char)0x0153,(char)0x9C); // oe
  8. mystr = mystr.Replace((char)0x2026,(char)0x85); // …
  9. mystr = mystr.Replace((char)0x2013,(char)0x96); // –
  10. mystr = mystr.Replace((char)0x201C,(char)0x93); // “
  11. mystr = mystr.Replace((char)0x201D,(char)0x94); // ”
  12. mystr = mystr.Replace((char)0x2014,(char)0x97); // —
  13.  
  14. return mystr;
  15. }

On substitue grâce à la fonction chaque caractère reçu en UTF par son équivalent ISO, on a bien le résultat escompté :

config ISO ok

Bien entendu, ce n’est valable que dans une page ISO, si celle-ci passe en UTF, les caractères n’auront plus de sens – d’où la difficulté de passer tout ou partie d’un existant en UTF où il y a des hacks de ce type : le faire en une seule fois, et repasser sur toutes les pages, bon courage :-)

Conclusion : il est préférable que toute la chaîne soit en UTF : le contenu des fichiers, l’encodage renvoyé par le serveur Web, les données enregistrées dans la base de données, sinon, gare aux astuces de programmation.

Un site où vous pourrez retrouver tous les codes d’un caractère en le recherchant.

Google apps : héberger votre domaine pour vos mails

Posted by – April 19, 2008

Préambule

J’ai déménagé, aussi, en attendant le raccordement à mon nouveau domicile, j’ai dû demander à un copain (que je remercie infiniment au passage) d’héberger mon blog (hébergé sur mon serveur à la maison). Comme je ne voulais pas abuser de l’invitation, seules les applications Web (blog, photos) étaient accessibles; en ce qui concerne le mail (@olivier-duval.info), j’ai porté mon choix vers Google apps qui permet d’héberger son infrastructure mail à moindre coût.

Mis à part le côté curiosité et le défi de mettre en place un serveur MTA (serveur SMTP, anti-spams, …), maintenir ce type de serveur peut s’avérer chronophage, autant faire confiance à Google apps pour héberger sa messagerie. C’est au détour d’un billet sur Korben, que l’idée m’est venue.

More

.NET : service Web (SOAP), ordre des paramètres des méthodes et sérialisation

Posted by – April 8, 2008

Pour l’utilisation des services Web (en .NET 2.0), je n’utilise pas les classes générées par le proxy pour les objets échangés, mais directement nos classes métiers, ces dernières étant sérialisables. Je m’aperçois que l’ordre des objets passés dans une méthode peut s’avérer important, il semble préférable de mettre les objets complexes à la fin.

Par exemple, entre

public String getLinkRSS(string libelle,string service,string urlback,string action,string csshref,   ServicePerimetre perim, long perimid, SerializableHashtable param)

et

public String getLinkRSS(string libelle,string service,string urlback,string action,string csshref,  SerializableHashtable param,  ServicePerimetre perim, long perimid)

et bien, la n’arrive pas à désérialiser l’énuméré perim (placé directement après param, un objet complexe), entre le proxy (ie : le client) et le serveur (ie : l’asmx), la valeur se perd dans les abimes, pour l’instant pas de réelle explication (si, toi, visiteur inconnu ou pas, tu as une explication à me fournir, n’hésite pas).

Bon à savoir donc, être vigilant dans l’ordre des paramètres pour nos méthodes services Web.

Blogger, Blog, référencement et SEO

Posted by – April 3, 2008

Préambule

Nous allons mettre en place un blog pour un évènement annuel. Ce blog sera hébergé sur la plateforme Blogger. Celle-ci permet de répondre tout ou partie des besoins exprimés : une personnalisation du blog aux couleurs locales, et également de pouvoir avoir son domaine personnel qui pointe sur l’URL des blogs Blogger, à savoir http://monblog.blogsport.com

More