Développement de composants Fractal adaptatifs

Développement de composants Fractal adaptatifs

Caractéristiques des logiciels adaptatifs

Dans cette section, nous définissons plus précisément la notion d’adaptation, en général et dans le cas du logiciel, puis nous étudions les caractéristiques spécifiques des logiciels adaptatifs et les critères qui nous servirons de grille de lecture dans le chapitre 3 qui étudie l’état de l’art. 

Adaptation et logiciels adaptatifs

D’après le dictionnaire, adapter consiste à « rendre (un dispositif, des mesures, etc.) apte à assurer ses fonctions dans des conditions particulières ou nouvelles. » Cette définition implique la présence d’un système (le dispositif), qui réalise une fonction particulière. La fa¸con dont le système réalise cette fonction dépend – au moins en partie – du contexte dans lequel il se trouve. Lorsque le contexte est modifié, créant des conditions particulières ou nouvelles, le système doit donc être adapté afin de continuer à réaliser sa fonction dans le nouveau contexte. Une adaptation est donc une modification d’un système, en réponse à un changement dans son contexte, avec l’objectif que le système résultant soit mieux à même de réaliser sa fonction dans le nouveau contexte. Il est à noter que si toute adaptation est mise en œuvre par une modification du système, une modification quelconque d’un système n’est pas systématiquement une adaptation. Elle ne peut l’être que si le nouveau système, modifié, est meilleur que l’ancien, compte tenu des nouvelles conditions. Cette distinction est fondamentale, car elle met en évidence que l’on ne peut parler de l’adaptation d’un système que si l’on dispose de critères permettant d’évaluer sa qualité, qui détermine ce que « meilleur » signifie. Plus formellement, étant donné un système S, on se donne une fonction f (pour fitness, ou adéquation), qui évalue la qualité de S. En pratique, un système n’est jamais complètement isolé, et existe dans un contexte qui influence son fonctionnement. Si C représente ce contexte, alors f(S, C) représente l’adéquation de S au contexte C. Si S se trouve dans un contexte différent C 0 , il peut arriver que f(S, C 0 ) < f(S, C), c’est-`a-dire que S est moins bien adapté à C 0 qu’`a C. Dans ce cas, nous devons donc modifier S afin d’obtenir un nouveau système S 0 tel que f(S 0 , C 0 ) ≥ f(S, C 0 ) 7 . Dans un système dynamique, le contexte évolue de fa¸con continue au cours du temps. Ce processus d’adaptation doit donc lui aussi être renouvelé pendant toute la durée de vie du système, soit de fa¸con continue, soit par étapes discrètes, suivant la nature du système. Dans la suite de cette thèse, on dira qu’un système est adaptable s’il peut être adapté par une entité extérieure (logicielle ou non), et qu’un système est adaptatif s’il s’adapte automatiquement et de fa¸con autonome. Un système adaptatif est à la fois le sujet et l’acteur de l’adaptation Ledoux et al.; Dowling and Cahill ; il se modifie donc lui-même, en fonction des évolutions de son contexte afin de toujours offrir la meilleure qualité possible relativement à ce contexte. Dans le cadre du génie logiciel, cette notion de système adaptatif correspond à un logiciel qui s’adapte dynamiquement – c’est-`a-dire au cours de son exécution – aux caractéristiques et aux évolutions de son contexte d’exécution. Un système adaptatif peut être caractérisé par : – Un ensemble d’opérations permettant de modifier le système. Etan ´ t donné un état initial, cet ensemble d’opérations définit un espace d’états regroupant tous les états possibles du système. Dans le cas du logiciel, ces opérations se traduisent par des mécanismes de reconfiguration dynamique. Les caractéristiques de différents mécanismes possibles sont décrits et discutés dans la section 1.2.2. – Un contexte, qui regroupe tous les éléments externes au système qui influencent son fonctionnement. Ce contexte est le plus généralement dynamique, évoluant de fa¸con plus ou moins prévisible au cours du temps. Bien entendu, le système peut lui-même avoir une influence sur certains éléments de ce contexte. Ce point est approfondi dans le cas du logiciel à la section 1.2.3. – Une fonction d’adéquation, qui permet à tout moment de savoir dans quelle mesure le système réalise ses objectifs relativement au contexte dans lequel il se trouve. Par définition, un système 7Le problème de l’adaptation est très proche de celui de l’optimisation, qui cherche à maximiser la fonction f en modifiant le système, c’est-`a-dire à déterminer le système Smax tel que ∀S, f(S) ≤ f(Smax). La différence est que l’optimisation se fait « à contexte constant », alors que le contexte, ses évolutions et son impact sur le système sont au cœur du problème de l’adaptation. On peut donc voir le processus d’adaptation comme une optimisation en continue, perpétuellement remise en cause (au moins partiellement) par les évolutions du contexte dans lequel fonctionne le système. est « une combinaison de composants qui agissent ensemble afin de réaliser une fonction impossible à réaliser par aucune des parties » (définition de l’ieee), et cette fonction est donc d’une certaine manière inhérente au système. En pratique, cette fonction est très rarement définie explicitement, et fait souvent appel à des critères plus ou moins subjectifs pour évaluer la qualité d’un système, qui peuvent dépendre de l’observateur. Dans notre cas particulier, cette fonction correspond à la spécification du problème pour lequel le logiciel à été con¸cu et aux critères de qualité de service. – Une stratégie d’adaptation, chargée de mettre en œuvre le processus d’adaptation dans le système, afin qu’il soit toujours le plus performant possible (tel qu’évalué par la fonction d’adéquation), relativement à son contexte d’utilisation, et ce malgré les variations de ce dernier. Dans un logiciel, elle va se traduire par un ensemble d’algorithmes et de données de l’application adaptative chargés de réaliser les adaptations. Cette stratégie utilise pour cela les autres éléments du système : sa connaissance du contexte d’exécution, et l’existence de mécanismes de reconfigurations. La nature et les caractéristiques de cette stratégie sont développés dans la section 1.2.4.

