jjacques68 Posté(e) le 22 décembre 2020 Signaler Partager Posté(e) le 22 décembre 2020 Hello tout le monde, Petite question de bon sens... avant de me lancer dans de longues heures de codage et tout recommencer Actuellement, j'ai 2 scènes qui me gère mes lampes de chevet (gauche et droite) pour simuler le réveil. Ce qui est bête c'est que ce sont 2 scènes exactement identiques ! Y a juste l'ID du dimmer qui change !!! J'ai un QA type générique qui me permet d'activer/désavtiver les scènes et de régler l'heure. Celle-ci est stockée dans une VG spécifique à chaque réveil (gauche et droite). On est complement dans l'esprit de la HC2 Donc l'idée serait de créer un QA Parent avec 2 Child (une pour chaque lumière) Ces Child serait de type binarySwitch, pour activer/désactiver le réveil - logique... Le soucis va être le réglage de l'heure de chacun ! Le QA parent aura toujours un IHM pour effectuer ces réglages. MAIS où stocker l'information ???? dans une VG ? dans une VG du QA Child ? dans une VG du QA Parent ? Dans le cas des VG QA, je ne pourrais pas récupérer ce paramètre depuis un autre QA (du moins facilement...) Nécessaire afin de mettre en place le trigger (ça c'est un autre sujet). Le top aurait été de pouvoir créé un QA Child de plus pour lui donner l'heure de réglage comme value "07:00"... Mais c'est pas possible ça... A moins de prendre un multiLevelSensor et de stocker non pas l'heure sous la forme "07:00" mais sous la forme d'un nombre entier ! mais c'est un peu bof comme méthode... Mais là je pourrais interroger l'heure depuis n'importe où ! Si vous avez de meilleurs idées ?! merci pour vos conseils !!! Lien vers le commentaire Partager sur d’autres sites More sharing options...
Lazer Posté(e) le 22 décembre 2020 Signaler Partager Posté(e) le 22 décembre 2020 ça ressemble sacrément à ce que je vais faire pour le QA Alarm de GEA (transposition du VD) Dans un QA, on ne peut plus stocker d'information dans les Labels car l'info n'est plus persistante, donc les labels sont utilisables uniquement pour afficher l'information Donc je pense qu'il faut stocker l'information dans une variable du QuickApp (chaque Child), car elle est persistante (stockée dans son JSON). Après ce qui est pénible c'est qu'on ne puisse pas personnaliser l'IHM des QA enfants.... y ajouter des labels et boutons serait pratique. Je ne comprend pas pourquoi tu dis qu'on ne peut pas lire une variable dans un QA. Il suffit d'aller chercher.... dans le JSON du module justement ! Je me suis fait une petite fonction dans ma librairie tools, on peut obtenir la variable dans self, un child, ou bien n'importe quel QA en donnant juste son ID sous forme numérique. Cerise sur le gâteau, on n'a pas de message d'avertissement disgracieux dans la console si la variable n'existe pas. Dans ce cas, au lieu de récupérer une variable contenant "" (une chaine vide), on obtient nil, ce qui est quand même plus parlant : -- -- Get variable silently without showing warning message in case variable does not exist -- -- Usage : -- local mavariable = tools.getVariable(self, "debug") -- local mavariable = tools.getVariable(child, "debug") -- local mavariable = tools.getVariable(1234, "debug") -- function tools:getVariable(variable) local id = type(self) == "userdata" and self ~= tools and self.id or type(self) == "number" and self > 0 and self if id then if type(variable) == "string" and name ~= "" then local device if type(self) == "userdata" then device = self else device = api.get('/devices/' .. tostring(id)) end if device then if type(device.properties) == "table" and type(device.properties.quickAppVariables) == "table" then for _, v in ipairs(device.properties.quickAppVariables) do if v.name == variable then return v.value end end else tools:warning("tools:getVariable() : can't find any QuickApp variable") end else tools:error("tools:getVariable() : can't find device", type(self), tostring(self)) end else tools:error("tools:getVariable() : invalid variable name :", type(variable), tostring(variable)) end else tools:error("tools:getVariable() : invalid self device :", type(self), tostring(self)) end end Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 22 décembre 2020 Auteur Signaler Partager Posté(e) le 22 décembre 2020 il y a 48 minutes, Lazer a dit : e ne comprend pas pourquoi tu dis qu'on ne peut pas lire une variable dans un QA. si ! je sais qu'on peut, mais c'est pas "simple"... après pourquoi pas utilisé l'option "fichier" des QA, qui permet de partager des fonctions... Il faudrait alors juste créer une fonction qui renvoie la variable locale au QA qui partage sa fonction. avec un simple : function QuickApp:ReturnVG(MaVg) return self:getVariable(MaVg) end Mais bon... Faut partager le fichier, l'inclure dans le QA qui a besoin de cette ressource... Y a moins de ligne de code que ta solution, Mais c'est pas plus "simple" non plus ! Mais c'est pas bête ! nan ? Lien vers le commentaire Partager sur d’autres sites More sharing options...
Lazer Posté(e) le 22 décembre 2020 Signaler Partager Posté(e) le 22 décembre 2020 pas simple ? Pour un enfant c'est exactement la même méthode que pour le parent, en 1 seule ligne, je ne vois pas où est la difficulté ? Tu y mets de la mauvaise volonté là child:getVariable("mavariable") Ma fonction est un peu longue car elle effectue des vérifications, affiche des messages d'erreurs, permet d'obtenir la variable de n'importe quel module, bref elle se veut juste générique, et c'est pour cela que je l'ai incluse dans ma librairie d'outils, ainsi je peux l'utiliser dans n'importe quel QuickApp, simplement en 1 seule ligne (comme la commande Fibaro officielle) Je trouve que la méthode que tu proposes avec fichiers bien lourde, complexe à maintenir, et qui détourne totalement l'usage prévu des fichiers. Bref, c'est sale. Je ne comprend vraiment pas ce qui te déplait dans les variables de Quickapp ? C'est typiquement fait pour cet usage. 1 seule ligne de code LUA, simple, efficace, portable, pérenne. Parfois faut pas chercher la complication, juste utiliser les outils mis à notre disposition par Fibaro. Ah oui et aussi, faut arrêter de raisonner "HC2", comme tu t'en es rendu compte. On oublie les Variables Globales, il n'y a plus beaucoup de cas de figure où on a encore besoin des VG à vrai dire. Même pour gérer le statut de la maison (présent, absence, nuit, vacances, etc) on n'en a plus besoin, les profils font tout cela et bien plus (mais c'est un autre sujet) Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 22 décembre 2020 Auteur Signaler Partager Posté(e) le 22 décembre 2020 (modifié) il y a 19 minutes, Lazer a dit : et c'est pour cela que je l'ai incluse dans ma librairie d'outils cette librairie d'outil est un bien un partage de fichier entre QA ? non ? où tu copies/colles la fonction ? Citation Je ne comprend vraiment pas ce qui te déplait dans les variables de Quickapp ? C'est typiquement fait pour cet usage. on s'est mal compris, je n'utilise pas les VG ! mais bien les variable des quickapp que j'appelle "VG Quickapp"..; il y a 19 minutes, Lazer a dit : On oublie les Variables Globales, il n'y a plus beaucoup de cas de figure où on a encore besoin des VG à vrai dire. ben justement actuellement, j'en ai 3 : 2 qui stockent l'heure, justement pour chaque réveil et 1 pour le backup auto. alors que sur la HC2, j'en avais des dizaines ! Citation et qui détourne totalement l'usage prévu des fichiers. alors là, j'ai vraiment pas compris l'intérêt de partager des fonctions entre quickapp !! Modifié le 22 décembre 2020 par jjacques68 Lien vers le commentaire Partager sur d’autres sites More sharing options...
Lazer Posté(e) le 22 décembre 2020 Signaler Partager Posté(e) le 22 décembre 2020 Les fichiers des QuickApp permettent de découper son code.... en plusieurs fichiers ! Exactement comme on le ferait avec n'importe quel langage de programmation, allant du C jusqu'au PHP L'idée, c'est plutôt que d'avoir un seul fichier monolithique de plusieurs milliers de lignes, on a plusieurs petits fichiers dans lesquels il est facile de retrouver la fonction recherchée. Après pour l'organisation, c'est à l'appréciation de chacun, mais perso ce que j'aime bien faire pour les QuickApp : - main : le code de QuickApp lui-même, c'est à dire toutes les fonctions qui appartiennent à la classe QuickApp, donc sont accessibles par l'utilisateur au travers de l'API fibaro.call(). On va retrouver la gestion de actions, des boutons, etc - tools : ma librairie d'outils avec pleins de fonctions utiles dans mes différents codes, et qui manquent dans le LUA natif proposé par Fibaro ("print" améliorés avec des couleurs, createChild amélioré, getVariable amélioré, createVG, Wake-on-LAN, round(), split(), base64(), log(), getView(), etc ...) - notification : pour envoyer des notifcations (Push, SMS, etc) - config : pour que l'utilisateur y stocke ses paramètres (s'ils sont trop nombreux pour tenir dans les variables du QA, comme par exemple GEA, Network Monitor, etc... et prochainement IPX800v4/EDRT2) - XXX : celui là est dépendant du QA, il contient le cœur du QA, c'est à dire toutes les fonctions spécifiques au QA. Donc ça va être SNMP pour l'onduleur Eaton, ou bien KODI pour gérer l'API Kodi, etc Dans cette liste, certains fichiers (notification, tools) vont se retrouver dans plusieurs QA différents, il me suffit de faire un copier/coller pour en bénéficier automatiquement, facile, rien à intégrer dans le code "main", c'est un fichier à part. Note : je n'utilise pas la méthode de recopie automatique des fichiers proposée par @jang, personnellement je n'aime pas ce genre d'automatisme, une nouvelle version de ma librairie tools pourrait casser la compatibilité avec l'existant et rendre inopérant toute une tripotée de QA existants. (pour des raisons un peu similaires, je n'utilise jamais, ou rarement, la dernière version des logiciels, aussi bien sur mon PC, que mon Smartphone, ou bien ma box domotique... je préfère faire les mises à jour manuellement en cliquant sur un bouton, avec un décalage, je n'ai pas envie d'avoir la primeur des nouveaux bugs qui s'installent automatiquement) Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 22 décembre 2020 Auteur Signaler Partager Posté(e) le 22 décembre 2020 interessant, mais lors des modifications, tu dois te taper tous les QA où tu utilises ces fonctions !!! pour ma culture, je ne comprends absolument pas cette ligne de code ??? y a eu un loupé dans le copier/coller ? local id = type(self) == "userdata" and self ~= tools and self.id or type(self) == "number" and self > 0 and self Lien vers le commentaire Partager sur d’autres sites More sharing options...
Lazer Posté(e) le 22 décembre 2020 Signaler Partager Posté(e) le 22 décembre 2020 Pas besoin de me retaper les QA, puisqu'ils fonctionnent avec l'ancienne librairie tools Si par contre je souhaite reprendre le QA pour lui apporter des nouvelles possibilités, améliorations, corrections de bugs, etc, alors là c'est l'occasion de lui "installer" la nouvelle librairie. Cette ligne de code est une astuce pour récupérer l'ID du module passé en paramètre (variable self implicite correspondant au 1er paramètre lors de l'appel de la fonction) - SI type(self) == "userdata" (c'est à dire le quickapp lui-même ou l'un de ses enfants) ET que ce n'est pas tools lui-même (test inutile car en pratique tools est de type "table") ALORS on renvoie self.id - SI type(self) == "number" ET qu'il est positif (on ne sait jamais, dès fois qu'un ID négatif se perde par là), ALORS on renvoie directement le nombre lui-même (contenu dans self) Dans les commentaires je t'ai justement mis la façon de l'utiliser. Cette astuce, je l'utilise dans plusieurs de mes fonctions de cette librairie tools, c'est hyper pratique à l'usage, je peux faire ce que je veux sur un module, qu'il soit self, child, ou un ID quelconque. Tu verras tools 2.0 quand je le partagerai dans IPX800/EDRT, mais la version 1 a déjà été partagée dans des QA (Kodi, Surv Station, ...) Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 22 décembre 2020 Auteur Signaler Partager Posté(e) le 22 décembre 2020 ok pour l'explication, j'ai juste un problème avec la syntaxe, il manque un "if then"... faut impérativement que je jette un œil à tes QA. Mon esprit est trop resté à l'ancienne. Malgré ce que j'ai déjà fait... Lien vers le commentaire Partager sur d’autres sites More sharing options...
Lazer Posté(e) le 22 décembre 2020 Signaler Partager Posté(e) le 22 décembre 2020 Ah OK, c'est de l'optimisation de code LUA en une seule ligne avec uniquement des AND et OR, sans utiliser le lourd if .... then ... end Donc rien à avoir avec Fibaro, QuickApp, etc.... c'est du LUA pur et dur Mais cela rend le code moins compréhensible quand on n'a pas l'habitude Un peu dans l'esprit de ce qui est présenté dans ce mini benchmark (test n°5) : https://springrts.com/wiki/Lua_Performance#TEST_5:_Nil_Checks_.28.27if.27_vs._.27or.27.29 Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 22 décembre 2020 Auteur Signaler Partager Posté(e) le 22 décembre 2020 merci pour le lien, J'utilise déjà le local x=y or 1 Mais le tien, j'arrive toujours pas à le comprendre... J'essaye de le réécrire avec la syntaxe classique, mais même ça j'y arrive pas Lien vers le commentaire Partager sur d’autres sites More sharing options...
Lazer Posté(e) le 22 décembre 2020 Signaler Partager Posté(e) le 22 décembre 2020 Cela sera peut être plus clair ainsi, avec les parenthèses : local id = (type(self) == "userdata" and self ~= tools and self.id) or (type(self) == "number" and self > 0 and self) Ou bien en syntaxe traditionnelle : local id if type(self) == "userdata" and self ~= tools then id = self.id elseif type(self) == "number" and self > 0 then id = self end Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 22 décembre 2020 Auteur Signaler Partager Posté(e) le 22 décembre 2020 oh punaise j'y étais pas du tout merci !! Je viens de regarder vite fait ton QA KODI, En fait j'avais pas du tout pensé à cette manière utiliser les "fichiers". C'est de la bombe !! Je me permets : pour commences tu tes librairies avec tools = {} ou encore KODI = {} C'est obligatoire ? Lien vers le commentaire Partager sur d’autres sites More sharing options...
Lazer Posté(e) le 22 décembre 2020 Signaler Partager Posté(e) le 22 décembre 2020 Oui il faut le déclarer en tant que table {}, avant de pouvoir y ajouter des functions(), ou n'importe quel autre variable de type string, number, boolean, etc Là encore, c'est du LUA pur, j'en usais largement dans mes VD sur HC2. Et pour tout dire, je me suis inspiré à l'époque des codes des maitres @Krikroff et @Steven Le LUA a ceci de génial que tout est "rangé" dans une table. Mêmes les variables dont la portée est globale (le cas de tools qui nous intéresse, mais aussi QuickApp.... et absolument toutes les fonctions qu'on utilise (fibaro.*, math.*, json.*, etc) font en réalité partie d'un super tableau appelé _G dont l'appel est implicite. Voir à ce sujet ma petite exploration (j'ai découvert après coup que @jang avait partagé un code tout à fait similaire sur le forum officiel.... promis cette fois-ci je n'ai pas copié) Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 22 décembre 2020 Auteur Signaler Partager Posté(e) le 22 décembre 2020 ouiiiii j'avais vu ça ! Avais pas tout compris, mais avec ce que tu viens de dire, ça vaut le coup de s'y intéresser a nouveau ! Lien vers le commentaire Partager sur d’autres sites More sharing options...
Lazer Posté(e) le 22 décembre 2020 Signaler Partager Posté(e) le 22 décembre 2020 En fait, QuickApp, tools, KODI, etc.... ce sont tous des tables contenant des fonctions, et leur utilisation permet de faire de la programmation orientée objet. Même si ce n'est pas de la vraie POO au sens C++ du terme, cela s'en approche pas mal. Par exemple, ma pseudo classe SNMP utilisée pour l'onduleur (en réalité une table avec des variables et des fonctions) a été portée en un temps record sur la HC3, il m'a juste suffit de modifier les appels aux fonctions propriétaires (sockets UDP), et la classe entière devenant utilisable comme par magie dans un QuickApp. Pour GEA j'ai poussé le concept plus loin encore, puisque j'utilise le mécanisme de "class" proposé par Fibaro et qu'on utilise pour les QA enfants. Je l'ai adapté à GEA, j'en ai fait une classe, ce qui me permet d'en instancier 2 objets, avec chacune leur constructeur (la fonction __init()), et leur espace mémoire propre et bien distinct. Pour le coup cela devient propriétaire car le mécanisme de class proposé par Fibaro est spécifique à la HC3. Mais l'esprit est totalement dans le style POO. Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 22 décembre 2020 Auteur Signaler Partager Posté(e) le 22 décembre 2020 oui la tu vas trop vite pour moi Je viens juste de comprendre que tout était rangé dans des tableaux, Je me rends compte que moi-même il m'arrive de faire des tableaux de fonctions, mais ça s'arrête là... Je découvre cette manière de coder. C'est un vrai état d'esprit ! on sort du codage conventionnel, séquentiel, procédural, ... Faut s'y faire... Lien vers le commentaire Partager sur d’autres sites More sharing options...
Lazer Posté(e) le 22 décembre 2020 Signaler Partager Posté(e) le 22 décembre 2020 Exactement Basic d'un côté : lignes 10 20 30 etc Java de l'autre : full objet Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 22 décembre 2020 Auteur Signaler Partager Posté(e) le 22 décembre 2020 je développe énormément sous Windev au boulo... Qui est un "langage" si je peux dire ainsi, très très très très évolué. La POO est tout à fait réalisable avec, mais j'avoue resté à "l'ancienne". En même temps, leur système de base de données intégré (= HFSQL qui fonctionne à merveille) ne nous pousse pas à faire de la POO... Même pour des très gros projet, ça passe tout seul. Après je développe des applications. Pas des applications, pour créer des applications Là la POO serait plus que obligatoire... Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 23 décembre 2020 Auteur Signaler Partager Posté(e) le 23 décembre 2020 j'ai relu plusieurs fois cette discussion... c'est vachement intéressant !! Il y a 12 heures, Lazer a dit : Après pour l'organisation, c'est à l'appréciation de chacun, mais perso ce que j'aime bien faire pour les QuickApp : [...] - notification : pour envoyer des notifcations (Push, SMS, etc) c'est marrant justement, pour les notifications, moi j'ai un QA spécifique. Avec tout dedans (Push, Mail, TTS, Prowl) Pour envoyer une notification je fais appel à une méthode de ce QA avec par exemple : fibaro.call(ID_QA, "sendPush", "blablabla") ça fonctionne très bien. Mais la question se pose : est-il plus efficace (performance, réactivité, maintenabilité, ...) d'appeler une méthode d'un QA ou d'intégrer le code dans d'envoi dans un fichier comme tu le fais ? Lien vers le commentaire Partager sur d’autres sites More sharing options...
Lazer Posté(e) le 23 décembre 2020 Signaler Partager Posté(e) le 23 décembre 2020 Performance : il est plus rapide d'appeler une fonction dans le QuickApp lui-même que dans un autre QuickApp (car cela va alors passer par l'API, communication entre processus différents, etc.... opérations relativement lourde) Mais il faut relativiser, ce serait un problème si tu envoyais 10 notifications par seconde. En pratique, des notifications, c'est de l'ordre de quelques unes par jour... donc il n'y a aucune souci de performance en pratique. Ce qui nous amène à la maintenabilité, et c'est bien là le plus important. Organiser son code LUA dans des fonctions dans des "objets" dans fichiers dans des QuickApps dans la box domotique L'essentiel est de s'y retrouver, de pouvoir facilement utiliser un bout de code nécessaire entre plusieurs QuickApps, etc. Je ne sais pas s'il y a une meilleure façon de faire. Mon objet de notifications, tu peux le voir dans quelques QuickApps (Network Monitor, Onduleur Eaton, etc), j'ai préféré la copier/coller. Elle me sert à uniformiser l'envoie d'email, notification push, etc. dans mes différents codes. Et je ne dépend pas d'un QuickApp externe (dont l'ID pourrait changer) pour envoyer des notifications aussi basiques que email et push Mais pour l'envoi des SMS, elle se base elle même sur un QuickApp dédié, pour JPI. Car j'ai considéré que JPI étant une application externe sur un smartphone externe, cela nécessité un QuickApp dédié. Et facilement partageable en plus, un QuickApp utilisable par tous en tant qu'outil prêt à l'emploi. Lien vers le commentaire Partager sur d’autres sites More sharing options...
Lazer Posté(e) le 23 décembre 2020 Signaler Partager Posté(e) le 23 décembre 2020 Ce sujet de l'ID qui change est un problème chez Fibaro. Il manque toujours un truc sur la HC3, c'est la possibilité de se réaliser une vraie librairie d'outils partageables entre tous les QA. Difficile à stocker ça dans un QA quand tu sais que tu es lié à son ID.... qu'on ne peut pas choisir ! Il faudrait pouvoir nommer les QA (ou scènes) de manière unique pour les appeler sans ambuiguité depuis n'importe quel code LUA. L'ID on ne le choisit pas (et il change si on exporte/importe le module) Et le nom n'est pas unique car plusieurs QA peuvent porter le même nom. Il manque aussi un autre élément fondamental, c'est la possibilité de récupérer la valeur de retour d'une méthode appelée dans un autre QA. Là encore, @jang a proposé une solution, mais que je trouve un peu lourde, j'aurais préféré un truc prévu en standard par Fibaro, plus facilement maintenable. Donc en attendant, on organise notre code avec les fichiers, et l'appel de méthodes avec paramètres entre QA, c'est déjà un gros progrès par rapport à la HC2. Lien vers le commentaire Partager sur d’autres sites More sharing options...
jang Posté(e) le 23 décembre 2020 Signaler Partager Posté(e) le 23 décembre 2020 Shared code/modules are an interesting topic. It would be nice if the community could agree about a "module" format that made it easy to use each other's modules without polluting the Lua global namespace too much... https://forum.fibaro.com/topic/49113-hc3-quickapps-coding-tips-and-tricks/?do=findComment&comment=223070 1 Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 23 décembre 2020 Auteur Signaler Partager Posté(e) le 23 décembre 2020 thanks @jang, I will read it Lien vers le commentaire Partager sur d’autres sites More sharing options...
jjacques68 Posté(e) le 23 décembre 2020 Auteur Signaler Partager Posté(e) le 23 décembre 2020 (modifié) Je me suis rendu compte pendant mes essais, que commencer un fichier avec class 'WAKEUP' (QuickAppChild) function WAKEUP:MyFunction() [...] end avait visiblement le même effet que si j'avais fait WAKEUP = {} function WAKEUP:MyFunction() [...] end Dans les 2 cas, Les fonctions sont accessibles dans le main en faisant : WAKEUP:MyFunction() C'est normal ça ?? est-ce la même chose ? D'ailleurs visiblement, on est pas obligé d'utilisé une class ou un tableau de fonctions dans un fichier ! On peut simplement y déplacer des fonctions du main ! Ce que j'ai fait pour le code des actions sur les boutons. Histoire de pas polluer le code dans le main... ça permet de ranger un peu la structure du code... Ne suis-je pas encore entrain de détourner son l'utilisation ? ça reste encore un peu obscure tout ça... il manque une sorte de représentation graphique de la structure d'un QA... Ce qui aiderait à mieux comprendre je pense. Bien que la petite phrase de @Lazer : Citation Le LUA a ceci de génial que tout est "rangé" dans une table. a résonné tout la journée dans la tête et m'a ouvert pas mal les yeux @jang : I have read your link more and more. I don't understand anymore with the "shared" sorry, it's too strange for me Modifié le 23 décembre 2020 par jjacques68 Lien vers le commentaire Partager sur d’autres sites More sharing options...
Messages recommandés