Affichage des articles dont le libellé est WLangage. Afficher tous les articles
Affichage des articles dont le libellé est WLangage. Afficher tous les articles

mercredi, mars 19, 2014

WEBDEV 19 - Intégration d'une gallerie d'image avec JQuery

On trouve beaucoup de de gallerie d'image sur le web. La plus part utilise JQuery et d'autres bibliothèques JavaScript.
J'ai choisi "Galleria", une version demo est téléchargeable sur le le site http://galleria.io/

Pour intégrer la gallerie d'image "galleria" dans WEBDEV 19, il faut commencer par télécharger sur le site de galleria le zip : galleria-1.3.5.zip. il contient les JS, CSS et une page HTML de démo.

mettre dans le répertoire _WEB/FR/gallerie , les fichiers suivants :



Dans WEBDEV, mettre un champ HTML puis dans le d'initialisation de la page :


ensuite mettre le code HTML de la demo de galleria

en fait il faut mettre tout le contenu de la div "galleria" du fichier classic-demo.html

Pour finir mettre dans le code navigateur de chargement de la page (onload) l'appel de la fonction initialise() qui faut déclarer en procédure local navigateur (code en JS) :

function initialise()
{
// Load the classic theme
Galleria.loadTheme('./gallerie/galleria.classic.min.js');

// Initialize Galleria
Galleria.run('#galleria', {
height: parseInt($('#galleria').css('height')),
wait: true
});
}

Il reste plus qu'à personnaliser le code HTML du champ HTML.

Modèle de champ avec Menu contextuel

Dans un modèle de champ si vous ajoutez un menu contextuel, ce dernier sera copié dans la fenêtre lors de l'insertion de champ modèle de champs. Or lorsque l'on supprime ce champ modèle de champ, le menu contextuel n'est pas supprimé de la fenêtre par conséquent, dans certain cas, des erreurs de compilation peuvent apparaître sur des variables globales du modèle champ.

Astuce, dans le menu contextuel, dans le code des options de menu, ne pas utiliser directement les variables globales du modèle. Il faut mieux faire l'appel du procédure local au modèle qui effectuera le traitement.

En cas de suppression du modèle de champs dans la fenêtre, ne pas oublier du supprimer également le menu contextuel.

mercredi, février 12, 2014

Variables de type date et heure initialisées avec la date et heure du jour !!!

Avant une variable date ne contenait rien lors de la déclaration. J'en ai eu marre d'avoir mes variables de type date et heure initialisées avec la date et heure du jour, j'ai donc cherché et j'ai trouvé la fonction du va bien : DateHeureParDéfaut

