4 # Codé par 20-100 (commencé le 23/04/12)
6 # Un bot IRC qui, un jour, s'interfacera avec la Note Kfet 2015
13 import socket
, ssl
, json
17 from commands
import getstatusoutput
as ex
20 config_debug_stdout
=True
21 if "--quiet" in sys
.argv
:
22 config_debug_stdout
=False
24 config_irc_password
="NK2015BasileB0t"
25 config_irc_pseudo
="Basile"
26 config_chanlist
=["#bot","#flood"]
27 config_stay_channels
=["#bot","#flood"]
28 config_quiet_channels
=[]
29 config_note_pseudo
="Basile"
30 config_note_password
="NK2015BasileB0tr4nd0omp4assword]6_+{#]78{"
31 config_logfile_template
="basile.%s.log"
32 def get_config_logfile(serveur
):
33 serveurs
={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
34 return config_logfile_template
%(serveurs
[serveur
])
35 config_overops
=["[20-100]","[20-100]_", "PEB"]
37 config_report_bugs_to
=["[20-100]"]
39 # config "ce bot a été codé par 20-100, tu te rappelles ?"
40 config_manzana
= ["[20-100]", "Petite-Peste"]
41 # config "mais PEB aussi est passé par là"
42 config_manzana_bis
= ["PEB"]
44 # config "tu m'traites ?"
45 config_insultes
=[u
"conna(rd|sse)",u
"pute",u
"con(|ne)",u
"enf(oiré|lure)",
46 u
"sal(op(|e(|rie)|ard)|aud)",u
"p(e|')tite bite",u
"imbécile",u
"idiot",u
"stupid(|e)",u
"débile",u
"crétin",
47 u
"pétasse",u
"enculé",u
"chagasse",u
"cagole",u
"abruti",u
"ahuri",u
"analphabète",u
"andouille",
48 u
"atardé",u
"avorton",u
"bachibouzouk",u
"(balais|brosse) (de|à) chiotte(|s)",
49 u
"batard",u
"blaireau",u
"bouffon",u
"branque",u
"bouseux",u
"branleur",u
"catin",u
"chacal",
50 u
"charogne",u
"chiant(|e)",u
"chieur",u
"cochon",u
"coprophage",u
"couillon",u
"crapule",u
"crevard",
51 u
"cruche",u
"cuistre",u
"ducon",u
"décérébré",
52 u
"emmerdeur",u
"feignasse",u
"fainéant",u
"fourbe",u
"freluquet",u
"frigide",
53 u
"garce",u
"glandu",u
"gogol",u
"goujat",u
"gourdasse",u
"gredin",u
"gringalet",u
"grognasse",
54 u
"naze",u
"truie",u
"iconoclaste",
55 u
"peigne(-|)cul",u
"ignare",u
"illétré",u
"lèche(|-)cul",u
"malotru",u
"motherfucker",u
"nabot",u
"nigaud",
56 u
"nul",u
"escroc",u
"pouffiasse",u
"pourriture",u
"raclure",u
"relou",u
"sagouin",u
"putain",
58 config_insultes_answers
=[
59 u
"Oh non ! Quelle insulte ! Je crois que je ne m'en relèverai jamais…\nEnfin presque.",
60 u
"J'entends comme un vague murmure, vous disiez ?",
61 u
"Je vais prendre ça pour un compliment.",
62 u
"Vous savez, pour vous c'est peut-être une insulte, mais pour moi ce n'est qu'une suite de 0 et de 1…",
63 u
"Permettez-moi de vous retourner le compliment.",
64 u
"Votre indélicatesse vous sied à ravir.",
65 u
"Parfois, je me demande pourquoi je fais encore ce métier…",
66 u
"Le saviez-vous : l'invective ne déshonore que son auteur.",
67 u
"Le saviez-vous : vous perdez plus de temps à m'insulter qu'à vous taire.",
68 u
"Mais je ne vous permets pas ! Enfin, pas comme ça…"]
70 # config "à peine quelques kilos octets"
71 config_gros
=[u
"gros",u
"énorme",u
"lourd"]
72 config_thisfile
= os
.path
.realpath( __file__
)
74 return ex("ls -s %s"%(config_thisfile))[1].split()[0]
76 # config spéciale-iota
77 config_buffer_fail_answers
=[u
"Pas de chance !",u
"Révisez vos classiques !",
78 u
"Encore un effort, je sais que vous pouvez le faire. ;)",
79 u
"Where did you learn to type?"]
81 # config "jeu", d'ailleurs, j'ai perdu.
82 config_premier_groupe_terminaisons
=u
"(e|es|ons|ez|ent|er(|ai|as|a|ons|ez|ont)|(|er)(ais|ait|ions|iez|aient)|(a(i|s|)|â(mes|tes|t)|èrent)|ass(e(|s|nt)|i(ons|ez))|é(|s|e|es))"
83 config_regexp_etre
=u
"(être|suis|e(s|t)|so(mmes|nt)|êtes|(ét|ser)(ai(s|t|ent)|i(ons|ent)|)|ser(ai|as|a|ons|ez|ont)|so(i(s|t|ent)|y(ons|ez))|f(u(s|t|rent)|û(mes|tes|t))|fuss(e(|s|nt)|i(ons|ez))|étant)"
84 config_regexp_etre_avec_c
=u
"c'(e(s|st)|étai(t|ent))"
85 config_regexp_faire
=u
"fais"
86 config_perdu
=[u
"perd(|s|ons|ez|ent|r(e|ai|as|a|ons|ez|ont)|(|r)(ais|ait|ions|iez|aient))"
87 u
"perd(i(s|t|rent)|î(mes|tes|t))", # oui, j'ai inclus qu'il perdît
88 u
"perdiss(e(|s|nt)|i(ons|ez))",
89 u
"perdu(|s|e|es)",u
"perdant(|s|e|es)",u
"perte(|s)",
91 u
"(gagn|trouv)"+config_premier_groupe_terminaisons
,u
"gagnant(|s|e|es)",u
"gain(|s)",
93 u
"trouvant",u
"trouvaille(|s)",
95 u
"victoire(|s)",u
"vaincu(|s|e|es)",
96 u
"loose",u
"lost",u
"looser(|s)",u
"win(|ner)(|s)",
97 u
"jeu(|x)",u
"game(|s)"]
98 config_time_between_perdu_trigger
=3600*3 #temps moyen pour perdre en l'absence de trigger
99 config_time_between_perdu_trigger_delta
= 30*60 #marge autorisée autour de ^^^
100 config_time_between_perdu
=30*60 #temps pendant lequel on ne peut pas perdre
103 config_tag_triggers
=[u
"t(|a)g",u
"ta gueule",u
"la ferme",u
"ferme( |-)la",u
"tais-toi",u
"chut",u
"tu fais trop de bruit",u
"tu parles trop"]
104 config_tag_actions
=[u
"se tait",u
"se tient coi"]
106 u
"Ç'aurait été avec plaisir, mais je ne crois pas que vous puissiez vous passer de mes services.",
107 u
"Dès que cela sera utile.",
108 u
"Une autre fois, peut-être.",
109 u
"Si je me tais, qui vous rappellera combien vous me devez ?",
110 u
"J'aurais aimé accéder à votre requête, mais après mûre réflexion, j'en ai perdu l'envie.",
111 u
"Je ne ressens pas de besoin irrésistible de me taire, navré."]
114 config_tesla_triggers
=[u
"t('|u )es là \?",u
"\?",u
"plop \?",u
"plouf \?"]
115 config_tesla_answers
=[
118 u
"En quoi puis-je me rendre utile ?",
119 u
"On a besoin de moi ?"
121 config_tesla_actions
=[u
"est là",u
"attend des instructions",u
"est toujours disponible"]
123 # config en cas de non-insulte
124 config_compliment_triggers
=[u
"gentil",u
"cool",u
"sympa",u
"efficace"]
125 config_compliment_answers
=[
126 u
"Merci, c'est gentil de votre part. :)",
127 u
"Permettez-moi de vous retourner le compliment, sans ironie cette fois.",
128 u
"Je vous remercie.",
129 u
"C'est trop d'honneur.",
130 u
"Vous êtes bien aimable."
134 config_merci_triggers
=[u
"merci",u
"remercie",u
"thx",u
"thank(|s)"]
135 config_merci_answers
=[u
"Mais de rien.",u
"À votre service. ;)",u
"Quand vous voulez. :)",
136 u
"Tout le plaisir est pour moi."]
139 config_tamere_triggers
=[u
"ta mère"]
140 config_tamere_answers
=[u
"Laissez donc ma mère en dehors de ça !",
141 u
"Puis-je préciser que je n'ai pas de mère ? Seulement deux pères…",
142 u
"""Un certain Max chantait "♩ J'ai vu ta mère sur chat rouleeeeeeette ♫", vous êtes de sa famille ?""",
143 u
"""N'avait-on pas dit "pas les mamans" ?"""]
145 # config pour les actions désagréables à Basile
146 config_bad_action_triggers
=[u
"(frappe|cogne|tape)(| sur)",u
"(démolit|dégomme|fouette|agresse|tabasse)",
147 u
"(vomit|pisse|chie|crache) sur",u
"slap(|s)"]
148 config_bad_action_answers
=[
149 u
"Je ne peux pas dire que j'apprécie, mais je l'ai sans doute bien mérité.",
150 u
"{}: Pourquoi tant de violence en ce monde si doux ?",
151 u
"""Si je n'étais pas aussi prude, je dirais "Mais euh…", cependant, je me contenterai de hausser un sourcil.""",
152 u
"{}: J'aurais préféré que vous ne fassiez pas cela en public.",
153 u
"{}: Entre nous, cela vous gratifie-t-il ?",
154 u
"{}: Une telle relation entre nous deux n'est pas saine, revenons à quelque chose de plus conventionnel. :D",
155 u
"J'ai la désagréable impression que {} cherche comment tuer le temps en ce moment…"
157 config_bad_action_actions
=[u
"prend de la distance, par précaution…",u
"esquive",u
"est bon pour prendre une semaine de repos… virtuel !",u
"n'aime pas servir de souffre douleur, mais n'a malheureusement pas le choix", u
"s'en souviendra sans doute longtemps… de quoi parlait-on déjà ?"]
159 # config pour les actions agréables à Basile
160 config_good_action_triggers
=[u
"fait (:?des bisous|un c(?:â|a)lin|des c(?:â|a)lins) à",u
"embrasse",u
"c(?:â|a)line",u
"caresse"]
161 config_good_action_answers
=[u
":D",u
"{}: Moi aussi je vous aime. ♡",u
"Tant de délicatesse ne saurait être ignorée !",u
"Pour une fois que quelqu'un me considère à ma juste valeur…"]
162 config_good_action_actions
=[u
"ronronne",u
"aimerait exprimer avec des mots simples le bonheur que {} lui procure !",u
"éprouve une joie indescriptible",u
"apprécie que des personnes comme {} soient sur IRC, sans quoi il n'y aurait sans doute jamais personne pour tenir compte de lui"]
164 # config bonjour/bonsoir/que fais-tu encore debout à cette heure, gros sale !
165 config_bonjour_triggers
=[u
"(s|)(a|'|)lu(t|)",u
"hello",u
"pl(o|i)p",u
"pr(ou|ü)t",u
"bonjour",u
"bonsoir",u
"coucou"]
166 config_bonjour_answers
=[u
"Bien le bonjour, {}.",u
"Bonjour {}.",u
"{}: bonjour.",u
"{}: Quel beau temps aujourd'hui (arrêtez-moi si je me trompe) !",u
"Meteo: Cachan"]
167 config_bonsoir_answers
=[u
"Bonsoir {} !",u
"{}: bonsoir.",u
"Quel beau te… euh… bonsoir !",u
"{}: Je cherche désespérément une formule pour vous dire bonsoir, mais j'avoue que mon lexique est un peu… limité."]
168 config_night_answers
=[u
"{}: vous m'avez fait peur, je m'étais assoupi !", u
"Debout à une heure pareille, {} ? Que vous arrive-t-il ?",u
"Vous venez prendre la relève, {} ?"]
169 config_daytime
= [7,18]
170 config_nighttime
= [3, 6]
173 config_bonne_nuit_triggers
=[u
"bonne nuit",u
"'?nite",u
"'?nuit",u
"'?night",u
"good night",u
"'?nenuit"]
174 config_bonne_nuit_answers
=[u
"{}: thanks, make sweet dreams tonight ! ;)",u
"Bonne nuit {}.",u
"À demain {}. :)",u
"{}: si seulement j'avais le droit de dormir… enfin, bonne nuit !",u
"{}: à vous aussi !"]
176 # config PEB est encore en train d'abuser de ses droits.
177 config_kick_answers
=[u
"Suis-je de trop ici ?",u
"{}: je m'excuse pour ce bruit indu qui a stimulé votre colère",u
"{} a le /kick facile, sans doute la fatigue.",u
"{}: j'ai l'impression que vous n'allez pas bien aujourd'hui, vous vous en prenez à un robot !"]
178 config_kick_actions
=[u
"sera désormais exemplaire",u
"prépare une lettre d'excuses à {}",u
"essaiera de ne plus s'attirer les foudres de {}",u
"croyait avoir tout bien fait… cruelle déception."]
180 # config on m'a demandé de mourir/partir
181 config_quit_messages
=[u
"Bien que cela me désole, je me vois dans l'obligation de vous abandonner."]
182 config_leave_messages
=config_quit_messages
184 class NKError(Exception):
185 def __init__(self
,msg
):
186 Exception.__init
__(self
)
190 def __unicode__(self
):
191 return unicode(self
.msg
)
193 class NKRefused(NKError
):
196 class NKHelloFailed(NKError
):
199 class NKUnknownError(NKError
):
202 def log(serveur
,channel
,auteur
=None,message
=None):
203 f
=open(get_config_logfile(serveur
),"a")
204 if auteur
==message
==None:
205 # alors c'est que c'est pas un channel mais juste une ligne de log
206 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
208 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
210 if config_debug_stdout
:
217 # On établit la connexion sur port 4242
218 sock
.connect(("127.0.0.1",4242))
220 sock
=ssl
.wrap_socket(sock
,ca_certs
='../keys/ca_.crt')
222 sock
.write('hello "Basile"')
223 # On récupère la réponse du hello
226 except Exception as exc
:
227 # Si on a foiré quelque part, c'est que le serveur est down
228 raise NKRefused(str(exc
))
229 if out
["retcode"]==0:
231 elif out
["retcode"]==11:
232 raise NKHelloFailed(out
["errmsg"])
234 raise NKUnknownError(out
["errmsg"])
236 def login_NK(username
,password
,typ
="bdd"):
238 if typ
=="special": # ça c'est pour Basile lui-même
241 masque
='[["all"],["all"],false]'
243 # Basile a un compte special user
244 commande
='login [%s,%s,"%s",%s]'%(json
.dumps(username
),json
.dumps(password
),typ
,masque
)
247 except Exception as exc
:
248 # Si on a foiré quelque part, c'est que le serveur est down
249 raise NKRefused(str(exc
))
250 # On vérifie ensuite que le login
251 return json
.loads(out
),sock
254 def is_something(chain
,matches
,avant
=u
".*(?:^| )",apres
=u
"(?:$|\.| |,|;).*",case_sensitive
=False,debug
=False):
256 chain
=unicode(chain
,"utf8")
258 chain
=unicode(chain
,"utf8").lower()
259 allmatches
="("+"|".join(matches
)+")"
260 reg
=(avant
+allmatches
+apres
).lower()
261 o
=re
.match(reg
,chain
)
264 def is_insult(chain
,debug
=True):
265 return is_something(chain
,config_insultes
,avant
=".*(?:^| |')")
266 def is_not_insult(chain
):
267 chain
=unicode(chain
,"utf8")
268 insult_regexp
=u
"("+u
"|".join(config_insultes
)+u
")"
269 middle_regexp
=u
"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
270 reg
=".*pas %s%s.*"%(middle_regexp
,insult_regexp
)
271 if re
.match(reg
,chain
):
275 def is_compliment(chain
,debug
=True):
276 return is_something(chain
,config_compliment_triggers
,avant
=".*(?:^| |')")
278 return is_something(chain
,config_perdu
)
280 return is_something(chain
,config_tag_triggers
)
282 return is_something(chain
,config_gros
)
284 return is_something(chain
,config_tesla_triggers
,avant
=u
"^",apres
=u
"$",debug
=True)
286 return is_something(chain
,config_merci_triggers
)
287 def is_tamere(chain
):
288 return is_something(chain
,config_tamere_triggers
)
289 def is_bad_action_trigger(chain
,pseudo
):
290 return is_something(chain
,config_bad_action_triggers
,avant
=u
"^",
291 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
292 def is_good_action_trigger(chain
,pseudo
):
293 return is_something(chain
,config_good_action_triggers
,avant
=u
"^",
294 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
295 def is_bonjour(chain
):
296 return is_something(chain
,config_bonjour_triggers
,avant
=u
"^")
297 def is_bonne_nuit(chain
):
298 return is_something(chain
,config_bonne_nuit_triggers
,avant
=u
"^")
300 return re
.match(u
"^(pan|bim|bang)( .*)?$",unicode(chain
,"utf8").lower().strip())
303 _
,_
,_
,h
,m
,s
,_
,_
,_
=time
.localtime()
304 return (conf
[0],0,0)<(h
,m
,s
)<(conf
[1],0,0)
306 return is_time(config_daytime
)
308 return is_time(config_nighttime
)
311 class UnicodeBotError(Exception):
313 def bot_unicode(chain
):
315 unicode(chain
,"utf8")
316 except UnicodeDecodeError as exc
:
317 raise UnicodeBotError
319 class Basile(ircbot
.SingleServerIRCBot
):
320 def __init__(self
,serveur
,debug
=False):
321 temporary_pseudo
=config_irc_pseudo
+str(random
.randrange(10000,100000))
322 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
323 temporary_pseudo
,"Basile, le bot irc.[Codé par 20-100, fouettez-le]", 10)
326 self
.overops
=config_overops
327 self
.ops
=self
.overops
+config_ops
328 self
.report_bugs_to
=config_report_bugs_to
329 self
.chanlist
=config_chanlist
330 self
.identities
=pickle
.load(open("identities.pickle","r"))
331 self
.stay_channels
=config_stay_channels
332 self
.quiet_channels
=config_quiet_channels
336 def new_connection_NK(self
,serv
,username
,password
,typ
="bdd"):
338 login_result
,sock
=login_NK(username
,password
,typ
)
339 droits
,retcode
,errmsg
=login_result
["msg"],login_result
["retcode"],login_result
["errmsg"]
340 except NKRefused
as exc
:
341 for report
in self
.report_bugs_to
:
342 serv
.privmsg(report
,"Le Serveur NK2015 est down.")
344 except NKHelloFailed
as exc
:
345 for report
in self
.report_bugs_to
:
347 "La version du site utilisée n'est pas supportée par le serveur NK2015.")
349 except NKUnknownError
as exc
:
350 erreurs
=["Une fucking erreur inconnue s'est produite"]
351 erreurs
+=str(exc
).split("\n")
352 for report
in self
.report_bugs_to
:
354 serv
.privmsg(report
,err
)
356 except Exception as exc
:
357 # Exception qui ne vient pas de la communication avec le serveur NK2015
358 log(self
.serveur
,"Erreur dans new_connection_NK\n"+str(exc
))
365 def give_me_my_pseudo(self
,serv
):
366 serv
.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo
,config_irc_password
))
367 serv
.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo
,config_irc_password
))
369 serv
.nick(config_irc_pseudo
)
371 def on_welcome(self
, serv
, ev
):
372 self
.serv
=serv
# ça serv ira :)
373 self
.give_me_my_pseudo(serv
)
374 serv
.privmsg("NickServ","identify %s"%(config_irc_password))
375 log(self
.serveur
,"Connected")
377 self
.chanlist
=["#bot"]
378 for c
in self
.chanlist
:
379 log(self
.serveur
,"JOIN %s"%(c))
381 # on ouvre la connexion note de Basile, special user
382 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,config_note_password
,"special")[1]
384 for report
in self
.report_bugs_to
:
385 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
387 def lost(self
,serv
,channel
,forced
=False):
388 if self
.last_perdu
+config_time_between_perdu
<time
.time() or forced
:
389 if not channel
in self
.quiet_channels
or forced
:
390 serv
.privmsg(channel
,"J'ai perdu !")
391 self
.last_perdu
=time
.time()
392 delay
=config_time_between_perdu_trigger
393 delta
=config_time_between_perdu_trigger_delta
394 serv
.execute_delayed(random
.randrange(delay
-delta
,delay
+delta
),self
.lost
,(serv
,channel
))
396 def pourmoi(self
, serv
, message
):
397 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
400 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
401 return (True,message
[size
+1:].lstrip(" "))
403 return (False,message
)
405 def on_privmsg(self
, serv
, ev
):
406 message
=ev
.arguments()[0]
407 auteur
= irclib
.nm_to_n(ev
.source())
409 test
=bot_unicode(message
)
410 except UnicodeBotError
:
412 "Si je n'avais pas été créé avec la plus grande attention, votre encodage aurait eu raison de moi…")
414 message
=message
.split()
415 cmd
=message
[0].lower()
418 helpdico
={"help":["""HELP <commande>
419 Affiche de l'aide sur la commande""",None,None],
420 "identify": ["""IDENTIFY <username> <password>
421 Vérifie le mot de passe et me permet de savoir à l'avenir quel est votre pseudo note kfet.
422 Sans paramètre, je vous précise sous quel pseudo je vous connais.""",None,None],
423 "drop":["""DROP <password>
424 Vérifie le mot de passe et me fait d'oublier votre pseudo note kfet.""",None,None],
426 Affiche votre solde, si je connais votre pseudo note kfet.""",
428 Affiche le solde de la personne désignée (par son pseudo note).""",None],
429 "join": [None, """JOIN <channel>
430 Me fait rejoindre le channel""",None],
431 "leave": [None,"""LEAVE <channel>
432 Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
433 "quiet": [None,"""QUIET <channel>
434 Me rend silencieux sur le channel.""",None],
435 "noquiet": [None,"""NOQUIET <channel>
436 Me rend la parole sur le channel.""",None],
437 "lost": [None,"""LOST <channel>
438 Me fait perdre sur le channel.""",None],
439 "reconnect": [None,"""RECONNECT
440 Établit à nouveau la connexion avec le serveur NK2015""",None],
441 "say": [None,None,"""SAY <channel> <message>
442 Me fait parler sur le channel."""],
443 "do": [None,None,"""DO <channel> <action>
444 Me fait faitre une action (/me) sur le channel."""],
445 "stay": [None,None,"""STAY <channel>
446 Ajoute le channel à ma stay_list."""],
447 "nostay": [None,None,"""NOSTAY <channel>
448 Retire le channel de ma stay_list."""],
449 "ops": [None,None,"""OPS
450 Affiche la liste des ops."""],
451 "overops": [None,None,"""OVEROPS
452 Affiche la liste des overops."""],
453 "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
454 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
455 "die": [None,None,"""DIE
456 Me déconnecte du serveur IRC."""]
458 helpmsg_default
="Liste des commandes disponibles :\nHELP IDENTIFY DROP SOLDE"
459 helpmsg_ops
=" JOIN LEAVE QUIET NOQUIET LOST RECONNECT"
460 helpmsg_overops
=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
461 op
,overop
=auteur
in self
.ops
, auteur
in self
.overops
463 helpmsg
=helpmsg_default
467 helpmsg
+=helpmsg_overops
469 helpmsgs
=helpdico
.get(message
[1].lower(),["Commande inconnue.",None,None])
471 if op
and helpmsgs
[1]:
473 helpmsg
+="\n"+helpmsgs
[1]
476 if overop
and helpmsgs
[2]:
478 helpmsg
+="\n"+helpmsgs
[2]
481 for ligne
in helpmsg
.split("\n"):
482 serv
.privmsg(auteur
,ligne
)
483 elif cmd
=="identify":
485 if self
.identities
.has_key(auteur
):
486 serv
.privmsg(auteur
,"Je vous connais sous le pseudo note %s."%(
487 self
.identities
[auteur
].encode("utf8")))
489 serv
.privmsg(auteur
,"Je ne connais pas votre pseudo note.")
490 elif len(message
)>=3:
491 username
,password
=message
[1],unicode(" ".join(message
[2:]),"utf8")
492 success
,_
=self
.new_connection_NK(serv
,username
,password
)
494 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
495 serv
.privmsg(auteur
,"Identité enregistrée.")
496 self
.identities
[auteur
]=username
497 pickle
.dump(Xself
.identities
,open("identities.pickle","w"))
499 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
500 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
502 serv
.privmsg(auteur
,u
"Syntaxe : IDENTIFY [<username> <password>]")
505 if self
.identities
.has_key(auteur
):
506 password
=" ".join(message
[1:])
507 success
,_
=self
.new_connection_NK(serv
,self
.identities
[auteur
],password
)
509 del self
.identities
[auteur
]
510 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
511 pickle
.dump(self
.identities
,open("identities.pickle","w"))
512 serv
.privmsg(auteur
,"Identité oubliée.")
514 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
515 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
517 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
519 serv
.privmsg(auteur
,"Syntaxe : DROP <password>")
521 if auteur
in self
.ops
:
523 if message
[1] in self
.chanlist
:
524 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
526 serv
.join(message
[1])
527 self
.chanlist
.append(message
[1])
528 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
529 log(self
.serveur
,"priv",auteur
," ".join(message
))
531 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
535 if auteur
in self
.ops
and len(message
)>1:
536 if message
[1] in self
.chanlist
:
537 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
538 self
.quitter(message
[1]," ".join(message
[2:]))
539 self
.chanlist
.remove(message
[1])
540 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
542 serv
.privmsg(auteur
,"Non, je reste !")
543 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
545 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
549 if auteur
in self
.overops
:
551 if message
[1] in self
.stay_channels
:
552 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
553 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
555 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
556 self
.stay_channels
.append(message
[1])
557 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
559 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
563 if auteur
in self
.overops
:
565 if message
[1] in self
.stay_channels
:
566 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
567 self
.stay_channels
.remove(message
[1])
568 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
570 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
571 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
576 if auteur
in self
.overops
:
577 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
581 elif cmd
=="reconnect":
582 if auteur
in self
.ops
:
584 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,
585 config_note_password
,"special")[1]
586 except Exception as exc
:
588 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
590 serv
.privmsg(auteur
,"%s: done"%(auteur))
591 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
593 serv
.privmsg(auteur
,"%s: failed"%(auteur))
594 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
595 for report
in self
.report_bugs_to
:
596 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ? Server dead ?")
600 if auteur
in self
.ops
:
602 if message
[1] in self
.quiet_channels
:
603 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
604 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
606 self
.quiet_channels
.append(message
[1])
607 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
608 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
610 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
614 if auteur
in self
.ops
:
616 if message
[1] in self
.quiet_channels
:
617 self
.quiet_channels
.remove(message
[1])
618 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
619 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
621 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
622 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
626 if auteur
in self
.overops
and len(message
)>2:
627 serv
.privmsg(message
[1]," ".join(message
[2:]))
628 log(self
.serveur
,"priv",auteur
," ".join(message
))
629 elif len(message
)<=2:
630 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
634 if auteur
in self
.overops
and len(message
)>2:
635 serv
.action(message
[1]," ".join(message
[2:]))
636 log(self
.serveur
,"priv",auteur
," ".join(message
))
637 elif len(message
)<=2:
638 serv
.privmsg(auteur
,"Syntaxe : DO <channel> <action>")
642 if auteur
in self
.overops
and len(message
)>2:
643 serv
.kick(message
[1],message
[2]," ".join(message
[3:]))
644 log(self
.serveur
,"priv",auteur
," ".join(message
))
645 elif len(message
)<=2:
646 serv
.privmsg(auteur
,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
650 if auteur
in self
.ops
and len(message
)>1:
651 serv
.privmsg(message
[1],"J'ai perdu !")
652 log(self
.serveur
,"priv",auteur
," ".join(message
))
653 elif len(message
)<=1:
654 serv
.privmsg(auteur
,"Syntaxe : LOST <channel>")
659 if self
.identities
.has_key(auteur
):
661 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(self
.identities
[auteur
])))
662 ret
=json
.loads(self
.nk
.read())
663 solde
=ret
["msg"][0]["solde"]
664 pseudo
=ret
["msg"][0]["pseudo"]
665 except Exception as exc
:
667 serv
.privmsg(auteur
,"failed")
668 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
670 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
671 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
673 serv
.privmsg(canal
,"Je ne connais pas ton pseudo note.")
674 elif auteur
in self
.ops
:
676 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(message
[1])))
677 ret
=json
.loads(self
.nk
.read())
678 solde
=ret
["msg"][0]["solde"]
679 pseudo
=ret
["msg"][0]["pseudo"]
680 except Exception as exc
:
681 serv
.privmsg(auteur
,"failed")
682 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
684 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
686 if auteur
in self
.overops
:
687 serv
.privmsg(auteur
," ".join(self
.ops
))
691 if auteur
in self
.overops
:
692 serv
.privmsg(auteur
," ".join(self
.overops
))
698 serv
.privmsg(auteur
,"Je n'ai pas compris. Essayez HELP…")
700 def on_pubmsg(self
, serv
, ev
):
701 auteur
= irclib
.nm_to_n(ev
.source())
703 message
= ev
.arguments()[0]
705 test
=bot_unicode(message
)
706 except UnicodeBotError
:
707 if not canal
in self
.quiet_channels
:
709 "%s: Si je n'avais pas été créé avec la plus grande attention, votre encodage aurait eu raison de moi…"%(auteur))
711 pour_moi
,message
=self
.pourmoi(serv
,message
)
712 if pour_moi
and message
.split()!=[]:
713 cmd
=message
.split()[0].lower()
715 args
=" ".join(message
.split()[1:])
718 if cmd
in ["meurs","die","crève"]:
719 if auteur
in self
.overops
:
720 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
723 serv
.privmsg(canal
,"%s: mourrez vous-même !"%(auteur))
724 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
726 elif cmd
in ["part","leave","dégage","va-t-en","tut'tiresailleurs,c'estmesgalets"]:
727 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
728 or auteur
in self
.overops
):
730 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
731 if canal
in self
.chanlist
:
732 self
.chanlist
.remove(canal
)
734 serv
.privmsg(canal
,"%s: Navré, mais je me vois contraint de refuser, je ne peux pas céder aux exigences du premier venu."%(auteur))
735 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
737 elif cmd
in ["reconnect"]:
738 if auteur
in self
.ops
:
740 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,
741 config_note_password
,"special")[1]
742 except Exception as exc
:
744 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
746 serv
.privmsg(canal
,"%s: done"%(auteur))
747 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
749 serv
.privmsg(canal
,"%s: failed"%(auteur))
750 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
751 for report
in self
.report_bugs_to
:
752 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ? Server dead ?")
754 serv
.privmsg(canal
,"%s: Encore eût-il fallu que je sois programmé pour vous obéir !"%(auteur))
755 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
757 elif cmd
in ["deviens","pseudo"]:
758 if auteur
in self
.ops
:
761 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
763 if cmd
in ["meur", "meurt","meurre","meurres"] and not canal
in self
.quiet_channels
:
764 serv
.privmsg(canal
,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
765 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
766 serv
.privmsg(canal
,"%s: pong"%(auteur))
768 elif cmd
in ["solde","!solde"]:
769 if self
.identities
.has_key(auteur
):
770 pseudo
=self
.identities
[auteur
]
772 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(pseudo
)))
773 ret
=json
.loads(self
.nk
.read())
774 solde
=ret
["msg"][0]["solde"]
775 pseudo
=ret
["msg"][0]["pseudo"]
776 except Exception as exc
:
777 serv
.privmsg(canal
,"%s: failed"%(auteur))
778 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
780 serv
.privmsg(canal
,"%s: %s (%s)"%(auteur
,float(solde
)/100,pseudo
.encode("utf8")))
781 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
783 serv
.privmsg(canal
,"%s: Je ne connais pas votre pseudo note."%(auteur))
784 log(self
.serveur
,canal
,auteur
,message
+"[unknown]")
785 elif (re
.match("!?(pain au chocolat|chocolatine)",message
.lower())
786 and not canal
in self
.quiet_channels
):
787 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
788 elif re
.match("!?manzana",message
.lower()) and not canal
in self
.quiet_channels
:
789 if auteur
in config_manzana
:
790 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
791 elif auteur
in config_manzana_bis
:
792 serv
.action(canal
,"sert un grand verre de jus de pomme à %s : tout le monde sait qu'il ne boit pas."%(auteur))
794 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
795 if is_insult(message
) and not canal
in self
.quiet_channels
:
796 if is_not_insult(message
):
797 answer
=random
.choice(config_compliment_answers
)
798 for ligne
in answer
.split("\n"):
799 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
801 answer
=random
.choice(config_insultes_answers
)
802 for ligne
in answer
.split("\n"):
803 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
804 elif is_compliment(message
) and not canal
in self
.quiet_channels
:
805 answer
=random
.choice(config_compliment_answers
)
806 for ligne
in answer
.split("\n"):
807 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
808 gros_match
=is_gros(message
)
809 if gros_match
and not canal
in self
.quiet_channels
:
810 taille
=get_filesize()
811 answer
=u
"Mais non, je ne suis pas %s, %sKo tout au plus…"%(gros_match
.groups()[0],taille
)
812 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
.encode("utf8")))
813 if is_tesla(message
) and not canal
in self
.quiet_channels
:
814 l1
,l2
=config_tesla_answers
,config_tesla_actions
815 n1
,n2
=len(l1
),len(l2
)
816 i
=random
.randrange(n1
+n2
)
818 serv
.action(canal
,l2
[i
-n1
].encode("utf8"))
820 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
821 if is_tamere(message
) and not canal
in self
.quiet_channels
:
822 answer
=random
.choice(config_tamere_answers
)
823 for ligne
in answer
.split("\n"):
824 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
825 if is_tag(message
) and not canal
in self
.quiet_channels
:
826 if auteur
in self
.ops
:
827 action
=random
.choice(config_tag_actions
)
828 serv
.action(canal
,action
.encode("utf8"))
829 self
.quiet_channels
.append(canal
)
831 answer
=random
.choice(config_tag_answers
)
832 for ligne
in answer
.split("\n"):
833 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
834 if is_merci(message
):
835 answer
=random
.choice(config_merci_answers
)
836 for ligne
in answer
.split("\n"):
837 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
838 out
=re
.match(ur
"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
839 unicode(message
.upper(),"utf8"))
840 if re
.match("ma bite dans ton oreille",message
) and not canal
in self
.quiet_channels
:
841 serv
.privmsg(canal
,"%s: Seul un olasd peut imiter un olasd dans un de ses grands jours !"%(auteur))
842 if out
and not canal
in self
.quiet_channels
:
846 serv
.privmsg(canal
,"%s: %s !"%(auteur
,out
+1))
848 serv
.privmsg(canal
,"%s: Ciel, un maxint ! Heureusement que je suis en python…"%(auteur))
850 if out
+1>1000 and random
.randrange(4)==0:
851 serv
.privmsg(canal
,"%s: Vous savez, moi et les chiffres…"%(auteur))
853 except Exception as exc
:
855 if re
.match("[A-Y]",out
):
856 alphabet
="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
857 serv
.privmsg(canal
,"%s: %s !"%(auteur
,alphabet
[alphabet
.index(out
)+1]))
859 serv
.privmsg(canal
,"%s: Je ne vous remercie pas, j'ai l'air idiot ainsi… [ ?"%(auteur))
861 serv
.privmsg(canal
,"%s: Nous devrions nous en tenir là, ça va finir par poser des problèmes…"%(auteur))
862 elif re
.match(ur
"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out
):
864 return "".join([{u
"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i
]:u
"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i
]
865 for i
in range(20)}[j
]
867 out
=int(translate(out
))
868 serv
.privmsg(canal
,"%s: %s !"%(auteur
,translate(str(out
+1)).encode("utf8")))
869 if is_bonjour(message
) and not canal
in self
.quiet_channels
:
871 answer
=random
.choice(config_night_answers
)
873 answer
=random
.choice(config_bonjour_answers
)
875 answer
=random
.choice(config_bonsoir_answers
)
876 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
877 if is_bonne_nuit(message
) and not canal
in self
.quiet_channels
:
878 answer
=random
.choice(config_bonne_nuit_answers
)
879 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
880 if is_pan(message
) and not canal
in self
.quiet_channels
:
881 serv
.privmsg(canal
,"%s: ce n'est pas sur moi qu'il faut tirer, même si je sais que j'attire l'œil !"%(auteur))
883 if message
in ["!pain au chocolat","!chocolatine"] and not canal
in self
.quiet_channels
:
884 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
885 if message
in ["!manzana"] and not canal
in self
.quiet_channels
:
886 if auteur
in config_manzana
:
887 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
888 elif auteur
in config_manzana_bis
:
889 serv
.action(canal
,"sert un grand verre de jus de pomme à %s : tout le monde sait qu'il ne boit pas."%(auteur))
891 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
892 if re
.match(u
'^ *(.|§|!|/|/|:|)(w|b) [0-9]+$',message
.decode("utf8")) and not canal
in self
.quiet_channels
:
893 failanswers
=config_buffer_fail_answers
894 answer
=random
.choice(failanswers
)
895 serv
.privmsg(canal
,("%s: %s"%(auteur
,answer
)).encode("utf8"))
896 if not canal
in self
.quiet_channels
:
898 if re
.match((u
"^("+u
"|".join(config_bonjour_triggers
)
899 +u
")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
900 ).format(mypseudo
).lower(), message
.strip().lower()):
901 answer
=random
.choice(config_bonjour_answers
)
902 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
903 if (is_perdu(message
) and not canal
in self
.quiet_channels
):
904 # proba de perdre sur trigger :
905 # avant 30min (enfin, config) : 0
906 # ensuite, +25%/30min, linéairement
907 deltat
=time
.time()-self
.last_perdu
908 barre
=(deltat
-config_time_between_perdu
)/(2*3600.0)
909 if random
.uniform(0,1)<barre
:
910 serv
.privmsg(canal
,"%s: J'ai perdu !"%(auteur))
911 self
.last_perdu
=time
.time()
913 def on_action(self
, serv
, ev
):
914 action
= ev
.arguments()[0]
915 auteur
= irclib
.nm_to_n(ev
.source())
916 channel
= ev
.target()
918 test
=bot_unicode(action
)
919 except UnicodeBotError
:
920 serv
.privmsg(channel
,
921 "%s: Si je n'avais pas été créé avec la plus grande attention, votre encodage m'aurait déjà tué…"%(auteur))
925 if is_bad_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
926 l1
,l2
=config_bad_action_answers
,config_bad_action_actions
927 n1
,n2
=len(l1
),len(l2
)
928 i
=random
.randrange(n1
+n2
)
930 serv
.action(channel
,l2
[i
-n1
].format(auteur
).encode("utf8"))
932 serv
.privmsg(channel
,l1
[i
].format(auteur
).format(auteur
).encode("utf8"))
933 if is_good_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
934 l1
,l2
=config_good_action_answers
,config_good_action_actions
935 n1
,n2
=len(l1
),len(l2
)
936 i
=random
.randrange(n1
+n2
)
938 serv
.action(channel
,l2
[i
-n1
].format(auteur
).format(auteur
).encode("utf8"))
940 serv
.privmsg(channel
,l1
[i
].format(auteur
).format(auteur
).encode("utf8"))
942 def on_kick(self
,serv
,ev
):
943 auteur
= irclib
.nm_to_n(ev
.source())
944 channel
= ev
.target()
945 victime
= ev
.arguments()[0]
946 raison
= ev
.arguments()[1]
947 if victime
==self
.nick
:
948 log(self
.serveur
,"%s kické de %s par %s (raison : %s)" %(victime
,channel
,auteur
,raison
))
951 l1
,l2
=config_kick_answers
,config_kick_actions
952 n1
,n2
=len(l1
),len(l2
)
953 i
=random
.randrange(n1
+n2
)
955 serv
.action(channel
,l2
[i
-n1
].format(auteur
).encode("utf8"))
957 serv
.privmsg(channel
,l1
[i
].format(auteur
).encode("utf8"))
959 def quitter(self
,chan
,leave_message
=None):
960 if leave_message
==None:
961 leave_message
=random
.choice(config_leave_messages
)
962 self
.serv
.part(chan
,message
=leave_message
.encode("utf8"))
965 quit_message
=random
.choice(config_quit_messages
)
966 self
.die(msg
=quit_message
.encode("utf8"))
969 return self
.serv
.get_nickname()
970 nick
=property(_getnick
)
973 if __name__
=="__main__":
976 print "Usage : basile.py <serveur> [--debug]"
979 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
983 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
984 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
986 serveur
=serveurs
[serveur
]
988 print "Server Unknown : %s"%(serveur)
990 basile
=Basile(serveur
,debug
)