Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 26/04/2020, à 14:40

Hizoka

Temps d'execution d'une fonction / même code hors fonction

Bonjour à vous,

j'ai besoin d'améliorer le temps d’exécution d'un script sur lequel je bosse, chaque dixième de seconde est bon à prendre.

En faisant des tests, je me suis rendu compte de la chose suivante : le temps d'appel à une fonction interne alourdi beaucoup le temps de travail ?!

Je venais donc vers vous pour avoir vos avis, est-ce normal ?
Au final faut il se passer de fonction et allonger le code ?!

Quelles sont les bonnes pratiques lors de la création de fonction ?


Exemple très proche de mes besoins :
Le but est d'éliminer les %[0-9]/[0-9] et %[0-9] où chaque nombre peut être constitué entre 1 et 3 chiffres.
L'ordre est important car il ne faudrait pas dégager %1/1 avant %1/10 car sinon ce dernier se changera en 0.

PS : Si vous avez une façon plus rapide de réaliser cette action, je prends smile
Donc exit les sed & co ou les =~.


Version la plus rapide : 0m0,264s

time for x in {0..1000}
do 
    Value="%1 Bonjour %2/5 Monsieur"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9]* ]] && Value="${Value//%[0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]}"
    [[ ${Value} == *%[0-9]* ]] && Value="${Value//%[0-9]}"
    a="${Value}"

    Value="%1/5 Bonjour %2 Monsieur"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9]* ]] && Value="${Value//%[0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]}"
    [[ ${Value} == *%[0-9]* ]] && Value="${Value//%[0-9]}"
    b="${Value}"

    Value="%5/1 Bonjour %5 Monsieur"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9]* ]] && Value="${Value//%[0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]}"
    [[ ${Value} == *%[0-9]* ]] && Value="${Value//%[0-9]}"
    c="${Value}"
done

Visuellement c'est lourd, ça rallonge la taille du fichier...


Version avec une pseudo fonction, pratiquement aussi rapide : 0m0,312s

function ColorCleaning
{
    Value="${1}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9]* ]] && Value="${Value//%[0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]}"
    [[ ${Value} == *%[0-9]* ]] && Value="${Value//%[0-9]}"
}

time for x in {0..1000}
do 
    ColorCleaning "%1 Bonjour %2/5 Monsieur"
    a="${Value}"

    ColorCleaning "%1/5 Bonjour %2 Monsieur"
    b="${Value}"

    ColorCleaning "%5/1 Bonjour %5 Monsieur"
    c="${Value}"
done 

Je n'aime pas trop, je n'ai pas l'impression que c'est une "vraie fonction" (elle ne renvoie rien) et pas fan du côté toutes les variables sont globales et se mélangent entre le script et la fonction.
Mais c'est moins de lignes et plus lisible.


La même chose avec ce que je considère comme une vrai fonction : 0m9,696s :

function ColorCleaning
{
    # Valeur à nettoyer
    local Value="${1}"

    # Nettoyage des couleurs possibles
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9]* ]] && Value="${Value//%[0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]}"
    [[ ${Value} == *%[0-9]* ]] && Value="${Value//%[0-9]}"

    # Renvoie du résultat
    echo "${Value}"
}

time for x in {0..1000}
do 
    a=$(ColorCleaning "%1 Bonjour %2/5 Monsieur")
    b=$(ColorCleaning "%1/5 Bonjour %2 Monsieur")
    c=$(ColorCleaning "%5/1 Bonjour %5 Monsieur")
done 

Visuellement agréable, la fonction renvoie une valeur récupérée, mais niveau timing, c'est juste pas possible.


Merci à vous, bon dimanche et bon courage pour le confinement.


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne

#2 Le 26/04/2020, à 15:33

Watael

Re : Temps d'execution d'une fonction / même code hors fonction

j'aurais fait un tableau et une boucle :

for motif in "${arMotifs[@]}"; do [[ $Value == $motif* ]] && Value="${Value//$motif}"; done

Le tableau est défini au début du script, et plus de fonction.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#3 Le 26/04/2020, à 15:46

kamaris

Re : Temps d'execution d'une fonction / même code hors fonction

À mon avis, tu peux laisser bash faire tous ces tests en interne, pour obtenir des performances similaires à ton premier cas de test, mais en beaucoup plus léger et lisible :

shopt -s extglob

