Des «onglets» de style navigateur pour emacs?


22

Je voudrais des onglets comme firefox mais pour emacs.

J'ai trouvé ceci: http://emacswiki.org/emacs/TabBarMode

Mais il suffit d'ajouter à chaque tampon ( fenêtre dans la terminologie Emacs) une barre qui affiche les tampons actuellement ouverts.

Je voudrais qu'un onglet puisse contenir plusieurs tampons ( fenêtres dans la téminologie Emacs), que je peux diviser comme vous le souhaitez. C'est-à-dire que chaque onglet doit correspondre à un "état de fenêtre" (au sens de window-state-get).

J'aurais un onglet pour mes tâches, un autre pour le code, un autre pour la lecture web etc.

Est-ce possible? La barre d'onglets peut-elle être adaptée à cette fin?

[edit2]
Cette question a attiré plus d'attention que je ne l'avais prévu. Il semble qu'il existe une solution, mais qui nécessiterait un peu de recherche et de peaufinage. Bien que cette semaine / la semaine prochaine soit un peu chargée pour moi, je vais analyser les réponses et essayer de construire quelque chose qui fonctionne, puis je modifierai cette question pour refléter mes résultats. Veuillez patienter =)

[modifier]
Sorte de semblable à:
/programming/24157754/make-frames-in-emacs-gui-behaves-like-frames-in-terminal

Je réglerais également avec plusieurs trames en une seule session GUI.


2
"Je voudrais qu'un onglet puisse contenir plusieurs tampons, que je peux diviser comme vous le souhaitez." Voulez-vous dire plusieurs fenêtres ?
Malabarba

