Contenu | Rechercher | Menus

Annonce

Ubuntu-fr.org recrute toujours de nouveaux modérateurs, avec de l'expérience.

Ubuntu 16.04 LTS
Commandez vos DVD et clés USB Ubuntu-fr !

Si vous avez des soucis pour rester connecté, déconnectez vous et reconnectez vous depuis ce lien en cochant le case
Me connecter automatiquement lors de mes prochaines visites.

nombre réponses : 25

#0 Re : -1 »  /* Topic des codeurs [9] */ » Le 06/05/2016, à 13:53

grim7reaper
Réponses : 81
Oni_Shadow a écrit :

Des nouvelles d'Arpège enfait ? tongue

Ça avance, très lentement mais ça progresse un peu ^^

#1 Re : -1 »  /* Topic des codeurs [9] */ » Le 18/05/2016, à 08:26

grim7reaper
Réponses : 81
Elzen a écrit :

(Oui, je sais, python2, mais la lecture du pad en python3 me renvoie un objet bytes dont j'ai la flemme de chercher maintenant comment convertir proprement)

Version Python 3

#! /usr/bin/env python3
# coding: utf-8

import os
import urllib.request
import sys

with urllib.request.urlopen(sys.argv[1] + '/export/txt') as pad:
    new = pad.read().decode('utf-8')

try:
    with open(sys.argv[2], 'r', encoding='utf-8') as fp:
        old = fp.read()
except FileNotFoundError:
    old = ''

if new != old:
    with open(sys.argv[2], 'w', encoding='utf-8') as fp:
        fp.write(new)

Trois petites remarques :
- c’est plus propre/sûr d’utiliser "with … as" pour ouvrir les fichier (la fermeture est géré automatiquement, même en cas d‘exception).
- il faut mieux essayer d’ouvrir le fichier et attraper l’exception si souci plutôt que tester l’existence du fichier avant ouverture (risque de race : le fichier eput être supprimé entre la réussite de ton test et l’ouverture du fichier).
- toujours préciser les encodages utilisés (There Ain't No Such Thing As Plain Text).

Bon y’a peu de chance que ça importe dans un script de 25 lignes, mais je le dit quand même tongue



The Uploader a écrit :

(Vivement que GTK soit abandonné et que le code source de GTK atterrisse dans un seul et unique disque dur qui finira sa vie dans un incendie explosif ! tongue )

Ouais, Qt est tellement meilleur avec son préprocesseur/générateur de code maison…
Moi je je dis NCurses rule them all!

#2 Re : -1 »  /* Topic des codeurs [9] */ » Le 18/05/2016, à 15:27

grim7reaper
Réponses : 81
Elzen a écrit :
grim7reaper a écrit :

- il faut mieux essayer d’ouvrir le fichier et attraper l’exception si souci plutôt que tester l’existence du fichier avant ouverture (risque de race : le fichier eput être supprimé entre la réussite de ton test et l’ouverture du fichier).

Hum, sachant que les deux instructions se suivent immédiatement (donc qu’il faut quand même y aller pour caser la suppression pile au bon moment depuis un autre processus)

Ça, ça ne veut rien dire. Ton processus peut se faire préempter/mettre en pause pendant un temps plus ou moins long entre la ligne X et X+1 et du coup, quand tu exécutes la ligne X+1 ton test de la ligne X est déjà obsolète.
C’est un vrai problème (cf. TOCTTOU).
Et puis, elles se suivent au niveau du code source Python mais à l’exécution il se passe pleins de trucs au niveau interpréteur, elles sont séparées par beaucoup plus que le code ne le laisse croire.

Elzen a écrit :

et qu'au pire, un plantage à ce niveau ne serait pas franchement grave (il suffirait de relancer make une seconde fois), est-ce vraiment important ?

On est d’accord, dans ton cas précis ce n’est pas très important. Je faisais plus une remarque d’ordre générale, et c’est le genre de choses à savoir quand on fait du code où ça importe.
Et puis autant faire du code qui fonctionne à tout les coup wink

Elzen a écrit :

À la base, quand j'ai appris à coder, on m'a expliqué que c'était toujours préférable de gérer des conditionnelles plutôt que des exceptions, donc j'ai spontanément tendance à faire ça (mais c'est vrai que je n'ai jamais eu de réelle explication sur le sujet)

En général je suis d‘accord avec cette approche, mais ici c’est un bon exemple où il faut “Ask for forgiveness, not permission” car faire un test est buggué.

Elzen a écrit :

(On note d'ailleurs que j'étais fatigué au moment de poster, puisque le « bon » test à faire dans ce cas n'est pas « os.path.exists(filepath) », mais « os.access(filepath, os.R_OK) »…)

Il faudrait aussi ajouter le test os.path.isfile tongue

#3 Re : -1 »  /* Topic des codeurs [9] */ » Le 19/05/2016, à 08:35

grim7reaper
Réponses : 81
Pylades a écrit :

Dépêchez-vous, Python 8 arrive. tongue

Fixed tongue

#4 Re : -1 »  /* Topic des codeurs [9] */ » Le 21/05/2016, à 17:20

grim7reaper
Réponses : 81
Elzen sur fadrienn.irlnc.org/galeries/outils/petite_base_de_donnees a écrit :

Naturellement, tout retour à ce sujet sera le bienvenu!

J’ai seulement jeté un œil à _base.py pour le moment, voilà mes remarques.
Le layout du code est un peu bizarre par endroit je trouve, mais bon c’est ton style je suppose ^^

Fonction `query`
Tu pourrais utiliser le context manager pour avoir auto/commit-rollback
Cf. la doc.


Fonction `check`
Tu pourrais pas utiliser finally pour le conn.close?


Fonction `escape`
Je ne comprends pas trop tes critères d’échappements.
J’ai trouvé ce post à ce sujet, mais ça ne correspond peut-être pas à ce que tu veux faire.


Fonction `loaddate`
Cette ligne est pas franchement claire :

return tuple(int(part) for part in parts)+(1,)*(3-len(parts))+(len(parts),)

Il pourrait aussi y avoir une docstring sur le format géré en entrée.


Fonction `savedate`
Les 0,1,2, et 3 pourrait être une énumération pour plus de lisibilité.


Fonction `loadcoords`
Il pourrait y avoir une docstring sur le format géré en entrée. Ce n’est pas clair en lisant le code.
Y’a une trailing space l. 131


Fonction `savecoords`
Il pourrait y avoir une docstring sur le format produit en sortie.
Tu pourrais lancer une exception un peu plus claire que Exception (qui est très générique), et puis ajouter un message d’erreur aussi.


Dans le "main"
C’est bizarre ce code au milieu de nulle part, ni dans une fonction ni guardé par un if __name__ == '__main__':

if dbfile is None: sys.exit(0)

=> Pourrait donner un message d’erreur.

elif os.access(dbfile, os.R_OK) and os.access(dbfile, os.W_OK):

=> Fait plutôt un try/catch (os.access ne vérifie pas que c’est un fichier, donc tu peux toujours échouer).


C’est tout pour le moment big_smile

#5 Re : -1 »  /* Topic des codeurs [9] */ » Le 22/05/2016, à 23:52

grim7reaper
Réponses : 81
Elzen a écrit :

Tu as le droit de dire que c'est moche ^^'

C’est pas très esthétique par endroit (quand tu mets beaucoup de choses sur une ligne), en effet tongue

Elzen a écrit :

(j'ai mis du temps à découvrir le finally, et je ne l'ai encore jamais utilisé en Python)

Ça existe aussi en Java pourtant.
Quoique depuis que Java supporte try-with-resources (Java 7) ça deviens moins indispensable.

Elzen a écrit :

uniquement des lettres non-accentuées, des chiffres et des underscore, en s'assurant que le nom de la table commence par une lettre.

Ok, une petite réecriture rends la choses plus lisible je pense (mais ça ne mange pas de pain d’ajouter une docstring quand même wink).

def escape(name):
    name = unicodedata.normalize('NFKD', name).replace(' ', '_')
    allowed_chars = string.ascii_letters + string.digits + '_'
    esc = ''.join(c for c in name if c in allowed_chars)
    return esc if esc and esc[0].isalpha() else None
Elzen a écrit :

Le retour doit être de la forme «(année, mois, jours, précision)», avec la précision qui varie entre 1 (à l'année près) et 3 (au jour près), en fonction de ce que contient la chaîne d'entrée («2010-05», par exemple, correspond à Mai 2010 avec une précision de 2, et le jour étant inconnu, on va mettre le premier du mois).

Du coup, un split sur le tiret, dont on convertit les éléments en entiers, on bourre des 1 à la fin, et on ajoute la taille pour la précision.

Je trouve qu’en utilisant une petite classe ça devient plus lisible :

class Date(object):
    def __init__(self, precision, year, month=1, day=1):
        self.precision = precision
        self.year  = year
        self.month = month
        self.day   = day

    @classmethod
    def load(cls, date):
    """Doc sur le format d’entrée"
        # Centuries (written as roman numbers)
        if 'e' in date:
            century, suffix = date.split('e', 1)
            century = roman.fromRoman(century) - 1
            if re.sub(r'[. ]', '', suffix.lower()).endswith("avjc"):
                century = -century
            return cls(precision=0, year=century*100)
        else:
            parts = map(int, date.split('-'))
            return cls(precision=len(parts), *parts)
Elzen a écrit :

Sans doute, mais je n'ai encore jamais créé d'énumérations en Python, il faudra que j'aille me renseigner sur comment on fait.

Avant, fallait bidouiller.
Mais depuis Python 3.4 il y a un module pour ça.

Elzen a écrit :

Tu sais s'il existe un format «standard» facile à parser pour noter les lattitude/longitude? (Du genre du «AAAA-MM-JJ» pour les dates).

ISO 6709 peut-être.

Elzen a écrit :

Hum, os.access renvoie False quand le fichier demandé n'existe pas, quel que soit le droit d'accès demandé. Ce qui correspond à ce que je veux à ce niveau

Ce que je veux dire c’est que os.access va te renvoyer True même si c’est un répertoire au lieu d’un fichier.

Elzen a écrit :

D'ailleurs, si ça intéresse d'autres gens, coder une petite appli de ce genre peut former un genre de défi TdC, ça fait longtemps ^^

Faudrait qu’il y ai plus de gens actifs pour qu’avoir un défi soit intéressant je pense.

#6 Re : -1 »  /* Topic des codeurs [9] */ » Le 23/05/2016, à 18:14

grim7reaper
Réponses : 81
Elzen a écrit :

D'ailleurs, comment fait-on pour gérer les plugins de manière propre? J'aimerais bien qu'il soit possible de rajouter un nouveau type de données à la base en ayant juste à coder le fichier .py qui va bien et en le posant dans le répertoire, sans avoir à modifier le reste du projet…

Je pense qu’il suffit de définir une interface à implémenter pour ton plugin (ton type ici donc) et d’avoir un moyen de l’enregistrer au sein du projet pour qu’il soit utilisable par le reste du code.

#7 Re : -1 »  /* Topic des codeurs [9] */ » Le 27/05/2016, à 10:30

grim7reaper
Réponses : 81

@Elzen : il suffirait pas que la factory (ou ce que tu vas utiliser pour centraliser tes types) exporte une methode register_type et que les type/plugin vont appeler pour s’enregistrer auprès de ladite factory ?

#8 Re : -1 »  /* Topic des codeurs [9] */ » Le 27/05/2016, à 13:27

grim7reaper
Réponses : 81
Elzen a écrit :

Mais si rien dans le reste du code ne les importe, comment on les charge?

Y’a pas de magie : va falloir charger le code à un moment (même en C ou C++, quand tu fais des plugin à un moment tu les charges avec dlopen).
importlib devrait te permettre de faire ça (via import_module peut-être).

#9 Re : -1 »  /* Topic des codeurs [9] */ » Le 27/05/2016, à 13:55

grim7reaper
Réponses : 81

Sinon j’ai regardé _data.py (un peu moins en détails que _base.py)

Tu pourrais avoir une classe abstraite à la base de tout ça (cf. abc).
Même si c’est pas obligatoire en Python ça rendrait le code plus sûr (y'aurait pas d’oubli d’implémenter une méthode requise) et ça permettrait de factoriser un peu le code (genre label pourrait être dans la classe de base).
Ça permettrait aussi de documenter ton interface (parce que là, le booléen renvoyé par la méthode prepare je n‘ai aucune idée de son rôle (ça viendra sûrement en lisant le reste du code, mais je devrais pas avoir à faire ça pour comprendre normalement)).


Pourquoi

sys.modules["_base"]

plusieurs fois au lieu de faire un simple import _base.
Je suppose que c’est liée à une des remarques de mon message précédent (à propos du code qui traîne en dehors de toute fonctions).


while parent.get_parent() is not None: parent = parent.get_parent()

Ça c’est moche sérieusement, le while sur une ligne (j’ai vu que tu le faisais pour les if/else et c’est déjà pas terrible, mais le while…)


if value is not None and value != "":

Ça pourrait être if value tout simplement je pense


for i in range(len(combo.get_model())):
    if combo.get_model()[i][0] == value:
        combo.set_active(i)

Tu pourrais utiliser enumerate ici:

for idx, val in enumerate(combo.get_model()):
    if val[0] == value:
        combo.set_active(idx)

Ce genre de trucs

wv.load_uri(url); scroll.add(wv)

et

try: entry.set_text(sys.modules["_base"].savecoords(wv.get_uri()))
except Exception: pass

C‘est aussi très très moyen, surtout que tu le fait de manière aléatoire on dirait (du coup c'est moche ET pas cohérent…).
Les virgules aussi (un coup y’ une espace après, et des fois non…).
Ça aide vraiment pas à lire le code (un code qui n’a pas de cohérence est difficile à suivre : la forme empêche de se concentrer sur le fond) hmm

#10 Re : -1 »  /* Topic des codeurs [9] */ » Le 31/05/2016, à 08:53

grim7reaper
Réponses : 81

Hey bienvenue !

Du sang neuf !

Slystone a écrit :

si vous avez des conseils pour un programmeur en codeur en herbe, je suis preneur

Hésite pas à poster ton code pour avoir des retours : ça évite de prendre de mauvaise habitudes quand on débutes et ça permets de découvrir certains trucs du langage plus rapidement (un exemple juste au dessus de ton message, avec enumerate wink).
Sinon tu peux aussi utiliser Pylint sur ton code pour vérifier que tu respectes bien la PEP 8 (même si pylint est parfois plus royaliste que le roi, ça peut aider quand même).

Slystone a écrit :

listes d'exercices (classés par difficulté croissante) pour se faire la main

Project Euler et Rosalind sont sympa je trouve.

Slystone a écrit :

forum/chat pour les noobs

chat : je ne sais pas.
forum : tu peux poser tes questions ici, ça fera vivre le topic smile

#11 Re : -1 »  /* Topic des codeurs [9] */ » Le 16/06/2016, à 13:26

grim7reaper
Réponses : 81
Oni_Shadow a écrit :

méthode : commencer à 2, ajouter un nombre comme premier s'il n'est divisible par aucun nombre premier qui le précède.

Ça ressemble à la méthode des divisions successives, tu aurais aussi pu utiliser le crible d’Ératosthène.
Note que tu n’as pas besoin de tester tout les nombre premier qui le précède : pour tester N, tu peux te contenter de tester les nombres premiers ≤ √N.

Oni_Shadow a écrit :

utiliser des addition plutôt que des multiplication pour trouver la plus grande somme (et en retenir la position) ; il me semble que les additions sont moins coûteuses.

Optimisation prématurée, et qui ne te donnera sûrement aucun gain en Python de toute façons. Ça va seulement rendre ton code moins lisible pour rien.
Ton code me semble compliqué.

Personnellement, je découperai le travail comme ça :
1. Découper le nombre en bloc de N chiffre : f("123456789", 4) => ["1234", "2345", "3456", "4567", "5678", "6789"].
2. Calculer le produit de chaque bloc.
3. Garder le maximum.

Ça tiens en 10 lignes de Python, mais je ne vais pas poster tout de suite, ça te spoilerai.
Je pense que tu n’es pas loin de la solution, mais tu as tellement compliqué ton code en essayant de l’optimiser (de la mauvaise façon) que tu as du rajouter des bugs en chemin.
Repart sur un truc plus simple et ça devrait le faire wink

#12 Re : -1 »  /* Topic des codeurs [9] */ » Le 20/06/2016, à 19:56

grim7reaper
Réponses : 81

Mouais, pas convaincu.
En C++ c’est ignoble (moc…) dans les autres langages c’est la chiasse pour faire un binding (C++…) s’il existe pas déjà.

#13 Re : -1 »  /* Topic des codeurs [9] */ » Le 21/06/2016, à 07:59

grim7reaper
Réponses : 81

C’est pas un argument ça, on peut faire d’excellentes (et encore, c’est subjectif…) choses avec un langage perfectible™ et du code très moche. L’un n’empêche par l’autre.

#14 Re : -1 »  /* Topic des codeurs [9] */ » Le 21/06/2016, à 09:32

grim7reaper
Réponses : 81
The Uploader a écrit :

Il n'y a nul besoin de rejeter un opinion sans arguments (cf. "c'est ignoble")

Bah j’ai cité pourquoi je considérait que c’était ignoble en C++ : moc.
C’est pas le summum de l’élégance…

The Uploader a écrit :

"Plein de gens l'utilisent depuis 15 ans et en sont très contents, […], ça doit pas être si mal que ça".

On peut dire ça de [insérer ici un truc merdique utilisé par beaucoup de gens] aussi hein, et pourtant…

De toute façon, je pense pas qu‘il y ai besoin de se lancer dans un long débat stérile : Elzen à déjà essayé Qt et n’a pas été convaincu (Cf. premier message de la page précédente).

#15 Re : -1 »  /* Topic des codeurs [9] */ » Le 21/06/2016, à 16:03

grim7reaper
Réponses : 81
The Uploader a écrit :
grim7reaper a écrit :

Bah j’ai cité pourquoi je considérait que c’était ignoble en C++ : moc.
C’est pas le summum de l’élégance…

Pourquoi ?

Parce qu’une bibliothèque qui t’impose de passer un préprocesseur sur ton code c’est très moche.
T’imagine si toute les bibliothèques étaient comme ça ?

The Uploader a écrit :

Et si ça marche bien, c'est si ignoble que ça ?

Encore une fois, le fait que ça marche bien ne change rien au fait que ça soit dégueulasse.
Je peux écrire un programmes de 20 000 lignes en mettant tout dans la fonction main, ça va marcher mais ça sera toujours autant dégueulasse. L’un n’empêche pas l’autre.

#16 Re : -1 »  /* Topic des codeurs [9] */ » Le 23/06/2016, à 08:51

grim7reaper
Réponses : 81
Elzen a écrit :

KDE n'utilisait pas Qt, mais un truc maison basé dessus.

KDE a toujours utilisé Qt, mais avec une surcouche importante par dessus c’est vrai. Je crois que certains de trucs de KDE ont été intégrés dans Qt et la surcouche est peut-être moins importante maintenant.

The Uploader a écrit :

De ce que je comprends, c'est pas l'auteur de l'application Qt qui maintient moc, il ne fait que l'utiliser.
Si ça ne fait pas une application non-maintenable (ou du code pourri) dès le départ, j'dirais que c'est pas si grave...

C’est pas le problème (encore heureux que c’est pas à l’utilisateur de faire la maintenance oO), mais ça fait un truc à ajouter au système de build (et c’est bien le dev’ qui s’occupe de ça à priori, sauf à avoir une équipe dédiée), si chaque bibliothèque venait avec son préprocesseur maison et qu’il fallait l’intégrer au processus de build ça serait l’enfer…
Donc oui, Qt en C++ c’est moche à cause de moc (et certains ajouterais à cause de C++ aussi, mais c’est un autre débat tongue).

#17 Re : -1 »  /* Topic des codeurs [9] */ » Le 23/06/2016, à 13:55

grim7reaper
Réponses : 81

Non, t’as rien à ajouter dans ton code (enfin si des macros, mais bon…) mais ça ajoute des trucs dans ton système de build donc la maintenance est seulement déplacée.
Et s’il y a que Qt qui fait ça, ça passe. Si toutes les bibliothèques le font ça devient l’enfer => donc c’est pas une bonne approche.

#18 Re : -1 »  /* Topic des codeurs [9] */ » Le 24/06/2016, à 08:14

grim7reaper
Réponses : 81
Elzen a écrit :

Question bête: existe-t-il un moyen de savoir, depuis une application externe, à quel position sur l'écran se situe le curseur d'un éditeur de texte ayant actuellement le focus?

Pas que je sache, et ça m’étonnerait que ce genre de chose soit possible hmm

Cela dit, c’est pas non plus terrible d’avoir une application qui écrit dans le presse-papier et ensuite tu colles depuis l’éditeur de texte.

#19 Re : -1 »  /* Topic des codeurs [9] */ » Le 24/06/2016, à 12:42

grim7reaper
Réponses : 81

Je viens de me rendre compte que ma dernière phrase était ambiguë hmm
Quand je dit

me a écrit :

Cela dit, c’est pas non plus terrible d’avoir une application qui écrit dans le presse-papier et ensuite tu colles depuis l’éditeur de texte.

Je voulais dire que c’est pas trop dérangeant d’avoir à coller à la main.
Je voulais pas dire que c’est moche de faire comme ça.

#20 Re : -1 »  /* Topic des codeurs [9] */ » Le 04/07/2016, à 12:54

grim7reaper
Réponses : 81
Elzen a écrit :

Qu'en pensez-vous ?

Que je ne vois pas comment tu vas gérer ls -A parce que au niveau FS tu ne verras pas la différence entre un ls et un ls -A donc je ne vois pas comment tu vas faire pour que ls renvoie toute la liste et ls -A renvoie la liste filtrée. À moins de coder ta version de ls mais là on sort d’une solution pure FUSE.

#21 Re : -1 »  /* Topic des codeurs [9] */ » Hier à 15:45

grim7reaper
Réponses : 81

Usine à gaz.

Elzen a écrit :

En gros, les avantages que j'y vois:

  • Ça facilite les MàJ des biblis communes, puisque « ls elzapps/*/elzlibs/machin.py » indique directement quelles applis utilisent une bibli donnée, et en cas de modif impactant plusieurs applis, ça fait un seul commit pour les corrections.

  • Si je veux proposer une appli particulière à quelqu'un, pas besoin de lui faire cloner tout le dépôt dont la grosse majorité ne servira pas, il y a juste à récupérer le répertoire de l'appli en question, et toutes mes dépendances à moi sont dedans.

Tu peux avoir ces avantages avec git et les sous-modules. Par contre ça sera pas la même organisation niveau arborescence.
Mais si tu as un (des) dépôt pour les bibliothèques communes et un dépôt par applications ça a les avantages que tu cites :

  • correction en un commit : fix le bug dans le dépôt du package puis met à jour les sous-module de chaque applications qui utilise ce package (bon ça fait plus de un commit du point de vue Git, mais point de vue dev ça te fait qu'un commit je dirais).

  • Si je veux proposer une appli particulière à quelqu'un : clone le dépôt de l’application, avec la bonne option ça va clôner les sous-modules (et donc les dépendances).

Un problème que je vois avec les liens physiques c’est que si à un moment tu as deux applications qui ont besoins de deux versions différentes de ton package commun tu est bloqué, non?
Avec les sous-modules ça se gère facilement.

Mais si tu veux rester avec ton organisation bien précise, je pense pas qu’il y ai de gestionnaires de versions qui gèrent ça (du moins à ma connaissance, mais à part Darcs et Git j’en connais pas beaucoup en détails).

#22 Re : -1 »  /* Topic des codeurs [9] */ » Hier à 22:05

grim7reaper
Réponses : 81
Elzen a écrit :

Si ça arrivait, il «suffirait» de refaire deux fichiers séparés, non?

Mais tu aurais deux copies quasi identiques qui représentent deux versions du même fichier, c’est de la gestion de version à la CPOLD tongue
Mais oui, dans ton cas ça a peu de chance d‘arriver de toutes façons.

#23 Re : -1 »  Recherche de langage pr programmation algorithmique : finance 2 marché » Le 23/06/2016, à 09:07

grim7reaper
Réponses : 8
Sgt.KA a écrit :

Mes recherches m'ont mené vers les langages OCaml et Haskell notamment.

Salut,

Ce sont de bonnes pistes.
Déjà parce qu’ils sont vraiment utilisés dans ces domaines (Jane Street utilise OCaml et Standard Chartered utilise Haskell par exemple).
Ensuite, parce que ce sont des langages fonctionnels et que c’est vraiment quelque chose de bien à connaître (approche différente de la programmation).

#24 Re : -1 »  [C] Mais que fait donc cette déclaration ? » Le 06/05/2016, à 08:49

grim7reaper
Réponses : 6

L’intérêt c’est surtout d’avoir accès aux variables de la fonction parente je suppose (je n‘ai jamais utilisé cette extension GNU, d’ailleurs je me borne au C standard quand j’en fait, histoire de portabilité).