Partager via


Enregistrer des instantanés de tas à l’aide de l’outil Mémoire (type de profilage « Tas instantané »)

Utilisez le profileur de tas dans l’outil Mémoire pour effectuer les opérations suivantes :

  • Enregistrez des captures instantanées de tas JavaScript (tas JS).
  • Analyser les graphiques de mémoire.
  • Comparer les instantanés.
  • Rechercher les fuites de mémoire.

Le profileur de tas DevTools affiche la distribution de mémoire utilisée par les objets JavaScript et par les nœuds DOM associés sur la page web rendue.

Prendre un instantané

  1. Ouvrez la page web que vous souhaitez analyser. Par exemple, ouvrez la page de démonstration Objets dispersés dans une nouvelle fenêtre ou un nouvel onglet.

  2. Pour ouvrir DevTools, cliquez avec le bouton droit sur la page web, puis sélectionnez Inspecter. Vous pouvez également appuyer sur Ctrl+Maj+I (Windows, Linux) ou Cmd+Option+I (macOS). DevTools s’ouvre.

  3. Dans DevTools, dans la barre d’activité, sélectionnez l’onglet Mémoire . Si cet onglet n’est pas visible, cliquez sur le bouton Autres outils (icône Autres outils).

  4. Dans la section Sélectionner le type de profilage, sélectionnez le bouton d’option Tas instantané.

  5. Sous Sélectionner une machine virtuelle JavaScript instance, sélectionnez la machine virtuelle JavaScript que vous souhaitez profiler.

  6. Cliquez sur le bouton Prendre instantané :

L’outil Mémoire, l’option Instantané tas est sélectionnée et le bouton Prendre instantané est mis en surbrillance

Une fois que le instantané de segment de mémoire nouvellement enregistré a été chargé dans DevTools et analysé, le instantané s’affiche et une nouvelle entrée s’affiche dans la barre latérale Profils sous Instantanés du tas :

Taille totale des objets accessibles

Le numéro sous le nouvel élément de barre latérale indique la taille totale des objets JavaScript accessibles. Pour en savoir plus sur les tailles d’objet dans le tas instantané, consultez Tailles et distances des objets dans la terminologie mémoire.

Le instantané affiche uniquement les objets du graphique mémoire accessibles à partir de l’objet global. La prise d’une instantané commence toujours par un garbage collection.

Prenez une autre instantané

Pour prendre une autre instantané lorsqu’un est déjà affiché dans l’outil Mémoire, dans la barre latérale, cliquez sur Profils au-dessus du instantané existant :

Le bouton Profils pour prendre une autre instantané

Effacer les instantanés

Pour effacer tous les instantanés de l’outil Mémoire , cliquez sur l’icône Effacer tous les profils (icône effacer) :

Supprimer des instantanés

Afficher les instantanés

Les instantanés de tas peuvent être consultés de plusieurs façons différentes dans l’outil Mémoire . Chaque façon d’afficher un tas instantané dans l’interface utilisateur correspond à une tâche différente :

Afficher Contenu Utilisé pour
Résumé Affiche les objets regroupés par nom de constructeur. Recherche d’objets et de la mémoire qu’ils utilisent, en fonction des types regroupés par nom de constructeur. Utile pour le suivi des fuites DOM.
Comparaison Affiche les différences entre deux instantanés. Comparaison de deux instantanés mémoire (ou plus) avant et après une opération. L’inspection du delta dans la mémoire libérée et l’inspection du nombre de références vous aident à confirmer la présence et la cause d’une fuite de mémoire, et à en déterminer la cause.
Confinement Permet l’exploration du contenu du tas. Fournit une meilleure vue de la structure des objets, ce qui permet d’analyser les objets référencés dans l’espace de noms global (fenêtre) pour déterminer ce qui maintient les objets autour. Utilisez-le pour analyser les fermetures et plonger dans vos objets à un niveau inférieur.

Pour basculer entre les vues, utilisez la liste déroulante en haut de l’outil Mémoire :

Sélecteur de basculement de vues

Éléments omis dans les instantanés de tas

Les propriétés implémentées à l’aide de getters qui exécutent du code natif ne sont pas capturées dans le tas instantané, car ces propriétés ne sont pas stockées sur le tas JavaScript.

Les valeurs non-chaînes, telles que les nombres, ne sont pas capturées.