Mécanismes de reconfiguration dynamique

La capacité d’un système adaptatif en général à être adapté est déterminée en grande partie par le nombre et la nature des opérations applicables au système, elles-mêmes en partie déterminées par la structure du système. Plus un système supporte d’opérations permettant de le modifier, et plus ces opérations sont « puissantes », plus il est souple et donc a priori capable d’être adapté à un grand nombre de situations. Nous nous intéressons ici aux différents mécanismes existants permettant de reconfigurer dynamiquement une application. Il existe de très nombreux mécanismes différents permettant de reconfigurer une application. Il n’est bien entendu pas possible de les citer tous ici. Nous verrons dans le chapitre suivant comment un certain nombre d’entre eux sont appliqués dans les solutions existantes pour la construction d’applications adaptatives. Dans cette section, nous tentons plutôt de dégager un certain nombre de critères qui nous permettront d’évaluer ces solutions du point de vue des mécanismes utilisés. En effet, bien que tous ces mécanismes puissent être utilisés dans le cadre d’une adaptation, la plupart n’ont rien de spécifique à cette utilisation et peuvent être utilisés pour d’autres besoins. Cependant, les contraintes spécifiques de l’adaptation les rendent plus ou moins appropriés. Garanties. Nous l’avons déj`a dit plus haut, il est important de trouver le bon équilibre entre la puissance des reconfigurations possibles et le maintient de la cohérence de l’application. Les opérations de reconfigurations utilisées pour l’adaptation doivent donc offrir des garanties quand à leurs effets sur le système. Cela implique d’une part que l’effet de chaque opération soit prévisible et d’autre part que leurs définitions se basent sur une description plus ou moins formelle de la structure et du comportement du système. Ces deux sous-critères sont essentiels pour pouvoir raisonner a priori sur les effets des différentes opérations sur le système, c’est-`a-dire sans avoir à les réaliser. On peut imaginer de nombreux types de garanties différentes, comme par exemple concernant les effets sur les performances de telle ou telle opération, mais la plus fondamentale, est la garantie du maintient de la cohérence du système adapté. Cette garantie stipule que quelles que soient les opérations appliquées au système, celui-ci continuera de fonctionner correctement. Il faut distinguer ici un système qui fonctionne correctement, c’est-`a-dire qui produit les bons résultats sans erreur, d’un système qui fonctionne bien, c’est-`a-dire qui, en plus d’être correct, utilise efficacement les ressources à sa disposition. Dans le cadre de l’adaptation, l’objectif est de faire en sorte qu’un système fonctionne au mieux, et donc le minimum que l’on doive garantir est qu’un système correct reste correct quelles que soient les adaptations qu’on lui applique. C’est ce que signifie le critère de maintient de la cohérence. Modularité. La modularité représente le fait de pouvoir appliquer des modifications à une partie du système sans affecter les autres. Ce critère est un critère général du génie logiciel, qui n’est pas spécifique à l’adaptation. Cependant, il est particulièrement important dans notre cas, car il permet d’adapter des systèmes complexes en raisonnant sur leur propriétés locales, et donc sans avoir à se préoccuper d’interactions non prévues avec l’extérieur. Cela signifie que si une adaptation est rendue nécessaire par une modification du contexte, par exemple une baisse de la qualité de connexion réseau, il est possible de n’adapter que les parties du système qui interagissent directement avec le réseau, en ayant un impact minimal (idéalement nul) sur le reste. Cela signifie aussi que l’on doit facilement adapter tous les éléments concernés. En effet, si dans l’exemple précédent du réseau on ne modifie que le côté client sans toucher au serveur, ceux-ci risquent de ne plus pouvoir communiquer. La possibilité d’effectuer des modifications de fa¸con modulaire ne dépend pas uniquement de la nature des mécanismes utilisés et de leur granularité, mais aussi de la structure de l’application. Si l’application est mal modularisée, ou modularisée d’une fa¸con incompatible avec une adaptation donnée, on retrouve ici le problème bien connu de la tyrannie de la décomposition dominante [Ossher and Tarr, 1999] qui ne peut être résolu que par des techniques de programmation par aspects. Performance. La performance des reconfigurations est cruciale. Les mécanismes utilisés pour l’adaptation dynamique doivent pouvoir d’être implémentés efficacement, aussi bien en terme de vitesse d’exécution que d’utilisation de ressources. En effet, ils ne doivent pas perturber le fonctionnement de l’application plus que nécessaire. Un mécanisme qui nécessiterait plusieurs secondes pour s’exécuter serait inutilisable dans la plupart des applications. Même si le système résultant de son utilisation était beaucoup plus performant que le système initial, son cout ˆ serait prohibitif. Au del`a des interférences avec l’exécution normale de l’application, une reconfiguration qui prend trop de temps risque de ne plus être valide une fois terminée si le contexte a évolué entre temps. Ouverture. Il est en général impossible aux programmeurs d’une application de prévoir toutes les circonstances dans lesquelles elle sera utilisée, et donc les adaptations qu’elle devra supporter. Bien que cela ne soit pas à proprement parler nécessaire pour pouvoir parler d’application adaptative, en pratique il est important pour une telle application de supporter des modifications non anticipées au moment du développement. Un système fermé, qui ne supporterait que des adaptations prévues serait forcément limité, et deviendrait rapidement beaucoup trop complexe à développer s’il devait s’adapter à des scénarios réalistes. Transparence. Enfin, notre dernier critère, lié au précédent, concerne la transparence des mécanismes du point de vue du programmeur initial de l’application. En effet, si l’on veut pouvoir adapter une application de fa¸con non anticipée, il faut éviter des mécanismes qui nécessitent que le programmeur de l’application « prépare » l’application pour ces modifications. Il est important que la création d’applications adaptatives ne se fasse pas au dépend de la complexité du développement initial, déj`a suffisamment difficile. Au contraire, notre objectif est plutôt de simplifier le travail des programmeurs en modularisant le code spécifique à l’adaptation dans un aspect, ce qui devrait rendre le code métier plus simple. 

