Equivalent de [self class]

Bonjour,


 


Je cherche seulement un moyen d'écrire [self class] en swift avant d avoir initialisé l'instance.


 


Imaginons le code ci dessous :



@interface MyObject : NSObject

- (instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER;

@property (readwrite, strong, nonatomic) NSString *name;

+ (NSString *)defaultName;

@end

@implementation MyObject

- (instancetype)initWithName:(NSString *)name
{
self = [super init];
if (self) {
_name = name;
}
return self;
}

- (instancetype)init
{
NSString *name = [[self class] defaultName]; // impossible à  reproduire en swift
return [self initWithName:name];
}

+ (NSString *)defaultName
{
return @Untitled;
}

@end

Comment reproduire ca si c est possible ?


«1

Réponses

  • Joanna CarterJoanna Carter Membre, Modérateur
    août 2014 modifié #2

    Voilà  !



    class MyObject: NSObject
    {
    class var defaultName: String
    {
    return "Untitled"
    }

    lazy var name: String =
    {
    return defaultName
    }()

    override init()
    {
    super.init()
    }

    init(name: String)
    {
    super.init()

    self.name = name
    }
    }

  • Il n'y a aucun moyen d'obtenir la classe d'un objet Switf pour faire un appel de méthode de classe dessus ? 


     


    Car là  c'est gentil de passer par une ivar à  la construction, mais ça ne résout pas le problème si on cherche à  appeler des méthodes de factory ou autre.


  • AliGatorAliGator Membre, Modérateur
    self.Type.defaultName ?
  • Joanna CarterJoanna Carter Membre, Modérateur
    Comme tu peux voir dans mon code, on peut accéder les vars et méthodes de la classe en écrivant seulement le nom
  • Joanna CarterJoanna Carter Membre, Modérateur
    août 2014 modifié #6

    Correction. On peut accéder les vars par nom mais, pour les méthodes, il faut utiliser self.dynamicType.maMethode() ou MyObject.maMethode()


  • JE729JE729 Membre
    août 2014 modifié #7

    Merci pour toutes ces réponses ;)


    J'arrive à  ca :



    class MyObject {

    var name : String?

    init (name : String?) {
    self.name = name
    }

    convenience init () {

    var name : String? = nil

    // First solution
    // name = self.dynamicType.funcDefaultName()
    // name = self.dynamicType.varDefaultName()
    // Error : Use of `self`in delegating initializer before self.init is called

    // Second solution
    // name = MyObject.funcDefaultName()
    // name = MyObject.varDefaultName
    // Works well but we cannot override the default name

    self.init(name: name)
    }

    class var varDefaultName: String {
    return "Untitled"
    }

    class func funcDefaultName() -> String? {
    return "Untitled"
    }

    }

    class MySubObject : MyObject {

    override class var varDefaultName: String {
    return "Override"
    }

    override class func funcDefaultName() -> String? {
    return "Override"
    }

    }

    J'arrive à  ca

    Les solutions fonctionnent mais non plus aucun intérêt car on ne peut pas sous classer et changer la valeur

    Yoann a surement raison aucun moyen existe en pure swift

     


  • Il reste à  essayer en passant par Objective-C et un bridging header mais c'est pas terrible terrible ...


  • Joanna CarterJoanna Carter Membre, Modérateur
    août 2014 modifié #9

    N'utilises pas l'init pour initialiser le nom à  défaut. Plutôt, utilises le class var et un lazy var comme ci :



    class MyObject: NSObject
    {
    private class var defaultName: String
    {
    return "Untitled"
    }

    lazy var name: String =
    {
    return self.dynamicType.defaultName
    }()

    override init()
    {
    super.init()
    }

    init(name: String)
    {
    super.init()

    self.name = name
    }
    }

    class SubObject : MyObject
    {
    private override class var defaultName: String
    {
    return "Override"
    }
    }

  • OK, donc d'après ce que j'ai rapidement lu, la seule bonne méthode à  appliquer c'est self.dynamicType.


     


    Swift étant fait par des gens qui n'aiment pas le runtime dynamique, tu te retrouve avec tous les problèmes de sous classe de Java et autre : self.type renvois vers le type d'origine ayant défini une méthode et non une sous classe éventuelle. (ce qui est totalement débile de mon point de vue car c'est strictement identique à  faire un appel explicite à  la classe directement, aucun avantages)


     


    Si tu veux faire comme en Objective-C et utiliser le runtime pour appeler une méthode de classe sur la classe effective à  l'exécution (et donc autoriser les surcharge par les sous classes) tu dois passer par self.dynamicType.


  • AliGatorAliGator Membre, Modérateur

    @yoann JE729 a parfaitement résumé le problème :

    • Pour accéder au type d'une variable, comme [self class] en ObjC, l'équivalent Swift est self.dynamicType
    • Sauf que, pour des raisons de sécurité (expliquées par Apple lors des WWDC concernant Swift) justifiées, il est interdit d'utiliser "self" dans une méthode d'init. C'était déjà  le cas en ObjC mais implicitement, sans que cela ne soit empêché explicitement, nous permettant de le faire sans erreur de compilation alors que c'était mal... mais en Swift c'est carrément interdit officiellement par le compilateur pour signaler tout écart à  cette règle.


    Le truc c'est que si l'utilisation prohibée de self dans init() en Swift est totalement justifiée et une bonne idée à  la base (cf les Use-Cases problématiques expliqués dans les confs WWDC à  ce sujet), pour le cas de dynamicType c'est un peu particulier et je pense qu'ils pourraient l'autoriser. Ca vaudrait le coup de remonter un BugReport je pense pour signaler le cas d'usage et demander à  ce que le compilateur fasse une exception pour ce type de cas de réflexion.


    Après, dans tous les autres cas (en dehors d'une méthode d'init, une fois que l'objet est totalement initialisé et donc qu'il est autorisé d'utiliser self), aucun problème pour utiliser self.dynamicType en équivalent d'un [self class] qu'on utiliserait en ObjC. Ca marche très bien ailleurs. C'est juste dans le cas du init à  cause de la restriction d'interdiction d'appeler self avant qu'il ait fini d'être totalement initialisé.

     


    ---



    Je pense que pour ce genre de cas, la solution de Joanna (lazy initialized var) est la plus adaptée, et est même la solution qui est sans doute préconisée par les équipes de Swift dans ce cas (j'ai déjà  vu des exemples Apple ressemblant à  ce type de solution pour des problématiques similaires).


     


    En gros, faire de la propriété "name" une lazy var avec defered initialization, ce qui permet du coup d'utiliser self.dynamicType après l'init grâce au côté lazy + defered init. Ce qui consiste tout simplement non pas à  déclarer "var name: String?" d'un côté et affecter name à  self.dynamicType.defaultName dans le init, mais déclarer + faire une initialisation lazy en même temps via "lazy var name: String? = { return self.dynamicType.defaultName }()".


     


    Finalement c'est rien de + que ça la solution de Joanna, c'est ce que propose Swift pour solutionner ce problème d'init de variable qu'on ne peut faire qu'après / à  l'extérieur du init.


  • JE729JE729 Membre
    août 2014 modifié #12

    Je vais surement diverger un peu du sujet mais pour le coup Swift me paraissait sexy et maintenant je le trouve plus que frustrant


    Je sais pas si c'était vraiment mal mais en tout cas c'était super utile d'utiliser [self class]

    Par exemple, pour les NSWindowController j'aurais aimé avoir la possibilité d'une de ces deux choses : 

     



    // Premier cas impossible à  cause des designated initializer
    class PrefWindowController : NSWindowController {

    override init () {
    super.init(windowNibName: "PrefWindowController")
    }

    }

    // Deuxieme cas impossible car on ne peux pas appeler self.dynamicType avant l'initialisation
    class WindowController : NSWindowController {

    override init () {
    let nibName = self.dynamicType.defaultNibName();
    var window : NSWindow? = nil
    // Extraction depuis le nib
    // .....
    // Puis appel au designated initializer
    super.init(window: window)
    }

    override class func defaultNibName() -> String? {
    println("defaultNibName should be overridden")
    return nil
    }

    }

    class PrefWindowController : NSWindowController {

    override class func defaultNibName() -> String? {
    return "PrefWindow"
    }

    }

    // Solution actuelle
    // Ne pas cacher le nom du fichier nib dans tout le code
    let prefWindowController = PrefWindowController(windowNibName: "PrefWindow")


    Le problème de ce cas la avec le NSWindowController a été de nombreuses fois parlé sur StackOverflow et autres.


    Il est pas hyper grave car la dernière solution fonctionne mais c'est frustrant...


     


    Apres pour les nouveaux objets qu'on écrira, il y aura plus qu'à  tricher comme fait plus haut avec le lazy


  • AliGatorAliGator Membre, Modérateur
    août 2014 modifié #13

    Je ne comprends pas bien pourquoi le premier cas est impossible ? Ca compile pas ?


     


    Pour la 2ème solution, je ne vois pas en quoi l'utilisation du "lazy" est un hack. En fait je dirais plutôt que c'est la solution qu'on utilisait avant en ObjC qui est un hack parce qu'on n'avait pas mieux à  l'époque... (et puis on s'y est tellement habitué qu'on a cru que c'était la norme)


     


    Tu fais juste un "lazy var windowNibName: String? = { return self.className }()" dans ta classe parente, et c'est fini. Et si tu veux que ça soit une autre valeur dans une des sous-classes, tu overrides cette déclaration, ça devrait suffire je pense.


  • @JE729


    Je ne me suis pas vraiment plongé dans Swift mais pour ton N°1 (class PrefWindowController : NSWindowController) si tu ne fournis pas de "designated initializer" et en fonction de ce que disent les règles d'héritages automatique tu ne peux pas tenter un qqchose comme ca ?



    class PrefsWindowController : NSWindowController {

    override convenience init() {
    self.init(windowNibName: "ddd")
    }
    }
  • J'espère ne pas trop me mélanger les pinceaux avec ces histoires de designated et convenience


     


    Cette solution devrait fonctionner en théorie, j'ai une erreur que je comprends pas, j'ai joint un screenshot

     


    Pour le premier cas, comme le designated initializer est initWithWindow: le nouveau designated doit appeler celui de la classe supérieur et donc ne peut pas appeler initWithWindowNibName:

     

    Pour le deuxieme cas, avec la solution du lazy, on obtient bien le nom du nib comme voulu mais trop tard car on a besoin du nom du fichier avant que celui ci soit initialisé car il faut extraire la window pour la passer en argument dans le initWithWindow:

  • AliGatorAliGator Membre, Modérateur


     


    @AliGator


    Pour le premier cas, comme le designated initializer est initWithWindow: le nouveau designated doit appeler celui de la classe supérieur et donc ne peut pas appeler initWithWindowNibName:



    Ah ben oui, mais si tu veux appeler "self.init(windowNibName:)" depuis ton initializer, ça veut dire que cet initializer est un convenience init et pas un designated init.


     


    Le "designated initializer" c'est l'initializer qui fait le gros du boulot et finit par appeler "super".


    Un "convenience initializer" c'est un constructeur de commodité, qui finalement se contente d'appeler un autre constructeur, mais en déterminant en général lui-même la valeur de certains arguments.


     


    Par exemple le designated initializer dans ton cas sera "init(windowNibName:)" puisque c'est lui qui fait tout le boulot et appelle super, et que de tout façon dans la classe mère cet initializer est déjà  le designated init.


    Mais par contre la méthode "init()" tout court, son rôle à  elle c'est juste de te faciliter la vie et de se contenter au final d'appeler in fine "init(windowNibName:)" mais avec le bon argument automatiquement déterminé pour toi, plutôt que d'avoir à  le rentrer à  la main. Donc c'est de la commodité, au final, car il se contente de déterminer des valeurs par défaut et finir par appeler un autre initializer du même objet (self).


     


    Si tu es perdu sur la différence entre les 2, il y a une session WWDC sur Swift qui explique cela plutôt bien, mais c'est aussi assez bien expliqué dans le PDF qu'a publié Apple concernant Swift sur le iBook Store.

  • Je viens tout juste de relire la section du bouquin ^^


    Du coup, d'ou vient l'erreur quand je reste en convenience init(), j'avais joint un screenshot plus haut.(ca semble rien avoir)


  • AliGatorAliGator Membre, Modérateur

    Bonne question




    • Sauf que, pour des raisons de sécurité (expliquées par Apple lors des WWDC concernant Swift) justifiées, il est interdit d'utiliser "self" dans une méthode d'init. C'était déjà  le cas en ObjC mais implicitement, sans que cela ne soit empêché explicitement, nous permettant de le faire sans erreur de compilation alors que c'était mal... mais en Swift c'est carrément interdit officiellement par le compilateur pour signaler tout écart à  cette règle.

     




     


    De quelles sessions WWDC tu parles ? Je suis curieux de voir ce qu'ils ont à  dire sur le sujet.


     


    L'appel à  self dans le init si le init est construit correctement n'est pas franchement un problème.

  • AliGatorAliGator Membre, Modérateur
    Je n'ai plus le numéro de la session en tête mais concrètement un des cas que j'ai retenu est dans le cas où tu appelles une méthode ou propriété de self dans le init avant que toutes les variables soient initialisées, si jamais cette méthode que tu appelles est surchargée dans une sous-classe et que cette surcharge essaye d'accéder à  une variable non initialisée ça peut vite être la cata.


    Il me semble aussi que c'est un peu abordé autour des pages 472 et suivantes du Swift Programming Language Book.
  • Joanna CarterJoanna Carter Membre, Modérateur

    Je n'ai plus le numéro de la session en tête mais concrètement un des cas que j'ai retenu est dans le cas où tu appelles une méthode ou propriété de self dans le init avant que toutes les variables soient initialisées, si jamais cette méthode que tu appelles est surchargée dans une sous-classe et que cette surcharge essaye d'accéder à  une variable non initialisée ça peut vite être la cata.




    ça se trouve en session 403 entre 25:00 et 38:00


  • Je n'ai plus le numéro de la session en tête mais concrètement un des cas que j'ai retenu est dans le cas où tu appelles une méthode ou propriété de self dans le init avant que toutes les variables soient initialisées, si jamais cette méthode que tu appelles est surchargée dans une sous-classe et que cette surcharge essaye d'accéder à  une variable non initialisée ça peut vite être la cata.


    Il me semble aussi que c'est un peu abordé autour des pages 472 et suivantes du Swift Programming Language Book.




     


    Je viens de regarder la session en question (merci Joanna pour la ref).


     


    ça m'étonne de toi Ali mais tu as totalement extrapolé la documentation et les recommandations Apple pour arriver sur une assertion qui est fausse.


     


    Tu dis "il est interdit d'utiliser "self" dans une méthode d'init", c'est totalement faux.


     


    Ce qui est _déconseillé_, c'est d'appeler des getter et des setter qui vont envoyer les willChange et didChange du KVO et potentiellement foutre le bordel vu que l'objet n'est pas initialisé en plein.


     


    Ce qui est également recommandé, c'est de n'appeler que des méthodes tierces qui sont explicitement prévu pour être appelé depuis le init (en clair : réfléchir 5 min à  ce qu'on est en train d'écrire).


     


    L'appel à  self est tout sauf interdit et encore heureux ! Il est nécessaire dans bien des cas, y comrpis dans le designated initializer.


     


    Les exemples montré dans la conférence Swift expliquant que "oh mon dieu, une méthode appelé dans le init peut être surchargé" sont juste complètement aberrant ! Heureusement qu'elles peuvent être surchargé ! Personnellement j'utilise ce genre de pratique à  tout bout de champ pour économiser un maximum de code lorsque je travail sur des système à  plugin (les truc qu'on a pas le droit d'utiliser sur iOS). La seule et unique bonne parade aux problèmes que cela peut poser est très simple : documenter son code.


     


    Swift impose des gardes fou qui sont nécessaire pour forcer les fainéant à  faire leur travail comme il faut. Mais il interdit aussi aux personnes compétentes de faire leur travail. C'est ce que je hais clairement dans ce langage.


     


    Il a des fonctions très avancé, très intéressante, mais putain non, c'est hors de questions que je perde mon temps à  écrire du code inutile pour un compilo paranoà¯aque.


     


    Tout ce merdié est basé sur Clang Analyzer et cie. C'est très pratique en Objective-C de l'avoir à  la demande et en recommandation uniquement. Et heureusement, car dès qu'on tombe sur des cas avancé (mix d'ObjC / C / C++, travail avec des structures, etc.) toutes ces guignoleries sont perdu.


     


    Et pour ma part, tous les projets sur lesquels je bosse finissent toujours avec des truc du genre.


     


    D'ailleurs, des apps aussi débile qu'ARD Inspector (un lecteur de base de donnée chiffré en AES) sont juste impossible à  écrire en Swift. Le langage est tellement limité qu'il est impossible de se servir des décennies d'acquis en C. Si je veux me servir de CommonCrypto en Swift, je suis obliger d'en faire un wrapper Objective-C, quelle efficacité !


     


     


     


     


    Je suis peut être un peu brute de décoffrage sur le sujet, mais le fait que tout le monde dise amen à  un truc aussi mauvais et dangereux me fait peur.


     


    Tout le monde dit "sa s'améliorera avec le temps" / "ils ne peuvent pas couper Objective-C, ils ont trop de code dessus" etc. mais quand on se rappel l'histoire de WebObject et des autres produits tué par Apple pour simple décision de manager alors que le produit se porte extrêmement bien, on ne peut qu'avoir peur.

  • AliGatorAliGator Membre, Modérateur
    août 2014 modifié #23
    Du grand yoann encore à  dire que tout est de la merde dès ça ne lui plait pas, quoi.
  • Joanna CarterJoanna Carter Membre, Modérateur


    L'appel à  self est tout sauf interdit et encore heureux ! Il est nécessaire dans bien des cas, y comrpis dans le designated initializer.




     


    Je te prie m'excuser si je ne t'ai pas bien entendu...


     


    On ne parle pas de Objective-C, C++ ou même C, on parle de Swift, un tout nouveau langage. Ses concepteurs ont décidé d'introduire les nouveaux concepts qui ne sont pas comparables à  ces autres langages, car ces concepts n'étaient pas auparavant réalisable.


     


    Dès que l'arrivée de Swift, il n'est plus nécessaire de faire tous l'initialisation dans l'init, même l'init désigné. On a, désormais, les lazy vars, comme j'ai démontré au-dessus.


     


    Les concepteurs ont également décidé d'introduire des "règles" qui sont là  pour améliorer la fiabilité du code, non parce qu'ils veulent bouleverser le monde mais à  cause des décennies d'experience des problèmes causé par les développeurs qui n'ont pas assez bien entendus ceux qu'ils fassent.


     


    Peut-être tu es exceptionnel en n'ayant pas besoin d'aide à  trouver les petits indiscrétions de logique mais, pendant les 23 dernières années comme développeur, j'ai appris que, le plus que le compilateur puisse me montrer comme source de soucis, le moins de temps je suis obligée de fouiller dans mon code et les docs pour trouver les soucis, souvent cachés, souvent bien obscurs.


     


    Je me trouve parmi eux qui n'aime pas encore l'intégralité de Swift mais j'y trouver pas mal de bonnes idées et, bien que je viens d'avoir 60 ans, je suis contente de continuer à  apprendre les nouveautés que ce langage nous apporte.



  •  


    On ne parle pas de Objective-C, C++ ou même C, on parle de Swift, un tout nouveau langage. Ses concepteurs ont décidé d'introduire les nouveaux concepts qui ne sont pas comparables à  ces autres langages, car ces concepts n'étaient pas auparavant réalisable.


     


    Dès que l'arrivée de Swift, il n'est plus nécessaire de faire tous l'initialisation dans l'init, même l'init désigné. On a, désormais, les lazy vars, comme j'ai démontré au-dessus.


     


     




     


    La vidéo que tu cite prend pour exemple l'Objective-C comme pratique dangereuse justifiant les limitations de Swift.


     


    Quand aux lazy vars, désolé mais on peut le faire en ObjC, faut juste faire son travail de dev au lieu d'espérer que le compilo le fasse pour nous...



  • Du grand yoann encore à  dire que tout est de la merde dès ça ne lui plait pas, quoi.




     


    Si la communauté arrêtait de voir Swift comme un truc génial et prenait 5 min de pause pour mettre ça en perspective avec l'histoire d'Apple, je ne serais peut-être pas autant à  cran sur le sujet.


     


    On va dans un mur et tout le monde est content.


     


    ça me sidère...

  • Que ce soit bien clair, les nouveautés technique de Swift, c'est gentil, ça servira peut être à  certains, ça évitera aux SSII de faire de la merde, et ça donnera du boulot à  tous les formateurs et conférencier pour 10 ans. Moi ça me va coté business.


     


    Ce qui me fait extrêmement peur c'est la connerie qu'Apple est en train de faire vis à  vis d'un marché mature et stable aujourd'hui.


     


    Le système OS X et iOS ne survivra pas à  un nouveau changement de langage. Les petits dev plierons le dos comme ils l'ont toujours fait, mais pas les grosses boites.


     


    Avec autant de fanatisme autour de Swift que ce que l'on voit actuellement (formation sur un truc pas fini, conférence pour dire du vent autour d'un produit pas sorti, etc.), il y a toute les chance pour qu'Apple se lance dans un shift complet vers Swift pour les produits externe. Le résultat sera sans appel : appauvrissement de la plateforme.


  • DrakenDraken Membre
    août 2014 modifié #28
    Et le serpent dit à  la Pomme "Mange le Swift, c'est le fruit de l'arbre de la connaissance". Et la Pomme mangea le fruit empoisonné !
  • AliGatorAliGator Membre, Modérateur
    août 2014 modifié #29


    Si la communauté arrêtait de voir Swift comme un truc génial et prenait 5 min de pause pour mettre ça en perspective avec l'histoire d'Apple, je ne serais peut-être pas autant à  cran sur le sujet.

    J'ai l'impression que c'est toi qui voit ça comme ça.


    Perso j'ai jamais dit que Swift était un truc trop génial et une révolution ni dit amen à  tout ce qu'il y avait autour de Swift. Si tu le vois comme ça, c'est sans doute que tu as un filtre de perception négatif sur le sujet, à  ne voir que le mauvais côté de la chose (pour être tout à  fait franc, ça ne m'étonnerait pas de toi...)


    J'apprécie pas mal de nouveautés de Swift car j'apprécie le renouvellement, les nouvelles idées, ça ouvre des horizons. Un peu comme un débat, je n'ai pas les idées arrêtées et j'apprécie les nouvelles propositions de réflexion autour de nouveaux concepts.

    Je dis pas que toutes les idées sont bonnes ni que tout est parfait, loin de là .

    Mais de là  à  dire à  tout bout de champ que c'est de la grosse merde comme tu le fais, c'est un peu saoulant.


    Que ce soit bien clair, les nouveautés technique de Swift, c'est gentil, ça servira peut être à  certains, ça évitera aux SSII de faire de la merde, et ça donnera du boulot à  tous les formateurs et conférencier pour 10 ans.

    Et encore une fois le "faire de la merde" et cette idée tenace dans ton esprit que tout le monde fait de la merde si on ne fait pas selon ton idée. C'est saoulant comme discours.


    Tu me sembles encore une fois très sectaire et surtout très carré sur ta vision des choses, tout blanc ou tout noir, et pas très ouvert à  la discussion sur le sujet malheureusement. Ou plutôt ouvert à ... hijacker chaque discussion autour de Swift sur le forum pour à  chaque fois ressortir le même terme comme quoi "c'est de la merde"...


    Avec autant de fanatisme autour de Swift que ce que l'on voit actuellement (formation sur un truc pas fini, conférence pour dire du vent autour d'un produit pas sorti, etc.), il y a toute les chance pour qu'Apple se lance dans un shift complet vers Swift pour les produits externe. Le résultat sera sans appel : appauvrissement de la plateforme.

    Encore une vision noire et pessimiste qui t'es si propre... J'en viens presque à  être désolé pour toi que tu ne vois que le côté négatif de choses... Je ne dis pas qu'il faut voir tout tout blanc, Swift est très loin d'être parfait. Mais il ouvre d'autres horizons, pas parfaits mais qui sont intéressants à  considérer. Bref, c'est ni du tout blanc, ni du tout noir, mais de là  à  dire sans cesse que c'est de la merde, c'est saoulant.
  • Hijack plutôt que highjack ;-)
  • Joanna CarterJoanna Carter Membre, Modérateur
    septembre 2014 modifié #31

    Suite à  ma solution originale...


     


    Si on ne voulait pas hériter de NSObject, le code devrait être un peu différent



    class MyObject
    {
    private class var defaultName: String
    {
    return "Untitled"
    }

    lazy var name: String =
    {
    return self.dynamicType.defaultName
    }()

    init() {}

    init(name: String)
    {
    self.name = name
    }
    }

    class SubObject : MyObject
    {
    private override class var defaultName: String
    {
    return "Override"
    }
    }

Connectez-vous ou Inscrivez-vous pour répondre.