Vue récapitulative

L’affichage Résumé de l’outil Mémoire répertorie les éléments suivants :

  • Groupes de constructeurs d’objets.
  • Noms de catégorie spéciaux, tels que (tableau),(code compilé), ou une liste de propriétés telles que {foo, bar, baz}.

Au départ, un tas instantané s’ouvre dans la vue Résumé, qui affiche une liste de constructeurs :

Vue récapitulative

Chaque constructeur de la liste peut être développé pour afficher les objets qui ont été instanciés à l’aide de ce constructeur.

Pour chaque constructeur de la liste, la vue Résumé affiche également un nombre tel que ×123, indiquant le nombre total d’objets créés avec le constructeur. La vue Résumé affiche également les colonnes suivantes :

Nom de colonne Description
Distance Affiche la distance à la racine à l’aide du chemin d’accès simple le plus court des nœuds. Consultez La terminologie distance dans la mémoire.
Taille superficielle Affiche la somme des tailles superficielles de tous les objets créés par une fonction de constructeur spécifique. La taille superficielle est la taille du tas JavaScript qui est directement détenu par un objet. La taille superficielle d’un objet est généralement petite, car un objet JavaScript stocke souvent uniquement sa description de l’objet, et non les valeurs, dans la mémoire directement détenue de l’objet. La plupart des objets JavaScript stockent leurs valeurs dans un magasin de stockage qui se trouve ailleurs dans le tas JavaScript et exposent uniquement un petit objet wrapper sur la partie du tas JavaScript qui appartient directement à l’objet. Consultez Taille superficielle dans la terminologie de la mémoire.
Taille conservée Affiche la taille maximale conservée parmi le même ensemble d’objets. La taille de la mémoire que vous pouvez libérer après la suppression d’un objet (et que les dépendants ne sont plus accessibles) est appelée taille conservée. Consultez Taille conservée dans la terminologie de la mémoire.

Après avoir développé un constructeur dans la vue Résumé , toutes les instances du constructeur s’affichent. Pour chaque instance, les tailles superficielles et conservées sont affichées dans les colonnes correspondantes. Le nombre après le @ caractère est l’ID unique de l’objet, ce qui vous permet de comparer des instantanés de tas par objet.

Entrées de constructeur

L’affichage Résumé de l’outil Mémoire répertorie les groupes de constructeurs d’objets :

Groupes de constructeurs

Les groupes de constructeurs dans la vue Résumé peuvent être des fonctions intégrées telles que Array ou Object, ou il peut s’agir de fonctions définies dans votre propre code.

Pour afficher la liste des objets qui ont été instanciés par un constructeur donné, développez le groupe de constructeurs.

Noms de catégorie spéciaux

La vue Résumé de l’outil Mémoire inclut les noms de catégories spéciales suivants, qui ne sont pas basés sur les constructeurs. La plupart de ces noms de catégorie sont affichés entre parenthèses.

Nom de catégorie Description
(tableau) Divers objets internes de type tableau qui ne correspondent pas directement aux objets visibles à partir de JavaScript, tels que le contenu des tableaux JavaScript ou les propriétés nommées des objets JavaScript.
(code compilé) Données internes dont V8 (moteur JavaScript de Microsoft Edge) a besoin pour exécuter des fonctions définies par JavaScript ou WebAssembly. V8 gère automatiquement l’utilisation de la mémoire dans cette catégorie : si une fonction s’exécute plusieurs fois, V8 utilise davantage de mémoire pour cette fonction afin que la fonction s’exécute plus rapidement. Si une fonction ne s’est pas exécutée depuis un certain temps, V8 peut supprimer les données internes de cette fonction.
(chaîne concaténée) Lorsque deux chaînes sont concaténées ensemble, comme lors de l’utilisation de l’opérateur JavaScript + , V8 peut choisir de représenter le résultat en interne sous la forme d’une chaîne concaténée. Au lieu de copier tous les caractères des deux chaînes dans une nouvelle chaîne, V8 crée un petit objet qui pointe vers les deux chaînes.
(forme d’objet) Informations sur les objets, telles que le nombre de propriétés qu’ils possèdent et une référence à leurs prototypes, que V8 gère en interne lors de la création et de la mise à jour des objets. Cela permet à V8 de représenter efficacement les objets avec les mêmes propriétés.
(chaîne segmentée) Lors de la création d’une sous-chaîne, par exemple lors de l’utilisation de la méthode JavaScript substring , V8 peut choisir de créer un objet de chaîne segmentée plutôt que de copier tous les caractères pertinents de la chaîne d’origine. Ce nouvel objet contient un pointeur vers la chaîne d’origine et décrit la plage de caractères de la chaîne d’origine à utiliser.
(système) Divers objets internes qui n’ont pas encore été classés de manière plus significative.
{foo, bar, baz} Objets JavaScript bruts classés par interface (liste de propriétés), en accolades. Les objets JavaScript bruts ne sont pas répertoriés dans une catégorie nommée Object, mais sont représentés par des noms et des catégories basés sur les propriétés que l’objet contient, telles que {foo, bar, baz}.
InternalNode Objets alloués en dehors de V8, tels que les objets C++ définis par Blink, le moteur de rendu de Microsoft Edge.
system / Context Variables locales à partir d’une étendue JavaScript accessible par une fonction imbriquée. Chaque fonction instance contient un pointeur interne vers le contexte dans lequel elle s’exécute, afin qu’elle puisse accéder à ces variables.

