Seb a écrit 26 commentaires

  • [^] # Re: Oui

    Posté par  (site web personnel) . En réponse au journal SSHFS est un vrai système de fichiers en réseau. Évalué à 2.

    Je l'utilise au quotidien aussi : une "VM" de développement par projet client (généralement des conteneurs LXC, mais pas que), et l'éditeur/IDE sur l'hôte qui va taper sur les systèmes de fichiers distants montés via SSHFS.

    Quelques problèmes avec les UID (ex : la manipulation de dépôts Mercurial ne fonctionne pas de base via SSHFS si les UID diverges, ça se contourne), et des performances pas terribles sur certaines opérations (hg/git clone, merge importants… à faire de préférence directement sur le système de fichiers cible et non via le montage). Cela fait plusieurs années que l'on travaille ainsi à mon taf, et on est plutôt satisfaits dans l'ensemble.

    Est-ce qu'il y aurait d'autres façons d'avoir ses outils de devs communs à plusieurs environnements de développement ?

  • [^] # Re: Don't be evil

    Posté par  (site web personnel) . En réponse au journal Petite prévision pour l'avenir. Oracle !. Évalué à 6.

    En équivalent à rman pour PostgreSQL tu peux voir du côté de barman (full hot backup, PITR…) => http://www.pgbarman.org/ (dispo dans Debian également).

  • [^] # Re: Vivre du développement de logiciels libres

    Posté par  (site web personnel) . En réponse au journal Moi aussi j'ai créé une entreprise !. Évalué à 2.

    Si on réalise des développements spécifiques sur un logiciel de type GPL, on redistribue les sources à l'utilisateur, càd le client. Aucun problème, c'est bien libre, même si ce n'est pas diffusé à la planète entière.
    On se rend bien compte de l'avantage que ça a quand un client veut changer de prestataire et vient taper à notre porte (parce que son prestataire actuel ne lui plaît pas, ou parce que celui-ci a fermé boutique).

    Dans l'écosystème d'Odoo cela arrive que des modules génériques soient développés lors d'un projet client, et certains sont publiés et accessibles par toute la communauté ensuite.

  • [^] # Re: Mercurial

    Posté par  (site web personnel) . En réponse au journal Git a fêté ses 10 ans hier .... Évalué à 3. Dernière modification le 09 avril 2015 à 15:18.

    Si on enlève evolve, Mercurial est au même niveau que Git sur la facilité de réécrire l'historique.

    Sans evolve il est pourtant impossible de faire un amend/rebase/mq sur des changesets déjà publié, chose que Git autorise. C'est dangereux, mais pour celui qui sait ce qu'il fait ça offre plus de souplesse. C'est ça que je veux dire en disant que Mercurial n'autorise pas la réécriture d'historique par défaut (sans evolve) :

    $ echo paf > pouf
    $ hg add pouf
    $ hg ci -m "ajout pouf" pouf
    $ hg phase -p tip    # pour simuler un changeset déjà pushé ou provenant d'un pull
    $ echo paf2 >> pouf
    $ hg ci --amend
    abandon : cannot amend public changesets

    Ce n'est pas un défaut de Mercurial ou un avantage à Git (tout dépend du besoin recherché), juste que Git autorise le dev à tout péter pour le meilleur et pour le pire, c'est dangereux mais souple.

  • [^] # Re: Mercurial

    Posté par  (site web personnel) . En réponse au journal Git a fêté ses 10 ans hier .... Évalué à 1.

    C'est vrai j'avais oublié evolve. Je m'y étais intéressé l'année dernière, mais l'avais mis de côté car j'évitais les extensions qui ne sont pas fournies en standard ou qui sont expérimentales. Apparemment ce n'est toujours pas fournie en standard ou jugée suffisamment stable, je ne la trouve pas dans la liste http://mercurial.selenic.com/wiki/UsingExtensions. J'attend ça avec impatience car pouvoir réécrire l'historique sans rien détruire, et pouvoir relire ces réécritures, c'est une tuerie.

    Mais ça n'enlève rien à Git qui ne propose peut-être pas cette fonctionnalité, mais qui répond quand même au besoin de beaucoup de dev sur la facilité de réécrire l'historique, et ça depuis qu'il existe.

  • [^] # Re: Mercurial

    Posté par  (site web personnel) . En réponse au journal Git a fêté ses 10 ans hier .... Évalué à 5.

    J'ajouterai une petite conclusion à mon commentaire plus haut :
    Même si Git à une UI désastreuse (n'ayons pas peur des mots), je le trouve beaucoup plus adapté pour des développements communautaires, parce qu'il est très flexible. Dans un contexte de travail non-communautaire (donc avec une population de contributeurs qu'on maîtrise) ayant des process de travail bien établis, je préfère Mercurial, simplement car on évite les mauvaises surprises, on forme plus rapidement un nouveau venu, un stagiaire, ou même des non-techos grâce aux GUI matures existantes pour Hg (TortoiseHG notamment).

  • [^] # Re: Mercurial

    Posté par  (site web personnel) . En réponse au journal Git a fêté ses 10 ans hier .... Évalué à 6.

    Pas vraiment. git log ne traite que l'historique local. En effectuant ta commande, je ne peux pas voir le travail que mon collègue a réalisé entre temps sur le dépôt distant (et quelle que soit la branche). Du coup il faudrait faire un git fetch au préalable, mais là du coup on perd l'avantage de hg ingoing/hg outgoing qui est justement de simuler un pull/push sans rien toucher à son dépôt local.

    Et puis, autre avantage à ces commandes : autant hg log -p permet d'afficher le diff complet d'un changeset local (équivalent à git show), autant on peut faire pareil avec les changesets qu'on peut pusher (hg out -p) ou - beaucoup plus utile - les changesets qu'on peut récupérer (hg in -p).

  • [^] # Re: Mercurial

    Posté par  (site web personnel) . En réponse au journal Git a fêté ses 10 ans hier .... Évalué à 10. Dernière modification le 08 avril 2015 à 20:12.

    J'utilise les deux au travail, Mercurial pour les développements internes/clients, Git pour les projets communautaires parce que GitHub.

    En faisant abstraction de son horrible UI, Git permet d'être plus souple au quotidien : quand je fork un dépôt Git pour y contribuer, je peux me permettre de retravailler l'historique de ma branche comme je le souhaite sur mon dépôt perso (y'a peu de chance que quelqu'un l'ait forké à son tour donc je me permet de tout péter à coup de git rebase et git push -f avant de faire la pull request sur le projet upstream). Simple et rapide pour moi dans le cadre des petites contributions, et historique lisible pour ceux qui vont faire la revue de code avant un éventuel merge.

    Par contre j'ai déployé Mercurial dans l'entreprise (pour remplacer SVN) car :

    • UI vraiment bien faite, les commandes sont cohérentes et évoluent en même temps suivant les plugins activés,

    • je suis le seul "barbu" dans l'équipe, et souhaite que le reste de l'équipe soit le plus autonome possible,

    • pas de git push --force, Mercurial ne fait que de l'ajout sur les dépôts distants : quand c'est pushé, c'est pushé ! En cas de grosses erreurs (genre commit d'un mot de passe pas sensé être publié), j'interviendrais à la main dans le dépôt distant et demanderai à ceux ayant déjà pullé de détruire le commit concerné ou refaire un clone. Ce n'est jamais arrivé, et ça relève du cas exceptionnel.
      Bref, que de l'ajout sur les dépôts Mercurial distants, et cela veut aussi dire qu'on ne peut pas perdre des données de l'entreprise accidentellement, et pour moi c'était un critère important.
      Je suppose qu'on peut bien sûr limiter ça avec Git également, mais c'est natif dans Hg.

    • le système de phases :

      • changeset draft (donc pushable, une fois pushé il deviendra public), qu'on affiche en vert dans les logs
      • changeset public (présent sur le dépôt distant, et impossible à modifier/supprimer, une erreur s'afficherait alors), affiché en bleu
      • changeset secret (avec hg ci --secret, rend le changeset local, ne peut être pushé par accident), affiché en rouge
    • hg out / hg in : pour voir ce qu'on peut récupérer, ou ce qu'on peut pusher, ça me manque énormément sous Git.

    Mais je reconnais que le système de branche légère de Git est appréciable, autant que le fait que des changesets non-référencés seront détruits au bout d'un moment, ça procure pas mal de flexibilité à l'usage. Seulement c'est si reposant de travailler avec Hg… l'outil se fait oublier, et mes nerfs me disent merci :)

  • [^] # Re: Oubli…

    Posté par  (site web personnel) . En réponse au journal Ansible ton conteneur !. Évalué à 2.

    Avec ansible-pull on n'est pas forcé non plus d'avoir une connexion directe aux serveurs : http://docs.ansible.com/playbooks_intro.html#ansible-pull
    Je ne l'ai jamais utilisé, mais a priori c'est équivalent à un checkout Git d'une configuration sur laquelle on exécute ansible-playbook.

  • [^] # Re: Tu aimes Heroku ?

    Posté par  (site web personnel) . En réponse au journal Docker, la plateforme à la mode. Évalué à 2.

    Clever Cloud avait fait une présentation de leur utilisation de Docker lors d'une mini-conférence à Rennes : https://www.youtube.com/watch?feature=player_embedded&v=3bg9ij4XwW4

  • [^] # Re: c'est pas parce que c'est pas bien pour la prod qu'il faut tout jeter non plus

    Posté par  (site web personnel) . En réponse au journal Docker, la plateforme à la mode. Évalué à 10. Dernière modification le 07 mars 2015 à 15:46.

    Pour tous les besoins que tu évoques, LXC fait bien l'affaire (Docker aussi, mais comme j'utilise essentiellement LXC c'est de lui dont je vais parler).

    Sur une Ubuntu 14.04 LTS, créer rapidement un conteneur Debian Wheezy (ou autre) se résume à :

    $ sudo apt-get install lxc
    $ sudo lxc-create -n monconteneur -t download -- -d debian -r wheezy -a amd64
    $ sudo lxc-start -n monconteneur
    $ sudo lxc-ls -f  # relever l'IP du conteneur
    

    Maintenant si on souhaite y mettre un serveur SSH :

      $ sudo lxc-console -n monconteneur    # se connecter en root
      # apt-get install python openssh-server
    

    Et passer le relai à un outil tel qu'Ansible pour déployer toute la configuration :

      $ echo IP >> inventory
      $ vim monplaybook.yml
      $ ansible-playbook -i inventory monplaybook.yml -e "ansible_ssh_user=root" -k
    

    Après toute la création du conteneur LXC peut également se faire depuis Ansible, et cela sera encore plus facile avec le module prévu à cet effet qui a été mergé depuis peu : https://github.com/ansible/ansible-modules-extras/pull/123

    L'avantage ici c'est de séparer les responsabilités : la techno s'occupant du conteneur n'est pas lié à la techno s'occupant du build, c'est Ansible/Puppet/Salt qui s'en occupe et les recettes/playbooks peuvent s'appliquer aussi bien à des machines physiques, du KVM, de l'HyperV, du LXC, ou de l'OpenVZ, peu importe au fond, chacun son rôle, le couplage entre tout ce beau monde est plus faible.

    Pour le conteneur en lui même, on peut en faire un tar et le passer au collègue si on le souhaite. Mais on préfèrera reconstruire l'environnement de A à Z de manière identique sur la machine cible avec Ansible (on utilisera le même outil pour construire l'environnement de dev, de preprod et de prod).

    Aujourd'hui déployer une application complexe tel qu'un ERP avec son SGBD, une réplication du SGBD (pour du failover), du reverse proxy, la mise en place des backups, de la supervision et tout le toutim, c'est fun et rapide avec un outil comme celui-ci.

  • [^] # Re: Liquidprompt

    Posté par  (site web personnel) . En réponse au journal Gérer son espace de travail git avec "gws". Évalué à 1.

    powerline est vraiment extra.
    Et pour les utilisateurs de Mercurial qui veulent personnaliser leur PS, il y a hg-prompt de Steve Losh. C'est une extension à Hg qui introduit une nouvelle commande qui prend en argument notre template. Tiré de la doc :

    hg_ps1() {
        hg prompt "{ on {branch}}{ at {bookmark}}{status}" 2> /dev/null
    }
    
    export PS1='\u at \h in \w$(hg_ps1)\n$ '

    http://sjl.bitbucket.org/hg-prompt/quickstart/

  • [^] # Re: Sympa

    Posté par  (site web personnel) . En réponse au journal Gérer son espace de travail git avec "gws". Évalué à 1.

    Hélas, c'est sur un dépôt interne à l'entreprise où je travaille. C'est du multiprocess en Python, et le support de Git n'est pas aussi complet que pour Mercurial (notamment en ce qui concerne hg ingoing et hg outgoing).

  • # Sympa

    Posté par  (site web personnel) . En réponse au journal Gérer son espace de travail git avec "gws". Évalué à 1.

    J'avais bricolé un outil similaire supportant Git et Mercurial mais lié à RhodeCode/Kallithea.
    L'outil (écrit en Python avec méthode LA RACHE) récupère la liste des dépôts auxquels on a droit via JSON-RPC sur RhodeCode/Kallithea, puis s'occupe de les synchroniser en local avec la même organisation en créant les répertoires qui vont bien avant d'y cloner les dépôts.
    Au lancement le script se met à jour de lui même (pull sur son propre dépôt) puis se relance pour faire le reste, tout en vérifiant l'état des dépôts déjà en place, la sortie donne quelque chose comme :

    Check script updates...
    PULL+UP  checker
    MAKEDIRS path/to
    SKIP     temp/TEST
    CLONE    path/to/TRUC
    WARNING  clients/TRUC (changesets not pushed)
    WARNING  outils/TOTO (non-committed changes detected)
    LOCAL    test
    
  • [^] # Re: Mise à jour

    Posté par  (site web personnel) . En réponse au journal Migration d'une infra lamp vers docker. Évalué à 0.

    si le paquet apache est mis à jour dans les dépots,
    il faudra reconstruire l'image docker:

    Quel système utilises-tu pour être notifié des mises à jour à effectuer dans ton conteneur ? J'imagine que tout se fait depuis l'hôte à coup de docker exec CMD_CHECK_UPDATE pour le remonter au système de supervision ? Je suis intéressé par des retours sur ce type de sujet.
    J'en avais discuté un jour avec quelqu'un à une conférence sur Docker, et eux appliquaient une politique de livraison continue en reconstruisant 1 fois /jour les conteneurs, et c'est vrai que Docker facilite grandement cette approche (même si on peut en faire tout autant avec Ansible+LXC).

  • [^] # Re: Debian fait partie du passé

    Posté par  (site web personnel) . En réponse à la dépêche Debian 7.8, huitième mise à jour de Wheezy. Évalué à 4.

    Surveiller chaque paquet c'est ok pour un serveur, pas quand tu en gères 150. Te poses-tu vraiment la question en voyant la page d'accueil du site "est-ce que j'utilise ce paquet parmi les 150 serveurs que je gère ?", et ce, tous les jours ?
    L'urgence elle existe si tu n'as pas regardé la page d'accueil au préalable : ça a pété, faut que tu répares.
    Et ce n'était pas du troll, ne t'en déplaise, mais la façon de travailler dont tu parles c'est juste du bricolage. Aucun support à grande échelle n'est possible avec Archlinux, et ce n'est pas un mal, ce n'est juste pas une distribution faite pour.

  • [^] # Re: Debian fait partie du passé

    Posté par  (site web personnel) . En réponse à la dépêche Debian 7.8, huitième mise à jour de Wheezy. Évalué à 5.

    Sauf que les besoins fonctionnels d'Archlinux (leurs serveurs) sont assez bien ciblés, et n'ont pas dû beaucoup changer en 10 ans, j'imagine. Je veux dire par là que leurs besoins sont loin de représenter les besoins du reste du monde, qui lui va faire tourner des applications dont l'équipe d'Archlinux n'a même pas conscience.

    C'est quand même pratique d'avoir un système figé. Par exemple la version de python-crypto de Debian Squeeze a un bug permettant une "mauvaise" utilisation de son API, bug résolu dans la version dispo dans Wheezy.
    Seulement certaines de nos données ont été chiffrées avec la version de Squeeze, et en migrant vers Wheezy les données deviennent indéchiffrables en l'état.
    Le problème a pu être décelé en testant une migration vers Wheezy puis corrigé et testé tranquillement pendant la durée restante du support de Squeeze. Ça apporte une bonne dose de sérénité une distribution stable, même ce bug a été volontairement non-corrigé dans Debian pour éviter une régression (je n'ai plus le lien vers le bug report).

    C'est préférable de pouvoir maîtriser les problèmes pour planifier leurs corrections pèpère et non dans l'urgence. Je ne me vois pas utiliser un système où chaque paquet mis à jour est susceptible d'apporter une régression, en fait.

  • [^] # Re: Ruby

    Posté par  (site web personnel) . En réponse au journal Python comme premier langage de programmation ?. Évalué à 4.

    Le résultat n'est pas le même surtout.

    L'équivalent de la list comprehension du dessus serait plutôt :

    val = 2
    l = []
    for x in range(4):
        l.append(x * val)
    print(l)

    À choisir, ma préférence va pour la list comprehension pour ce genre de constructions simples (moins de bruits autour).
    À noter que je maintiens du code Python au quotidien, mon avis est un peu biaisé.

  • [^] # Re: Docker vs LXC

    Posté par  (site web personnel) . En réponse à la dépêche La folie Docker. Évalué à 5.

    Merci pour ces éclaircissements !

    Pour donner plus de précision, l'appli en question est Odoo/OpenERP, et on est amené à personnaliser cette application très régulièrement, différemment d'un client à l'autre (besoins qui peuvent évoluer au cours du temps suivant les demandes, rien n'est jamais figé).

    Mon ressenti c'est que Docker est très bien adapté pour faire des dizaines voir des milliers de livraisons identiques. En dehors de ce cas, c'est se compliquer la vie que d'adopter un tel outil comparé à une VM standard ou un conteneur OpenVZ/LXC, vu qu'il faut :

    • créer un(des) volume(s) à part pour stocker les fichiers de configuration ou le code source qui diffère d'un client à l'autre,
    • re-créer les images entièrement pour les mises à jour régulières (à ce propos, comment être averti des mises à jour à réaliser sur un conteneur par Nagios/NRPE par exemple ? Avec les volumes ça doit être jouable, mais ça ajoute de la complexité pour peu de valeur ajoutée à mon sens),
    • utiliser des outils tiers non-réutilisables en dehors de Docker pour une connexion directe au conteneur (nsenter ou le futur builtin).

    Docker encourage le "mono-process", impliquant la mise en place de volumes communs si on veut que 2 conteneurs communiquent, et la livraison de conteneurs identiques à très grandes échelle. De l'autre côté LXC exécute un système complet (comportement par défaut), dans lequel se trouvent plusieurs process fonctionnant de manière cohérente. Si j'ai besoin d'installer un module Python pour générer des fichiers Excel, nul besoin de re-générer une image (un ajout à la conf Ansible et c'est bon, en plus d'être versionné pour garder l'historique).
    Idem si je veux connecter un serveur Barman à un serveur PostgreSQL existant : SSH est déjà présent sur les deux pour la communication.

    Loin de moi l'idée de critiquer Docker (vu son succès !), j'essaie juste de calquer mes besoins avec l'outil, mais ça renforce un peu mon opinion que Docker n'est peut-être tout simplement pas adapté comparé à d'autres solutions.

  • # Docker vs LXC

    Posté par  (site web personnel) . En réponse à la dépêche La folie Docker. Évalué à 5.

    J'ai essayé un peu Docker il y a quelques mois pour voir s'il pourrait remplacer mon utilisation de LXC à terme, mais plusieurs points m'ont bloqués.

    Comment peut-on mettre à jour simplement un conteneur Docker par exemple (MAJ de sécu etc) ? Si le conteneur doit être reconstruit, il me faut du coup mettre les données des applications dans un autre volume (faut y penser dès le départ donc, /home, /var…).

    Dans le cas de PostgreSQL, si je veux profiter de l'authentification par socket UNIX (conf par défaut sous Debian, en ayant un compte utilisateur système nommé de façon identique au compte dans PostgreSQL, pour qu'un autre service s'executant sous cet utilisateur accède à PostgreSQL tranquilou), comment s'y prendre avec Docker ? PostgreSQL + mon application dans le même conteneur (lancer init mais ça semble "non-supporté" et trop aléatoire, bidouiller ça avec supervisord ou similaire) ? Ça ne semble pas la "philosophie" Docker, qui vise à encapsuler une seule application par conteneur, mais ceci apporte une dose de complexité je trouve.

    Pour le moment je trouve la solution LXC + Ansible plus simple et confortable pour mes besoins, du fait que LXC lance un système Linux complet accessible par SSH, et dans lequel je peux faire évoluer mon besoin comme réaliser un montage CIFS exploitable par l'application qui y tourne (et la conf. Ansible est applicable sur n'importe quelle machine cible, que ça soit du LXC ou autre, ce qui est cool pour préserver l'historique du parc), mais je ne peux m'empêcher de me dire que je dois mal utiliser Docker, que quelque chose m'échappe.

    Des retours sur ce type d'utilisation ?

  • [^] # Re: Debian Jessie

    Posté par  (site web personnel) . En réponse à la dépêche Nouvelle vulnérabilité dans l’implémentation OpenSSL. Évalué à 3.

    Un outil bien pratique pour tester les process qui tournent sur d'anciennes libs après une mise à jour, c'est checkrestart :

    # apt-get install debian-goodies
    # checkrestart

    Tant qu'il le peut il listera les services concernés, sinon il est parfois utile de le lancer avec -v pour obtenir plus de détails.

  • [^] # Re: Merci pour l'info

    Posté par  (site web personnel) . En réponse au journal Outils de pseudo gestion de projet et développement. Évalué à 1.

    Ça dépend ce que tu entends par "assez complète", RhodeCode ne fait que gestion de dépôts (qu'on peut organiser en groupe/sous-groupe), les droits d'accès aux groupes/dépôts, un pastebin/gist intégré, gestion des pull-requests, intégration avec LDAP…
    Mais il n'y a pas de wiki, et pas de bugtracker intégré (la communication avec d'autres bugtrackers est encouragée).
    Il n'y a pas non plus de prise en charge SVN. On peut seulement activer hgsubversion dans le panneau d'administration pour cloner un dépôt SVN dans un dépôt Mercurial.

    Niveau ressources, ça tourne plutôt bien sur de l'Atom, ma première installation était sur un Fit-PC (Atom Z530), que j'ai migré sur un Kimsufi chez OVH (Atom N2800), et mon instance occupe actuellement 150mo en mémoire. Ceci-dit c'est une forge perso, il n'y a jamais plus de 2 utilisateurs, mais ça doit passer sans problème avec une petite équipe.

    À voir sinon du côté de Trac ?

  • [^] # Re: Merci pour l'info

    Posté par  (site web personnel) . En réponse au journal Outils de pseudo gestion de projet et développement. Évalué à 3.

    Il existe RhodeCode pour ceux qui préfère installer du Python, et ça supporte aussi bien Mercurial que Git.

  • [^] # Re: Pas de révision d'historique

    Posté par  (site web personnel) . En réponse au journal Chiselapp ferme ses portes. Évalué à 1.

    Concernant Mercurial (voir Git, mais je connais moins bien), le principe des phases que tu mentionnes est vraiment très pratique. Seulement, existe t-il un moyen de pusher ses révisions sur un dépôt externe pour sauvegarder/mettre de côté son travail (pas forcément avec l'objectif de le partager) pour pouvoir le reprendre depuis une autre machine, sachant qu'à partir du moment où l'on push, les changesets sont marqués comme publiques et donc immuables, et l'on doit forcer le passage à l'état brouillon avec hg phase pour ensuite les retravailler avec MQ ou autre (chose pas très pratique à l'usage).

    Globalement, une fonctionnalité peut être longue à développer et j'ai besoin de passer mon travail d'une machine à l'autre et un jour pouvoir retravailler tout mon historique avant de l'inclure sur la branche principale. Comment vous vous y prenez dans ce genre de situation ?

  • [^] # Re: Squeeze=testing?

    Posté par  (site web personnel) . En réponse à la dépêche Entretien avec Stefano Zacchiroli, Responsable du Projet Debian. Évalué à 6.

    Debian a trois branches : stable, testing et unstable.
    unstable aura toujours comme nom de code Sid.
    testing désigne la prochaine version stable, actuellement son nom de code est Squeeze.
    stable est la version stable... qui se nomme actuellement Lenny.
    Résumons :
    stable -> Lenny
    testing -> Squeeze
    unstable -> Sid

    Quand la prochaine version stable sortira (ici Squeeze) ça donnera :
    stable -> Squeeze
    testing -> [nom de jouet de Toy Story encore inconnu]
    unstable -> Sid
    Lenny sera alors qualifiée de "oldstable". Et cætera.

    Pour plus de détails, tout est là : http://www.debian.org/doc/FAQ/ch-ftparchives.fr.html