Multiposte avec plusieurs cartes graphiques

De Le Wiki du Forum-Debian.fr
Aller à la navigation Aller à la recherche

Intro

Faire du multi-poste n'est pas quelque chose de naturel pour un particulier mais est très utilisé dans les bibliothèques ou universités pour démultiplier le nombre de postes informatiques disponibles à moindre coût.

Dans notre cas nous allons mettre en place la solution la plus répandue.
Pour cela il vous faut 1 PC unique pour tout les postes, dans lequel vous mettez 1 carte graphique par poste de travail souhaité, et bien évidement un couple clavier+souris par poste.

Sachez qu'il est possible de réduire le nombre de cartes graphiques nécessaires en exploitant plusieurs des sorties disponibles mais la technique est plus délicate à mettre en place et a plus de désavantages.


Configuration de X

Par défaut le fichier de configuration du serveur X («xorg.conf») n'est plus indispensable pour un poste de travail classique, mais dans notre cas il est indispensable pour s'y retrouver.
Vous avez le choix entre créer plusieurs fichiers de configuration distincts, un par poste, ou en faire un unique qui comportera l'ensemble des configurations qui seront classées dans des «Layout» différents.

Personnellement je vous conseille un seul fichier de configuration pour deux postes, mais au-delà ça commence à devenir illisible donc de faire un fichier par poste.

Pour notre exemple nous allons configurer 2 postes dans un seul fichier de configuration dans lequel nous allons définir les «Layout»s que nous allons utiliser.
Ce fichier regroupe l'ensemble de la configuration des postes, le «screen» (écran + carte graphique) et les périphériques d'entrée (clavier / souris).

Section "ServerLayout"
  #L'identifiant qui nous permettra de dire à X d'utiliser cette configuration
    Identifier     "poste0"
  #Le premier «0» désigne l'écran, comme vous pouvez avoir plusieurs écrans par carte/poste vous pouvez avoir des lignes supplémentaires avec un 1, 2 et ainsi de suite.
  # «ecran0» désigne une section que l'on verra plus tard. Enfin les 2 autres «0» positionnent l'écran suivant des coordonnées si plusieurs écran sont en jeux. 
    Screen      0  "ecran0" 0 0 
  #Désigne la section pour un périphérique d'entrée, ici un clavier
    InputDevice    "clavier0" "CoreKeyboard" 
  #Désigne la section pour un périphérique d'entrés, ici une souris
    InputDevice    "souris0" "CorePointer" 
EndSection


Section "ServerLayout"
    Identifier     "poste1"
    Screen      0  "ecran1" 0 0
    InputDevice    "clavier1" "CoreKeyboard"
    InputDevice    "souris1" "CorePointer"
EndSection

Ensuite nous définissons les périphériques d'entrée (ici juste pour le poste 0).

Pour identifier les périphériques matériels et leur point d'entrée logiciel il vous suffit d'aller faire un tour dans «/dev/input/*»,
et de faire un «cat» sur un des fichiers présents et de générer des événements clavier/souris.

Si votre «cat» vous sort quelque chose, alors vous avez identifié le périphérique correspondant.

####################################
# Périphérique d'entrée du poste 0 #
####################################
#Clavier du poste 0
Section "InputDevice"
  #Identifiant permettant au Layout de l'appeler
    Identifier    "clavier0" 
    Driver    "evdev"
  #Clavier branché sur un port PS/2, donc l'accès par «by-path» est toléré, mais il vaut mieux «by-id»
    Option    "Device"     "/dev/input/by-path/platform-i8042-serio-0-event-kbd" 
    Option    "XkbLayout"  "fr"
    Option    "XkbVariant" "latin9"
  #IMPORTANT, permet un accès exclusif au périphérique.
  # Sans ça les serveurs X ajouteront automatiquement tous les périphériques disponibles au contrôle,
  #  et du coup toutes les souris/clavier contrôleront tous les pointeurs.
    Option    "GrabDevice" "on" 
EndSection

#Souris du poste 0
Section    "InputDevice"
    Identifier    "souris0"
    Driver "evdev"
  #Souris branchée en USB et comme à chaque redémarrage le chemin peut se modifier (ou pas) il faut préféré l'identification par «by-id»
    Option "Device" "/dev/input/by-id/usb-B16_b_02_USB-PS_2_Optical_Mouse-event-mouse" 
    Option "GrabDevice" "on"
EndSection

Ensuite on définit la section «screen» qui est une agrégation d'une carte graphique et d'un écran.

#######################################
# Carte graphique et écran du poste 0 #
#######################################

Section "Device"
    Identifier     "carteVideo0"
   # par défaut mettre "vesa"
    Driver         "radeon"
    VendorName     "AMD/ATI"
    BoardName      "Radeon HD 6550D"
  #Trouvable en faisant un «lspci», pour ici «00:01.0 VGA compatible controller» se trouvait dans la sortie de la commande.
    BusID          "PCI:0:1:0"
  #Définition du premier (et seul) écran
    Screen          0
  #Avec un «xrandr» vous pouvez savoir quelle prise est utilisée pour connecter l'écran (DVI, HDMI, DP, VGA).
  # Le «Monitor-» est une nécessité de nommage et le «-0» représente la carte graphique utilisée, la première (donc «0») dans ce cas,
  #  mais pour le deuxième poste on pourra trouver «Monitor-DVI-1»
        Option         "Monitor-HDMI-0" "HannsG"
EndSection

Section "Monitor"
    Identifier     "LCD28"
    VendorName     "Hanns.G"
    ModelName      "HSD Hanns.G HG281"
    Option         "PreferredMode" "1920x1200"
EndSection

# Section qui relie les 2 composants ensemble.
Section "Screen"
    Identifier     "ecran0"
    Device         "carteVideo0"
    Monitor        "LCD28"
    DefaultDepth    24
    Option         "TwinView" "0"
    Option         "metamodes" "DFP: 1920x1200 +0+0"
    SubSection     "Display"
        Depth       24
        Modes      "1920x1200_60"
    EndSubSection
EndSection

 NOTE : Attention, les valeur données par lspci pour le BUSID sont en hexadécimal, donc si vous avez "15:0a.2", vous devez renseigner "21:10:2"


Donc au final on obtient un fichier tel que celui-ci :

#Configuration multi-poste

#############
# Serveur X #
#############

Section "ServerLayout"
    Identifier     "poste0"
    Screen      0  "ecran0" 0 0
    InputDevice    "clavier0" "CoreKeyboard"
    InputDevice    "souris0" "CorePointer"
EndSection


Section "ServerLayout"
    Identifier     "poste1"
    Screen      0  "ecran1" 0 0
    InputDevice    "clavier1" "CoreKeyboard"
    InputDevice    "souris1" "CorePointer"
EndSection

#Section "Files"
#    RgbPath         "/usr/X11R6/lib/X11/rgb"
#EndSection

Section "Module"
    Load        "dbe"
    Load        "extmod"
    Load        "type1"
    Load        "freetype"
    Load        "glx"
EndSection

Section "ServerFlags"
    Option      "Xinerama"          "0"
#    Option      "AutoEnableDevices" "false"
#    Option      "AutoAddDevices"    "false"
#    Option      "AllowEmptyInput"   "true"
#    Option      "AutoAddGPU"        "false"
EndSection

####################################
# Périphérique d'entrée du poste 0 #
####################################
#Clavier du poste 0
Section "InputDevice"
    Identifier    "clavier0"
    Driver    "evdev"
    Option    "Device"     "/dev/input/by-path/platform-i8042-serio-0-event-kbd"
    Option    "XkbLayout"  "fr"
    Option    "XkbVariant" "latin9"
    Option    "GrabDevice" "on"
EndSection

#Souris du poste 0
Section    "InputDevice"
    Identifier    "souris0"
    Driver "evdev"
#    Option "ZAxisMapping" "4 5"
    Option "Device" "/dev/input/by-id/usb-B16_b_02_USB-PS_2_Optical_Mouse-event-mouse"
    Option "GrabDevice" "on"
EndSection

####################################
# Périphérique d'entrée du poste 1 #
####################################
#Clavier du poste 1
Section "InputDevice"
    Identifier    "clavier1"
    Driver    "evdev"
    Option    "Device"     "/dev/input/by-id/usb-TrulyErgonomic.com_Truly_Ergonomic_Computer_Keyboard-event-kbd"
    Option    "XkbLayout"  "fr"
    Option    "XkbVariant" "bepo"
    Option    "GrabDevice" "on"
EndSection

#Souris du poste 1
Section "InputDevice"
    Identifier    "souris1"
    Driver    "evdev"
#    Option    "ZAxisMapping" "4 5"
    Option    "Device" "/dev/input/by-id/usb-1d57_Game_mouse-if01-event-mouse"
    Option    "GrabDevice" "on"
EndSection

#######################################
# Carte graphique et écran du poste 0 #
#######################################

Section "Device"
    Identifier     "carteVideo0"
    Driver         "radeon"
    VendorName     "AMD/ATI"
    BoardName      "Radeon HD 6550D"
    BusID          "PCI:0:1:0"
    Screen          0
    Option         "Monitor-HDMI-0" "HannsG"
EndSection

Section "Monitor"
    Identifier     "LCD28"
    VendorName     "Hanns.G"
    ModelName      "HSD Hanns.G HG281"
    Option         "PreferredMode" "1920x1200"
EndSection

Section "Screen"
    Identifier     "ecran0"
    Device         "carteVideo0"
    Monitor        "LCD28"
    DefaultDepth    24
    Option         "TwinView" "0"
    Option         "metamodes" "DFP: 1920x1200 +0+0"
    SubSection     "Display"
        Depth       24
        Modes      "1920x1200_60"
    EndSubSection
EndSection

#######################################
# Carte graphique et écran du poste 1 #
#######################################

Section "Device"
    Identifier     "carteVideo1"
    Driver         "radeon"
    VendorName     "AMD/ATI"
    BoardName      "Radeon HD 6450/7450/8450 / R5 230 OEM"
    BusID          "PCI:1:0:0"
    Screen         0 
    Option         "Monitor-DVI-1" "Acer"
EndSection

Section "Monitor"
    Identifier     "LCD22"
    VendorName     "ACER"
    ModelName      "ACER B229w"
    Option         "PreferredMode" "1680x1050"
EndSection

Section "Screen"
    Identifier     "ecran1"
    Device         "carteVideo1"
    Monitor        "LCD22"
    DefaultDepth    24
    Option         "TwinView" "0"
    Option         "metamodes" "DFP: 1680x1050 +0+0"
    SubSection     "Display"
        Depth       24
        Modes      "1680x1050_60"
    EndSubSection
EndSection


Test de la configuration

Pour cela il vous suffit de vous mettre dans une console et de taper la commande suivante :

X -layout <mon layout> -vtX

Où le X doit être remplacé par un numéro de console libre, 8, 9, 10, 11 ou 12 en général.

Vous devriez changer de console pour celle visée et voir un écran gris avec le curseur manipulable, et si c'est bien le cas, c'est que votre configuration est bonne. Si vous voyez juste un écran noir mais que dans les logs tout semble bon, votre configuration est peut être aussi correct.

Configuration systemd

Il existe un soucis qui fait que seul le premier poste (seat0) est détecté par «systemd-logind» et du coup ça empêche certaines fonctionnalités de s'exécuter correctement.
Par exemple le montage automatique des clés USB en cliquant sur l'icône qui apparaît.

Pour vérifier cela il faut vous connecter à 2 postes minimum et lancer la commande suivante :

loginctl

Si vous voyez tous vous utilisateurs connectés sur leur siège tant mieux pour vous,
sinon il faut faire les manipulations suivantes :


Rattachement du matériel

Tout d'abord faites la commande suivante, elle vous donne tous les matériels rattachés au premier poste et vous permettra de récupérer les chemins vers certains périphériques nécessaires.

loginctl seat-status seat0

Ensuite faites un premier essai en rattachant manuellement certains périphériques, ici la carte graphique :

loginctl attach seat1 /sys/devices/pci0000:00/0000:00:02.0/0000:01:00.0/drm/card1 
loginctl attach seat1 /sys/devices/pci0000:00/0000:00:02.0/0000:01:00.0/graphics/fb1

Normalement en refaisant la commande «loginctl list-seats» vous devriez voir le nouveau «seat».
Repérez les chemins vers les périphériques de votre siège (clavier / souris / carte son / carte graphique / … ), sachant qu'au minimum il nous faut la carte graphique.

Une fois le fichier modifier la commande suivant vous permet de tester les nouvelles règles dynamiquement

udevadm control --reload-rules && udevadm trigger


Cas spécial du «seat0»

Le «seat0» est spécial dans le sens ou il existera toujours et que tout périphérique lui est attaché par défaut, c'est le point de référence de «logind».

Automatisation

Le fait d'attacher un périphérique à un «seat» créé automatiquement la règle udev (dans «/etc/udev/rules.d/») qui permet, après une extinction, de retrouver les réglages.
Cependant ces règles sont basiques et il faut les démultiplier pour prendre en compte tout un poste.

Il peut être plus intéressant de les retoucher pour englober tout un poste si tout ses périphériques sont branchés sur un même concentrateur USB.
Pour cela les commandes suivantes vous seront utiles :

udevadm info -a -p <chemin en /sys/… >

Vous donnera toutes les informations sur un périphérique particulier et toute sa hiérarchie de connexion.

Au final cela m'a donné les règles suivantes

# add master-of-seat tag to video cards
KERNEL=="card[0-9]*", SUBSYSTEM=="drm", TAG+="master-of-seat"
KERNEL=="fb[1-9]", SUBSYSTEM=="graphics", TAG+="master-of-seat"

# Carte graphique
TAG=="seat", KERNEL=="fb1", SUBSYSTEM=="graphics", ATTR{virtual_size}=="1680,1050", ENV{ID_SEAT}="seat1", TAG+="seat1"
TAG=="seat", KERNEL=="card1", SUBSYSTEM=="drm", ENV{ID_SEAT}="seat1", TAG+="seat1"

# Clavier
TAG=="seat", SUBSYSTEM=="input", ATTR{name}=="TrulyErgonomic.com Truly Ergonomic Computer Keyboard", ENV{ID_SEAT}="seat1", TAG+="seat1"
TAG=="seat", SUBSYSTEM=="input", ATTR{name}=="ErgoDox ErgoDox ergonomic keyboard", ENV{ID_SEAT}="seat1", TAG+="seat1"

# Souris
TAG=="seat", SUBSYSTEM=="input", ATTR{name}=="Game mouse", ENV{ID_SEAT}="seat1", TAG+="seat1"

#Lecteur de carte
TAG=="seat", SUBSYSTEM=="input", DEVPATH=="/sys/devices/pci0000:00/0000:00:10.0/usb1/*", ENV{ID_SEAT}="seat1", TAG+="seat1", TAG+="seat0"

Ce n'est pas l'optimum mais suffisant pour ce que je voulais faire.
Le TAG «master-of-seat» ne semble pas indispensable mais est fortement conseillé sur au moins un périphérique par poste, il semble que ça permette à systemd de trouver un référent au nouveau poste.

Si vous rattachez un concentrateur USB à un siège il sera exclusif à ce dernier, ce qui a ses avantages pour brancher de nouveaux périphériques USB que l'on veux visible par un seul siège. Le lecteur de carte été ajouté aux deux siège pour partager ce périphérique.

Configuration de LightDM

Ici rien de plus simple, il suffit de dire à lightDM de lancer un deuxième serveur X avec une configuration particulière. Pour cela il faut modifier son fichier de configuration («/etc/lightdm/lightdm.conf»)

[Seat:seat0]
xserver-command=/usr/bin/X :0 -auth /var/run/lightdm/:0 -nolisten tcp -novtswitch vt7
xserver-layout=poste0

[Seat:seat1]
xserver-command=/usr/bin/X :1 -auth /var/run/lightdm/:1 -nolisten tcp -novtswitch vt8
xserver-layout=poste1

Certains tutoriels ajoutent les options «sharevts» ou «keeptty»,
mais «sharevts» me bloquait l'affichage sur l'interface graphique alors que les commandes passaient bien sur un VT,
et «keeptty», d'après la doc, n'est utile que pour le debug, mais pas plus («Prevent the server from detaching its initial controlling terminal.»).

Ici, seul le siège principal (seat0) a un accès aux VT (Ctrl + Maj + Fx). Pour info le nom du siège est placé dans la variable "xdg-seat" pour l'identification des postes par systemd.

L'option «xserver-layout» parle d'elle même et permet de sélectionner une configuration particulière dans un fichier de conf Xorg,
et «xserver-config» permet de sélectionner un fichier de conf particulier si on a choisi de séparer la configuration des X.

L'option «xdg-seat» est indispensable pour logind si vous l'utilisez encore afin de faire le lien entre le poste graphique et les droits à lui accorder.

Si tout s'est bien passé vous devriez voir apparaître les 2 écrans de connexion avec le clavier et souris rattachée. Cependant il ne faut pas s'arrêter en si bon chemin et le système a encore besoin de quelques configurations.


 NOTE : Attention, si un seul (le seat0) se lance c'est qu'un seul «seat» est détecté et répertorié par systemd. Pour faire comprendre a systemd qu'il y a un deuxième poste il faut lui rattacher un ou plusieurs périphérique (clavier, sourie, écran, …). Pour cela reportez vous au paragraphe précédent


Configuration de Pulseaudio

Par défaut «pulseaudio» se lance en espace utilisateur, cela veut dire qu'une fois que vous vous déconnectez de votre session, votre PC ne peut plus émettre un son.
Le fait que le serveur de son soit rattaché à la connexion d'un utilisateur, empêche l'utilisation du son d'un second utilisateur, ce qui serait fort dommage dans notre cas.

Donc nous allons changer cela pour que «pulseaudio» s'exécute en tant que daemon système (ne pas tenir compte du message d'avertissement qui vous le déconseillerait, nous n'avons pas le choix dans notre cas),
et régler les droits utilisateurs pour que tous puisse accéder a ce daemon.


Configuration des droits

Normalement vous devez déjà avoir les groupes "pulse" et "pulse-access" de créés sur votre machine.

  • Modifier les utilisateurs en les ajoutant au groupe "pulse-access"
usermod -aG pulse-access <username>
  • On peut enlever l'utilisateur des groupes "audio" et "pulse" pour éviter qu'il ne prenne la main sur la carte son ou Pulseaudio
deluser <username> audio
deluser <username> pulse


Création du daemon système PulseAudio

Bien que ce soit déconseillé de faire tourner pulseaudio en tant que daemon système, c'est le seul moyen pour que les 2 postes aient accès à la carte son en même temps.
Pour cela il faut légèrement modifier la configuration de pulseaudio.

Dans un premier temps nous recopions les fichier de conf system au niveau utilisateur

$ cp /etc/pulse/default.pa ~/.pulse/

ou

$ cp /etc/pulse/default.pa ~/.config/pulse/


Ensuite /etc/pulse il faut modifier les fichiers suivant :

daemon.conf

...
daemonize = yes
...
local-server-type = system
...

client.conf

...
autospawn = no
auto-connect-localhost = yes
...

system.pa (default.pa est utilisé uniquement quand pulseaudio est lancé en process utilisateur)

...
# Ouverture des connexions en local
load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1
load-module module-native-protocol-unix auth-group=pulse-access
# pour debug (http://localhost:4714/)
load-module module-http-protocol-tcp
...

Ensuite il faut créer/compléter le fichier suivant /etc/dbus-1/system.d/pulseaudio-system.conf

<?xml version="1.0" encoding="UTF-8"?>
<busconfig>

  <!-- System-wide PulseAudio runs as 'pulse' user. This fragment is
       not necessary for user PulseAudio instances. -->

  <policy user="pulse">
    <allow own="org.pulseaudio.Server"/>
    <allow send_destination="org.pulseaudio.Server"/>
    <allow receive_sender="org.pulseaudio.Server"/>
  </policy>

</busconfig>

Dans la config utilisateur il faut modifier le fichier ~/.pulse (ou ~/.config/pulse)

# Config pour multiposte
autospawn = no
default-server = 127.0.0.1


Automatisation du lancement au démarrage système avec systemd

Pour cela il faut créer le fichier /etc/systemd/system/pulseaudio.service

[Unit]
Description=Pulseaudio sound server
Documentation=man:pulseaudio(1)
After=avahi-daemon.service network.target
#Before=sound.target
Requires=dbus.socket
 
[Service]
Type=forking
BusName=org.pulseaudio.Server
ExecStart=/usr/bin/pulseaudio --system --disallow-exit --disallow-module-loading
ExecStop=/usr/bin/pulseaudio --kill
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
 
[Install]
WantedBy=multi-user.target

Et lancer la commande suivante pour qu'il soit exécuté au démarrage :

systemctl enable pulseaudio.service

Si vous voulez tester tout de suite le service il vous suffit de faire

systemctl start pulseaudio.service

S'il ne démarre pas il faut le lancer directement pour voir la sortie des logs

pulseaudio --system

Fermeture de session

Un autre problème est qu'il se peut que certains programmes ne se ferment pas correctement quand vous quittez votre session.
Pour cela, sur un autre poste que celui qui vient de se déconnecter, il vous suffit de taper la commande suivante pour trouver les coupables :

loginctl session-status <numéro de session visé>

Dans mon cas il s'agissait de «gpg-agent» et de «gnome-keyring-daemon», comme je ne les utilisais pas je les ai simplement supprimé.
Ce n'est pas vraiment une solution et l'exécution d'un script lors de la déconnexion (param ligtdm) est sûrement préférable mais je n'en n'ai pas vraiment eu l'utilité pour l'instant.

Problèmes possibles

Je ne vois pas les clés USB branchées

Et oui c'est un souci que je n'ai pas encore résolu, le hub USB sur lequel est branché la clé appartient à l'un des deux postes, donc seul l'un des deux est en mesure d'inter-agir avec.
Donc avec un «loginctl attach» il est possible d'affecter un port/hub à un poste en particulier mais pas de le partager ... pour l'instant.


VLC/clementine/virtualbox/... ne s'ouvre pas/ met du temps sur le seatX

C'est un problème avec l'accessibilité (spi).
Normalement en regardant vos variables d'environnement vous devriez voir «QT_ACCESSIBILITY=1», cela signifie que vous offrez de la synthèse vocale et autre aménagement pour l'accessibilité.

Mais, comme cela ne m'était pas nécessaire, j'ai supprimé les paquets suivants, et tout est rentré dans l'ordre.

espeak-data
gnome-orca
libespeak1
libsonic0
python3-pyatspi
qt-at-spi
speech-dispatcher
speech-dispatcher-audio-plugins

J'ai peut-être fait trop de ménage, mais au moins ça fonctionne.

Il semble que changer la config avec la commande suivante permet de ne pas setter «QT_ACCESSIBILITY» et donc de résoudre le soucis (ref https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=762672).

gsettings set org.gnome.desktop.interface toolkit-accessibility false


Le poste X ne peut éteindre le PC / monter une clé qui apparait sur le bureau

Cela veut dire qu'il n'est pas reconnu en tant que «seat» par le système et qu'il vous manque quelque chose.
Vérifiez les «seat» par

loginctl

et

loginctl seat-status seatX


Ma disposition de clavier n'est pas prise en compte

Il semble que la prise en compte d'une disposition autre que la standard du système ne soit pas correctement faite,
dans le cas où la disposition est spécifiée dans la section "InputDevice" comme définit plus haut.

Heureusement pour nous, il est possible de définir d'une autre manière une disposition pour un clavier : Il faut passer par une section "InputClass".
Au lieu de définir les options pour un clavier spécifique, on définit des option pour un type de clavier.
Ce qui donne dans notre cas :

Section "InputClass"
   Identifier   "Truely"
   MatchIsKeyboard "True"
   MatchProduct "Truly Ergonomic Computer Keyboard"
#   MatchVendor "TrulyErgonomic.com"
   Driver "evdev"
   Option    "XkbLayout"  "fr"
   Option    "XkbVariant" "bepo"
EndSection

La valeur à remplir dans le "MatchVendor/Product" est trouvable en faisant un "lsusb -v | grep -e idProduct -e idVendor"


Améliorations possibles

  • Partage de concentrateur USB : Dans mon cas c'est plus le partage de lecteur de carte, mais je n'ai pas encore trouvé comment faire pour que 2 ou plus postes puissent accéder à un périphérique.
  • Répartition des enceintes : Sur les cartes son en général il y a 2 prises pour la sortie audio, il serait intéressant que pour 2 postes chacun ait une paire propre.
  • Gérer le branchement à chaud des périphériques : Cela semble supporté depuis un moment mais je n'ai pas encore trouvé pourquoi cela ne fonctionne pas ici. => fonctionne
  • La convention semble vouloir que les postes autres que le «seat0» soient de la forme «seat-x», mais cela ne fonctionnait pas pour moi, et comme je n'y avais pas d'intérêt pour l'instant …


Ressources