Vue de comparaison

Pour rechercher les objets fuites, comparez plusieurs instantanés les uns aux autres. Dans une application web, en règle générale, l’exécution d’une action, puis l’action inverse ne doit pas conduire à davantage d’objets en mémoire. Par exemple, lors de l’ouverture d’un document, puis de sa fermeture, le nombre d’objets en mémoire doit être le même qu’avant l’ouverture du document.

Pour vérifier que certaines opérations ne créent pas de fuites :

  1. Prenez un tas instantané avant d’effectuer une opération.

  2. Effectuez l’opération. Autrement dit, interagissez avec la page d’une manière ou d’une autre, ce qui peut provoquer une fuite.

  3. Effectuez l’opération inverse. Autrement dit, faites l’interaction inverse et répétez-la plusieurs fois.

  4. Prenez un deuxième tas instantané.

  5. Dans le deuxième segment de mémoire instantané, remplacez l’affichage par Comparaison, en le comparant à l’instantané 1.

Dans la vue Comparaison , la différence entre deux instantanés s’affiche :

Vue de comparaison

Lorsque vous développez un constructeur dans la liste, les instances d’objet ajoutées et supprimées s’affichent.

Affichage contenant-contenu

La vue Contenant-contenu vous permet d’examiner les fermetures de fonctions, d’observer les objets internes de machine virtuelle qui composent vos objets JavaScript et de comprendre la quantité de mémoire utilisée par votre application à un niveau très bas :

Affichage contenant-contenu

La vue Contenant-contenu affiche les types d’objets suivants :

Points d’entrée de la vue d’endiguement Description
Objets DOMWindow Objets globaux pour le code JavaScript.
Racines du GC Racines GC utilisées par le garbage collector de la machine virtuelle JavaScript. Les racines gc sont composées de mappages d’objets intégrés, de tables de symboles, de piles de threads de machine virtuelle, de caches de compilation, d’étendues de handle et de handles globaux.
Objets natifs Objets créés par le navigateur, tels que les nœuds DOM et les règles CSS, qui sont affichés dans la machine virtuelle JavaScript pour autoriser l’automatisation.

La section Retainers

La section Retainers s’affiche en bas de l’outil Mémoire et affiche tous les objets qui pointent vers l’objet sélectionné. La section Retainers est mise à jour lorsque vous sélectionnez un autre objet dans la vue Résumé, Contenant-contenu ou Comparaison .

Dans la capture d’écran suivante, un objet chaîne a été sélectionné dans la vue Résumé, et la section Retainers montre que la chaîne est conservée par la x propriété d’un instance de la Item classe, qui se trouve dans le example-03.js fichier :

La section Retainers

Masquer les cycles

Dans la section Retainers , lorsque vous analysez les objets qui conservent l’objet sélectionné, vous pouvez rencontrer des cycles. Des cycles se produisent lorsque le même objet apparaît plusieurs fois dans le chemin de rétention de l’objet sélectionné. Dans la section Retainers , un objet cycle est indiqué par grisé.

Pour simplifier le chemin de rétention, masquez les cycles dans la section Rétentions en cliquant sur le menu déroulant Filtrer les arêtes , puis en sélectionnant Masquer les cycles :