time for x in {0..1000}
do
    Value="%1 Bonjour %2/5 Monsieur"
    a=${Value//%+([0-9])?(\/)*([0-9])}

    Value="%1/5 Bonjour %2 Monsieur"
    b=${Value//%+([0-9])?(\/)*([0-9])}

    Value="%5/1 Bonjour %5 Monsieur"
    c=${Value//%+([0-9])?(\/)*([0-9])}
done

Hors ligne

#4 Le 26/04/2020, à 15:52

Hizoka

Re : Temps d'execution d'une fonction / même code hors fonction

@Watael
En effet, pourtant je fais des trucs équivalents, j'aurais pu y penser smile

C'est pratiquement aussi rapide que les 1eres propositions : 0m0,403s

arMotifs=("%[0-9][0-9][0-9]/[0-9][0-9][0-9]" "%[0-9][0-9][0-9]/[0-9][0-9]" "%[0-9][0-9][0-9]/[0-9]" "%[0-9][0-9]/[0-9][0-9][0-9]" "%[0-9][0-9]/[0-9][0-9]" "%[0-9][0-9]/[0-9]" "%[0-9]/[0-9][0-9][0-9]" "%[0-9]/[0-9][0-9]" "%[0-9]/[0-9]" "%[0-9][0-9][0-9]" "%[0-9][0-9]" "%[0-9]")

time for x in {0..1000}
do 
    a="%1 Bonjour %2/5 Monsieur"
    for motif in "${arMotifs[@]}"
    do
        [[ ${a} == *${motif}* ]] && a="${a//${motif}}"
    done

    b="%1/5 Bonjour %2 Monsieur"
    for motif in "${arMotifs[@]}"
    do
        [[ ${b} == *${motif}* ]] && b="${b//${motif}}"
    done

    c="%5/1 Bonjour %5 Monsieur"
    for motif in "${arMotifs[@]}"
    do
        [[ ${c} == *${motif}* ]] && c="${c//${motif}}"
    done
done 

C'est assez propre aussi.


@kamaris
Je pense jamais à shopt... sad

Pour le coup, il faut au moins 0.5sec, donc un chouille plus long smile
Mais niveau lisibilité, c'est top !


Après, mes questions de base vis à vis des fonctions restent d'actualité smile
Si y a des bonnes pratiques, des conseils...

De ce que je comprends de vos retours, c'est qu'il faut se passer des fonctions si possible XD

Merci smile

Dernière modification par Hizoka (Le 26/04/2020, à 16:02)


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne

#5 Le 26/04/2020, à 16:01

kamaris

Re : Temps d'execution d'une fonction / même code hors fonction

J'ai fait une petite erreur en fait, en #3.
Pour être équivalent à tes tests plus haut, il faut faire

${Value//%+([0-9])?(\/+([0-9]))}

Du coup, c'est plus simple à tester, et j'ai des résultats un peu plus rapide qu'avec ton premier cas de test.
Ce qui serait rassurant : à tests logiquement équivalents, bash s'en sort mieux en interne qu'avec une suite de tests passés de l'extérieur.

Hors ligne

#6 Le 26/04/2020, à 16:11

kamaris

Re : Temps d'execution d'une fonction / même code hors fonction

Pour les appels de fonctions, ça n'est jamais gratuit, mais ce qui coûte cher dans ton troisième cas de test, c'est la substitution de commande (un peu comme dans ce précédent sujet : ./viewtopic.php?id=2051383).
Car si tu fais

time for x in {0..1000}
do 
    ColorCleaning "%1 Bonjour %2/5 Monsieur" >/dev/null
    ColorCleaning "%1/5 Bonjour %2 Monsieur" >/dev/null
    ColorCleaning "%5/1 Bonjour %5 Monsieur" >/dev/null
done

tu retombes sur les mêmes ordres de grandeur.

Hors ligne

#7 Le 26/04/2020, à 16:11

Watael

Re : Temps d'execution d'une fonction / même code hors fonction

grosso modo :

uneFonctionCorrecte()
{
    local argumentFonction modification
    argumentFonction=$1
    modification=">$argumentFonction<"
    echo "$modification"
}

argumentScript=$1
argumentScript=$(uneFonctionCorrecte "$argumentScript")
echo "$argumentScript"

Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#8 Le 26/04/2020, à 16:17

Hizoka

Re : Temps d'execution d'une fonction / même code hors fonction

Oui j'avais bien remarqué que c'était le même cas mais je me suis dis que j'étais peut être passé à côté d'un truc...
Ce que je pige pas, c'est pourquoi l'attribution des valeurs aux variables prend autant de temps...

et j'aime bien les fonctions, c'est facile à maintenir tongue


@Watael
Oui, c'est à ça que ressemble mes fonctions.
Mais pour le coup :

argumentScript=$(uneFonctionCorrecte "$argumentScript")

Ça prend beaucoup de temps...


@karamis
J'aime ta proposition qui est classe mais si on complique la phrase, ouille...
0m15,651s

time for x in {0..1000}
do
    Value="%1In %10opulentae %100domus %1/1quod %1/10indulta %1/100quorum %10/1extorres %10/10puniti %10/100converso %100/1indulta."
    a=${Value//%+([0-9])?(\/+([0-9]))}
done

0m0,294s

time for x in {0..1000}
do
    Value="%1In %10opulentae %100domus %1/1quod %1/10indulta %1/100quorum %10/1extorres %10/10puniti %10/100converso %100/1indulta."
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]/[0-9]* ]] && Value="${Value//%[0-9][0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9][0-9]* ]] && Value="${Value//%[0-9]\/[0-9][0-9]}"
    [[ ${Value} == *%[0-9]/[0-9]* ]] && Value="${Value//%[0-9]\/[0-9]}"
    [[ ${Value} == *%[0-9][0-9][0-9]* ]] && Value="${Value//%[0-9][0-9][0-9]}"
    [[ ${Value} == *%[0-9][0-9]* ]] && Value="${Value//%[0-9][0-9]}"
    [[ ${Value} == *%[0-9]* ]] && Value="${Value//%[0-9]}"
    a="${Value}"
done

0m0,322s

arMotifs=("%[0-9][0-9][0-9]/[0-9][0-9][0-9]" "%[0-9][0-9][0-9]/[0-9][0-9]" "%[0-9][0-9][0-9]/[0-9]" "%[0-9][0-9]/[0-9][0-9][0-9]" "%[0-9][0-9]/[0-9][0-9]" "%[0-9][0-9]/[0-9]" "%[0-9]/[0-9][0-9][0-9]" "%[0-9]/[0-9][0-9]" "%[0-9]/[0-9]" "%[0-9][0-9][0-9]" "%[0-9][0-9]" "%[0-9]")

time for x in {0..1000}
do 
    a="%1In %10opulentae %100domus %1/1quod %1/10indulta %1/100quorum %10/1extorres %10/10puniti %10/100converso %100/1indulta."
    for motif in "${arMotifs[@]}"
    do
        [[ ${a} == *${motif}* ]] && a="${a//${motif}}"
    done
done 

Merci à vous pour vos retours et votre aide toujours aussi précieuse et de qualité wink

Dernière modification par Hizoka (Le 26/04/2020, à 16:24)


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne

#9 Le 26/04/2020, à 16:22

kamaris

Re : Temps d'execution d'une fonction / même code hors fonction

Ah oui, ça c'est vrai que ça peut vite arriver, tu as raison :

man bash a écrit :

Complicated extended pattern matching against long strings is slow, especially when the patterns contain alternations and the strings contain multiple matches. Using separate matches against shorter strings, or using arrays of strings instead of a single long string, may be faster.

Donc la proposition de Watael.

Hors ligne

#10 Le 26/04/2020, à 16:40

kamaris

Re : Temps d'execution d'une fonction / même code hors fonction

Ou bien découper la chaine (je ne m'avoue pas vaincu big_smile) :

shopt -s extglob

time for x in {0..1000}
do
    Value="%1In %10opulentae %100domus %1/1quod %1/10indulta %1/100quorum %10/1extorres %10/10puniti %10/100converso %100/1indulta."
    a=''
    for p in $Value; do a+="${p//%+([0-9])?(\/+([0-9]))} "; done
    a=${a:0:-1}
done

Hors ligne

#11 Le 26/04/2020, à 16:49

Hizoka

Re : Temps d'execution d'une fonction / même code hors fonction

Pas mal pas mal en effet lol

Mais on s'éloigne de la simplicité smile

Mais c'est toujours très sympa de lire ce genre de code.


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne

#12 Le 29/04/2020, à 14:04

LeoMajor

Re : Temps d'execution d'une fonction / même code hors fonction

bonjour,

autant compiler le regex si il est répété n fois; donc exit le shell, et la bienvenue aux langages qui savent le faire (python, ruby, java, c#, gambas, ...)

#!/usr/bin/python3.5
# -*- coding: utf-8 -*-
import re, time

deb = time.time()
l=[]
Value="%1In %10opulentae %100domus %1/1quod %1/10indulta %1/100quorum %10/1extorres %10/10puniti %10/100converso %100/1indulta."

pat=re.compile('%[0-9]+[/0-9]*')

for item in list(range(0,1000)):
    res=pat.sub("",Value)
    l.append(res)
    #print(item,res)


print(l[1],len(l))

fin=time.time()
print("durée:",fin - deb)
In opulentae domus quod indulta quorum extorres puniti converso indulta. 1000
durée: 0.016808032989501953

Hors ligne

#13 Le 29/04/2020, à 14:21

Sciensous

Re : Temps d'execution d'une fonction / même code hors fonction

grillé: j'allais proposer -> pour être rapide, faire du C
wink

Dernière modification par Sciensous (Le 29/04/2020, à 14:22)


antiX 19 et 21 et Ubuntu 20.04 et 22.04
( sous LXDE et gnome-shell )

Hors ligne

#14 Le 29/04/2020, à 15:26

Hizoka

Re : Temps d'execution d'une fonction / même code hors fonction

En effet, c'est rapide mais ça ne correspond aux autres tests.

La boucle est là pour simuler n appels au script, la regex sera exécutée à chaque lancement.

J'adore python mais pour le coup, là c'est un script bash smile


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne