Comment rendre linéaire un arbre - Annuler un arbre / Annuler / Rétablir


10

Lors de l'exécution undo-tree-undo/redosuccessive de la commande , les choses sont annulées / refaites en fonction de la branche active actuelle. Bien que l'utilisateur reçoive un message de point de branche en cours de route, les branches précédentes sont ignorées, sauf si un utilisateur sélectionne manuellement une branche différente.

Je comprends que je peux ouvrir le visualiseur et sélectionner une branche différente, cependant, il serait très utile de maintenir enfoncée la touche annuler / rétablir et de regarder tout se passer dans l'ordre inverse exact. Idéalement, cela devrait fonctionner indépendamment du fait que le visualizertampon soit ouvert, c'est-à-dire calculer par programme l'ordre de la fin au début et du début à la fin.

Q : Il s'agit essentiellement d'une demande de fonctionnalité à étendre undo-treepour permettre des annulations / rétablissements successifs linéaires, que le tampon du visualiseur soit ouvert ou non. [Les nouvelles fonctions et les raccourcis clavier alternatifs pour cette nouvelle fonctionnalité sont certainement acceptables.]


Le code de undo-treesemble faire partie du concept selon lequel vous pouvez basculer librement entre buffer-undo-treeet buffer-undo-listen basculant undo-tree-mode. Si je comprends bien votre question, le traitement d'origine buffer-undo-listfait ce que vous voulez. Il se propose donc de s'éteindre temporairement undo-tree-modepour votre usage. Dommage que la commutation entre buffer-undo-treeet buffer-undo-listsemble être buggée (au moins pour moi). Alors peut-être que le chemin à parcourir serait juste un rapport de bogue au responsable de undo-tree. Mais, peut-être que ma supposition sur le concept original est fausse.
Tobias

Je pense que la meilleure solution à votre problème serait de réparer de undo-tree-modetelle sorte que la commutation entre buffer-undo-treeet buffer-undo-listfonctionne parfaitement. Avez-vous envisagé d'émettre un rapport de bogue sur `toby-undo-tree @ dr-qubit.org`?
Tobias

@Tobias - J'aimerais voir et utiliser le visualiseur de undo-treetout en utilisant la nouvelle linearfonctionnalité; et, je voudrais que la nouvelle linearfonctionnalité fonctionne sans que le tampon du visualiseur soit nécessairement visible. En général, j'implémente mes propres améliorations / modifications à Emacs, à la fois ses bibliothèques tierces intégrées et facultatives. Lorsque je suis bloqué ou que je vois quelque chose de super complexe comme la undofonctionnalité, je demande de l'aide. Une demande de fonctionnalité au responsable ne pouvait pas faire de mal, mais je préférerais la traiter ici.
lawlist

@Tobias - En regardant le undo-tree.elcode aujourd'hui, j'ai vu qu'il existe une fonction d'horodatage du nœud. Je ne sais pas si chaque nœud a un horodatage valide et si ceux-ci survivent à la prochaine session Emacs (lors de la restauration de l'historique), mais cela semble pouvoir être raccourci pour résoudre cette nouvelle demande de fonctionnalité - c'est-à-dire trier et sélectionner la précédente ou la suivante dans le temps. Je n'ai pas encore vu à quoi ressemble l'aménagement du terrain à un point de branchement, mais ... ce sont mes réflexions préliminaires. . . .
lawlist

Je pense que la clé d'une promenade linéaire à travers le défaire est undo-list-rebuild-from-tree. Il faut letlier la variable buffer-undo-listet laisser undo-list-rebuild-from-treefaire son travail. Copiez ensuite cette valeur dans une autre variable locale, par exemple my-undo-list, et laissez la letforme pour la liaison buffer-undo-list. La variable my-undo-listdicte le chemin linéaire à travers le undo-tree. En y regardant, undo-list-rebuild-from-treevous voyez que cette fonction utilise également des horodatages. Plus tôt, j'ai envisagé d'utiliser des horodatages. Mais j'avais l'impression que ceux-ci changent trop souvent.
Tobias

Réponses:


7

Ce qui suit est une implémentation prototype d'une approximation de ce que vous voulez. Il exploite le fait que de nouvelles branches dans l'arbre d'annulation sont ajoutées sur le côté gauche du nœud actuel.

La séquence de clés C-M-_est liée à undo-tree-walklaquelle parcourt la partie supérieure droite de l'arborescence d'annulation à partir du nœud actuel.

Le comportement diffère de ce que vous voulez si la branche active d'un sous-arbre sur le côté droit du nœud actuel n'est pas la branche la plus à gauche dans ce sous-arbre.

Vous pouvez entrer dans un tel état par des séquences d'annulation / de rétablissement non valables.

Essayez-le par vous-même pour voir si cela est suffisant pour votre application.

(defvar-local undo-tree-walk
  "Possible values:
nil: not in undo/redo-chain
undo: traversing undo tree upwards
redo: traversing undo tree downwards
")

(setq undo-tree-walk nil)

(defun undo-tree-walk ()
  "Walk the right-upper part of the undo-tree starting at the current node."
  (interactive)
  (when (eq buffer-undo-list t)
    (user-error "No undo information."))
  (unless undo-tree-mode
    (user-error "`undo-tree-walk' should only be used with `undo-tree-mode'."))
  (undo-list-transfer-to-tree)
  (set-transient-map undo-tree-walk-map t #'undo-tree-walk-off)
  (let ((num-branches (undo-tree-num-branches)))
    (cond
     ((= num-branches 0) ; arrived at leaf
      (setq undo-tree-walk 'undo))
     ((> num-branches 1) ; 
      (let ((branch (undo-tree-node-branch (undo-tree-current buffer-undo-tree))))
    (setf (undo-tree-node-branch (undo-tree-current buffer-undo-tree))
          (if (>= (1+ branch) (undo-tree-num-branches))
          (progn
            (setq undo-tree-walk 'undo)
            (1- (undo-tree-num-branches)))
        (setq undo-tree-walk 'redo)
        (1+ branch))))
      ;; no state change for (= num-branches 1)
      )
     ))
  (case undo-tree-walk
   (undo
    (undo-tree-undo-1))
   (redo
    (undo-tree-redo-1))
   (t
    (setq undo-tree-walk 'undo)
    (undo-tree-undo-1)))
  (let ((curbuf (current-buffer)))
    (undo-tree-visualize)
    (switch-to-buffer-other-window curbuf)))

(defun undo-tree-walk-off ()
  "Switch `undo-tree-walk' off."
  (setq undo-tree-walk nil))

(defvar undo-tree-walk-map
  (make-sparse-keymap)
  "Keymap active while `undo-tree-walk'.")

(define-key undo-tree-walk-map (kbd "C-M-_") #'undo-tree-walk)

(global-set-key (kbd "C-M-_") #'undo-tree-walk)

Notez que j'ai ajouté undo-tree-visualizeà la fin de undo-tree-walkpour afficher les conséquences de la marche de l'annulation de l'arbre avec undo-tree-walk. N'hésitez pas à modifier le code à votre guise.

Notez également que j'ai dû choisir cette approximation la plus simple d'une solution à votre problème en raison de contraintes de temps.


J'ai ajouté ce qui suit au début de undo-tree-walkpour surmonter certaines erreurs initiales, peut-être parce que je n'ai pas ce mode globalement actif. (when (eq buffer-undo-list t) (user-error "No undo information.")) (undo-list-transfer-to-tree) Cela a fait taire mes erreurs initiales dans un nouveau tampon en essayant cette réponse. Ma prochaine observation a été que undo-tree-walkle point de branchement atteint puis passe à la branche de droite, mais ne descend que la branche d' un cran / nodule avant de remonter la branche jusqu'au tronc. Ma configuration préférée crée une encoche / nodule pour chaque coup de clé.
lawlist

Il n'y a absolument aucune hâte sur une solution. N'hésitez pas à prendre tout le temps dont vous avez besoin - au-delà de la période de prime est parfaitement acceptable. Une fois mise en œuvre, je suis sûr que j'utiliserai cette fonctionnalité quotidiennement dans un avenir prévisible et à en juger par les votes positifs jusqu'à présent, d'autres personnes souhaiteraient également utiliser cette fonctionnalité.
lawlist

@lawlist Malheureusement, mon temps est limité. Si c'était possible, j'aurais écrit cette réponse plutôt comme un commentaire que comme une réponse. Espérons que quelqu'un d'autre propose quelque chose de mieux avant la fin de la période de prime.
Tobias

@lawlist j'ai ajouté undo-list-transfer-to-treecomme vous l'avez proposé. Avant cela, je teste si undo-tree-modeest actif sinon undo-list-transfer-to-treepeut être fatal.
Tobias

Récompense récente pour les réponses dans les fils associés: emacs.stackexchange.com/a/32415/2287 et emacs.stackexchange.com/a/32416/2287 car ils sont les ingrédients clés de la mise en œuvre de la nouvelle fonctionnalité. En un mot, chaque nœud aura une liste d'horodatages - un pour chaque fois qu'un nœud devient courant après une annulation / restauration réussie et également lors de l'importation initiale. J'ai eu l'idée de visualiser en affichant des horodatages verticalement sous chaque nœud et en allongeant les branches en conséquence - il faudra un certain temps pour comprendre par programmation.
lawlist

3

Un merci spécial à @Tobias pour avoir écrit une fonction pour localiser l'horodatage suivant / précédent dans l'historique d'annulation / de rétablissement: https://emacs.stackexchange.com/a/32415/2287 ; et, pour avoir également rédigé une série de fonctions pour copier l'arborescence d'annulation: https://emacs.stackexchange.com/a/32230/2287 .

Comme certains lecteurs le savent peut-être déjà, les fourches ne sont acceptées par MELPA que dans des circonstances extrêmes. La création d'un module complémentaire est probablement réalisable, mais ne semble pas pratique compte tenu de la quantité de modifications apportées par @lawlist - y compris, mais sans s'y limiter, l'ajout d'éléments aux vecteurs de structure de données sous-jacents et la modification des noms de plusieurs fonctions / variables qui n'étaient pas conformes à la undo-tree-...convention de nommage des préfixes, etc. @lawlist a déjà contacté l'auteur original (Dr. Cubitt) pour offrir cette nouvelle fonctionnalité, ainsi que diverses corrections de bugs et améliorations.

Si quelqu'un est intéressé, n'hésitez pas à donner un coup de fouet à cette nouvelle fonctionnalité. Le commentaire contient un exemple de formulaire de soumission de rapport de bogue à partir emacs -qdu cas où quelqu'un aurait des problèmes.

Code source:   https://github.com/lawlist/undo_tree

Commentaire:

;;; This unofficial modification by @lawlist to the `undo-tree.el` library authored
;;; by Toby Cubitt adds semi-linear undo/redo support and a corresponding visualizer
;;; view accessible with `C-u C-x u` or by using the 3-way toggle with the letter `t`
;;; in the visualization buffer.  This entire library is meant to be a replacement
;;; of the stock version of `undo-tree.el`, which would need to be completely removed
;;; from the `load-path'.  In the visualization buffer, the letters `u` / `r`
;;; or `z` / `Z` are used for semi-linear undo/redo.  In the working buffer,
;;; `super-u` / `super-r` or `super-z`/`super-Z` are used for semi-linear undo/redo.
;;; Semi-linear undo/redo also work in the classic views of the visualization buffer.
;;; All previous keyboard shortcuts remain unchanged.  The mouse can be used to
;;; select semi-linear nodes or branch-point timestamps in the visualization buffer.
;;;
;;; The term `semi-linear` was chosen because the time-line is generally structured
;;; as follows:  When undoing, the movement is in an upward direction from the
;;; leaf to the branch-point and then the previous branch begins undoing from the
;;; leaf.  When redoing, the movement is in a downward direction from the branch-
;;; point to the leaf and then the next branch begins redoing from the branch-point.
;;; It is not a situation where we walk-up and back-down the same branch, or walk-
;;; down and back-up the same branch again.  If that missing feature is useful,
;;; then perhaps it could be implemented someday....
;;;
;;; In a nutshell, the classic version of undo-tree undo/redo limits a user to
;;; the active branch (skipping over inactive branches), unless the user calls
;;; `undo-tree-switch-branch' or `undo-tree-visualize-switch-branch-right' or
;;; `undo-tree-visualize-switch-branch-left' to select an alternative branch.  This
;;; generally means a user must pop-open the visualizer buffer to see what is going
;;; on to make a proper decision.  The new semi-linear feature is essentially
;;; "mindless" where the user can just hold down the forward/reverse button and
;;; go through every node of the tree in chronological order -- i.e., all branches
;;; and nodes are visited in the process (nothing is skipped over).
;;;
;;; The labels in the visualization buffer remain the same:  `o`, `x`, `s`, register.
;;; The branches are labeled consecutively as they are drawn with lowercase letters.
;;; The branch-points are labeled consecutively as they are drawn with uppercase
;;; letters.  The branches coming off of each branch-point are labeled with the nth
;;; numeric position of the branch -- e.g., far left is always nth 0.  The nodes of
;;; each branch are numbered consecutively commencing just after the branch-point.
;;;
;;; The features that are available in `undo-tree.el` version 0.6.6 remain the same;
;;; however, some of the functions have been consolidated and the names have changed.
;;;
;;; `undo-tree-history-save' and `undo-tree-history-restore' support input/output
;;; to/from a string or a file.  The history string/file contains three components:
;;; `buffer-file-name' (if it exists; else `nil`); SHA1 string; the `undo-tree-list'.
;;; Histories created with the unmodified stock version of `undo-tree.el` contained 2
;;; components and those previous versions are no longer supported.  Saving/exporting
;;; excludes all text-properties, yasnippet entries, and multiple-cursors entries.
;;; `read' chokes when encountering #<marker in no buffer> or #<overlay in no buffer>,
;;; that can make their way into the `undo-tree-list' when killing the visualizer
;;; buffer by brute force or when using the yasnippet library.  Those two known
;;; situations have been dealt with programmatically.  However, there are surely
;;; other libraries that use markers and/or overlays that could make their way into
;;; the tree and new ways of dealing with those entries will be required.  If you
;;; encounter an error message when performing `undo-tree-history-save', please
;;; inspect the `*Messages*` buffer for clues such as the above examples.  Inasmuch
;;; as there is now a sanity check at the tail end of `undo-tree-history-save', any
;;; problems should materialize before a user actually tries to restore the history.
;;;
;;; The persistent undo storage has been expanded by adding certain features borrowed
;;; from the built-in `image-dired.el' library:
;;;
;;; `undo-tree-history-autosave':  When non-nil, `undo-tree-mode' will save undo
;;;                                history to a file when a buffer is saved; and,
;;;                                the save/restore functions attached to the
;;;                                following hooks will become active:
;;;                                -  `write-file-functions'
;;;                                -  `find-file-hook'
;;;                                To exclude certain files, users may wish to let-
;;;                                bind this variable to `nil` if it has a global
;;;                                non-nil value.  See also the next variable below.
;;;
;;; `undo-tree-history-file-exclusions':  A list of absolute file names that will be
;;;                                       excluded from the auto save/restore process.
;;;
;;; `undo-tree-history-alist':  Used when `undo-tree-history-storage' is 'classic.
;;;                             See the doc-string for customization tips/tricks.
;;;
;;; `undo-tree-history-directory':  Directory where history files are stored when
;;;                                `undo-tree-history-storage' is 'central.
;;;
;;; `undo-tree-history-storage':  How to store undo-tree history files.
;;;                               'classic:  See `undo-tree-history-alist'.
;;;                               'home (md5):  A folder in the HOME directory.
;;;                               'central (md5):  See `undo-tree-history-directory'.
;;;                               'local:  Create sub-directory in working directory.
;;;
;;; For those users who wish to use Emacs to view the saved/exported history, be
;;; aware that the undo history is one long string, and Emacs has trouble viewing a
;;; buffer with very long lines.  `(setq-default bidi-display-reordering nil)` will
;;; help permit Emacs to view buffers with very long lines without bogging down.
;;;
;;; The primary interactive functions for undo/redo in the working buffer are:
;;;
;;;   M-x undo-tree-classic-undo
;;;   M-x undo-tree-classic-redo
;;;   M-x undo-tree-linear-undo
;;;   M-x undo-tree-linear-redo
;;;
;;; The primary interactive functions for undo/redo in the visualization buffer are:
;;;
;;;   M-x undo-tree-visualize-classic-undo
;;;   M-x undo-tree-visualize-classic-redo
;;;   M-x undo-tree-visualize-linear-undo
;;;   M-x undo-tree-visualize-linear-redo
;;;
;;; If the built-in undo amalgamation business is not to your liking, it can be
;;; disabled to permit undo boundaries after every command:
;;;
;;;   ;;; https://stackoverflow.com/a/41560712/2112489
;;;   (advice-add 'undo-auto--last-boundary-amalgamating-number :override #'ignore)
;;;
;;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27214
;;; https://emacs.stackexchange.com/q/33248/2287
;;; GARBAGE COLLECTION:  @lawlist has encountered a few situations where garbage
;;; collection truncates the `undo-tree-canary' in the `buffer-undo-list', which
;;; causes `undo-tree-transfer-list' to replace the existing `undo-tree-list'
;;; with the new tree fragment obtained from the `buffer-undo-list'.  In this
;;; circumstance, the user loses the entire undo-tree saved history!  The internal
;;; function responsible is `truncate_undo_list' in `undo.c`.  @lawlist has added a
;;; programmatic warning when loss of the existing `undo-tree-list' is about to
;;; occur; however, that does not fix the problem.  The relevant section from
;;; `truncate_undo_list' in `undo.c` is as follows:
;;;          /* When we get to a boundary, decide whether to truncate
;;;      either before or after it.  The lower threshold, undo_limit,
;;;      tells us to truncate after it.  If its size pushes past
;;;      the higher threshold undo_strong_limit, we truncate before it.  */
;;;          if (NILP (elt))
;;;     {
;;;       if (size_so_far > undo_strong_limit)
;;;         break;
;;;       last_boundary = prev;
;;;       if (size_so_far > undo_limit)
;;;         break;
;;;     }
;;; @lawlist opines that setting the `undo-limit' to the same value as
;;; `undo-strong-limit' will cause `truncate_undo_list' to preserve the
;;; `undo-tree-canary' in the `buffer-undo-list' by truncating before the boundary.
;;; This workaround is not ideal because a more recent undo would be truncated in
;;; lieu of an older undo.  One idea would be to convince the Emacs team to modify
;;; `truncate_undo_list' to preserve certain user-defined elements; e.g., a symbol
;;; of `undo-tree-canary'.
;;;
;;; The built-in function named `primitive-undo' defined in `simple.el` was used
;;; in the original version of `undo-tree.el`.  @lawlist created a modified
;;; function named `undo-tree--primitive-undo' that serves the same purpose, but
;;; permits setting a window-point in the working buffer while a user is in a
;;; different window such as the visualization buffer.  The revised version also
;;; merely reports a problem with a message instead of throwing an error when it
;;; encounters an `undo-tree-canary' in the wrong location.  This bug was noticed
;;; by @lawlist when performing undo/redo in region, and a Google search revealed
;;; that others too have experienced the same problem.  The bug is fairly easy to
;;; reproduce, but @lawlist has not yet invested the time to look for the cause
;;; and try to come up with a solution.  For anyone who wishes to work on fixing
;;; this and view other mentions of the same problem on the internet, Google:
;;;   "Unrecognized entry in undo list undo-tree-canary"
;;;
;;; The semi-linear visualization buffer view looks like this:
;;;
;;;        o-00001-a-0
;;;        20.34.55.46
;;;             |
;;;        o-br/pt-A-0
;;;        20.47.57.25
;;;        20.34.55.47
;;;         ____|_______________________________
;;;        /                                    \
;;;  o-00001-b-0                            o-00001-c-1
;;;  20.47.57.26                            20.34.55.48
;;;       |                                      |
;;;  o-00002-b-0                            o-00002-c-1
;;;  20.47.57.27                            20.34.55.49
;;;       |                                      |
;;;  o-00003-b-0                            o-00003-c-1
;;;  20.47.57.28                            20.34.55.50
;;;                                              |
;;;                                         o-00004-c-1
;;;                                         20.34.55.51
;;;                                              |
;;;                                         o-br/pt-B-1
;;;                                         21.25.32.05
;;;                                         20.35.06.89
;;;                                         20.35.02.23
;;;                                         20.34.58.43
;;;                                         20.34.55.57
;;;         _____________________________________|________________________
;;;        /            /                        |                        \
;;;  o-00001-d-0  o-00001-e-1               o-br/pt-C-2               o-00001-f-3
;;;  21.25.32.06  20.35.06.90               23.03.45.34               20.34.58.44
;;;                    |                    00.27.40.07                    |
;;;               o-00002-e-1               20.35.02.24               o-00002-f-3
;;;               20.35.06.91         ___________|___________         20.34.58.45
;;;                    |             /           |           \             |
;;;               o-00003-e-1  o-00001-g-0  o-00001-h-1  o-00001-i-2  o-00003-f-3
;;;               20.35.06.92  23.03.45.35  00.27.40.08  20.35.02.25  20.34.58.46
;;;                    |            |            |            |            |
;;;               o-00004-e-1  x-00002-g-0  o-00002-h-1  o-00002-i-2  o-00004-f-3
;;;               20.35.06.93  23:03:45:36  00.27.44.51  20.35.02.26  20.34.58.47
;;;                    |                                      |            |
;;;               o-00005-e-1                            o-00003-i-2  o-00005-f-3
;;;               20.35.06.94                            20.35.02.27  20.34.58.48
;;;                    |                                      |            |
;;;               o-00006-e-1                            o-00004-i-2  o-00006-f-3
;;;               20.35.06.95                            20.35.02.28  20.34.58.49
;;;                    |                                      |            |
;;;               o-00007-e-1                            o-00005-i-2  o-00007-f-3
;;;               20.35.06.96                            20.35.02.29  20.34.58.50
;;;                    |                                      |            |
;;;               o-00008-e-1                            o-00006-i-2  o-00008-f-3
;;;               20.35.06.97                            20.35.02.30  20.34.58.51
;;;
;;; To check for updates, please visit the source-code of the link listed at the
;;; top and also review the "Change Log" at the bottom.
;;;
;;; Bug reports and feature requests may be submitted via email to the address at
;;; the top.  Essentially, if it breaks in half, I can guarantee that you will
;;; have 2 pieces that may not necessarily be the same size.  :)  That being said,
;;; I will certainly make efforts to fix any problem that may arise relating to
;;; the semi-linear undo/redo feature.  A step 1-2-3 recipe starting from emacs -q
;;; would be very helpful so that @lawlist can observe the same behavior described
;;; in the bug report.  Here is an example to get you started:
;;;
;;; 1.  In an internet browser, visit: https://www.lawlist.com/lisp/undo-tree.el
;;;
;;;     Select/highlight all and copy everything to the clipboard.
;;;
;;; 2.  Launch Emacs without any user settings whatsoever:  emacs -q
;;;
;;;     If possible, please use the latest stable public release of Emacs.
;;;     @lawlist is using the GUI version of Emacs 25.2.1 on OSX.
;;;
;;; 3.  Switch to the `*scratch*` buffer.
;;;
;;; 4.  Paste the entire contents of the clpipboard into the `*scratch*` buffer.
;;;
;;; 5.  M-x eval-buffer RET
;;;
;;; 6.  M-x eval-expression RET (setq undo-tree-history-autosave t) RET
;;;
;;; 7.  M-x undo-tree-mode RET
;;;
;;;     The mode-line indicates `UT`, meaning that `undo-tree-mode' is active.
;;;
;;; 8.  M-x save-buffer RET
;;;
;;;     @lawlist chose to save the file to his desktop with the name `foo`, and
;;;     also chose to overwrite the file if it already existed; i.e., `y`.
;;;
;;;     Look at the lower left-hand side of the mode-line and notice that it
;;;     indicates an unmodified state; i.e., U:--- foo ....
;;;
;;; 9.  M-x undo-tree-classic-undo RET
;;;
;;;     Look at the lower left-hand side of the mode-line and notice that it
;;;     indicates we have returned to a modified state; i.e., U:**- foo ....
;;;
;;; 10. M-x undo-tree-classic-undo RET
;;;
;;;     The `undo-tree' library that we had previously pasted to the `*scratch*`
;;;     buffer should now be completely undone; i.e., removed.
;;;
;;; 11. M-x undo-tree-classic-undo RET
;;;
;;;     The buffer should be completely empty at this point; i.e., the initial
;;;     `*scratch*` message has been removed.
;;;
;;; 12. M-x undo-tree-classic-undo RET
;;;
;;;     The following `user-error' appears:
;;;
;;;       "user-error:  undo-tree--undo-or-redo:  No further undo information."
;;;
;;;     This is exactly the behavior that @lawlist expected would happen, so
;;;     everything up to this point appears to be working correctly.
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.