Le menu déroulant Filtrer les bords dans la section Rétentions, « Masquer les cycles » est sélectionné

Masquer les nœuds internes

Les nœuds internes sont des objets spécifiques à V8 (moteur JavaScript dans Microsoft Edge).

Pour masquer les nœuds internes dans la section Rétentions , dans le menu déroulant Filtrer les arêtes , sélectionnez Masquer l’interne.

Filtrer les instantanés de tas par types de nœuds

Utilisez des filtres pour vous concentrer sur des parties spécifiques d’un tas instantané. Lorsque vous examinez tous les objets d’un tas instantané dans l’outil Mémoire, il peut être difficile de se concentrer sur des objets spécifiques ou de conserver des chemins d’accès.

Pour vous concentrer uniquement sur des types de nœuds spécifiques, utilisez le filtre Types de nœuds, en haut à droite. Par exemple, pour voir uniquement les tableaux et les objets de chaîne dans le tas instantané :

  1. Pour ouvrir le filtre Types de nœuds , cliquez sur Par défaut dans le coin supérieur droit.

  2. Sélectionnez les entrées Tableau et Chaîne .

    Le tas instantané est mis à jour pour afficher uniquement les objets de tableau et de chaîne :

    Types de nœuds dans un tas instantané dans l’outil Mémoire

Rechercher un objet spécifique

Pour rechercher un objet dans le tas collecté, vous pouvez effectuer une recherche à l’aide de Ctrl+F et donner l’ID de l’objet.

Découvrir les fuites DOM

L’outil Mémoire peut afficher les dépendances bidirectionnelles qui existent parfois entre les objets natifs du navigateur (nœuds DOM, règles CSS) et les objets JavaScript. Cela permet de détecter les fuites de mémoire qui se produisent en raison de nœuds DOM oubliés et détachés qui restent en mémoire.

Pour les éléments détachés, consultez également Rechercher les fuites de mémoire de l’arborescence DOM (« Segment de mémoire instantané » de type > détaché), ci-dessous.

Considérez l’arborescence DOM suivante :

Sous-arborescences DOM

L’exemple de code suivant crée les variables treeRef JavaScript et leafRef, qui référencent deux des nœuds DOM dans l’arborescence :

// Get a reference to the #tree element.
const treeRef = document.querySelector("#tree");

// Get a reference to the #leaf element,
// which is a descendant of the #tree element.
const leafRef = document.querySelector("#leaf");

Dans l’exemple de code suivant, l’élément <div id="tree"> est supprimé de l’arborescence DOM :

// Remove the #tree element from the DOM.
document.body.removeChild(treeRef);

L’élément <div id="tree"> ne peut pas être récupéré par la mémoire, car la variable treeRef JavaScript existe toujours. La treeRef variable fait directement référence à l’élément <div id="tree"> . Dans l’exemple de code suivant, la treeRef variable est nullifiée :

// Remove the treeRef variable.
treeRef = null;

L’élément <div id="tree"> ne peut toujours pas être récupéré par la mémoire, car la variable leafRef JavaScript existe toujours. La leafRef.parentNode propriété fait référence à l’élément <div id="tree"> . Dans l’exemple de code suivant, la leafRef variable est nullifiée :

// Remove the leafRef variable.
leafRef = null;

À ce stade, l’élément <div id="tree"> peut être récupéré par la mémoire. leafRef Et treeRef doivent d’abord être nullifiés, pour que l’arborescence DOM entière sous l’élément <div id="tree"> soit récupérée par la mémoire.

Page web de démonstration : Exemple 6 : Fuite de nœuds DOM

Pour comprendre où les nœuds DOM peuvent fuir et comment détecter une telle fuite, ouvrez l’exemple de page web Exemple 6 : Fuite de nœuds DOM dans une nouvelle fenêtre ou un nouvel onglet.

Page web de démonstration : Exemple 9 : Fuites DOM plus importantes que prévu

Pour voir pourquoi une fuite DOM peut être plus grande que prévu, ouvrez l’exemple de page web Exemple 9 : Fuites DOM plus grandes que prévu dans une nouvelle fenêtre ou un nouvel onglet.

Analyser l’impact des fermetures sur la mémoire