1
C'est plus comme si j'aimerais avoir des onglets très dyanmiques. Je les créerais puis les remplirais de fenêtres. C'est-à-dire que j'aimerais qu'un onglet soit un cadre. Puis un nouvel onglet un nouveau cadre. À l'intérieur de chaque onglet / cadre, je pouvais ouvrir les fenêtres / tampons souhaités. Est-ce faisable? (C'est-à-dire, pas de noms de tampons codés en dur, etc.)
Leo Ufimtsev

1
Il y a une variable associée à des fenêtres particulières, mais cela fait un mois ou deux depuis que j'ai vu un fil qui en parlait et je ne sais pas comment on l'appelle à la main. Vous pouvez être intéressé par l'utilisation d'un système similaire à frame-bufs où une liste contient les tampons associés à une trame et cette liste est incorporée dans le paramètre de trame. Vous pouvez utiliser la variable associée à une fenêtre particulière et en faire une liste, ajouter / supprimer des tampons de la liste - cette liste serait un groupe de tampons à utiliser par la barre d'onglets. Tout cela est théorique, mais je pense que cela fonctionnerait.
lawlist

1
Je pense que vous pouvez vous référer à: stackoverflow.com/questions/24157754/… mais ce post ne semble pas avoir de réponse solide: - /
Leo Ufimtsev

1
Je recommanderais de jeter un œil au package elscreen.
blarghmatey

Réponses:


8

Diviser les tampons en groupes

C'est possible avec la barre d'onglets. Vous pouvez ajouter des règles aux tampons de groupe en groupes. Voici un extrait de base:

(defun tabbar-buffer-groups ()
  "Returns the list of group names the current buffer belongs to."
  (list
   (cond

    ;; ADD RULES TO SPLIT BUFFERS IN GROUPS HERE!

    ;; if buffer is not grouped by the rules you would add above 
    ;; put it in the "General" group:
    (t
       "General"
     ))))

Exemples de règles:

  1. Liste des noms de tampons:
    ((member (buffer-name)
             '("*scratch*" "*Messages*" "*Help*"))
     "Common" ;; this is a group name
     )
  1. En ce qui concerne les tampons communs, je préfère mettre en "Common" chaque tampon dont le nom commence par une étoile. Cela donne un exemple de création d'un tampon pour cette règle:
    ((string-equal "*" (substring (buffer-name) 0 1))
     "Common"
     )
  1. Voici un exemple de regroupement des tampons par mode principal:
    ((memq major-mode
           '(org-mode text-mode rst-mode))
     "Text"
     )
  1. Voici un exemple de regroupement des tampons en fonction du mode dont ils sont dérivés:
    ((or (get-buffer-process (current-buffer))
         ;; Check if the major mode derives from `comint-mode' or
         ;; `compilation-mode'.
         (tabbar-buffer-mode-derived-p
          major-mode '(comint-mode compilation-mode)))
     "Process"
     )
  1. Voici un exemple de regroupement des onglets par expression rationnelle:
    ((string-match "^__" (buffer-name))
     "Templates"
     )
  1. Grouper les tampons par mode principal:
    (if (and (stringp mode-name)
                  ;; Take care of preserving the match-data because this
                  ;; function is called when updating the header line.
                  (save-match-data (string-match "[^ ]" mode-name)))
             mode-name
           (symbol-name major-mode))

Une fois que vous avez composé les règles, vous pouvez appuyer sur + ou - sur la ligne de tabulation de la barre d'onglets pour basculer entre les groupes, et également sur ◀ et ▶ pour basculer entre les tampons. Ou liez simplement les défuns suivants:

tabbar-forward
tabbar-backward
tabbar-forward-group
tabbar-backward-group

et vous déplacer entre les onglets et les groupes d'onglets avec le clavier.

Personnellement, je groupe les onglets, afin de voir ce qui est ouvert, mais de les parcourir ido-switch-buffer.

Basculer entre un ensemble de règles

On peut également définir un ensemble différent de règles de regroupement de tampons et alterner entre celles-ci. Voici un exemple de cycle entre deux ensembles de règles de regroupement de tampons:

;; tab-groups!
(setq tbbr-md "common")
(defun toggle-tabbar-mode ()
  "Toggles tabbar modes - all buffers vs. defined in the `tabbar-buffer-groups'."
  (interactive)
  (if (string= tbbr-md "groups")
      (progn ;; then
        (setq tabbar-buffer-groups-function 'tabbar-buffer-groups-common)
        (setq tbbr-md "common"))
    (progn ;; else
      (setq tabbar-buffer-groups-function 'tabbar-buffer-groups)
      (setq tbbr-md "groups"))))
;; by default - all tabs:
(setq tabbar-buffer-groups-function 'tabbar-buffer-groups-common)

Cela permet de basculer entre les défuns de regroupement tabbar-buffer-groups-commonet de tabbar-buffer-groupstabulation.

Trier les tampons de la barre d'onglets par nom

Je trouve avantageux de trier les tampons de la barre de tabulation par nom. Voici comment l'obtenir:

(defun tabbar-add-tab (tabset object &optional append_ignored)
  "Add to TABSET a tab with value OBJECT if there isn't one there yet.
If the tab is added, it is added at the beginning of the tab list,
unless the optional argument APPEND is non-nil, in which case it is
added at the end."
  (let ((tabs (tabbar-tabs tabset)))
    (if (tabbar-get-tab object tabset)
        tabs
      (let ((tab (tabbar-make-tab object tabset)))
        (tabbar-set-template tabset nil)
        (set tabset (sort (cons tab tabs)
                          (lambda (a b) (string< (buffer-name (car a)) (buffer-name (car b))))))))))

Merci pour la réponse détaillée. J'essaierai d'essayer ce qui précède et je vous ferai savoir ~ éventuellement :)
Leo Ufimtsev

Mais l'OP ne veut pas "une barre d'onglets par fenêtre", il veut une barre d'onglets par cadre et chaque onglet de la barre d'onglets doit représenter une "configuration de fenêtre" (c'est-à-dire plusieurs fenêtres) plutôt qu'un tampon, donc le regroupement des tampons n'est pas le problème .
Stefan

6

ATTRIBUT: Le regroupement des tampons par trame est une implémentation directe des concepts et des portions sélectionnées de code développées / écrites par Alp Aker dans la bibliothèque frame-bufs: https://github.com/alpaker/Frame-Bufs

Voici un exemple d'utilisation tabbar.eldynamique de la bibliothèque et du groupe d'onglets / tampons par image en ajoutant des onglets / tampons avec C-c C-aou en supprimant des onglets / tampons avec C-c C-n. Il n'y a que deux (2) groupes - associés à la trame actuelle (c.-à-d. "A") Et NON associés à la trame actuelle (c.-à "N"-d.). Les groupes sont locaux de trame, ce qui signifie que chaque trame peut avoir son propre regroupement. Le regroupement personnalisé peut être réinitialisé avec C-c C-r. Basculez entre les groupes associés et non associés avec C-tab. Passez à l'onglet / tampon suivant dans le groupe actuel avec M-s-right. Basculez vers l'onglet / tampon précédent dans le groupe actuel avec M-s-left.

Les onglets / tampons peuvent être ajoutés ou supprimés par programme avec my-add-bufferet my-remove-buffer. Pour un exemple sur la façon d'ouvrir certains tampons dans des cadres sélectionnés, veuillez consulter le fil associé intitulé Comment intercepter un fichier avant son ouverture et décider quel cadre : /programming//a/18371427/2112489 La fonction my-add-bufferdevrait être incorporé aux emplacements appropriés du code dans le lien ci-dessus si un utilisateur choisit de mettre en œuvre cette fonctionnalité.

L'utilisateur peut souhaiter créer une entrée dans une personnalisation mode-line-formatqui affiche le nom du groupe d'onglets actuel dans la ligne de mode en incorporant l'extrait de code suivant: La (:eval (when tabbar-mode (format "%s" (tabbar-current-tabset t)))) personnalisation de la ligne de mode plus en détail, cependant, dépasse le cadre de cet exemple.

La fonction tabbar-add-taba été modifiée pour alphabétiser les tabulations / tampons.

La fonction tabbar-line-taba été modifiée afin de fournir quatre (4) faces différentes selon la situation. Si l'onglet / tampon est associé au cadre et EST sélectionné, utilisez alors tabbar-selected-associatedface. Si l'onglet / tampon est associé au cadre et NON sélectionné, utilisez tabbar-unselected-associatedface. Si l'onglet / tampon n'est PAS associé au cadre et EST sélectionné, utilisez tabbar-selected-unassociatedface. Si l'onglet / tampon n'est PAS associé au cadre et n'est PAS sélectionné, utilisez tabbar-unselected-unassociatedface.

;; Download tabbar version 2.0.1 by David Ponce:
;;   https://marmalade-repo.org/packages/tabbar
;; or use package-install for marmalade repositories.

;; Place tabbar-2.0.1.el in the `load-path` -- it is okay to rename it to tabbar.el
;; or add the directory (where `tabbar.el` resides) to the `load-path`.
;; EXAMPLE:  (setq load-path (append '("/Users/HOME/.emacs.d/lisp/") load-path))

(require 'tabbar)

(setq tabbar-cycle-scope 'tabs)

(remove-hook 'kill-buffer-hook 'tabbar-buffer-track-killed)

(defun my-buffer-groups ()
  "Function that gives the group names the current buffer belongs to.
It must return a list of group names, or nil if the buffer has no
group.  Notice that it is better that a buffer belongs to one group."
  (list
    (cond
      ((memq (current-buffer) (my-buffer-list (selected-frame)))
        "A")
      (t
        "N"))))

(setq tabbar-buffer-groups-function 'my-buffer-groups) ;; 'tabbar-buffer-groups

;; redefine tabbar-add-tab so that it alphabetizes / sorts the tabs
(defun tabbar-add-tab (tabset object &optional append)
  "Add to TABSET a tab with value OBJECT if there isn't one there yet.
If the tab is added, it is added at the beginning of the tab list,
unless the optional argument APPEND is non-nil, in which case it is
added at the end."
  (let ((tabs (tabbar-tabs tabset)))
    (if (tabbar-get-tab object tabset)
        tabs
      (let* ((tab (tabbar-make-tab object tabset))
             (tentative-new-tabset
               (if append
                 (append tabs (list tab))
                 (cons tab tabs)))
             (new-tabset
               (sort
                  tentative-new-tabset
                  #'(lambda (e1 e2)
                     (string-lessp
                       (format "%s" (car e1)) (format "%s" (car e2)))))))
        (tabbar-set-template tabset nil)
        (set tabset new-tabset)))))

;; AUTHOR:  Alp Aker -- https://github.com/alpaker/Frame-Bufs
;; @lawlist extracted/revised the function(ality) from said library.
(defun my-buffer-list (frame)
  ;; Remove dead buffers.
  (set-frame-parameter frame 'frame-bufs-buffer-list
    (delq nil (mapcar #'(lambda (x) (if (buffer-live-p x) x))
      (frame-parameter frame 'frame-bufs-buffer-list))))
  ;; Return the associated-buffer list.
  (frame-parameter frame 'frame-bufs-buffer-list))

(defun my-kill-buffer-fn ()
"This function is attached to a buffer-local `kill-buffer-hook'."
  (let ((frame (selected-frame))
        (current-buffer (current-buffer)))
    (when (memq current-buffer (my-buffer-list frame))
      (my-remove-buffer current-buffer frame))))

;; AUTHOR:  Alp Aker -- https://github.com/alpaker/Frame-Bufs
;; @lawlist extracted/revised the function(ality) from said library.
(defun my-add-buffer (&optional buf frame)
"Add BUF to FRAME's associated-buffer list if not already present."
(interactive)
  (let* ((buf (if buf buf (current-buffer)))
         (frame (if frame frame (selected-frame)))
         (associated-bufs (frame-parameter frame 'frame-bufs-buffer-list)))
    (unless (bufferp buf)
      (signal 'wrong-type-argument (list 'bufferp buf)))
    (unless (memq buf associated-bufs)
      (set-frame-parameter frame 'frame-bufs-buffer-list (cons buf associated-bufs)))
    (with-current-buffer buf
      (add-hook 'kill-buffer-hook 'my-kill-buffer-fn 'append 'local))
    (when tabbar-mode (tabbar-display-update))))

;; AUTHOR:  Alp Aker -- https://github.com/alpaker/Frame-Bufs
;; @lawlist extracted/revised the function(ality) from said library.
(defun my-remove-buffer (&optional buf frame)
"Remove BUF from FRAME's associated-buffer list."
(interactive)
  (let ((buf (if buf buf (current-buffer)))
        (frame (if frame frame (selected-frame))))
    (set-frame-parameter frame 'frame-bufs-buffer-list
      (delq buf (frame-parameter frame 'frame-bufs-buffer-list)))
    (when tabbar-mode (tabbar-display-update))))

;; AUTHOR:  Alp Aker -- https://github.com/alpaker/Frame-Bufs
;; @lawlist extracted/revised the function(ality) from said library.
(defun my-buffer-list-reset ()
    "Wipe the entire slate clean for the selected frame."
  (interactive)
    (modify-frame-parameters (selected-frame) (list (cons 'frame-bufs-buffer-list nil)))
    (when tabbar-mode (tabbar-display-update)))

(defun my-switch-tab-group ()
"Switch between tab group `A` and `N`."
(interactive)
  (let ((current-group (format "%s" (tabbar-current-tabset t)))
        (tab-buffer-list (mapcar
            #'(lambda (b)
                (with-current-buffer b
                  (list (current-buffer)
                        (buffer-name)
                        (funcall tabbar-buffer-groups-function))))
                 (funcall tabbar-buffer-list-function))))
    (catch 'done
      (mapc
        #'(lambda (group)
            (when (not (equal current-group
                          (format "%s" (car (car (cdr (cdr group)))))))
              (throw 'done (switch-to-buffer (car (cdr group))))))
        tab-buffer-list))))

(defface tabbar-selected-associated
  '((t :background "black" :foreground "yellow" :box (:line-width 2 :color "yellow")))
  "Face used for the selected tab -- associated with the `frame-bufs-buffer-list`."
  :group 'tabbar)

(defface tabbar-unselected-associated
  '((t :background "black" :foreground "white" :box (:line-width 2 :color "white")))
  "Face used for unselected tabs  -- associated with the `frame-bufs-buffer-list`."
  :group 'tabbar)

(defface tabbar-selected-unassociated
  '((t :background "black" :foreground "white" :box (:line-width 2 :color "firebrick")))
  "Face used for the selected tab -- UNassociated with the `frame-bufs-buffer-list`."
  :group 'tabbar)

(defface tabbar-unselected-unassociated
  '((t :background "black" :foreground "white" :box (:line-width 2 :color "blue")))
  "Face used for unselected tabs -- UNassociated with the `frame-bufs-buffer-list`."
  :group 'tabbar)

(setq tabbar-background-color "black")

(defsubst tabbar-line-tab (tab)
  "Return the display representation of tab TAB.
That is, a propertized string used as an `header-line-format' template
element.
Call `tabbar-tab-label-function' to obtain a label for TAB."
  (concat
    (propertize
      (if tabbar-tab-label-function
          (funcall tabbar-tab-label-function tab)
        tab)
      'tabbar-tab tab
      'local-map (tabbar-make-tab-keymap tab)
      'help-echo 'tabbar-help-on-tab
      'mouse-face 'tabbar-highlight
      'face
        (cond
          ((and
              (tabbar-selected-p tab (tabbar-current-tabset))
              (memq (current-buffer) (my-buffer-list (selected-frame))))
            'tabbar-selected-associated)
          ((and
              (not (tabbar-selected-p tab (tabbar-current-tabset)))
              (memq (current-buffer) (my-buffer-list (selected-frame))))
            'tabbar-unselected-associated)
          ((and
              (tabbar-selected-p tab (tabbar-current-tabset))
              (not (memq (current-buffer) (my-buffer-list (selected-frame)))))
            'tabbar-selected-unassociated)
          ((and
              (not (tabbar-selected-p tab (tabbar-current-tabset)))
              (not (memq (current-buffer) (my-buffer-list (selected-frame)))))
            'tabbar-unselected-unassociated))
      'pointer 'hand)
    tabbar-separator-value))

(define-key global-map "\C-c\C-r" 'my-buffer-list-reset)

(define-key global-map "\C-c\C-a" 'my-add-buffer)

(define-key global-map "\C-c\C-n" 'my-remove-buffer)

(define-key global-map (kbd "<M-s-right>") 'tabbar-forward)

(define-key global-map (kbd "<M-s-left>") 'tabbar-backward)

(define-key global-map [C-tab] 'my-switch-tab-group)

(tabbar-mode 1)

La capture d'écran suivante illustre les deux regroupements de tampons / onglets possibles: (1) à gauche se trouve un regroupement des tampons / onglets associés au cadre nommé SYSTEM[onglets jaune et blanc], avec la lettre majuscule "A" indiquée dans le ligne de mode; et (2) à droite se trouve un groupe de ces tampons / onglets qui ne sont PAS associés au cadre nommé SYSTEM[onglets bleu et rouge], avec une lettre majuscule "N" indiquée dans la ligne de mode.

Exemple


Mais l'OP ne veut pas "une barre d'onglets par fenêtre", il veut une barre d'onglets par trame et chaque onglet de la barre d'onglets doit représenter une "configuration de fenêtre" (c'est-à-dire plusieurs fenêtres) plutôt qu'un tampon.
Stefan

5

Pensez à vérifier elscreen , bien qu'il ne regroupe pas réellement les tampons.

Ce qu'il fait, c'est grouper les fenêtres et donner accès à plusieurs dispositions (onglets) parmi lesquelles vous pouvez vous déplacer rapidement. Mon flux de travail a souvent du code Ruby et des tests associés dans un écran, tandis que mes notes de tâches et d'organisation sont dans un autre, et peut-être un tampon de travail pour la rédaction de requêtes SQL se trouve dans un troisième. Cela me permet de basculer facilement entre les tâches et les projets, même si chaque écran utilise le même pool de tampons.


3

Et mon plugin, centaur-tabs? Il a beaucoup d'options de configuration, il est vraiment fonctionnel, il est pris en charge par des thèmes très populaires comme les thèmes Kaolin et dans l'ensemble, c'est un ensemble très esthétique et esthétique (selon les commentaires de l'utilisateur). Il est disponible dans MELPA et il ressemble à ceci:

entrez la description de l'image ici


Cela semble être une autre non-solution "chaque onglet représente un tampon et chaque fenêtre a sa propre barre d'onglets".
Stefan

Je viens d'ajouter une personnalisation pour afficher les groupes d'onglets au lieu des noms d'onglet, donc dans une fonction, vous établissez des règles (c'est-à-dire groupe elisp et lisp dans un groupe, groupe c et c ++ dans un autre et ainsi de suite) et dans les onglets, ces groupes sont affichés.
Emmanuel Bustos

Cela ne répond toujours pas à la question, où il devrait y avoir une barre d'onglets par cadre (plutôt que par fenêtre) et chaque onglet représente une configuration de fenêtre.
Stefan

Ok je n'ai pas compris. Je vais enquêter et travailler dessus!
Emmanuel Bustos

0

Voici ma config, pour ce qui en vaut la peine. Il comporte:

  • Opération de la souris sur les onglets ( mouse-2pour fermer, comme dans les navigateurs , mouse-3 pour ouvrir dans une nouvelle fenêtre Emacs, comme dans i3 )
  • Commandes du clavier ( M-leftet onglets de commutateur droit, comme dans TMux / Screen )
  • Couleurs (conformes à la moe-darkconfiguration " Thème Moe / " incluse)
  • Regroupement (actuellement, Emacs *buffers*et "régulier")
  • Mise à jour automatique (avec use-package )

Barre d'onglets

(use-package tabbar
  :ensure t
  :bind
  ("<M-left>" . tabbar-backward)
  ("<M-right>" . tabbar-forward)

  :config
  (set-face-attribute
   'tabbar-button nil
   :box '(:line-width 1 :color "gray19"))

  (set-face-attribute
   'tabbar-selected nil
   :foreground "orange"
   :background "gray19"
   :box '(:line-width 1 :color "gray19"))

  (set-face-attribute
   'tabbar-unselected nil
   :foreground "gray75"
   :background "gray25"
   :box '(:line-width 1 :color "gray19"))

  (set-face-attribute
   'tabbar-highlight nil
   :foreground "black"
   :background "orange"
   :underline nil
   :box '(:line-width 1 :color "gray19" :style nil))

  (set-face-attribute
   'tabbar-modified nil
   :foreground "orange red"
   :background "gray25"
   :box '(:line-width 1 :color "gray19"))

  (set-face-attribute
   'tabbar-selected-modified nil
   :foreground "orange red"
   :background "gray19"
   :box '(:line-width 1 :color "gray19"))

  (custom-set-variables
   '(tabbar-separator (quote (0.2))))

  (defun tabbar-buffer-tab-label (tab)
    "Return a label for TAB.
  That is, a string used to represent it on the tab bar."
    (let ((label  (if tabbar--buffer-show-groups
                      (format " [%s] " (tabbar-tab-tabset tab))
                    (format " %s " (tabbar-tab-value tab)))))
      (if tabbar-auto-scroll-flag
          label
        (tabbar-shorten
         label (max 1 (/ (window-width)
                         (length (tabbar-view
                                  (tabbar-current-tabset)))))))))

  (defun px-tabbar-buffer-select-tab (event tab)
    "On mouse EVENT, select TAB."
    (let ((mouse-button (event-basic-type event))
          (buffer (tabbar-tab-value tab)))
      (cond
       ((eq mouse-button 'mouse-2) (with-current-buffer buffer (kill-buffer)))
       ((eq mouse-button 'mouse-3) (pop-to-buffer buffer t))
       (t (switch-to-buffer buffer)))
      (tabbar-buffer-show-groups nil)))

  (defun px-tabbar-buffer-help-on-tab (tab)
    "Return the help string shown when mouse is onto TAB."
    (if tabbar--buffer-show-groups
        (let* ((tabset (tabbar-tab-tabset tab))
               (tab (tabbar-selected-tab tabset)))
          (format "mouse-1: switch to buffer %S in group [%s]"
                  (buffer-name (tabbar-tab-value tab)) tabset))
      (format "\
mouse-1: switch to %S\n\
mouse-2: kill %S\n\
mouse-3: Open %S in another window"
              (buffer-name (tabbar-tab-value tab))
              (buffer-name (tabbar-tab-value tab))
              (buffer-name (tabbar-tab-value tab)))))

  (defun px-tabbar-buffer-groups ()
    "Sort tab groups."
    (list (cond ((or
                  (eq major-mode 'dired-mode)
                  (string-equal "*" (substring (buffer-name) 0 1))) "emacs")
                (t "user"))))
  (setq tabbar-help-on-tab-function 'px-tabbar-buffer-help-on-tab
        tabbar-select-tab-function 'px-tabbar-buffer-select-tab
        tabbar-buffer-groups-function 'px-tabbar-buffer-groups)

  :init
  (tabbar-mode 1))

Annexe 1 - Thème Moe

(use-package moe-theme
  :ensure t
  :config
  (progn
    (load-theme 'moe-dark :no-confirm)
    (set-face-attribute 'fringe nil :background "gray19")))

Annexe 2 - Basculer les 2 derniers tampons (macro KB)

(define-key global-map [(control tab)] (kbd "C-x b <return>")) 
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.