Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 2019
-
22 janv. 2008 à 18:05
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 2019
-
28 janv. 2008 à 15:48
Bonjour et bonne année 2008, qu'elle vous soit (oui, à vous P.L., petit lecteur, lol) douce, agréable, et fructueuse (il est encore temps de faire ses veux) ,
J'adapte un code VB6 en VB.NET (et ce n'est pas si simple contrairement à ce que je pensais au départ, ce malgré la simplicité du code VB6 à adapté) le problème étant que je veut lire un fichier de stockage de données ou des structures de donnée on été écrite en binaire bout à bout (non je ne peut pas le modifier, d'autre 'truc' y accède dont des dll C). Problème (comme je m'y attendais) le code si dessous me renvoie l'erreur :
"Binary stream '255' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization."
Forcément puisque mon fichier ne contiens pas d'entête...
Par contre je ne veut pas récupérer un tableau de byte (char) et me cogné oct par oct la conversion vers ma structure (qui est en faite un tableau de structure et mon fichier contient env 2 500 enregistrement à charger, je sent que sa risquerais de prendre un temps infini à l'exécution. Pourtant ce n'est pas très compliqué à faire en théorie ... Je sent
venir la dll ... Décidément plus j'en apprend sur le Dot.Net et moins ça
me plais ...)
Heee svp comment je fait un truc équivalent à ça (c'est du VB6) en Dot.Net
-----------------------------------------------------------------------------------------------------
Private Function LireFichier(ByVal ChemainNomFichier As String) As Boolean
Dim Compteur As Long
Dim NumFichier As Integer
Dim Tampon As MaStructure
'On Error GoTo ErreurLecture
Compteur = 0
NumFichier = FreeFile()
Open ChemainNomFichier For Binary Access Read As NumFichier Len = 128
Get NumFichier, (Compteur * Len(Tampon)) + 1, Tampon
While Not EOF(NumFichier)
ReDim Preserve Fichier(0 To Compteur)
Fichier(Compteur) = Tampon
Compteur = Compteur + 1
Get NumFichier, (Compteur * Len(Tampon)) + 1, Tampon
Wend
Close NumFichier
LireFichierTABCRI = True
Exit Function
ErreurLecture:
Close NumFichier
LireFichierTABCRI = False
End Function
-----------------------------------------------------------------------------------------------------
Mon code qui plante (VB2005) :
-----------------------------------------------------------------------------------------------------
Private Function LireFichier(ByVal ChemainNomFichier As String) As Boolean
Dim Compteur As Long
Dim StreamFichier As System.IO.FileStream
Dim Tampon As MaStructure
Dim Serializer As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
Compteur = 0
StreamFichier = New System.IO.FileStream(ChemainNomFichier, System.IO.FileMode.Open, IO.FileAccess.Read)
While True
Try
Tampon = Serializer.Deserialize(StreamFichier) '<--- C'est la que l'erreur se produit
ReDim Preserve Fichier(0 To Compteur)
Fichier(Compteur) = Tampon
Compteur = Compteur + 1
Catch ex As Exception
Exit While
End Try
End While
StreamFichier.Close()
If Compteur = 0 Then
Return False
Else
Return True
End If
End Function
-----------------------------------------------------------------------------------------------------
NHenry
Messages postés15050Date d'inscriptionvendredi 14 mars 2003StatutModérateurDernière intervention30 mars 2023156 23 janv. 2008 à 10:30
Bonjour
Alors je t'explique le principe de la sérialisation comparé à la méthode utilisée par les autres programmes que tu cites :
1) En .NET, il y a un entête qui permet de déterminer le nom (complet) du type de la déssérialisation (de là il en détermine la taille des données à extraire), la version (pour éviter les surprises du chef), ...
Alors que dans les autres, il n'y a pas cet entête, les données sont mises tel quel et c'est au développeur de se débrouiller pour que ça marche.
2) Les données sont stockée de manière différentes :
En .NET : Les données sont précédé du nom du champ auquel elles sont liées
Autre : Les données sont mises tel quel et si une inversion des champs intervient, tant pis.
Donc si tu veux faire pareil, il existe une méthode, à base de CopyMemory (l'API), et pour définir la structure (là c'est la joie), il faut définir la taille et la position ainsi que le type .NET des champs (pour la syntaxe exacte, convertit un projet VB6 avec une structure d'exemple).
Attention quand même, il peut t'arriver quelques surprises, .NET n'est pas compilé, il est comme Java (sur ce point), il est pseudo compilé et tourne avec un interpréteur, donc il se peut que parfois tu ais quelques pb (si tu te trompe sur la taille de la structure par exemple.
Dans Word, j'Excel. (juste pour la citation)
VB (6, .NET1&2), C++, C#.Net1
Mon site
NHenry
Messages postés15050Date d'inscriptionvendredi 14 mars 2003StatutModérateurDernière intervention30 mars 2023156 23 janv. 2008 à 14:01
Bonjour
En .NET, le Any n'existe plus, mais c'est possible de déclarer le CopyMemory :
A la place de Any, tu met un type (déclaré par toi mme ou du FramWork)
Tu peux déclarer plusieurs fois la fonction exemple :
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Single, ByRef Source As Byte, ByVal Length As Long)
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Byte, ByRef Source As Single, ByVal Length As Long)
Dans Word, j'Excel. (juste pour la citation)
VB (6, .NET1&2), C++, C#.Net1
Mon site
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 20191 23 janv. 2008 à 16:04
La ligne que j'ai posté fonctionne mais (je pense) qu'elle m'affecte de la mémoire (du fait de la présence du "new"), mémoire qui ne me servira jamais à rien. De toute façon il me semble qu'en Dot.Net une tache de font tourne et désaffecte la mémoire qui n'est plus référencé (soit qui n'a plus de nom de variable). Mais il est possible que je me trompe. Merci pour tes idées.
Toujours la même fonction mais avec le calcul de la taille de la structure en plus :
8<-----------------------------------------------------------------------------------------------------------------------------------------------------------
Private
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef
Destination As MaStructure, ByRef Source As Byte, ByVal Length As
Int16) 'La déclaration de l'API (ATTENTION : l'Alias est important ! )
Private Function LireFichier(ByVal ChemainNomFichier As String) As Boolean
Dim Compteur As Long 'Compteur utilisé pour remplire le tableau de structure
Dim NombreDeStructure As Long 'Varable utilisé pour stocké le nombre de structure à extraire
Dim StreamFichier As System.IO.FileStream 'Streameur fichier (ce qui permet de lire le fichier)
Dim TailleDeLaStructure As UInt16 'Variable utilisé pour stocké la taille de la structure
TailleDeLaStructure = System.Runtime.InteropServices.Marshal.SizeOf(New MaStructure) 'Sauvegarde de la taille de la structure
Dim Tampon(0 To TailleDeLaStructure - 1) As Byte 'Le tampon ou les données vont être placé à la lecture (-1 car le tableau commence à 0 et non pas à 1)
Compteur = 0 'Init du compteur si non le complo renvoie un Warning
StreamFichier = New System.IO.FileStream(ChemainNomFichier, System.IO.FileMode.Open, IO.FileAccess.Read) 'L'ouverture du fichier
If StreamFichier.Length Mod TailleDeLaStructure <> 0 Then 'Si le fichier ne contiens pas exactement n fois la structure alors erreur
StreamFichier.Close() 'Ferme le fichier
Return False 'La fonction retourne faux (sous entendu ne fonctionne pas avec ce fichier)
Exit Function 'Quite la fonction
End If
NombreDeStructure = StreamFichier.Length / TailleDeLaStructure 'Sauvegarde du nombre de structure à priorie présente dans le fichier
ReDim Fichier(0 To NombreDeStructure - 1) 'Création du tableau de structure servant à recevoir les données
While Compteur < NombreDeStructure 'Temps que toute les structure n'ont pas été lut
Try 'Gestion d'erreur
StreamFichier.Read(Tampon, 0, TailleDeLaStructure) 'Lit les données et les met dans le tampon
CopyMemory(Fichier(Compteur), Tampon(0), TailleDeLaStructure) 'Copie des données du tampon dans la structure
Compteur = Compteur + 1 'Incrémentation du compteur de boucle
Catch ex As Exception 'Si une erreur se déclenche dans le block Try Catch
StreamFichier.Close() 'Ferme le fichier
Return False 'Retourne faux
Exit Function 'Quite la fonction
End Try 'Fin de la gestion d'erreur
End While 'Fin de la boucle
StreamFichier.Close() 'Ferme le fichier
Return True 'Retourne Vrais (sous entendu tout c'est passé correctement)
End Function 'Fin de la fonction
----------------------------------------------------------------------------------------------------------------------------------------------------------->8
Remarque : Cette fonction à pour objectif d'être insérer dans un module de classe si vous souaitez la mettre dans un module je conseil d'ajouté dans les variable passé à la fonction le tableau de structure (nomé ici Fichier) à fin d'éviter les variables globales. Comme ça : "Private Function LireFichier(ByVal ChemainNomFichier As String, ByRef Fichier() As MaStructure) As Boolean" et pouf, tout fonctionneras bien (Attention néanmoins, le contenu de la variable Fichier sera perdu à l'exécution de cette fonction)
Amicalement
Pensez "Réponse acceptée"
Vous n’avez pas trouvé la réponse que vous recherchez ?
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 20191 28 janv. 2008 à 15:48
J'ai hue à lire un fichier binaire mais cette fois contenant d'autre structure. Bà, ce fut difficile. Pour info je poste ma résolution (ça serviras sans doute à quelqu'un un jours) :
J'ai fini par trouvé une solution
(Je ne l'es trouvé nul part donc je diffuse le même post un peut
partout, ou le sujet semble être lié au problème que j'ai rencontré
quand même)
Attention ça ne fonctionneras pas dans tout les cas, à moins de l'adapter à mort...
La déclaration de chaine de longueur fixe (qui ne fonctionne que dans le cas ci-dessous, tout du moins dans mes test) :
Il faut cette déclaration dans une structure simple (soit dans une structure ne contenant pas d'autre structure)
Mon objectif été de lire dans un fichier binaire des données écrite
avec la méthode put de VB6 et de les chargé dans une structure complexe
(j'entends par là contenant d'autre structures)
Méthode :
1) Déclaration de mes structures et variables comme d'habitude
2) Déclaration de nouvelle structure simple basé sur le même schéma que les structure complexe mais sans les sous structures
3) Lecture du fichier en placent les données dans un tableau de byte (mentionnés pour contenir le bon nombre de données)
4) Copie des données grâce à CopyMemory (ou sans doute marchal.copy
mais je n'es pas fait de test avec, donc à valider) dans les structures
simples.
5) Copie des structure simple dans les structure complexe.
Bon je suis conscient que ça peut paraitre obscure je mes donc un exemple.
8<----------------------------------------------------------------------------------------------------
Private Declare Sub CopyMemory Lib "kernel32" Alias
"RtlMoveMemory" (ByRef Destination As S_Simple, ByRef Source As Byte,
ByVal Length As Int16)
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory"
(ByRef Destination As S_Creation, ByRef Source As Byte, ByVal Length As
Int16)
TailleTotalDeLaStructure = TailleRacine + (TailleNiveau1 * C_NbSousStrucutre) 'Sauvegarde de la taille de la structure
Dim Tampon(0 To TailleTotalDeLaStructure - 1) As Byte 'Le
tampon ou les données vont être placé à la lecture (-1 car le tableau
commence à 0 et non pas à 1)
Compteur = 0 'Init du compteur si non le complo renvoie un Warning
StreamFichier = New System.IO.FileStream(ChemainNomFichier,
System.IO.FileMode.Open, IO.FileAccess.Read) 'L'ouverture du fichier
NombreDeStructure = StreamFichier.Length /
TailleTotalDeLaStructure 'Sauvegarde du nombre de structure à priorie
présente dans le fichier
ReDim DonneesFichier(0 To NombreDeStructure - 1) 'Création du tableau de structure servant à recevoir les données
While Compteur < NombreDeStructure 'Temps que toute les structure n'ont pas été lut
Try 'Gestion d'erreur
Dim Position As UInt16
StreamFichier.Read(Tampon, 0, TailleTotalDeLaStructure) 'Lit les données et les met dans le tampon
CopyMemory(ConstruitRacine, Tampon(0), TailleRacine) 'Copie des données du tampon dans la structure
For CompteurMaj As UInt16 = 0 To C_NbSousStrucutre - 1
CopyMemory(ConstruitNiveau1(CompteurMaj),
Tampon(TailleRacine + TailleNiveau1 * CompteurMaj), TailleNiveau1)
'Copie des données du tampon dans la structure
Si la sous structure avais par exemple été entre "Chaine" et "Valeur" il aurais fallut ajouté encore une étape à la lecture.
1) CopyMemory de "Chaine"
2) CopyMemory des sous structure
3) CopyMemory de "Valeur"
(et sans doute une variable qui sauvegarde la position courante dans le tampon)
Voila j'espère avoir été claire. Mais franchement sur ce coup Microbof ne cherche vraiment pas à nous arrangé.
ATTENTION : Je parle ici de lecture d'un fichier binaire qui aurais été
crée et/ou encore utilisé par d'autre programme si non il existe des
méthode "BinaryFormatter.Serialize" et "BinaryFormatter.Deserialize"
simple à utilisé mais qui insère une entête de fichier contenant le
type et la version de ce qui à été sauvegarder. Il n'est donc pas
possible de lire avec ces méthode si l'entête est absent. De plus le
développeur n'a plus complètement les main libre sur la façon dont ses
données seront sauvegarder.
BruNews
Messages postés21041Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 22 janv. 2008 à 22:40
Tu parles de temps d'exécution et je vois 'Redil Preserve' dans une boucle...
Regarde la taille du fichier avant de boucler et dimensionne ton tableau 1 seule fois avant la boucle.
Désolé pour .NET, je n'y connais rien.
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 20191 23 janv. 2008 à 10:20
Coucou et merci de vous occupé de mon problème,
Effectivement BruNews tu à totalement réson par rapport au "redim preserve" dans la boucle , merci je vais faire la pitite modif .
NHenry : Mon fichier de données est un 'vieux truc' qu'utilise le programme que je fait évoluer (il à été crée, et est toujours utilisé par du code C et Fortran). Mon objectif est de charger ces données, effectuer des traitement dessus, modifié les données en fonction de mes résultats, et réécrit ce dit fichier (je n'en suis qu'au chargement de données pour le moment)
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 20191 23 janv. 2008 à 10:52
Renfied :
En faite ça ne m'aide pas vraiment pour mon problème ici présent, mais je suis sure que ça pourra me servir un de ces jours, je me met le lient sous le coude (il commence à en y avoir beaucoup sous mon coude et c'est temps mieux ).
Merci quand même
NHenry :
Oki merci bien
Si je comprend bien je lit le fichier en mettant mes données dans un tableau d'octet (char) puis j'utilise CopyMemory pour mettre ces données dans ma structure (pour la déclaration de la structure j'ai déjà fait le nécessaire, enfin je crois ). Je le fait, puis je test, et répond (en collant mon code si ça fonctionne ).
BruNews
Messages postés21041Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 23 janv. 2008 à 12:09
Dans tous les cas si vraiment il faut des perfs, faut exclure .NET à tout coup.
Comme expliqué plus haut, impossible de lire direct dans des structures sans faire des CopyMemory (tu auras le temps de boire un café tranquille).
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 20191 23 janv. 2008 à 13:51
BruNews :
Merci de l'info mais je sait que le VB.NET n'est pas l'idéale au niveau perf (loooiiinnn de là, pire que le VB6 à ce que j'ai entendu. VB6 qui été déjà nul niveau perf comparer au C ou C++) mais j'essaie de ne pas en rajouté avec un développement qui ferais des truc à la co_ (du style de mon 'redim preserve' dans la boucle au début ).
Heeee par contre tu laisse entendre que CopyMemory n'es pas top niveau perf ??? Je pensais le contraire (moi je voilais cette fonction comme un bout ce code C/C++ qui récup une adrs et la copie à l'ards de destination, et ça en C/C++ c'est plus que rapide, enfin il me semble)
NHenry :
Haaaa (en fait je commence à vouloir la mort de Dot.Net, je m'explique). Je n'arrive pas à déclarer l'API "CopyMemory" dans VB.NET (le type Any n'existe plus, mais ça ce n'est pas nouveau) du coup je tente pour la première fois de faire un "Marshal.Copy" (ou "Marshal.PtrToStructure") et c'est fout comme l'utilisation de cette saleté est simple et est bien expliqué (ironie)... Quoi que je tente j'ai l'erreur "Overload resolution failed [...]" avec "Copy" et je n'arrive pas à récupérer l'adrs de mon Tampon (mon tableau de byte) vue que "IntPtr.ToPointer" ne fonctionne pas en VB2005 (il me semblais que VB2005 été parfaitement équivalents au C#... Encore un bon point pour le VB2005)...
BruNews
Messages postés21041Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 23 janv. 2008 à 14:05
C'est l'APPEL CopyMemory qui est une calamité (et en boucle on n'en parle même pas).
C/C++ n'est bien entendu pas concerné par cela, le compilo met memcpy inline direct dans le code sans aucun appel externe.
do {*pdst++ = *psrc++;} while(--len);
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 20191 23 janv. 2008 à 14:26
BruNews :
Merci pour l'info
NHenry :
Heee voila autre chose... Ma déclaration :
Private Declare Sub CopyMemory Lib "kernel32" (ByRef Destination As Object, ByRef Source As Byte, ByVal Length As Integer)
Quand je cherche à l'utilisé (comme ça : "CopyMemory(Fichier(Compteur), Tampon(0), 128)") je récupérè l'erreur "System.EntryPointNotFoundException" ??? Ça veut dire que VB2005 ne trouve pas la procédure CopyMemory dans kernel32 ou autre chose parce que là je commence à sérieusement en avoir ras le bol (plus d'une demis journée pour lire une structure dans un fichier... Sois je suis complètement nul en développement, alors que je me croyais juste pas doué, lol, et dans ce cas il faut que je change d'emploi très rapidement soit ça viens de VB2005 et je vais alerter ma hiérarchie qu'on fout dehors cette saleté et qu'on repasse sous VB6)
Aller je m'acharne encore un peut avant les solution radicale évoquer plus haut...
Amicalement
Pensez "Réponse acceptée"
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 20191 23 janv. 2008 à 14:40
Heee oui effectivement "as object" pourquois ??? Je commence sans doute à fatigué (qui à dit "la bonne excuse" ? lol). Avec ma structure dans la déclaration j'ai toujours la même erreur ??? Par contre tu dit 'IDE VB 2005' pourquois IDE ??? (Si non je suis aussi sous XP Pro SP2)
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 20191 23 janv. 2008 à 15:21
CA MARCHE !!! C'est fout mais c'est vrais !!!
J'ai simplement ajouté {Alias "RtlMoveMemory"} à ma déclaration... Je n'est pas du bien comprendre la déclaration des API. Le nom de la fonction dans la dll c'est quoi exactement "CopyMemory" ou "RtlMoveMemory" ?
Ma fonction qui fonctionne (pour du vrais en plus, j'ai vérif les données récupérés. Avec un max de commentaire comme ça j'espère que d'autre n'auront pas à se faire chi__ comme moi aujourd'hui) :
8<----------------------------------------------------------------------------------------------
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As MaStructure, ByRef Source As Byte, ByVal Length As Int16) 'La déclaration de l'API (ATTENTION : l'Alias est important)
Private Function LireFichier(ByVal ChemainNomFichier As String) As Boolean
Dim Compteur As Long 'Compteur utilisé pour remplire le tableau de structure
Dim NombreDeStructure As Long 'Varable utilisé pour stocké le nombre de structure à extraire
Dim StreamFichier As System.IO.FileStream 'Streameur fichier (ce qui permet de lire le fichier)
Dim Tampon(0 To 127) As Byte 'Le tampon ou les données vont être placé app la lecture
Compteur = 0 'Init du compteur si non le complo renvoie un Warning
StreamFichier = New System.IO.FileStream(ChemainNomFichier, System.IO.FileMode.Open, IO.FileAccess.Read) 'L'ouverture du fichier
If StreamFichier.Length Mod 128 <> 0 Then 'Si le fichier ne contiens pas exactement n fois la structure alors erreur
StreamFichier.Close() 'Ferme le fichier
Return False 'La fonction retourne faux (sous entendu ne fonctionne pas avec ce fichier)
Exit Function 'Quite la fonction
End If
NombreDeStructure = StreamFichier.Length / 128 'Sauvegarde du nombre de structure à priorie présente dans le fichier
ReDim Fichier(0 To NombreDeStructure - 1) 'Création du tableau de structure servant à recevoir les données
While Compteur < NombreDeStructure 'Temps que toute les structure n'ont pas été lut
Try 'Gestion d'erreur
StreamFichier.Read(Tampon, 0, 128) 'Lit les données et les met dans le tampon
CopyMemory(Fichier(Compteur), Tampon(0), 128) 'Copie des données du tampon dans la structure
Compteur = Compteur + 1 'Incrémentation du compteur de boucle
Catch ex As Exception 'Si une erreur se déclenche dans le block Try Catch
StreamFichier.Close() 'Ferme le fichier
Return False 'Retourne faux
Exit Function 'Quite la fonction
End Try 'Fin de la gestion d'erreur
End While 'Fin de la boucle
StreamFichier.Close() 'Ferme le fichier
Return True 'Retourne Vrais (sous entendu tout c'est passé correctement)
End Function 'Fin de la fonction
---------------------------------------------------------------------------------------------->8
Une derniers toute petite question et je vous laisse tranquille (déjà MERCI mille fois)
Comment récupérer la taille en oct de ma structure parceque j'ai peur que la ligne ci dessous ne m'affecte de la mémoire pour rien :
System.Runtime.InteropServices.Marshal.SizeOf(New MaStructure)
Amicalement
Pensez "Réponse acceptée"
NHenry
Messages postés15050Date d'inscriptionvendredi 14 mars 2003StatutModérateurDernière intervention30 mars 2023156 23 janv. 2008 à 15:34
Bonjour
Je n'ai jamais eu besoin de ce genre de chose en .NET.
Je te propose :
- Tu utilises la taille fournie à partir des autres prog
- Tu calcul la taille par toi même
Mais normalement la ligne que tu utilises devrais fonctionner.
dsl.
Dans Word, j'Excel. (juste pour la citation)
VB (6, .NET1&2), C++, C#.Net1
Mon site
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 20191 23 janv. 2008 à 17:27
Hooo
Je viens de faire un test supplémentaire (avec un fichier volontairement plus gros que celui qui sera réellement utilisé) et ce code extrais 35 000 structure de données en 406 mili-seconde en débug !!! Loin d'être lente cette pitite fonction dit donc !!!