4 # Codé par 20-100 le 25/05/12
6 # Un bot IRC qui pose des questions d'histoire
15 from cast_as_date
import *
17 config_password
="EtTaMère,ElleEstNéeQuand?"
18 config_pseudo
="historien"
19 config_chanlist
=["#bot","#flood"]
20 config_play_channels
=["#flood"]
21 config_stay_channels
=["#flood","#bot"]
22 config_overops
=["[20-100]","[20-100]_"]
23 config_ops
=["PEB","Petite-Peste"]
25 config_source_file
="dates.txt"
26 config_played_file_template
="played.%s.txt" #il faut rajouter le nom du serveur
27 def get_config_played_file(serveur
):
28 serveurs
={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
29 return config_played_file_template
%(serveurs
[serveur
])
30 ttrig
=120 #time trigger (normalement 120, mais diminué pour les tests)
31 Ttrig
=600 #between two enigms
32 config_time_incompressible
=15 #on peut pas retrigger en dessous de ce temps (60)
33 config_time_incompressible_clue
=60 #on peut pas forcer la demande d'indice en dessous
35 config_score_file
="scores.pickle"
37 config_tag_triggers
=[u
"t(|a)g",u
"ta gueule",u
"la ferme",u
"ferme( |-)la",u
"tais-toi",u
"chut"]
38 config_tag_actions
=[u
"se tait",u
"ferme sa gueule",u
"se la ferme",u
"la ferme"]
39 config_tag_answers
=[u
"J'me tais si j'veux !",
40 u
"Je t'entends pas :°",
42 u
"Non, j'ai pas envie",
43 u
"Peut-être quand toi tu la fermeras, et encore…"]
48 config_debug_stdout
= True
49 config_logfile_template
="historien.%s.log"
50 def get_config_logfile(serveur
):
51 serveurs
={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
52 return config_logfile_template
%(serveurs
[serveur
])
54 config_quit_messages
=[u
"%s : %s quitte le serveur IRC"]
56 config_leave_messages
=[u
"%s : %s quitte le channel"]
58 class UnicodeBotError(Exception):
60 def bot_unicode(chain
):
63 except UnicodeDecodeError:
66 def log(serveur
,channel
,auteur
=None,message
=None):
67 f
=open(get_config_logfile(serveur
),"a")
68 if auteur
==message
==None:
69 # alors c'est que c'est pas un channel mais juste une ligne de log
70 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
72 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
74 if config_debug_stdout
:
79 def reussi(message
,answer
,auteur
):
80 print message
, "#?#", answer
81 if auteur
in config_level3
:
82 return answer
in message
83 if auteur
in config_level2
:
84 return answer
in message
87 date
=cast_as_date(message
.lower())
89 except ThisIsNotADate
:
91 as_string
="%02d/%02d/%d"%(date
[2],date
[1],date
[0])
98 def is_something(chain
,matches
,avant
=u
".*(?:^| )",apres
=u
"(?:$|\.| |,|;).*",case_sensitive
=False,debug
=False):
100 chain
=unicode(chain
,"utf8")
102 chain
=unicode(chain
,"utf8").lower()
103 allmatches
="("+"|".join(matches
)+")"
104 reg
=(avant
+allmatches
+apres
).lower()
105 o
=re
.match(reg
,chain
)
109 return is_something(chain
,config_tag_triggers
)
111 class RefuseError(Exception):
114 class Deconnaisseur(ircbot
.SingleServerIRCBot
):
115 def __init__(self
,serveur
,debug
=False):
116 temporary_pseudo
=config_pseudo
+str(random
.randrange(10000,100000))
117 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
118 temporary_pseudo
,"Un bot irc qui a au moins l'agreg d'histoire", 10)
121 self
.overops
=config_overops
122 self
.ops
=self
.overops
+config_ops
123 self
.chanlist
=config_chanlist
124 self
.stay_channels
=config_stay_channels
125 self
.play_channels
=config_play_channels
126 self
.play_status
={i
:[0] for i
in self
.play_channels
}
127 self
.quiet_channels
=[]
129 def give_me_my_pseudo(self
,serv
):
130 serv
.privmsg("NickServ","RECOVER %s %s"%(config_pseudo
,config_password
))
131 serv
.privmsg("NickServ","RELEASE %s %s"%(config_pseudo
,config_password
))
133 serv
.nick(config_pseudo
)
135 def on_welcome(self
, serv
, ev
):
136 self
.serv
=serv
# ça serv ira :)
137 self
.give_me_my_pseudo(serv
)
138 serv
.privmsg("NickServ","identify %s"%(config_password))
139 log(self
.serveur
,"Connected")
141 self
.chanlist
=["#bot"]
142 self
.play_channels
=["#bot"]
143 for c
in self
.chanlist
:
144 log(self
.serveur
,"JOIN %s"%(c))
146 for c
in self
.play_channels
:
147 token
=time
.time()-3600
148 self
.play_status
[c
]=[0,token
]
149 serv
.execute_delayed(random
.randrange(ttrig
),self
.start_enigme
,(serv
,c
,token
))
151 def start_enigme(self
,serv
,channel
,token
=None):
152 if self
.play_status
[channel
][0]==0 and channel
in self
.play_channels
:
154 if token
==self
.play_status
[channel
][-1]:
157 if time
.time() > self
.play_status
[channel
][-1]+config_time_incompressible
:
162 date
,evenement
=self
.get_enigme()
163 log(self
.serveur
,channel
,u
"$Date$".encode("utf8"),("%s : %s"%(date
, evenement
)).encode("utf8"))
164 serv
.privmsg(channel
,evenement
.encode("utf8"))
166 self
.play_status
[channel
]=[1,date
,evenement
,token
]
167 serv
.execute_delayed(random
.randrange(ttrig
*3,ttrig
*5),self
.give_indice
,(serv
,channel
,token
))
170 def give_indice(self
,serv
,channel
,token
):
171 if self
.play_status
[channel
][0]==1:
173 # c'est donc que l'indice a été demandé
174 if self
.play_status
[channel
][-1]+config_time_incompressible_clue
<time
.time():
175 token
=self
.play_status
[channel
][-1]
176 if self
.play_status
[channel
][-1]==token
:
177 date
=self
.play_status
[channel
][1]
179 serv
.privmsg(channel
,"indice : %s"%(indice).encode("utf8"))
180 self
.play_status
[channel
][0]=2
181 serv
.execute_delayed(random
.randrange(ttrig
*1,ttrig
*3),self
.give_answer
,(serv
,channel
,token
))
182 def give_answer(self
,serv
,channel
,token
):
183 if self
.play_status
[channel
][0]==2 and self
.play_status
[channel
][-1]==token
:
184 date
=self
.play_status
[channel
][1]
185 serv
.privmsg(channel
,"C'était le %s"%(date).encode("utf8"))
187 self
.play_status
[channel
]=[0,token
]
188 serv
.execute_delayed(random
.randrange(Ttrig
*5,Ttrig
*10),self
.start_enigme
,(serv
,channel
,token
))
190 def get_enigme(self
):
191 # on récupère les dates
192 f
=open(config_source_file
)
195 l
=[i
.split(" : ",2) for i
in l
]
196 dates
={int(i
[0]):i
[1:] for i
in l
}
197 # on va chercher combien de fois elles ont été jouées
198 played_file
=get_config_played_file(self
.serveur
)
202 l
=re
.findall("(.*):(.*)",t
)
203 played
={int(i
[0]):int(i
[1]) for i
in l
}
204 # on récupère le nombre d'occurrences le plus faible
205 mini
=min(played
.values())
206 # on choisit un id dans ceux qui ont ce nombre d'occurences
207 id_choisi
=random
.choice([k
for k
,v
in played
.items() if v
==mini
])
208 date
,evenement
=dates
[id_choisi
]
209 evenement
=evenement
.replace("\n","")
210 # on incrémente la choisie
212 # on enregistre le played_file
213 f
=open(played_file
,"w")
214 f
.write("\n".join(["%-4s : %s"%(k
,v
) for k
,v
in played
.items()]))
216 return map(lambda x
:x
.decode("utf8"), [date
,evenement
])
218 def pourmoi(self
, serv
, message
):
221 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
222 return (True,message
[size
+1:].strip(" "))
224 return (False,message
)
226 def on_privmsg(self
, serv
, ev
):
227 message
=ev
.arguments()[0]
228 auteur
= irclib
.nm_to_n(ev
.source())
230 test
=bot_unicode(message
)
231 except UnicodeBotError
:
233 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
235 message
=message
.split()
236 cmd
=message
[0].lower()
239 helpmsg_default
="""Liste des commandes :
240 HELP Affiche ce message d'aide
241 SCORE Affiche ton score (SCORE TRANSFERT <pseudo> [<n>] pour transférer des points)
242 SCORES Affiche les scores"""
244 JOIN Faire rejoindre un channel (sans paramètres, donne la liste des chans actuels)
245 LEAVE Faire quitter un channel
246 PLAY Passe un channel en mode "jouer"
247 NOPLAY Passe un channel en mode "ne pas jouer"
248 QUIET Se taire sur un channel
249 NOQUIET Opposé de QUIET"""
251 SCORES {DEL|ADD|SUB} Tu veux un dessin ?
252 SAY Fais envoyer un message sur un chan ou à une personne
253 STAY Ignorera les prochains LEAVE pour un chan
254 NOSTAY Opposé de STAY
255 STATUS Montre l'état courant
257 helpmsg
=helpmsg_default
258 if auteur
in self
.ops
:
260 if auteur
in self
.overops
:
261 helpmsg
+=helpmsg_overops
262 for ligne
in helpmsg
.split("\n"):
263 serv
.privmsg(auteur
,ligne
)
265 if auteur
in self
.ops
:
267 if message
[1] in self
.chanlist
:
268 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
270 serv
.join(message
[1])
271 self
.chanlist
.append(message
[1])
272 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
273 log(self
.serveur
,"priv",auteur
," ".join(message
))
275 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
279 if auteur
in self
.ops
and len(message
)>1:
280 if message
[1] in self
.chanlist
:
281 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
282 self
.quitter(message
[1]," ".join(message
[2:]))
283 self
.chanlist
.remove(message
[1])
284 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
286 serv
.privmsg(auteur
,"Non, je reste !")
287 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
289 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
293 if auteur
in self
.overops
:
295 if message
[1] in self
.stay_channels
:
296 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
297 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
299 self
.stay_channels
.append(message
[1])
300 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
301 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
303 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
307 if auteur
in self
.overops
:
309 if message
[1] in self
.stay_channels
:
310 self
.stay_channels
.remove(message
[1])
311 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
312 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
314 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
315 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
319 if auteur
in self
.ops
:
321 if message
[1] in self
.play_channels
:
322 serv
.privmsg(auteur
,"Je play déjà sur %s."%(message
[1]))
323 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
325 self
.play_channels
.append(message
[1])
326 self
.play_status
[message
[1]]=[0,time
.time()-3600]
327 serv
.privmsg(auteur
,"Play channels : "+" ".join(self
.play_channels
))
328 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
330 serv
.privmsg(auteur
,"Play channels : "+" ".join(self
.play_channels
))
334 if auteur
in self
.ops
:
336 if message
[1] in self
.play_channels
:
337 self
.play_channels
.remove(message
[1])
338 serv
.privmsg(auteur
,"Play channels : "+" ".join(self
.play_channels
))
339 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
341 serv
.privmsg(auteur
,"Je ne play pas sur %s."%(message
[1]))
342 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
346 if auteur
in self
.ops
:
348 if message
[1] in self
.quiet_channels
:
349 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
350 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
352 self
.quiet_channels
.append(message
[1])
353 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
354 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
356 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
360 if auteur
in self
.ops
:
362 if message
[1] in self
.quiet_channels
:
363 self
.quiet_channels
.remove(message
[1])
364 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
365 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
367 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
368 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
371 elif cmd
in ["states","status"]:
372 if auteur
in self
.overops
:
373 for k
in self
.play_status
.keys():
374 serv
.privmsg(auteur
,(u
"%s : %s"%(k
," | ".join([unicode(i
) for i
in self
.play_status
[k
]]))).encode("utf8") )
376 if auteur
in self
.overops
and len(message
)>2:
377 serv
.privmsg(message
[1]," ".join(message
[2:]))
378 log(self
.serveur
,"priv",auteur
," ".join(message
))
379 elif len(message
)<=2:
380 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
384 if auteur
in self
.overops
:
385 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
389 if len(message
) in [3,4] and message
[1].lower()=="transfert":
390 scores
=self
.get_scores()
391 de
,to
=auteur
,message
[2]
392 value
=scores
.get(de
,0)
395 asked
=int(message
[3])
397 serv
.privmsg(auteur
,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
402 serv
.privmsg(auteur
,"Vous n'avez pas de points")
405 serv
.privmsg(auteur
,"Bien tenté…")
408 serv
.privmsg(auteur
,"Vous n'avez que %s points"%(value))
411 self
.add_score(de
,-asked
)
412 self
.add_score(to
,asked
)
413 serv
.privmsg(auteur
,"Transfert de %s points de %s à %s"%(asked
,de
,to
))
415 serv
.privmsg(auteur
,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
417 serv
.privmsg(auteur
,"Votre score : %s"%(self
.get_scores().get(auteur
,0)) )
420 scores
=self
.get_scores().items()
422 scores
.sort(lambda x
,y
:cmp(x
[1],y
[1]))
424 serv
.privmsg(auteur
,"Scores by score : "+" ; ".join(["%s %s"%(i
[0],i
[1]) for i
in scores
]))
426 scores
.sort(lambda x
,y
:cmp(x
[0].lower(),y
[0].lower()))
427 serv
.privmsg(auteur
,"Scores by pseudo : "+" ; ".join(["%s %s"%(i
[0],i
[1]) for i
in scores
]))
428 elif auteur
in self
.overops
:
429 souscmd
=message
[1].lower()
433 scores
=self
.get_scores()
434 if scores
.has_key(todelete
):
436 self
.save_scores(scores
)
437 serv
.privmsg(auteur
,"Score de %s supprimé"%(todelete))
439 serv
.privmsg(auteur
,"Ce score n'existe pas : %s"%(todelete))
441 serv
.privmsg(auteur
,"Syntaxe : SCORES DEL <pseudo>")
442 elif souscmd
in ["add","sub"]:
444 toadd
,val
=message
[2],message
[3]
448 serv
.privmsg(auteur
,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
452 self
.add_score(toadd
,val
)
453 serv
.privmsg(auteur
,"Done")
455 serv
.privmsg(auteur
,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
457 serv
.privmsg(auteur
,"Syntaxe : SCORES {DEL|ADD|SUB} <pseudo> [<n>]")
463 serv
.privmsg(auteur
,"Je n'ai pas compris. Essaye HELP…")
465 def on_pubmsg(self
, serv
, ev
):
466 auteur
= irclib
.nm_to_n(ev
.source())
468 message
= ev
.arguments()[0]
470 test
=bot_unicode(message
)
471 except UnicodeBotError
:
472 if not canal
in self
.quiet_channels
:
474 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
477 pour_moi
,message
=self
.pourmoi(serv
,message
)
478 if pour_moi
and message
.split()!=[]:
479 cmd
=message
.split()[0].lower()
481 args
=" ".join(message
.split()[1:])
484 if cmd
in ["meurs","die","crève"]:
485 if auteur
in self
.overops
:
487 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
489 serv
.privmsg(canal
,"%s: crève !"%(auteur))
490 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
491 if cmd
in ["meur", "meurt","meurre","meurres"] and not canal
in self
.quiet_channels
:
492 serv
.privmsg(canal
,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
493 if cmd
in ["part","leave","dégage"]:
494 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
495 or auteur
in self
.overops
):
497 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
498 self
.chanlist
.remove(canal
)
500 serv
.privmsg(canal
,"%s: Non, je reste !"%(auteur))
501 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
503 if cmd
in ["deviens","pseudo"]:
504 if auteur
in self
.ops
:
507 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
508 if cmd
in ["coucou"] and not canal
in self
.quiet_channels
:
509 serv
.privmsg(canal
,"%s: coucou"%(auteur))
510 if cmd
in ["ping"] and not canal
in self
.quiet_channels
:
511 serv
.privmsg(canal
,"%s: pong"%(auteur))
512 if cmd
in ["date","dates","histoire","énigme","enigme","encore"]:
513 if canal
in self
.play_channels
:
514 if self
.play_status
.get(canal
,[-1])[0]==0:
516 self
.start_enigme(serv
,canal
)
518 serv
.privmsg(canal
,"%s: Je peux souffler une minute ?"%(auteur))
520 serv
.privmsg(canal
,("%s: Rappel : %s"%(auteur
,self
.play_status
[canal
][2])).encode("utf8") )
522 serv
.privmsg(canal
,"%s: pas ici…"%(auteur))
523 if cmd
in ["score","!score"]:
524 serv
.privmsg(auteur
,"Votre score : %s"%(self
.get_scores().get(auteur
,0)) )
525 if cmd
in ["scores","!scores"]:
526 scores
=self
.get_scores().items()
528 scores
.sort(lambda x
,y
:cmp(x
[1],y
[1]))
530 serv
.privmsg(auteur
,"Scores by score : "+" ; ".join(["%s %s"%(i
[0],i
[1]) for i
in scores
]))
532 scores
.sort(lambda x
,y
:cmp(x
[0].lower(),y
[0].lower()))
533 serv
.privmsg(auteur
,"Scores by pseudo : "+" ; ".join(["%s %s"%(i
[0],i
[1]) for i
in scores
]))
534 if cmd
=="indice" and canal
in self
.play_channels
:
535 self
.give_indice(serv
,canal
,None)
536 if is_tag(message
) and not canal
in self
.quiet_channels
:
537 if auteur
in self
.ops
:
538 action
=random
.choice(config_tag_actions
)
539 serv
.action(canal
,action
.encode("utf8"))
540 self
.quiet_channels
.append(canal
)
542 answer
=random
.choice(config_tag_answers
)
543 for ligne
in answer
.split("\n"):
544 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
550 if self
.play_status
.get(canal
,[-1])[0] in [1,2]:
551 answer
=self
.play_status
[canal
][1]
552 if reussi(message
.decode("utf8"),answer
,auteur
):
553 serv
.privmsg(canal
,(u
"%s: bravo ! (C'était le %s)"%(auteur
,answer
)).encode("utf8"))
554 log(self
.serveur
,canal
,auteur
+"$win",message
)
555 self
.add_score(auteur
,1)
557 self
.play_status
[canal
]=[0,token
]
558 serv
.execute_delayed(random
.randrange(Ttrig
*5,Ttrig
*10),self
.start_enigme
,(serv
,canal
,token
))
560 def on_kick(self
,serv
,ev
):
561 auteur
= irclib
.nm_to_n(ev
.source())
562 channel
= ev
.target()
563 victime
= ev
.arguments()[0]
564 raison
= ev
.arguments()[1]
565 if victime
==self
.nick
:
566 log(self
.serveur
,"%s kické par %s (raison : %s)" %(victime
,auteur
,raison
))
569 # on ne dit rien au rejoin
570 #l1,l2=config_kick_answers,config_kick_actions
571 #n1,n2=len(l1),len(l2)
572 #i=random.randrange(n1+n2)
574 # serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
576 # serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
578 def quitter(self
,chan
,leave_message
=None):
579 if leave_message
==None:
580 leave_message
=random
.choice(config_leave_messages
)
582 leave_message
=leave_message
%(time
.strftime("le %d/%m/%Y à %T").decode("utf8"),self
.nick
)
585 self
.serv
.part(chan
,message
=leave_message
.encode("utf8"))
588 quit_message
=random
.choice(config_quit_messages
)
590 quit_message
=quit_message
%(time
.strftime("le %d/%m/%Y à %T").decode("utf8"),self
.nick
)
593 self
.die(msg
=quit_message
.encode("utf8"))
595 def get_scores(self
):
596 f
=open(config_score_file
)
597 scores
=pickle
.load(f
)
601 def add_score(self
,pseudo
,value
):
602 scores
=self
.get_scores()
603 if scores
.has_key(pseudo
):
604 scores
[pseudo
]+=value
607 self
.save_scores(scores
)
609 def save_scores(self
,scores
):
610 f
=open(config_score_file
,"w")
611 pickle
.dump(scores
,f
)
615 return self
.serv
.get_nickname()
616 nick
= property(_getnick
)
618 if __name__
=="__main__":
621 print "Usage : deconnaisseur.py <serveur> [--debug]"
624 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
628 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
629 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
631 serveur
=serveurs
[serveur
]
633 print "Server Unknown : %s"%(serveur)
635 deco
=Deconnaisseur(serveur
,debug
)