io4it 2.1.0.1__tar.gz → 2.1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- io4it-2.1.0.2/PKG-INFO +33 -0
- io4it-2.1.0.2/io4it.egg-info/PKG-INFO +33 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/io4it.egg-info/requires.txt +1 -1
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/utils/offuscation_basique.py +123 -16
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/OWExportMarkdown.py +2 -2
- io4it-2.1.0.2/orangecontrib/IO4IT/widgets/OWMarkdownizer.py +652 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/OWS3Uploader.py +1 -1
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/OWmailLoader.py +3 -2
- io4it-2.1.0.2/orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui +51 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/setup.py +2 -2
- io4it-2.1.0.1/PKG-INFO +0 -7
- io4it-2.1.0.1/io4it.egg-info/PKG-INFO +0 -7
- io4it-2.1.0.1/orangecontrib/IO4IT/widgets/OWMarkdownizer.py +0 -563
- io4it-2.1.0.1/orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui +0 -59
- {io4it-2.1.0.1 → io4it-2.1.0.2}/io4it.egg-info/SOURCES.txt +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/io4it.egg-info/dependency_links.txt +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/io4it.egg-info/entry_points.txt +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/io4it.egg-info/namespace_packages.txt +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/io4it.egg-info/top_level.txt +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/__init__.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/ocr_function/__init__.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/ocr_function/word_converter.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/utils/__init__.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/utils/mail.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/OWChatGpt.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/OWDeep_Search.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/OWS3downloader.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/OWS3list.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/OWSpeechToText.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/OWmailSender.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/OWwordpdf2docx.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/__init__.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/__init__.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/chart.html +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/nogui.ui +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/ow_file_ext_selector.ui +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/owchatgpt.ui +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/owdeepsearch.ui +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/owmailloader.ui +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/owmailsender.ui +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/owmarkdownizer.ui +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/owspeechtotext.ui +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/owvisualizationer.ui +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/designer/wordpdf2docx.ui +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/__init__.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/chatgpt.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/deepsearch.svg +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/download.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/export_md.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/file_extensor.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/list_aws.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/mail_loader.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/mail_writer.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/md.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/speech_to_text.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/upload.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/visualizationer.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons/wordpdf2docx.png +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/IO4IT/widgets/icons_dev/__init__.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/orangecontrib/__init__.py +0 -0
- {io4it-2.1.0.1 → io4it-2.1.0.2}/setup.cfg +0 -0
io4it-2.1.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: io4it
|
|
3
|
+
Version: 2.1.0.2
|
|
4
|
+
Summary: UNKNOWN
|
|
5
|
+
Home-page:
|
|
6
|
+
Author:
|
|
7
|
+
Author-email:
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Keywords: orange3 add-on
|
|
10
|
+
Platform: UNKNOWN
|
|
11
|
+
Requires-Dist: pylatexenc
|
|
12
|
+
Requires-Dist: docopt
|
|
13
|
+
Requires-Dist: boto3
|
|
14
|
+
Requires-Dist: opencv-python-headless==4.6.0.66
|
|
15
|
+
Requires-Dist: docling==2.30.0
|
|
16
|
+
Requires-Dist: docling-core==2.26.3
|
|
17
|
+
Requires-Dist: speechbrain
|
|
18
|
+
Requires-Dist: whisper
|
|
19
|
+
Requires-Dist: whisper-openai
|
|
20
|
+
Requires-Dist: pyannote.audio
|
|
21
|
+
Requires-Dist: pyannote-core
|
|
22
|
+
Requires-Dist: pypandoc
|
|
23
|
+
Requires-Dist: pypandoc-binary
|
|
24
|
+
Requires-Dist: scikit-learn
|
|
25
|
+
Requires-Dist: openai
|
|
26
|
+
Requires-Dist: pip-system-certs==5.0
|
|
27
|
+
Requires-Dist: docx2pdf
|
|
28
|
+
Requires-Dist: doc2docx
|
|
29
|
+
Requires-Dist: msal
|
|
30
|
+
Requires-Dist: exchangelib
|
|
31
|
+
Requires-Dist: CATEGORIT
|
|
32
|
+
|
|
33
|
+
UNKNOWN
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: io4it
|
|
3
|
+
Version: 2.1.0.2
|
|
4
|
+
Summary: UNKNOWN
|
|
5
|
+
Home-page:
|
|
6
|
+
Author:
|
|
7
|
+
Author-email:
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Keywords: orange3 add-on
|
|
10
|
+
Platform: UNKNOWN
|
|
11
|
+
Requires-Dist: pylatexenc
|
|
12
|
+
Requires-Dist: docopt
|
|
13
|
+
Requires-Dist: boto3
|
|
14
|
+
Requires-Dist: opencv-python-headless==4.6.0.66
|
|
15
|
+
Requires-Dist: docling==2.30.0
|
|
16
|
+
Requires-Dist: docling-core==2.26.3
|
|
17
|
+
Requires-Dist: speechbrain
|
|
18
|
+
Requires-Dist: whisper
|
|
19
|
+
Requires-Dist: whisper-openai
|
|
20
|
+
Requires-Dist: pyannote.audio
|
|
21
|
+
Requires-Dist: pyannote-core
|
|
22
|
+
Requires-Dist: pypandoc
|
|
23
|
+
Requires-Dist: pypandoc-binary
|
|
24
|
+
Requires-Dist: scikit-learn
|
|
25
|
+
Requires-Dist: openai
|
|
26
|
+
Requires-Dist: pip-system-certs==5.0
|
|
27
|
+
Requires-Dist: docx2pdf
|
|
28
|
+
Requires-Dist: doc2docx
|
|
29
|
+
Requires-Dist: msal
|
|
30
|
+
Requires-Dist: exchangelib
|
|
31
|
+
Requires-Dist: CATEGORIT
|
|
32
|
+
|
|
33
|
+
UNKNOWN
|
|
@@ -2,6 +2,9 @@ import os
|
|
|
2
2
|
import json
|
|
3
3
|
import hashlib
|
|
4
4
|
import getpass
|
|
5
|
+
from cryptography.fernet import Fernet
|
|
6
|
+
import base64
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
|
|
7
10
|
from Orange.widgets.orangecontrib.AAIT.utils import MetManagement
|
|
@@ -47,12 +50,26 @@ def get_keys_dir(type_key: str = "MICROSOFT_EXCHANGE_OAUTH2") -> str:
|
|
|
47
50
|
if os.path.basename(base) != "keys":
|
|
48
51
|
base = os.path.join(base, "keys")
|
|
49
52
|
dossier = os.path.normpath(os.path.join(base, type_key))
|
|
50
|
-
print("dossier", dossier)
|
|
51
53
|
os.makedirs(dossier, exist_ok=True)
|
|
52
54
|
return dossier
|
|
53
55
|
except Exception as e:
|
|
54
56
|
raise RuntimeError(f"Erreur création/récupération dossier : {e}")
|
|
55
57
|
|
|
58
|
+
def get_fernet_key() -> bytes:
|
|
59
|
+
"""
|
|
60
|
+
Dérive une clé Fernet (32 octets base64) à partir du nom d'utilisateur local.
|
|
61
|
+
"""
|
|
62
|
+
username = getpass.getuser().encode("utf-8")
|
|
63
|
+
digest = hashlib.sha256(username).digest()
|
|
64
|
+
return base64.urlsafe_b64encode(digest[:32]) # 32 bytes en base64
|
|
65
|
+
|
|
66
|
+
def encrypt_secure(data: str) -> str:
|
|
67
|
+
fernet = Fernet(get_fernet_key())
|
|
68
|
+
return fernet.encrypt(data.encode("utf-8")).decode("utf-8")
|
|
69
|
+
|
|
70
|
+
def decrypt_secure(data: str) -> str:
|
|
71
|
+
fernet = Fernet(get_fernet_key())
|
|
72
|
+
return fernet.decrypt(data.encode("utf-8")).decode("utf-8")
|
|
56
73
|
|
|
57
74
|
|
|
58
75
|
# GSTION IMAP
|
|
@@ -160,6 +177,83 @@ def enregistrer_config_owa(mail,alias,server,username,password,interval):
|
|
|
160
177
|
print(f"❌ Erreur lors de l'enregistrement : {e}")
|
|
161
178
|
return 1
|
|
162
179
|
|
|
180
|
+
def enregistrer_config_owa_secure(mail, alias, server, username, password, interval):
|
|
181
|
+
try:
|
|
182
|
+
dossier = get_keys_dir("MICROSOFT_EXCHANGE_OWA_SECURE")
|
|
183
|
+
os.makedirs(dossier, exist_ok=True)
|
|
184
|
+
|
|
185
|
+
mdp_chiffre = encrypt_secure(password)
|
|
186
|
+
|
|
187
|
+
nom_fichier = os.path.join(dossier, f"{alias.replace('@', '_at_')}.json")
|
|
188
|
+
|
|
189
|
+
contenu = {
|
|
190
|
+
"mail": mail,
|
|
191
|
+
"alias": alias,
|
|
192
|
+
"server": server,
|
|
193
|
+
"username": username,
|
|
194
|
+
"password_encrypted": mdp_chiffre,
|
|
195
|
+
"interval_second": interval
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
with open(nom_fichier, "w", encoding="utf-8") as f:
|
|
199
|
+
json.dump(contenu, f, indent=4)
|
|
200
|
+
|
|
201
|
+
print(f"✅ Fichier OWA sécurisé enregistré : {nom_fichier}")
|
|
202
|
+
return 0
|
|
203
|
+
|
|
204
|
+
except Exception as e:
|
|
205
|
+
print(f"❌ Erreur d'enregistrement sécurisé OWA : {e}")
|
|
206
|
+
return 1
|
|
207
|
+
|
|
208
|
+
def enregistrer_config_cli_owa_secure():
|
|
209
|
+
print("\n🔐 Écriture fichier OWA avec chiffrement sécurisé :")
|
|
210
|
+
mail = input("📧 Mail (nom@domain.com) : ").strip()
|
|
211
|
+
alias = input("📛 Alias (visible) : ").strip()
|
|
212
|
+
server = input("🌐 Server : ").strip()
|
|
213
|
+
username = input("👤 Username (domain\\user) : ").strip()
|
|
214
|
+
password = input("🔑 Password (non masqué) : ").strip()
|
|
215
|
+
interval = int(input("⏱️ Interval (secondes) : ").strip())
|
|
216
|
+
if alias == "''" or alias == "\"\"" or alias == "":
|
|
217
|
+
alias = mail
|
|
218
|
+
|
|
219
|
+
if 0 != enregistrer_config_owa_secure(mail, alias, server, username, password, interval):
|
|
220
|
+
print("❌ Erreur lors de enregistrer_config_owa_secure !")
|
|
221
|
+
|
|
222
|
+
def lecture_config_cli_owa_secure():
|
|
223
|
+
fichier = input("📄 Nom du fichier JSON (sans chemin) : ").strip()
|
|
224
|
+
cfg = lire_config_owa_secure(fichier)
|
|
225
|
+
|
|
226
|
+
if cfg is None:
|
|
227
|
+
print("❌ Erreur")
|
|
228
|
+
return
|
|
229
|
+
|
|
230
|
+
print(f"\n📧 mail : {cfg[0]}")
|
|
231
|
+
print(f"📛 alias : {cfg[1]}")
|
|
232
|
+
print(f"🌐 server : {cfg[2]}")
|
|
233
|
+
print(f"👤 username : {cfg[3]}")
|
|
234
|
+
print(f"🔑 password : {cfg[4]}")
|
|
235
|
+
print(f"⏱️ intervalle : {cfg[5]}s")
|
|
236
|
+
|
|
237
|
+
def lire_config_owa_secure(chemin_fichier):
|
|
238
|
+
try:
|
|
239
|
+
chemin_fichier = os.path.join(get_keys_dir("MICROSOFT_EXCHANGE_OWA_SECURE"), chemin_fichier)
|
|
240
|
+
with open(chemin_fichier, "r", encoding="utf-8") as f:
|
|
241
|
+
contenu = json.load(f)
|
|
242
|
+
|
|
243
|
+
mdp_dechiffre = decrypt_secure(contenu["password_encrypted"])
|
|
244
|
+
|
|
245
|
+
return [
|
|
246
|
+
contenu["mail"],
|
|
247
|
+
contenu["alias"],
|
|
248
|
+
contenu["server"],
|
|
249
|
+
contenu["username"],
|
|
250
|
+
mdp_dechiffre,
|
|
251
|
+
int(contenu["interval_second"])
|
|
252
|
+
]
|
|
253
|
+
|
|
254
|
+
except Exception as e:
|
|
255
|
+
print(f"❌ Erreur de lecture sécurisée OWA : {e}")
|
|
256
|
+
return None
|
|
163
257
|
|
|
164
258
|
|
|
165
259
|
# Fonction pour lire le fichier de configuration et déchiffrer le mot de passe
|
|
@@ -357,21 +451,28 @@ def lire_config_api(service_name):
|
|
|
357
451
|
def enregistrer_config_cli_api():
|
|
358
452
|
print("\n📝 Écriture d’une clé API :")
|
|
359
453
|
service = input("🔖 Nom du service : ").strip()
|
|
360
|
-
api_key =
|
|
454
|
+
api_key = input("🔑 Clé API : ").strip()
|
|
361
455
|
desc = input("✏️ Description : ").strip()
|
|
362
456
|
if 0 != enregistrer_config_api(service, api_key, desc):
|
|
363
457
|
print("erreur!")
|
|
364
458
|
|
|
365
|
-
def lire_config_cli_api():
|
|
366
|
-
service
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
print(f"
|
|
459
|
+
def lire_config_cli_api(service=""):
|
|
460
|
+
if service == "":
|
|
461
|
+
service = input("🔖 Nom du service : ").strip()
|
|
462
|
+
try:
|
|
463
|
+
cfg = lire_config_api(service)
|
|
464
|
+
if cfg is None:
|
|
465
|
+
print("erreur")
|
|
466
|
+
return
|
|
467
|
+
print(f"\n📄 service : {cfg['service']}")
|
|
468
|
+
print(f"🔑 clé API : {cfg['api_key']}")
|
|
469
|
+
if cfg['description']:
|
|
470
|
+
print(f"📝 description : {cfg['description']}")
|
|
471
|
+
return cfg['api_key']
|
|
472
|
+
except Exception as e:
|
|
473
|
+
print(f"❌ Erreur lors de la lecture : {e}")
|
|
474
|
+
return None
|
|
475
|
+
|
|
375
476
|
|
|
376
477
|
|
|
377
478
|
# Gestion d’éléments de nxp (DOSSIER_NODE_ID, SERVEUR, USERNAME, PASSWORD) (HARD dossier aait_store/keys)
|
|
@@ -458,8 +559,6 @@ def lire_config_cli_nxp():
|
|
|
458
559
|
print(f"📝 description : {cfg['description']}")
|
|
459
560
|
|
|
460
561
|
|
|
461
|
-
|
|
462
|
-
|
|
463
562
|
if __name__ == "__main__":
|
|
464
563
|
print("1) ecrire fichier IMAP4_SSL")
|
|
465
564
|
print("2) dechiffer fichier IMAP4_SSL")
|
|
@@ -471,7 +570,10 @@ if __name__ == "__main__":
|
|
|
471
570
|
print("8) Déchiffrer fichier Microsoft Exchange (OWA)")
|
|
472
571
|
print("9) Écrire fichier Microsoft Exchange (OAuth2)")
|
|
473
572
|
print("10) Déchiffrer fichier Microsoft Exchange (OAuth2)")
|
|
474
|
-
|
|
573
|
+
print("11) Écrire fichier Microsoft Exchange (OWA) [SECURE]")
|
|
574
|
+
print("12) Déchiffrer fichier Microsoft Exchange (OWA) [SECURE]")
|
|
575
|
+
|
|
576
|
+
choix = input("👉 Que faire ? [1-12] : ").strip()
|
|
475
577
|
|
|
476
578
|
if choix == "1":
|
|
477
579
|
enregistrer_config_cli_imap4_ssl()
|
|
@@ -492,7 +594,12 @@ if __name__ == "__main__":
|
|
|
492
594
|
elif choix=="9":
|
|
493
595
|
enregistrer_config_cli_oauth2()
|
|
494
596
|
elif choix=="10":
|
|
495
|
-
|
|
597
|
+
lire_config_cli_oauth2()
|
|
598
|
+
elif choix == "11":
|
|
599
|
+
enregistrer_config_cli_owa_secure()
|
|
600
|
+
elif choix == "12":
|
|
601
|
+
lecture_config_cli_owa_secure()
|
|
602
|
+
|
|
496
603
|
|
|
497
604
|
else:
|
|
498
605
|
print("❌ Choix invalide. Réessayez.\n")
|
|
@@ -165,7 +165,7 @@ class OWExportMarkdown(widget.OWWidget):
|
|
|
165
165
|
|
|
166
166
|
try:
|
|
167
167
|
# DOCX
|
|
168
|
-
pypandoc.convert_file(tmp_md, to="docx", outputfile=docx_out)
|
|
168
|
+
pypandoc.convert_file(tmp_md, to="docx", format="gfm-yaml_metadata_block", outputfile=docx_out)
|
|
169
169
|
self.ajouter_en_tete_pied_docx(
|
|
170
170
|
docx_out,
|
|
171
171
|
"Rapport - Orange AI",
|
|
@@ -173,7 +173,7 @@ class OWExportMarkdown(widget.OWWidget):
|
|
|
173
173
|
)
|
|
174
174
|
|
|
175
175
|
# PPTX
|
|
176
|
-
pypandoc.convert_file(tmp_md, to="pptx", outputfile=pptx_out)
|
|
176
|
+
pypandoc.convert_file(tmp_md, to="pptx", format="gfm-yaml_metadata_block", outputfile=pptx_out)
|
|
177
177
|
self.ajouter_entete_pied_pptx(
|
|
178
178
|
pptx_out,
|
|
179
179
|
"Orange AI – Présentation",
|