Permet de définir la valeur par défaut des variables de type Date, Heure, et DateHeure (dixit l'aide)

bien, mais on peut pas passer une chaine vide ou la valeur null....dommage

vendredi, février 07, 2014

WINDEV Mobile 19 : Android/iOS Réplication de données (Réplication Universelle Assistée)

J'attendais la version 19 pour mettre la réplication en place sur des application Android/iOS. Au départ j'avais testé sur Android avec une base abonnée SQLite mais la réplication ne fonctionne qu'avec HFSQL. Pas grave et ça m'arrange.

Pourquoi la Réplication Universelle Assistée et pas la programmée ?

Car la Réplication Universelle Assistée permet de faire de la réplication avec un minimum de code (une dizaine de ligne). La plupart de la configuration s'effectue avec des assistants.

Mise en place 

J'ai réalisé quelques tests en m'appuyant sur la documentation : http://doc.pcsoft.fr/fr-FR/?1000021071. Les étapes sont bien précisées. Juste quelques commentaires :

1 - Installation du serveur de réplication.

L'aide en ligne sur le sujet est bien faite. Il cohabite très bien avec un Serveur d'application WEBDEV.
Si on utilise une base HFSQL classic, il faut penser à donner les droits à "l'invité internet" sur le répertoire des données (base maître).
Si les droits sont pas défini, un message pas très explicite apparaît sur le terminal du type "impossible d'accéder aux fichiers ....".

A noter également, qu'il n'est pas nécessaire de créer des comptes. Celui par défaut est largement suffisant.

Dans le volet publication, on peut ajouter une publication. Attention : le nom de l'application que l'on donne doit être identique au nom du fichier .wer (sans l'extension)

2 - Définition de la réplication. (ReplicEdit)

Pas de problématique, a part pour les pamaètres. Dans la description d'un fichier de données, onglet "Filtre". Si on souhaite mettre un paramètre, il faut bien dans la combo seléctionner "Nouveau Paramètre" exemple :


Autre chose également, si utilisation d'une base HFSQL classic, ne pas oublier de définir le répertoire de la base maître dans le menu "Réplication...Description de la réplication" onglet "Fichiers maîtres"

Si utilisation d'une base HFSQL client/serveur. Il faut avant même de lancer ReplicEdit avoir une connexion décrit dans l'analyse sinon c'est rapé.

3 - Publication

On peut le faire dans l'administrateur du serveur de réplication ou depuis ReplicEdit. Attention à la fin de l'assistant on propose un code. celui-ci ne contient ni le nom de la réplication, ni le login, ni le mot de passe défini dans l'assistant.

4 - Programmation dans WINDEV Mobile.

tout le code est donner dans l'aide. Attention à réplicSynchro dans le cas d'un replica immédiat, bien définir le deuxième paramètres ReplicaImmédiat. Sinon on a l'impression que ca marche pas.

Conclusion

Le résultat est assez bleuffant. Ajout, modification, suppression (par swipe) depuis une même application avec deux configuration de projet Android et iOS. Un code unique. Pas testé avec WINDEV et WEBDEV mais d'après la doc le code ne change.

Pour les tests j'ai utilisé que quelques fichiers avec 2 ou trois paramètres, on va voir à à l'usage...

par contre si Modification automatique des fichiers de données ou modification du .wer, ben à priori rien de prévu. Je pense qu'il faut refaire un ReplicInitialise après avoir fait un HModifieStructure. Mais bon cette dernière focntion ne me dit pas si la structure à vraiment changer ou pas.

Je sais pas comment vais faire pour l'instant. Mais on va tester....







vendredi, janvier 31, 2014

WINDEV Editeur de code : Sélection en colonne

La sélection en colonne dans l'éditeur de code est très pratique. Voici une petite vidéo rapide .
voir aide : http://doc.pcsoft.fr/fr-FR/?2010031#NOTE4_1


jeudi, janvier 30, 2014

WLangage : Opérateur Dans

L'opérateur DANS permet de comparer une valeur à une liste de valeurs. Son évaluation renvoie un booléen. très pratique et évite les opérateur _OU_ ou _ET_.

Si Mavaleur DANS(5,6,7) alors
         // trt

Fin

vendredi, janvier 18, 2008

WinDev 12 – Splitter une chaîne dans un tableau

Voici une procédure qui permet de mettre les valeurs d'une chaîne de caractères séparées par un séparateur défini, dans un tableau :

// Résumé : Permet de remplir un tableau de chaine à partir d'une chaine et d'un séparateur

// Syntaxe :

//[ = ] Split ( est chaîne, est chaîne [, est booléen [, est entier]])

//

// Paramètres :

// sChaineCara (chaîne) : Chaine de caractères à splitter

// sSeparateur (chaîne) : Le séparateur à utiliser

// bTrié (booléen - valeur par défaut=0) : Faux (valeur par défaut) le tableau n'est pas trié, vrai pour avoir un tableau trié

// pType (entier - valeur par défaut=1) : Type de trie : ttCroissant ou ttDécroissant

// Valeur de retour :

// tableau : // Tableau contenant les valeurs de la chaine passée en paramètre.

//

// Exemple :

// tabSP est un tableau dynamique de 0 chaines

//

// tabSP = Split("toto;abc;zoro;aab;tata",";",Vrai,ttCroissant)

PROCEDURE Split(sChaineCara est une chaîne, sSeparateur est une chaîne,bTrié est un booléen = Faux,pType est un entier = ttCroissant)

tabSplit est un tableau dynamique de 0 chaînes

s est une chaîne // variable de boucle

POUR TOUTE CHAINE s DE sChaineCara SEPAREE PAR sSeparateur

TableauAjouteLigne(tabSplit,s)

FIN

SI bTrié ALORS

SI pType = 0 ALORS pType = ttCroissant

TableauTrie(tabSplit,pType)

FIN

RENVOYER tabSplit

Exemple d'utilisation :

tabSP est un tableau dynamique de 0 chaîne

tabSP = Split("toto;abc;zoo;aab;tata",";",Vrai,ttCroissant)

mardi, janvier 15, 2008

WinDev 12 - Utilisation de MesParamètres

Cette instruction WLangage permet de passer autant de paramètres à une procédure que l'on souhaite grâce à l'opérateur *.

Exemple :

PROCEDURE Calcul(pParam1, *)

Dans cette procédure * représente les autres paramètres possibles.

Ces paramètres optionnels sont accessibles via l'instruction MesParamètres.

Le plus intéressant, avec cette instruction, c'est que l'on peut accéder à des propriétés d'un objet. Par exemple si on veut modifier la visibilité d'une colonne dans une procédure globale on peut passer en paramètre à la procédure le nom complet de la colonne :

Exemple code :

// Code d'un bouton
ModInterface(Fen_Fenêtre1.Table1.Col_Colonne1, faux)

PROCEDURE ModInterface(*)

MesParamètres[1]..visible = MesParamètres[2]

jeudi, juin 28, 2007

Code-Cible Conditionnel

Très utile lors de création de procédure utilisable dans WinDev, WebDev et WinDev Mobile.

Le Code-Cible Conditionnel permet de mettre un code différent en fonction de la plateforme choisie.

Ainsi une procédure créer en WinDev, avec l'utilisation de fonction non disponible en WebDev pourra être utilisée grâce au code cible.

Exemple la fonction "Dialogue" n'est pas disponible en WebDev. Donc dans WinDev on mettra les codes suivants.

Conseil : Bien suivre l'aide pour ajouter les zones de code-cible conditionnel.

jeudi, mai 10, 2007

WebDev - Comment après un code serveur utiliser la fonction NavigateurOuvre ?

Comment ouvrir un page Web après un traitement en code serveur ?

Il faut utiliser la fonction NavigateurOuvre. Toutefois, cette fonction est disponible qu'en code navigateur et pas en code serveur.

L'astuce consiste à utiliser un champ caché, qui fera office de booléen.
Dans un code serveur, on effectue le traitement souhaité, puis on affecte 1 au champ caché.
Puis dans le code d'onload de la page, on utilise la syntaxe suivante :

SI SAI_MonChamp <> 0 alors
NavigateurOuvre("http://www.monsite.fr")
FIN

mercredi, mai 02, 2007

Style CSS et WebDev 11

Comme ça n'est pas précisé dans la doc, voici comment mettre du code CSS dans la description d'un champ.

Prenons le champ lien, par exemple. Il faut aller dans la description du lien dans l'onglet Style.
Puis cliquer sur "Editer".
Ensuite dans la description du style dans l'onglet CSS, on va mettre un code css de survol du lien.
Sélectionner Survol et mettre le code (exemple) :
color:#411;
background:#aaa;
border-bottom: 1px solid #555;

Il faut oublier la syntaxe : "a{ }" et mettre que les attributs.
Voilà un effet de survol en CSS.

mercredi, avril 25, 2007

Récupérer un flux RSS dans WebDev

Pour récupérer le contenu d'un fichier XML, il faut utiliser la fonction HTTPRequête.

Voici le code :
sURL est une chaine = "http://nomDomaine.com/rep_du_Fichier_XML"

HTTPRequête(sURL,ProjetInfo(piNomProjet)) //
sres est une chaîne = HTTPDonneRésultat(HTTPRésultat)

Voila sres contient le fichier XML du flux RSS.
Ensuite il faut parcourir le fichier pour extraire les éléments. L'utilisation de fonction "XML" permet facilement d'obtenir le contenu.

Il existe un exemple complets dans WinDev : "Lecteur RSS", les procédures et classes sont utilisables dans WebDev.

Trouver des infos à partir de l'adresse IP

Il peut être intéressant, à partir d'une adresse ip, d'avoir le pays, la ville et les coordonnées géographique.
Cela est utile pour afficher des informations liées à la ville, ou positionner l'internaute sur une carte.
C'est possible avec le projet HostIp.
Voici une collection de procédures permettant de récupérer ces infos :

Déclarations des procédures globales :
Infos est un tableau associatif (*, *, *, 4) de chaînes

PROCEDURE RecupInfos(sIp est une chaîne)
s est une chaîne

// On interroge Hostip.
SI PAS HTTPRequête("http://api.hostip.info/get_html.php?ip="+sIp+"&position=true") ALORS
Erreur()
SINON
sres est une chaîne = HTTPDonneRésultat(HTTPRésultat)
// sRes est de la forme
// Country: FRANCE (FR)
// City: (Unknown city)
// Latitude:
// Longitude:
POUR TOUTE CHAINE s DE sres SEPAREE PAR Caract(10)
Infos[SansEspace(ExtraitChaîne(s,1,":",DepuisDébut))] = ExtraitChaîne(s,2,":",DepuisDébut)
FIN
FIN

PROCEDURE Pays()

RENVOYER Infos["Country"]

PROCEDURE Ville()

RENVOYER Infos["City"]

PROCEDURE Lattitude()

RENVOYER Infos["Latitude"]

PROCEDURE Longitude()

RENVOYER Infos["Longitude"]

jeudi, avril 05, 2007

Demarrer...Executer dans une Combo WinDev

J'ai voulu faire l'équivalent de "démarrer...exécuter" de Windows, avec une combo dans WinDev 11.






A chaque saisie de caractère, la combo propose les fichiers et répertoires commençant par ce caractère. Une sorte de saisie assistée.


Voici le code Utilisé :

Le code d'entrée de la combo.





Code à chaque modification de la combo :

ch est une chaîne = MoiMême..ValeurAffichée // Recupération de la valeur saisie dans la combo
pos est un entier = Position(ch,"\",0,DepuisFin) // Position du curseur.

SI Taille(ch) >= 2 ALORS // A partir du deuxième caractère on recherche les fichiers et répertoires
// Suppression du contenu de la combo
POUR i = ListeOccurrence(MoiMême) A 1 PAS -1
ListeSupprime(MoiMême,i)
FIN
SI ListeOccurrence(MoiMême) > 0 ALORS ListeModifie(MoiMême,"",1)
// Le premier caractère doit correspondre à une unité de disque : de A à Z
SI Asc("A") < pertoire =" fRep(ch+">""
// Liste des répertoires
ListeAjoute(MoiMême,ch[[1 A 2]]+["\"]+ch[[3 A pos]]+["\"]+sRépertoire)
// Répertoire suivant
sRépertoire = fRep("", frRépertoire)
FIN

// Ajout des fichiers qui sont à la racines
ListeAjoute(MoiMême,fListeFichier(ch+"*",frNonRécursif))
// Ouverture de la combo
ComboOuvre(MoiMême)
FIN
FIN


Code de Sélection de la Combo :







la propriété ..Curseur permet de positionner le curseur à la fin de la chaine saisie

vendredi, mars 16, 2007

Combo : clic sur la flèche

Comment afficher dans une combo, la liste des bases disponibles sur un serveur Hyper File, au clic sur la flèche (Ouverture de la combo) de la combo ?

Il faut utiliser l'événement : WM_NCLBUTTONDOWN.


Ne pas oublier de mettre EXTERN "WinConst.wl" dans la déclaration globale de la fenêtre.


Branchement de l'évènement : (Code global de la fenêtre)

Evénement("RemplitComboBaseHF","COMBO_Base",WM_NCLBUTTONDOWN)


Création de la procédure "RemplitComboBaseHF" :

PROCEDURE RemplitComboBaseHF()

// Ouverture de la connexion

SI PAS HOuvreConnexion("Moi",SAI_LoginHFCS,SAI_MdpHFCS,SAI_Serveur+":"+SAI_Port,"",hAccèsHFClientServeur) ALORS

Erreur()

SINON

// Récupération de la liste des bases disponibles

ListeBase est une chaîne = HListeBaseDeDonnées("Moi",hLstNormal)

ListeSupprimeTout(COMBO_Base)

s est une chaîne

// Ajout des bases dans la combo

POUR TOUTE CHAINE s DE ListeBase SEPAREE PAR TAB

ListeAjoute(COMBO_Base,s)

FIN

// Sélection de la première base.

SI ListeOccurrence(COMBO_Base) > 0 ALORS ListeSelectPlus(COMBO_Base,1)

HFermeConnexion("Moi")

FIN

jeudi, janvier 04, 2007

PersoMenu WinDev, WebDev et WinDev Mobile.

Le « PersoMenu » permet de lancer n'importe quel exécutable à partir de l'éditeur grâce à une ligne de commande et des macros.

Dans le billet précédent, je parlais de WebDev 11 (35c) qui ne configurait pas le serveur Apache 2.2.3 automatiquement.

J'ai donc fait un programme en Wlangage permettant d'ajouter l'alias pour chaque site dans le fichier httpd.conf.

Puis dans WebDev j'ai créé un Perso menu :

La ligne de commande est la suivante :

"D:\Projet\ModifHttpd.conf\Exe\ModifHttpd_conf.exe" "C:\Program Files\Apache Software

Foundation\Apache2.2\conf\httpd.conf" "{$RepProjet}"


{$RepProjet} : c'est une macro disponible est cliquant sur le bouton « Macro ». Elle renvoie le chemin du répertoire du projet.

ModifHttpd_conf.exe : Mon programme WinDev permettant d'ajouter l'alias au fichier httpd.conf.


Astuce : Dans l'aide il n'est pas précisé comment créer une ligne de commande avec un chemin d'accès contenant des espaces. Le plus simple est de tester la ligne de commande dans « Demarrer...executer » de windows.


Code du programme WinDev « ModifHttpd_conf.exe » :


// Code de déclaration global du projet

LOCAL

gsRes est une chaîne

gnIdFic est un entier

gsCheminFic est une chaîne

gsALias est une chaîne

gsNomSite est une chaîne

gbRes est un booléen


// exemple de ligne de commande:

//"D:\Projet\ModifHttpd.conf\Exe\ModifHttpd_conf.exe" "C:\Program Files\Apache Software Foundation\Apache2.2\conf\httpd.conf" "C:\WebDev 11\Exemples\Exemples complets\WW_Editeur_HTML"


gsCheminFic = LigneCommande(1) //C:\Program Files\Apache Software Foundation\Apache2.2\conf\httpd.conf

gsALias = LigneCommande(2) //C:\WebDev 11\Exemples\Exemples complets\WW_Editeur_HTML


// Ligne de code pour test

SI EnModeTest() ALORS

gsCheminFic = "C:\Program Files\Apache Software Foundation\Apache2.2\conf\httpd.conf"

gsALias = "C:\WebDev 11\Exemples\Exemples complets\WW_Editeur_HTML\"

FIN


SI gsCheminFic <> "" ALORS

// Ouverture du fichier httpd.conf

gnIdFic = fOuvre(gsCheminFic,foAjout)

SI gnIdFic <> -1 ALORS

SI gsALias <> "" ALORS

// On rajoute _WEB au chemin du site

SI Droite(gsALias,1) = "\" ALORS

gsALias = gsALias[[1 A (Taille(gsALias)-1)]]

FIN

gsNomSite = ExtraitChaîne(gsALias,1,"\",DepuisFin)

gsNomSite = "/"+Majuscule(gsNomSite)+"_WEB/"

// Change les \ en /

gsALias = Remplace(gsALias,"\","/")

// On construit le chemin complet

gsALias = gsALias+gsNomSite

// Construction de la chaîne à ajouter au fichier httpd.conf

gsRes = [

Alias %1 "%2"

Options None

AllowOverride None

Order allow,deny

Allow from all

]

gsRes = RC+ChaîneConstruit(gsRes,gsNomSite,gsALias)

// Écriture dans le fichier

gbRes = fEcritLigne(gnIdFic,gsRes)

SI PAS gbRes ALORS

Erreur()

FIN

fFerme(gnIdFic)

// Redemarrer le serveur.

sr est une chaîne = [

"%1" "%2"

]

sr = ChaîneConstruit(sr,"C:\Program Files\Apache Software Foundation\Apache2.2\bin\httpd.exe","-k restart")

LanceAppliAssociée(sr)

SINON

fFerme(gnIdFic)

gsRes = [

"%1"

]

gsRes = ChaîneConstruit(gsRes,gsCheminFic)

// que sous windows

LanceAppliAssociée(gsRes)

FIN

FIN

FIN


mercredi, décembre 27, 2006

WinDev 11 : Table hiérarchique

Je viens de me mettre à la table Hiérarchique. Afin de tester le fonctionnement, je me suis servi de l'analyse et des fichiers de l'exemple CRM livré avec WinDev 11.


But du test :

Afficher dans la table Hiérarchique la liste des lignes de commandes par commande et par client.


Résultat :

Code :


nIndiceParent est un entier

nIndiceFils est un entier

nIndiceProd est un entier


// Remplissage de la table
POUR TOUT
CLIENT SUR NumClient

nIndiceParent = TableAjouteLigne(TABLEH_TableHierarchique1,CLIENT.Civilité+
" "+CLIENT.NomClient)

// Affichage pour chaque client la liste de ses commandes
POUR TOUT
COMMANDE AVEC NumClient = CLIENT.NumClient
n
IndiceFils = TableAjouteFils(TABLEH_TableHierarchique1,nIndiceParent,
"Commande n° : " +COMMANDE.NumCommande)
POUR TOUT
LIGNECDE AVEC NumCommande = COMMANDE.NumCommande
// Recherche du libellé du produit
HLitRecherche
(PRODUIT,Reference,LIGNECDE.Référence)
nIndiceProd = TableAjouteFils(TABLEH_TableHierarchique1,nIndiceFils,PRODUIT.LibProd+
" "+LIGNECDE.Référence,LIGNECDE.Quantité,LIGNECDE.PrixVente)

FIN
FIN
FIN

TableEnrouleTout(TABLEH_TableHierarchique1)


Conclusion :

Look de la table plutôt agréable. L'utilisation des fonctions est simple.
Il est possible de modifier les images enroulées et déroulées grâce aux propriétés ..ImageEnroulée et ..ImageDéroulée.

NB : Voici le code pour mettre des images dans l'entête des colonnes.

TABLEH_TableHierarchique1.COL_Colonne1..Titre = gImage("01058-16-5.png")+"Clients /"+gImage("VST13340-16-5.png")+" Cde /"+gImage("01389-16-5.png")+" LigneCde"

Possibilité d'utiliser gStylo pour écrire dans une autre couleur.


vendredi, novembre 24, 2006

Comment récupérer la valeur d'une combo dans une table mémoire ?

On pourrait penser que pour récupérer la valeur du Glien d'une combo dans une table mémoire, il faudrais utiliser : NomTable[IndiceLigne][listeSelect(NomColonneCombo)]
he! bien non

Voici la bonne syntaxe :
NomColonneCombo[NomTable,NomTable]..valeur.

Cette syntaxe est uniquement valable pour une combo dans un table mémoire.
Pour une table fichier utiliser : NomColonneCombo..Valeur.

Comment modifier la police d'un libellé d'un champ de saisie

Soit un champ de saisie qui comme police de libellé : MS UI Gothic.



Pour modifier la police de du libellé "Champ de saisie", il utiliser le code suivant :

sLibel est une chaîne = SAI_Saisie1..Libellé

SAI_Saisie1..Libellé = gPolice("Arial")+sLibel

jeudi, novembre 23, 2006

Enlever les caractères Spéciaux tel que =E9,=E8,..

Il arrive de récupérer une chaine de caractère (un mail ou une page internet) avec des caractères tel que =E9 en lieu et place d'un caractères accentués.

[En savoir plus]

Pour afficher une chaine sans ces caractères, voici donc une procédure permettant de les remplacer :

PROCEDURE RemplaceCaractères(pMachaine est une chaîne)

ch est une chaîne = SansEspace(pMachaine )

// Remplacement des caractères
ch = Remplace(ch,"=?ISO-8859-15?Q?","")
ch = Remplace(ch,"=?ISO-8859-1?Q?","")
ch = Remplace(ch,"=E9","é")
ch = Remplace(ch,"=E8","è")
ch = Remplace(ch,"=EA","ê")
ch = Remplace(ch,"=E7","ç")
ch = Remplace(ch,"=C9","é")
ch = Remplace(ch,"=7E","~")
ch = Remplace(ch,"?=","")
ch = Remplace(ch,"=?","")
ch = Remplace(ch,"=27","'")
ch = Remplace(ch,"=22","""")
ch = Remplace(ch,"=28","'(")
ch = Remplace(ch,"=29","')")
ch = Remplace(ch,"=2E",".")
ch = Remplace(ch,"=3A",":")
ch = Remplace(ch,"=3F","?")
ch = Remplace(ch,"=E0","à")
ch = Remplace(ch,"=3B",";")
ch = Remplace(ch,"=2B","+")
ch = Remplace(ch,"_"," ")

RENVOYER ch