Pour analyser l’impact des fermetures sur la mémoire, essayez cet exemple :

  1. Ouvrez la page web de démonstration Eval is evil dans une nouvelle fenêtre ou un nouvel onglet.

  2. Enregistrer un tas instantané.

  3. Dans la page web rendue, cliquez sur le bouton Fermetures avec eval .

  4. Enregistrez un deuxième tas instantané.

    Dans la barre latérale, le nombre sous la deuxième instantané doit être supérieur au nombre situé sous la première instantané. Cela indique que la page web utilise davantage de mémoire après avoir cliqué sur le bouton Fermetures avec eval .

  5. Dans le deuxième instantané de tas, remplacez l’affichage par Comparaison, puis comparez le deuxième tas instantané au premier instantané.

    La vue Comparaison montre que de nouvelles chaînes ont été créées dans le deuxième tas instantané :

    La vue Comparaison, montrant que de nouvelles chaînes ont été créées dans la deuxième instantané

  6. Dans la vue Comparaison, développez le constructeur (chaîne).

  7. Cliquez sur la première entrée (chaîne).

    La section Retainers est mise à jour et indique que la largeStr variable conserve la chaîne sélectionnée dans la vue Comparaison .

    L’entrée largeStr est automatiquement développée et indique que la variable est conservée par la eC fonction, qui est la fermeture où la variable est définie :

    Section Retainers, montrant que la chaîne est conservée par la fonction eC

Conseil : fonctions de nom pour différencier les fermetures d’un instantané

Pour faire facilement la distinction entre les fermetures JavaScript dans un tas instantané, donnez des noms à vos fonctions.

L’exemple suivant utilise une fonction sans nom pour retourner la largeStr variable :

function createLargeClosure() {
    const largeStr = 'x'.repeat(1000000).toLowerCase();

    // This function is unnamed.
    const lC = function() {
        return largeStr;
    };

    return lC;
}

L’exemple suivant nomme la fonction, ce qui facilite la distinction entre les fermetures dans le tas instantané :

function createLargeClosure() {
    const largeStr = 'x'.repeat(1000000).toLowerCase();

    // This function is named.
    const lC = function lC() {
        return largeStr;
    };

    return lC;
}

Enregistrer et exporter des chaînes à partir d’un tas instantané vers JSON

Lorsque vous prenez un tas instantané dans l’outil Mémoire, vous pouvez exporter tous les objets de chaîne du instantané vers un fichier JSON. Dans l’outil Mémoire , dans la section Constructeur , cliquez sur le bouton Enregistrer tout dans le fichier en regard de l’entrée (string) :

Enregistrer toutes les chaînes d’un tas instantané dans JSON

L’outil Mémoire exporte un fichier JSON qui contient tous les objets de chaîne du tas instantané :

Chaînes du tas instantané, dans le fichier JSON

Rechercher les fuites de mémoire de l’arborescence DOM (type > de profilage « Tas instantané détaché »)

Une façon de rechercher et d’afficher tous les éléments détachés sur une page web consiste à utiliser le type de profilage Tas instantané de l’outil Mémoire, puis à taper Détaché dans la zone de texte Filtrer par classe, comme suit. Voir aussi Outils pour examiner les éléments détachés dans Résoudre les problèmes de mémoire.

Le code suivant produit des nœuds DOM détachés :

var detachedTree;

function create() {
    var ul = document.createElement('ul');
    for (var i = 0; i < 10; i++) {
        var li = document.createElement('li');
        ul.appendChild(li);
    }
    detachedTree = ul;
}
document.getElementById('create').addEventListener('click', create);

Ce code crée un ul nœud avec dix li enfants. Les nœuds sont référencés par le code, mais ils n’existent pas dans l’arborescence DOM, de sorte que chaque nœud est détaché.

Les instantanés de tas sont un moyen d’identifier les nœuds détachés. Un tas instantané montre comment la mémoire est distribuée entre les objets JS et les nœuds DOM de votre page au moment de l’instantané.

Utiliser le type de profilage « Heap instantané » pour rechercher des éléments détachés

Pour utiliser le tas instantané type de profilage pour rechercher des éléments détachés :

  1. Ouvrez une page web, telle que la page web de démonstration Éléments détachés, dans une nouvelle fenêtre ou un nouvel onglet.

  2. Cliquez avec le bouton droit sur la page web, puis sélectionnez Inspecter. Vous pouvez également appuyer sur Ctrl+Maj+I (Windows, Linux) ou Cmd+Option+I (macOS).

    DevTools s’ouvre.

  3. Dans DevTools, dans la barre d’activité, sélectionnez l’outil Mémoire (icône d’outil Mémoire).

    Si cet onglet n’est pas visible, cliquez sur le bouton Autres outils (icône Autres outils), puis sélectionnez Mémoire. L’outil Mémoire s’ouvre :

    Ouvrir l’outil Mémoire

    Si le bouton d’option Tas instantané n’est pas affiché, car un profil est déjà affiché, dans le coin supérieur gauche, cliquez sur Profils (icône Profils).

    Vous n’avez pas besoin de sélectionner le bouton d’option Heap instantané à ce stade, car la page web n’a pas encore généré d’éléments détachés.

    Générez des messages, qui seront stockés par le instance JavaScript de la classe Room :

  4. Dans la page web de démonstration, cliquez sur le bouton Trafic rapide .

    La page web de démonstration commence à générer des messages et à les afficher dans la page web :

    Génération de messages dans la page web de démonstration

  5. Une fois que certains messages sont affichés, cliquez sur le bouton Arrêter dans la page web de démonstration.

    Chaque message est un <div class="message"> élément référencé par le instance Room 1 de la Room classe . Il n’y a aucun élément détaché dans l’arborescence DOM de la page web, car tous les éléments de message sont attachés au présent, Salle 1 instance de la classe Room.

    Remplacez par un autre instance de la classe Room, afin que les éléments soient détachés :

  6. Dans la page web de démonstration, cliquez sur le bouton Salle 2, qui correspond à un autre instance de la Room classe.

    Dans la page web, les messages disparaissent :

    Vue initiale de la chambre 2

    Les messages générés pour la salle 1 instance de la classe Room (<div class="message"> éléments) ne sont plus attachés au DOM, mais ils sont toujours référencés par le instance room 1 de la classe Room. Il s’agit d’éléments détachés, ce qui peut entraîner des fuites de mémoire, sauf s’ils vont être réutilisés par la page web.

    Obtenez la liste des éléments détachés :

  7. Dans DevTools, dans l’outil Mémoire , cliquez sur l’icône Collecter la mémoire (icône « Collecter la mémoire ») :

    Prise d’un tas instantané

    Le navigateur exécute le garbage collection, en supprimant tous les nœuds qui ne sont plus référencés par un objet JavaScript.

  8. Dans l’outil Mémoire, sélectionnez le bouton d’option Tas instantané.

  9. Cliquez sur le bouton Prendre instantané en bas de l’outil Mémoire.

    Le instantané est traité, chargé, puis répertorié dans la barre latérale Profils, dans la section Instantanés du tas.

  10. Dans la zone de texte Filtrer par classe , tapez détaché :

    Filtrage des nœuds détachés et développement d’un nœud détaché

    Les éléments DOM détachés qui ne peuvent pas être collectés par la mémoire sont affichés.

    Identifiez le code JavaScript qui fait référence à un élément détaché particulier :

  11. Dans le tas instantané, développez un objet Detached, tel que Detached <div>, puis sélectionnez un nœud div détaché <class="message ».>

    Les informations sont affichées dans le volet Rétention en bas de l’outil Mémoire .

  12. Dans le volet Rétentions , cliquez sur le room.js:13 lien d’un élément non monté dans Salle sous Tableau. L’outil Sources s’ouvre, affichant room.js, fait défiler jusqu’à la ligne 13 :

    Code source JavaScript dans l’outil Sources

  13. Pour inspecter la fuite de mémoire possible, étudiez le code qui utilise le unmounted tableau et assurez-vous que la référence au nœud est supprimée lorsqu’il n’est plus nécessaire.

  14. Pour revenir à l’outil Mémoire , dans la barre d’adresses, sélectionnez l’outil Mémoire .

Pour obtenir d’autres façons d’afficher les éléments détachés, consultez Outils d’examen des éléments détachés dans Résoudre les problèmes de mémoire.

Voir aussi

Externe:

Remarque

Les parties de cette page sont des modifications basées sur le travail créé et partagé par Google et utilisées conformément aux termes décrits dans la licence internationale Creative Commons Attribution 4.0. La page originale se trouve ici et est créée par Meggin Kearney.

Licence Creative Commons Cette œuvre est concédée sous licence creative commons attribution 4.0 international.