C'est vous, propriétaire du compte, qui allez générer une clé disposant de permissions dans tel ou tel domaine. Vous devez ensuite passer ce jeton dans une application qui pourra alors accéder à vos données privées (ou du moins à une partie, en fonction des permissions accordées). L'application pourra conserver ce jeton (si possible dans un emplacement sécurisé) de manière à pouvoir le réutiliser plus tard. Donc, vous devrez, dans une certaine mesure, faire confiance à l'application pour qu'elle ne distribue pas votre jeton (tout comme vous devez faire confiances aux applications qui stockent ou utilisent vos identifiants ou mots de passe). Cependant, vous pouvez à tout moment résilier cette clé pour interdire de nouveau l’accès à votre compte : l'application ne peut alors plus accéder à vos données avec le jeton qu'elle détient.
Nous allons commencer par accéder à la liste des personnages et, pour les besoins de l'interface graphique, nous allons également accéder à votre compte et aux informations concernant les guides. Pour le moment les informations accessibles sont très basiques et il n'est pas du tout possible de récupérer votre adresse mél, d'effacer un personnage ou de modifier son inventaire ; donc il n'y a aucun soucis à avoir de ce coté là.
Il est inutile de préciser, je pense, que vous ne pourrez pas tester le programme fourni dans cet article si vous n'avez pas de compte de jeu actif (il faut donc avoir acheté Guild Wars 2 ou avoir testé une des périodes d'essai gratuit). Cependant, j'ai tout de même inclus un mode démo présentant un faux compte et de faux personnages et qui peut être utilisé sans compte réel et ni connexion avec le site web de l'API.
JSR 374
Hein, quoi, comment ? Mais c'est la JSR 353 qu'on utilise !
Oui, mais... la JSR 374 concerne le développement de l'API JSON-P 1.1 qui sera bien entendu une évolution de l'API JSON-P 1.0 actuelle et contiendra de nouvelles fonctionnalités (notamment le support de JSON Pointer, JSON Patch et JSON Merge Patch, ainsi qu'une plus grande intégration avec les fonctionnalités du JDK8). Bien qu'elle ne soit pas encore d’actualité ni complètement spécifiée, cela vaut le coup de conserver un œil sur le site des JCP pour se tenir au courant de son évolution et de sa future disponibilité.
Il est possible participer au développement de la JSR 374. Vous pouvez également montrer votre soutient à cette JSR via le programme Adopt-a-JSR (adoptez une JSR).
Charabia légal
Guild Wars et Guild Wars 2 sont des marques déposées de ArenaNet et NCsoft. De plus, toutes les images restent la propriété de ArenaNet. De même, la Web API utilisée reste la propriété de ArenaNet qui peut décider de la retirer ou d'en interdire l'utilisation comme bon lui semble. Et bien sûr, je ne suis affilié ni avec ArenaNet, ni avec NCsoft.
Création du jeton de sécurité
Ouvrez votre navigateur sur le site officiel du jeu (https://www.guildwars2.com/fr/) ou un de ses sites parents (forums officiels, support technique). Sur le coté droit de l’écran, cliquez sur Connectez-vous (sur le site principal) ou S'identifier (sur les forums). Saisissez maintenant les identifiants avec lesquels vous vous connectez en jeu, puis cliquez sur Connexion. Si vous utilisez l'autentificateur mobile et si c'est la première fois que vous vous connectez depuis votre emplacement actuel, vous serez probablement amenez à saisir un code de sécurité généré depuis votre téléphone ou tablette.
Déplacez vous dans la gestion de votre compte en cliquant sur Compte en dessous de votre identifiant et de votre adresse mél puis allez dans Clés d'application. Si vous n'avez jamais défini de jeton de sécurité auparavant, cette section devrait être vide. Cliquez maintenant sur Nouvelle clé.
Par défaut, tout jeton de sécurité a accès à certaines informations basiques sur votre compte mais nous avons besoin en plus d’accéder à la liste de vos personnages ; nous allons devoir lui donner un droit d’accès supplémentaire : pensez donc à cocher la case characters. Pour le moment nous n'avons pas besoin de la permission tradingpost qui permet d'accéder aux transaction effectuées sur le comptoir de vente donc vous pouvez la laisser désactivée si vous préférez. Enfin, donnez un nom à votre jeton (par exemple : Jeton de test) et cliquez sur Créer une clé d'application.
Votre compte dispose maintenant d'un jeton que vous pouvez saisir dans une application. Ce jeton se présente sous la forme d'une très très longue chaîne alphanumérique de style XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. Avec ce jeton, une application peut s'interfacer avec votre compte et peut en retirer des informations. Depuis quelques jours, il est également possible d'obtenir un QR code en cliquant sur le bouton le plus à droite de la clé. Cela vous permettra donc d'utiliser les fonctions existantes de votre plateforme ou de votre logiciel pour scanner l'image de ce code plutôt que de devoir ressaisir la clé à la main. Pour les besoin de ce test, nous allons rester simple et il faudra saisir la clé manuellement. Bien qu'il soit possible de modifier le nom de la clé en cliquant sur Modifier, il est impossible de changer les permissions ; donc si, après coup, vous avez besoin d'une clé disposant de permissions différentes, il vous suffit d'en créer une nouvelle.
Bien que vous allez être amenés à fournir publiquement cette clé dans des applications tierces auxquelles vous accorderez votre confiance, évitez quand même de la rendre publique sur des sites web ou de la distribuer n'importe où et à n'importe qui et ce pour des raisons de sécurité. Actuellement, l'API ne permet pas de faire de modifications sur un compte mais, dans le futur, il sera peut-être possible de participer aux enchères ou encore de gérer les inventaires de votre personnage, votre coffre de compte ou de guilde. Il serait stupide que quelqu'un puisse accéder à votre compte et le dépouiller de son contenu depuis une application tierce.
Vous pouvez, à tout moment, désactiver un jeton de sécurité en retournant dans l'interface d'administration de votre compte et en le supprimant en cliquant sur Supprimer, ce qui empêchera tout accès ultérieur à votre compte par cette clé.
Contexte
Généralement dans les jeux de ce type, chaque personnage a une seule guilde qui lui est propre. Guild Wars 1 avait géré la chose différemment en faisant que la guilde soit en fait une propriété du compte ; ainsi tous les personnages d'un compte faisaient automatiquement partie de la même guilde (et donc de la même alliance de guilde). Mais cela n’était pas au gout de tout le monde : certains joueurs préfèrent en effet avoir des moment d'anonymat sans pour autant être déclarés en mode "hors-ligne". D'autres encore considèrent tout simplement leurs personnages comme des "personnes" différentes et distinctes sans rapport direct les uns d'avec les autres et donc préfèrent avoir des contacts différents et des guildes différentes et distinctes pour chaque personnage.
Guild Wars 2 a essayé de ménager la chèvre et le chou en faisant qu'un compte dispose au maximum de 5 guildes différentes, et que chaque personnage peut représenter (c'est à dire faire partie) une seule guilde active à la fois, et ce indépendamment des autres personnages. Il est également possible de faire qu'un personnage ne représente aucune guilde.
En détails
À partir de maintenant, pour accéder aux données nécessitant une authentification, il va falloir envoyer le jeton de sécurité dans l'URL permettant d'interroger le point d’accès en utilisant le paramètre access_token de manière similaire à la syntaxe <url du point d'entree>?access_token=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. Bien qu'il soit tout à fait possible d'utiliser cette URL directement dans votre navigateur web pour vos tests de tentative d’accès comme nous l'avons fait précédemment, je vous déconseille de le faire. En effet, ce faisant, votre clé d'application restera visible dans votre historique de navigation, ce qui peut la rendre accessible à autrui. Donc pensez à purger votre historique de navigation ou à résilier la clé utilisée une fois vos test accomplis.
Nous allons récupérer la liste des personnage de votre compte. Les informations définies dans un personnage contiennent : son nom, sa profession, sa race, son niveau et la guilde qu'il représente. Certaines informations semblent être optionnelles : par exemple, lorsque j'ai fait mes premiers tests, nous étions en pleine période de bêta-test fermé de l'extension Heart of Thorns et donc j'avais un personnage de profession Revenant (profession rajoutée dans l'addon) qui était listé comme sans profession. On peut supposer qu'il en sera de même, le jour ou une extension ajoutera une nouvelle race. De plus, il est possible pour un personnage de ne pas représenter de guilde du tout, nous devons donc nous préparer à gérer des données vides ou absentes.
Pour accéder à la liste de vos personnages, vous devez accéder à l'endpoint characters disponible à l'URL https://api.guildwars2.com/v2/characters. Ainsi, une requête sur https://api.guildwars2.com/v2/characters?access_token=<jeton de sécurité> renverra un tableau JSON listant les noms de tous les personnages de votre compte.
| Code JSON : | Sélectionner tout |
[ "Logan Thackeray", "Eir Stegalkin"]
- https://api.guildwars2.com/v2/characters/<nom du personnage>?access_token=<jeton de sécurité> - Renvoie un objet JSON contenant les informations du personnage spécifié ;
- https://api.guildwars2.com/v2/characters?id=<nom du personnage>&access_token=<jeton de sécurité> - même chose ;
- https://api.guildwars2.com/v2/characters?ids=<nom du personnage 1>,<nom du personnage 2>,...,<nom du personnage N>&access_token=<jeton de sécurité> - Renvoie un tableau JSON contenant les informations des personnages spécifiés.
Lors de mes tests, un autre soucis majeur est apparu : il est possible d'utiliser des espaces et des diacritiques (caractères accentués, cédilles, etc. ) dans les noms des personnages ce qui pose des problème sur les URLs construites lors de leur utilisation dans l'API Java. Ainsi, il faudra remplacer les ' ' (espace) par des %20 ou les 'À' par des %C3%80 sous peine d'erreurs diverses lors des ouvertures de flux. Vous pouvez trouver une table de référence des diacritiques sur HTML URL Encoding Reference mais, de toute manière, l'API Java offre des méthodes permettant de remplacer ces caractères par la chaîne appropriée.
PS : une demande a été postée sur le forum pour que chaque personnage soit associé à une id, comme c'est le cas pour la plupart des autres valeurs retournées par la Web API, donc il est possible que dans le futur on puisse éviter de devoir utiliser les noms des personnages pour les requêtes. De plus, des demandes ont été faites pour que d'autres données telles que l'âge du personnage ou encore les tâches quotidiennes effectuées (ex : chemin de donjon) soient rajoutées dans l'objet obtenu. Cette partie de l'API est donc amenée à encore évoluer.
Suivant votre requête, un ou plusieurs objets JSON similaires à l'objet suivant vous seront retournés (oui, je sais que Logan n'est pas un Charr, mais c'est l'exemple de test montré sur le wiki et sur les forums) :
| Code JSON : | Sélectionner tout |
1 2 3 4 5 6 7 8 | { "name": "Logan Thackeray", "race": "Charr", "gender": "Male", "profession": "Guardian", "level": 80, "guild": "4BBB52AA-D768-4FC6-8EDE-C299F2822F0F" } |
Nous allons accéder au compte pour récupérer le nom du compte : une chaîne de texte unique qui identifie un compte et est distincte que l’adresse mél qui sert à vous connecter. Ce n'est pas une donnée privée car il s'agit tout simplement de l'ID utilisateur publiquement visible quand vous postez sur les forums officiels. Elle apparaît également quand vous vous connectez sur la gestion de votre compte ou, en jeu, sur l’écran de sélection des personnages. Nous allons également récupérer, la liste totales des guildes du compte ; j'ai en effet choisi de ne pas charger la guilde pour chaque personnage mais de charger directement les informations de toutes les guildes du compte. De toute manière un personnage ne peut pas représenter une guilde qui ne soit incluse dans le compte.
Pour accéder aux données de votre compte, vous devez accéder à l'endpoint account disponible à l'URL https://api.guildwars2.com/v2/account. Ainsi, une requête sur https://api.guildwars2.com/v2/account?access_token=<jeton de sécurité> renverra un objet JSON contenant votre identificateur, votre nom de compte, l'identificateur du monde auquel est affilié votre compte de même que les guildes auxquelles votre compte est affilié.
| Code JSON : | Sélectionner tout |
1 2 3 4 5 6 | { "id": "b8169418-1c11-405f-91bb-e2b29d602b8a", "name": "ExampleAccount.1234", "world": 1007 "guilds": ["75FD83CF-0C45-4834-BC4C-097F93A487AF"] } |
Pour accéder aux données des guildes, vous devez utiliser l'endpoint guild_details en interrogeant l'URL https://api.guildwars2.com/v1/guild_details.json. Ce point d’accès ne requiert pas d’authentification donc il n'est pas nécessaire de fournir le jeton de sécurité. Il est possible de fournir deux paramètres distincts pour récupérer des informations sur ce point d’entrées :
- https://api.guildwars2.com/v1/guild_details.json?guild_id=<id de la guilde> - Charge les détails de la guilde en se basant sur son identifiant.
- https://api.guildwars2.com/v1/guild_details.json?guild_name=<nom de la guilde> - Charge les détails de la guilde en se basant sur son nom.
Dans le cas où les deux paramètres sont spécifiés, c'est guild_id qui prend la précédence. Faites attention lors de l'utilisation du paramètre guild_name, en cas de présence de diacritiques dans le nom de la guilde. Il faudra penser à les échapper tout comme avec le nom du personnage.
L'objet guilde obtenu permet de récupérer également des informations concernant son logo (les identificateurs des images utilisées, les transformations et couleurs) mais il n'existe pas actuellement de source pour générer ou récupérer les logos sur la web API officielle. Donc si vous désirez afficher le logo d'une guilde, il faudra utiliser un pack d'images fourni par un joueur en attendant un futur support de cette fonctionnalité. Ici aussi les flags qui controlent l'orientation des couches d'images qui composent le logo d'une guilde sont des valeurs d'enum.
Voici, par exemple, l'objet définissant la guilde ArenaNet auxquels tous les modérateurs, GM (Game Masters ou maitres du jeu) et employés d'ArenaNet en jeu appartiennent.
| Code JSON : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | { "guild_id":"4BBB52AA-D768-4FC6-8EDE-C299F2822F0F", "guild_name":"ArenaNet", "tag":"ArenaNet", "emblem":{ "background_id":2, "foreground_id":40, "flags":["FlipBackgroundHorizontal","FlipBackgroundVertical"], "background_color_id":473, "foreground_primary_color_id":673, "foreground_secondary_color_id":71 } } |
Alors que je m'apprêtais à publier ce post, je suis allé faire un tour sur le forum officiel et me suis rendu compte qu'ils venaient de rajouter un nouveau point d'entée, tokeninfo qui permet de tester les permissions d'une clé d'application. J'ai donc modifié mon programme pour inclure cette nouvelle fonctionnalité de manière à effectuer un test sur les permissions avant de lancer la récupération des données du compte, des personnages et des guildes.
Donc si vous accédez à l'URL https://api.guildwars2.com/v2/tokeninfo en spécifiant votre jeton de sécurité dans le paramètre access_token, bien sûr, cela retournera un objet JSON similaire à :
| Code JSON : | Sélectionner tout |
1 2 3 4 5 6 7 8 | { "id": "017A2B0C-A6C5-CC4D-A055-680F427CE8FD", "name": "Jeton de test", "permissions": [ "account", "characters" ] } |
En tenant compte du nouvel endpoint permettant de tester le clé, on peut envisager notre programme comme suit :
L'utilisateur saisit sa clé.
- Tant que la clé saisie n'est pas valide (au niveau de son format, ce qui est facile à vérifier coté client), on ne fait rien.
- Lorsque le format de la clé est valide, on fait une requête pour récupérer les informations sur cette clé :
- Si la clé ne dispose pas des permissions appropriées, on affiche une erreur et on ne fait rien.
- Si la clé dispose des permissions appropriées, on lance un service récurrent qui s'exécute toutes les 5 minutes :
- On fait une requête pour récupérer les informations du compte (utile pour la liste de guilde).
- Pour chacune des guildes (puisqu'on ne peut pas faire de requête groupée dans l'API V1) :
- On fait une requête pour récupérer les informations de cette guilde.
- On fait une requête pour récupérer la liste de tous les personnages du compte.
- On fait une requête pour récupérer les informations de tous les personnages.
- On affiche toutes ces informations dans l'interface graphique.
Cooodage
Nous allons commencer par rajouter quelques nouvelles méthodes dans notre classe utilitaire QueryUtils.
| Code Java : | Sélectionner tout |
1 2 3 4 5 | public static String encodeURLParameter(final String value) throws UnsupportedEncodingException { String result = URLEncoder.encode(value, "utf-8"); // NOI18N. result = result.replaceAll("\\+", "%20"); // NOI18N. return result; } |
J'ai ensuite défini quelques méthodes de conversion de tableaux en listes :
| Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public static <T> List<T> jsonStringArrayToList(final JsonArray array, final Function<String, T> converter) { return jsonArrayToList(array, JsonString.class, jsonString -> { final String string = jsonString.getString(); return converter.apply(string); }); } public static <T> List<T> jsonObjectArrayToList(final JsonArray array, final Function<JsonObject, T> converter) { return jsonArrayToList(array, JsonObject.class, converter); } public static <T> List<T> jsonArrayArrayToList(final JsonArray array, final Function<JsonArray, T> converter) { return jsonArrayToList(array, JsonArray.class, converter); } |
| Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 | public static <S extends JsonValue, T> List<T> jsonArrayToList(final JsonArray array, final Class<S> sourceClass, final Function<S, T> converter) { final List<T> result = array.getValuesAs(sourceClass) .stream() .map(converter) .collect(Collectors.toList()); return Collections.unmodifiableList(result); } |
| Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | public static List<Character> characterInfos(final String applicationKey, final String... names) throws IOException, IllegalArgumentException { final boolean applicationKeyValid = ApplicationKeyUtils.validateApplicationKey(applicationKey); if (!applicationKeyValid) { throw new IllegalArgumentException(); } final String url = String.format("%s?ids=%s&access_token=%s", BASECODE, QueryUtils.encodeURLParameter(QueryUtils.idsToString(names)), applicationKey); // NOI18N. final JsonArray jsonArray = QueryUtils.queryArray(url); return QueryUtils.jsonObjectArrayToList(jsonArray, CharacterFactory::createCharacter); } |
Compte tenu du fait que de nouvelles valeurs d'enum peuvent être ajoutées avec le temps (ex : lorsque l'extension sera disponible et une fois l'API mise à jour, une valeur Revenant sera contenue dans le champs profession d'un personnage mais pour le moment ces personnages n'ont pas de profession), je vais utiliser une approche un peu plus précautionneuse. Dans chaque enum que je vais définir, je vais désormais inclure une valeur UNKNOWN (inconnu) qui permettra d'indiquer que la valeur récupérée par la requête est soit null soit nouvelle (ajoutée ultérieurement).
Prenons par exemple l'enum qui définit la profession :
| Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public enum Profession { ELEMENTALIST("Elementalist"), // NOI18N. ENGINEER("Engineer"), // NOI18N. GUARDIAN("Guardian"), // NOI18N. MESMER("Mesmer"), // NOI18N. NECROMANCER("Necromancer"), // NOI18N. RANGER("Ranger"), // NOI18N. REVENANT("Revenant"), // NOI18N. THIEF("Thief"), // NOI18N. WARRIOR("Warrior"), // NOI18N. UNKNOWN(null); private final String value; Profession(final String value) { this.value = value; } public static Profession find(final String value) { Profession result = Profession.UNKNOWN; if (value != null) { for (final Profession toTest : values()) { if (value.equals(toTest.value)) { result = toTest; break; } } } return result; } } |
Il nous faut également tenir compte du fait que certains champs peuvent être omis dans l'objet JSON reçu. Par exemple, lorsque je recevais le descriptif de mon personnage Revenant, le champ profession était tout simplement absent du JSON. Tenter d’accéder à ce champs absent levait une NullPointerException ; désormais, nous allons donc tester si le champ est présent avant d'y accéder. Ainsi, dans la fabrique chargée de créer les personnages, nous avons :
| Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | public static Character createCharacter(final JsonObject jsonObject) { final Character result = new Character(); [....] result.race = jsonObject.containsKey("race") ? Character.Race.find(jsonObject.getString("race")) : Character.Race.UNKNOWN; // NOI18N. result.profession = jsonObject.containsKey("profession") ? Character.Profession.find(jsonObject.getString("profession")) : Character.Profession.UNKNOWN; // NOI18N. [...] result.guild = jsonObject.containsKey("guild") ? jsonObject.getString("guild") : null; // NOI18N. [...] return result; } |
Maintenant que vous avez cela; le codage de l'objet TokenInfo ainsi que de l'enum définissant les permissions, de la fabrique et de l'objet requête associés est assez trivial. Il vous suffit donc de vous référer au code source.
Ceux qui sont intéressés par le code UI devraient également aller voir du coté du prédicat servant à filtrer la liste de personnages pour savoir comment sont gérés et configurés les divers critères de filtrage en fonction du nom du personnage, de son sexe, de sa race, de sa profession, etc. Idem pour l'utilisation d'une cellule customisée qui permet un affichage plus joli. Malheureusement l'API actuelle ne permet pas de récupérer les portraits des personnages pour le moment donc le cadre restera vide. Il peut être également intéressant de jeter un coup d’œil au code qui permet d'afficher le genre correct de la profession et de la race en fonction du sexe du personnage, chose qui n'est pas apparent en anglais mais plutôt utile en français (ex : en mode démo, Eir est marquée comme étant une Rôdeuse Norne et non pas un
À noter que pour ce que j'en ai vu, les jetons de sécurité sont principalement composés de caractères [0-9A-F]. Vous verrez dans le code source la classe test.text.ApplicationKeyTextFormatter, l'objet permettant de filtrer le champ d’édition, supporte également le symbole X que j'ai rajouté pour permettre la saisie de la clé de démo. Si jamais votre clé se compose de symboles autres, vous devez modifier cette classe, de même que la classe test.text.ApplicationKeyUtils. Pensez également à me le signaler en commentaire, que je puisse mettre à jour le code source sur GitHub.
Au final
Au lancement du programme, rien ne sera affiché ; vous devrez saisir votre jeton de sécurité dans le champ textuel approprié. Lorsque le programme détecte que la clé a un format valide, il lancera la récupération des permissions de la clé et, et en cas de permissions suffisantes, le service de mise à jour automatique. Si vous voulez tester le programme en mode démo, il vous suffit d'utiliser la clé XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX au lieu d'un clé de sécurité normale. Dans ce cas, le programme ira chercher des données JSON pré-générées contenues dans le package test.demo ; aucun accès ne sera fait sur le site de la web API du jeu ou à un quelconque compte de jeu.
Si vous ne voulez pas passer votre temps à coller ou retaper votre jeton d’accès dans le champ de saisi, vous pouvez également créer un fichier nommé settings.properties sur la racine du projet et y déclarer une valeur app.key contenant votre clé d'application. Évidement, il ne s'agit pas là d'un emplacement ou d'un stockage sécurisé, donc utilisez le avec parcimonie. Par exemple, avec la clé de démo :
| Code Properties : | Sélectionner tout |
app.key=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
Dans tous les cas, si la clé d'application est valide ou si vous utilisez la clé de démo, vous devriez obtenir un affichage similaire à :
Code source
... comme j'ai atteins mon quota de 5 fichiers max par message, je ne vous met pas d'archive cette fois-ci...
La version la plus récente du projet, au format NetBeans, est accessible sur GitHub.
Vous avez lu gratuitement 2 651 articles depuis plus d'un an.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.