Contexte explicite

Bien que le contexte soit pas définition extérieur au système, un système adaptatif doit être conscient de celui-ci afin de pouvoir réagir à ses évolutions. Un système ne peut pas être adaptatif s’il est « aveugle » à son contexte. L’étendue et la précision – aussi bien spatiale (niveau de détail et d’exactitude) que temporelle (temps de latence) – des connaissances que possède le système sur son contexte est déterminant pour la qualité des adaptations qu’il peut mettre en œuvre. Si le système ne possède que des informations partielles, inexactes, ou obsolètes, les adaptations qu’il pourra réaliser au mieux seront non optimales, et au pire auront un effet négatif sur les performances du système. Puisque l’adaptation d’un logiciel se fait par rapport à son contexte d’exécution et aux évolutions de celui-ci, il est primordial pour une application adaptative d’avoir conscience de ce contexte [Dey and Abowd, 2000]. Ce n’est pas le cas de la plupart des logiciels; au contraire, les environnements d’exécution modernes (machines virtuelles, middlewares) essayent plutôt de les isoler le plus possible des spécificités de leur environnement. Si cette approche a de nombreux avantages, comme une meilleure portabilité, elle empêche parfois les applications de tirer partie des particularités de leur contexte d’exécution. Le premier problème concerne l’identification du contexte du logiciel. La définition que nous utilisons (voir la section 5.1, page 71) indique que le contexte d’un logiciel regroupe tout ce qui influence la qualité de son fonctionnement, mais qui ne fait pas partie explicitement du logiciel. Ainsi, les caractéristiques matérielles de l’ordinateur hôte d’une application font partie de son contexte, mais pas les objets métiers qu’elle manipule directement. Dans ce document, nous ne nous intéressons pas à ce problème d’identification, mais seulement à la fa¸con dont le contexte, une fois identifié, intervient dans l’adaptation du logiciel. Un logiciel adaptatif doit donc contenir le code nécessaire pour le rendre sensible à son contexte. Les rôles de cette partie du logiciel sont : – découvrir des caractéristiques du contexte spécifique à une exécution du logiciel ; – détecter les changements significatifs qui se produisent dans le contexte d’exécution, et déclenchent éventuellement des adaptations du logiciel ; – offrir au reste du logiciel une interface lui permettant d’obtenir ces informations. Le chapitre 5 est spécifiquement consacré à cette problématique et à la solution que nous y proposons. Nous nous contenterons ici d’énumérer rapidement les critères les plus importants permettant d’évaluer cette partie d’un logiciel adaptatif : La précision des informations obtenues, aussi bien spatiale que temporelle. La précision spatiale, correspond au niveau de détails fournis, et doit être la plus élevée possible. La précision temporelle correspond au décalage dans le temps entre le moment ou` les informations sont re¸cues par le logiciel afin d’être exploitées, et l’instant (passé) auxquelles elles se sont produites. La richesse des informations correspond à l’étendue du contexte qui est effectivement observée par le système, et doit être la plus élevée possible. La généralité et la modularité du code implémentant l’observation du contexte dans le logiciel, doit elle aussi être maximisée, afin de pouvoir être réutilisée dans d’autres applications. En effet, certains éléments, comme les caractéristiques matérielles ou logicielles de la plate-forme d’exécution font partie du contexte de tous les logiciels. Les performances du code d’observation sont primordiales, afin d’éviter les interférences de cette partie du système adaptatif avec le fonctionnement normal du logiciel. 

Stratégie d’adaptation

La stratégie d’adaptation employée par le système est d’une certaine fa¸con chargée d’« incarner » la fonction d’adéquation sur le plan opérationnel. La fonction définit un objectif à atteindre, et la stratégie d’adaptation est chargée de réaliser cet objectif au mieux. La stratégie d’adaptation est l’élément le plus important d’un système adaptatif ; même si les opérations disponibles sont extrêmement puissantes et si le contexte est connu dans ses moindres détails, tout cela ne sert à rien si la stratégie n’est pas capable de tirer partie de ces informations. Dans notre cas particulier, la stratégie d’adaptation d’un logiciel adaptatif se présente sous la forme d’un ensemble d’algorithme et de données qui sont chargés, à partir des informations connues sur le contexte d’exécution, de décider quand et comment adapter le logiciel, en utilisant au mieux les mécanismes de reconfiguration disponibles. La stratégie est donc au cœur du logiciel adaptatif, puisqu’elle fait le lien entre les deux autres éléments analysés plus haut : mécanismes de reconfiguration et informations contextuelles. Voici les caractéristiques à notre sens les plus importantes d’une stratégie d’adaptation, qui nous serviront de critères d’évaluation. Notons que certains de ces critères sont des critères « classiques » du génie logiciel ; cependant, il sont tout particulièrement importants dans le cas d’une stratégie d’adaptation. Analysabilité. La mise en œuvre d’une stratégie d’adaptation va conduire à des modifications dans l’application adaptée. Ces modifications sont a priori con¸cues pour améliorer l’application, mais rien dans les mécanismes utilisés ne peut empêcher ces modifications de nuire à la qualité du logiciel (les seules garanties que ces mécanismes peuvent nous offrir est de conserver la consistance du système). Il est donc important que la stratégie d’un logiciel adaptatif puisse être analysée avant d’être exécutée afin de vérifier certaines propriétés (dépendant de l’application) et de garantir que la stratégie n’aura pas d’effets pervers, comme de rendre l’application inutilisable ou de générer des erreurs irrécupérables. Parmi les critères les plus importants concernant la qualité d’une stratégie d’adaptation, on trouve : La stabilité. Il peut arriver que le contexte d’exécution du logiciel évolue de fa¸con abrupte et totalement imprévisible. Une stratégie d’adaptation na¨ıve risquerait par des réactions trop précipitées ou disproportionnées de rendre le système instable. L’agilité. Le temps de réaction de la stratégie par rapport aux évolutions du contexte doit être le plus faible possible, non seulement afin de ne pas perturber le fonctionnement normal du logiciel, mais aussi car si la stratégie met trop de temps à se décider, le contexte peut avoir suffisamment évolué entre temps pour rendre sa décision caduque. Dynamicité. Tout comme pour les mécanismes de reconfigurations, il est important que la stratégie d’adaptation d’un logiciel soit ouverte, afin de pouvoir elle-même être adaptée et étendue de fa¸con non anticipée sans avoir à stopper, modifier, puis recompiler le logiciel. Généricité et réutilisabilité. De la même manière qu’elles partagent une partie de leur contexte (en particulier en ce qui concerne les caractéristiques matérielles des plates-formes hôtes), beaucoup d’applications utilisent des services non-fonctionnels de type middleware similaires, voire identiques. Les stratégies d’adaptation de ces couches logicielles sont relativement indépendantes de la fonction spécifique du logiciel et doivent donc pouvoir être réutilisées, au moins en partie, dans plusieurs applications adaptatives.

Table des matières

Introduction
I Problématique et état de l’art
1 Définition et analyse préliminaire de la problématique
1.1 Définition de la problématique et des objectifs
1.1.1 Constats et motivation
1.1.2 Problématique de la thèse
1.2 Caractéristiques des logiciels adaptatifs
1.2.1 Adaptation et logiciels adaptatifs
1.2.2 Mécanismes de reconfiguration dynamique
1.2.3 Contexte explicite
1.2.4 Stratégie d’adaptation
1.3 Conclusion
2 Concepts et technologies sous-jacents `a notre proposition
2.1 Séparation des préoccupations
2.2 Réflexion et méta-programmation
2.3 Composants logiciels
2.4 Langages dédiés
3 Etat ´ de l’art
3.1 Introduction et rappel de nos critères d’évaluation
3.2 Middlewares réflexifs et adaptatifs
3.2.1 Open-ORB
3.2.2 QuO
3.2.3 dynamicTAO
3.2.4 Middleware Control Framework
3.2.5 Extension de ScalAgent
3.2.6 CARISMA
3.2.7 QuA
3.3 Modèles de composants adaptatifs
3.3.1 Adaptive Components
3.3.2 MOLèNE
3.3.3 K-Components
3.3.4 ACEEL
3.3.5 PLASMA
3.4 Autres approches
3.4.1 Odyssey
3.4.2 DART
3.4.3 LEAD++
3.5 Conclusion
II Contributions
4 Architecture de SAFRAN
4.1 Introduction
4.2 Aper¸cu du modèle de composants Fractal
4.2.1 Introduction
4.2.2 Anatomie d’un composant Fractal
4.2.3 Le noyau du modèle et les interfaces de contrôle standards
4.3 Extensions de Fractal pour l’adaptabilité
4.3.1 Méta-composants Fractal
4.3.2 Spécification de contraintes architecturales métiers
4.4 Politiques d’adaptation SAFRAN
4.4.1 Un contrôleur Fractal pour gérer l’adaptation
4.4.2 Structure de politiques d’adaptation
4.4.3 SAFRAN en tant que système à aspects
4.5 Sensibilité au contexte avec WildCAT
4.5.1 Modélisation du contexte d’exécution
4.5.2 Interface de programmation
4.5.3 Ev´ énements SAFRAN
4.6 Reconfigurations dynamiques consistantes avec FScript
4.6.1 Expressions FPath
4.6.2 Programmes FScript
4.7 Modèle de développement d’applications adaptatives
4.7.1 Modèle de développement standard
4.7.2 Etap ´ es supplémentaires introduites par SAFRAN
4.7.3 Intégration de SAFRAN dans le modèle standard
4.8 Plan du reste du document
5 Développement d’applications sensibles au contexte
5.1 Introduction
5.2 Objectifs et critères d’évaluation
5.3 Le modèle de données WildCAT
5.3.1 Structuration des données
5.3.2 Ev´ olutions dynamiques du contexte
5.3.3 Conclusion
5.4 Interface de programmation
5.4.1 Désignation des ressources et des attributs
5.4.2 Interrogation du contexte et navigation
5.4.3 Abonnement et notifications asynchrones
5.5 Instanciation et configuration du système
5.5.1 Définition de la structure statique
5.5.2 Définition des sondes pour les attributs primitifs
5.5.3 Définition d’attributs synthétiques
5.5.4 Modélisation des aspects dynamiques du contexte
5.5.5 Conclusion
5.6 Mécanismes d’extensions de WildCAT
5.6.1 Développement de nouvelles sondes .
5.6.2 Création d’une nouvelle implémentation
5.7 Conclusion 98
6 FScript : un langage dédié pour la reconfiguration consistante de composants Fractal1
6.1 Introduction
6.2 Etude  de domaine
6.2.1 Fonctionnalités requises & pouvoir d’expression
6.2.2 Concepts spécifiques à la manipulation de composants Fractal
6.2.3 Critères de consistance
6.3 Navigation dans les architectures Fractal avec FPath
6.3.1 Chemins et types de données associés
6.3.2 Types de données et expressions de base
6.3.3 Quelques exemples d’expressions FPath
6.3.4 Interface de programmation
6.4 Reconfiguration de l’architecture avec FScript
6.4.1 Structure générale : définitions de fonctions et d’actions
6.4.2 Affectations, portée et durée de vie des variables
6.4.3 Structures de contrôle
6.4.4 Actions de reconfiguration primitives
6.5 Description de l’implémentation
6.5.1 Interface de programmation
6.5.2 Modèle d’exécution
6.6 Conclusion : limitations et extensions futures
7 Politiques d’adaptation SAFRAN
7.1 Introduction
7.2 Spécification et détection d’événements
7.2.1 Introduction
7.2.2 Ev´ énements primitifs
7.2.3 Descripteurs d’événements composites
7.2.4 Capture des occurrences
7.3 Structure des politiques d’adaptation
7.3.1 Introduction
7.3.2 Définition de règles réactives
7.3.3 Définition de politiques d’adaptation
7.4 Modèle d’exécution des politiques d’adaptation
7.4.1 Introduction
7.4.2 Cycle de vie des politiques
7.4.3 Comportement individuel des politiques
7.4.4 Interactions entre politiques d’un même composant
7.4.5 Interactions entre composants adaptatifs
7.5 Conclusion
8 Développement d’applications adaptatives avec SAFRAN
8.1 Introduction
8.2 Modèle et outils de développement
8.2.1 Programmation de composants adaptatifs
8.2.2 Configuration et initialisation du système
8.2.3 Contrôle à l’exécution
8.3 Méthodologie et critères d’évaluation
8.4 Exemple 1 : lecteur de courrier électronique
8.4.1 Présentation de l’application
8.4.2 Envoi de courriers en mode déconnecté
8.4.3 Mode de notification adapté au contexte d’utilisation
8.4.4 Ev´ aluation
8.5 Exemple 2 : serveur web
8.5.1 Présentation de l’application 9
8.5.2 Amélioration des performances par ajout d’un cache adaptable . 0
8.5.3 Adaptation dynamique du nombre de threads . 3
8.5.4 Ev´ aluation 6
8.6 Conclusion 6
Conclusion et perspectives 9
III Annexes
A Référence FPath & FScript
A.1 Syntaxe de FPath
A.2 Syntaxe de FScript
A.3 Axes de navigation FPath
A.4 Fonctions standards FPath
A.4.1 Nœuds attributs
A.4.2 Nœuds interfaces
A.4.3 Nœuds composants
A.5 Actions standards FScript

projet fin d'etudeTélécharger le document complet

Télécharger aussi :

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *