rbot 0.9.10 → 0.9.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (706) hide show
  1. data/AUTHORS +22 -4
  2. data/COPYING +5 -18
  3. data/ChangeLog +396 -0
  4. data/README +23 -25
  5. data/REQUIREMENTS +58 -12
  6. data/Rakefile +215 -0
  7. data/bin/rbot +47 -25
  8. data/bin/rbot-remote +76 -0
  9. data/data/rbot/languages/french.lang +5 -5
  10. data/data/rbot/languages/german.lang +4 -4
  11. data/data/rbot/languages/italian.lang +53 -0
  12. data/data/rbot/languages/japanese.lang +43 -0
  13. data/data/rbot/languages/russian.lang +60 -60
  14. data/data/rbot/languages/traditional_chinese.lang +75 -0
  15. data/data/rbot/plugins/alias.rb +192 -0
  16. data/data/rbot/plugins/autoop.rb +74 -37
  17. data/data/rbot/plugins/autorejoin.rb +15 -5
  18. data/data/rbot/plugins/bans.rb +454 -150
  19. data/data/rbot/plugins/bash.rb +173 -31
  20. data/data/rbot/plugins/botsnack.rb +37 -0
  21. data/data/rbot/plugins/cal.rb +11 -2
  22. data/data/rbot/plugins/chanserv.rb +132 -0
  23. data/data/rbot/plugins/chucknorris.rb +2 -2
  24. data/data/rbot/plugins/chucknorris.yml.gz +0 -0
  25. data/data/rbot/plugins/debugger.rb +136 -0
  26. data/data/rbot/plugins/deepthoughts.rb +89 -95
  27. data/data/rbot/plugins/delicious.rb +109 -0
  28. data/data/rbot/plugins/dice.rb +77 -25
  29. data/data/rbot/plugins/dict.rb +243 -0
  30. data/data/rbot/plugins/dictclient.rb +211 -0
  31. data/data/rbot/plugins/digg.rb +2 -2
  32. data/data/rbot/plugins/excuse.rb +4 -4
  33. data/data/rbot/plugins/factoids.rb +506 -0
  34. data/data/rbot/plugins/figlet.rb +127 -18
  35. data/data/rbot/plugins/fish.rb +93 -33
  36. data/data/rbot/plugins/forecast.rb +40 -27
  37. data/data/rbot/plugins/fortune.rb +86 -11
  38. data/data/rbot/plugins/freshmeat.rb +46 -12
  39. data/data/rbot/plugins/games/azgame.rb +565 -0
  40. data/data/rbot/plugins/games/quiz.rb +961 -0
  41. data/data/rbot/plugins/games/roshambo.rb +62 -0
  42. data/data/rbot/plugins/{roulette.rb → games/roulette.rb} +58 -8
  43. data/data/rbot/plugins/games/shiritori.rb +485 -0
  44. data/data/rbot/plugins/games/uno.rb +1205 -0
  45. data/data/rbot/plugins/games/wheelfortune.rb +615 -0
  46. data/data/rbot/plugins/grouphug.rb +76 -22
  47. data/data/rbot/plugins/hl2.rb +97 -0
  48. data/data/rbot/plugins/host.rb +10 -1
  49. data/data/rbot/plugins/httpd.rb.disabled +1 -0
  50. data/data/rbot/plugins/imdb.rb +511 -47
  51. data/data/rbot/plugins/insult.rb +32 -37
  52. data/data/rbot/plugins/iplookup.rb +224 -224
  53. data/data/rbot/plugins/karma.rb +45 -21
  54. data/data/rbot/plugins/keywords.rb +258 -160
  55. data/data/rbot/plugins/lart.rb +126 -95
  56. data/data/rbot/plugins/lastfm.rb +421 -12
  57. data/data/rbot/plugins/linkbot.rb +75 -0
  58. data/data/rbot/plugins/markov.rb +103 -46
  59. data/data/rbot/plugins/math.rb +6 -5
  60. data/data/rbot/plugins/modes.rb +114 -0
  61. data/data/rbot/plugins/nickrecover.rb +97 -0
  62. data/data/rbot/plugins/nickserv.rb +111 -48
  63. data/data/rbot/plugins/nslookup.rb +15 -19
  64. data/data/rbot/plugins/plugin.header +11 -0
  65. data/data/rbot/plugins/quakeauth.rb +74 -11
  66. data/data/rbot/plugins/quotes.rb +189 -233
  67. data/data/rbot/plugins/reaction.rb +415 -0
  68. data/data/rbot/plugins/remind.rb +11 -15
  69. data/data/rbot/plugins/remotectl.rb +29 -0
  70. data/data/rbot/plugins/ri.rb +74 -0
  71. data/data/rbot/plugins/rot13.rb +16 -1
  72. data/data/rbot/plugins/rss.rb +1219 -585
  73. data/data/rbot/plugins/salut.rb +226 -0
  74. data/data/rbot/plugins/script.rb +184 -0
  75. data/data/rbot/plugins/search.rb +233 -0
  76. data/data/rbot/plugins/seen.rb +44 -40
  77. data/data/rbot/plugins/shortenurls.rb +93 -0
  78. data/data/rbot/plugins/slashdot.rb +49 -11
  79. data/data/rbot/plugins/spell.rb +37 -27
  80. data/data/rbot/plugins/theyfightcrime.rb +36 -39
  81. data/data/rbot/plugins/threat.rb +25 -22
  82. data/data/rbot/plugins/time.rb +135 -0
  83. data/data/rbot/plugins/topic.rb +107 -50
  84. data/data/rbot/plugins/translator.rb +360 -0
  85. data/data/rbot/plugins/tube.rb +28 -40
  86. data/data/rbot/plugins/twitter.rb +187 -0
  87. data/data/rbot/plugins/urban.rb +62 -53
  88. data/data/rbot/plugins/url.rb +193 -409
  89. data/data/rbot/plugins/usermodes.rb +26 -0
  90. data/data/rbot/plugins/wall.rb +60 -0
  91. data/data/rbot/plugins/weather.rb +254 -598
  92. data/data/rbot/plugins/wow.rb +41 -37
  93. data/data/rbot/plugins/wserver.rb +17 -25
  94. data/data/rbot/plugins/youtube.rb +237 -0
  95. data/data/rbot/templates/lart/{larts → larts-english} +0 -0
  96. data/data/rbot/templates/lart/larts-italian +25 -0
  97. data/data/rbot/templates/lart/larts-japanese +10 -0
  98. data/data/rbot/templates/lart/{praises → praises-english} +0 -0
  99. data/data/rbot/templates/lart/praises-italian +4 -0
  100. data/data/rbot/templates/lart/praises-japanese +3 -0
  101. data/data/rbot/templates/quiz/win_messages +11 -0
  102. data/data/rbot/templates/salut/salut-english +40 -0
  103. data/data/rbot/templates/salut/salut-french +29 -0
  104. data/data/rbot/templates/salut/salut-italian +51 -0
  105. data/data/rbot/templates/salut/salut-japanese +31 -0
  106. data/lib/rbot/botuser.rb +940 -0
  107. data/lib/rbot/config-compat.rb +23 -0
  108. data/lib/rbot/config.rb +211 -276
  109. data/lib/rbot/core/auth.rb +1063 -0
  110. data/lib/rbot/core/basics.rb +214 -0
  111. data/lib/rbot/core/config.rb +330 -0
  112. data/lib/rbot/core/filters_ui.rb +64 -0
  113. data/lib/rbot/core/irclog.rb +292 -0
  114. data/lib/rbot/core/remote.rb +401 -0
  115. data/lib/rbot/core/unicode.rb +91 -0
  116. data/lib/rbot/core/userdata.rb +200 -0
  117. data/lib/rbot/core/utils/extends.rb +444 -0
  118. data/lib/rbot/core/utils/filters.rb +154 -0
  119. data/lib/rbot/core/utils/httputil.rb +689 -0
  120. data/lib/rbot/core/utils/utils.rb +717 -0
  121. data/lib/rbot/dbhash.rb +30 -9
  122. data/lib/rbot/irc.rb +1966 -0
  123. data/lib/rbot/ircbot.rb +816 -675
  124. data/lib/rbot/ircsocket.rb +246 -232
  125. data/lib/rbot/language.rb +86 -8
  126. data/lib/rbot/load-gettext.rb +154 -0
  127. data/lib/rbot/maskdb.rb +162 -0
  128. data/lib/rbot/message.rb +392 -65
  129. data/lib/rbot/messagemapper.rb +438 -94
  130. data/lib/rbot/pkgconfig.rb +6 -0
  131. data/lib/rbot/plugins.rb +713 -172
  132. data/lib/rbot/post-config.rb +1 -0
  133. data/lib/rbot/rbotconfig.rb +31 -12
  134. data/lib/rbot/registry.rb +79 -48
  135. data/lib/rbot/rfc2812.rb +927 -519
  136. data/lib/rbot/timer.rb +232 -167
  137. data/po/en_US/rbot-alias.po +82 -0
  138. data/po/en_US/rbot-autoop.po +0 -0
  139. data/po/en_US/rbot-autorejoin.po +0 -0
  140. data/po/en_US/rbot-azgame.po +200 -0
  141. data/po/en_US/rbot-bans.po +0 -0
  142. data/po/en_US/rbot-bash.po +0 -0
  143. data/po/en_US/rbot-botsnack.po +0 -0
  144. data/po/en_US/rbot-cal.po +3 -0
  145. data/po/en_US/rbot-chanserv.po +0 -0
  146. data/po/en_US/rbot-chucknorris.po +0 -0
  147. data/po/en_US/rbot-debugger.po +0 -0
  148. data/po/en_US/rbot-deepthoughts.po +0 -0
  149. data/po/en_US/rbot-delicious.po +0 -0
  150. data/po/en_US/rbot-dice.po +0 -0
  151. data/po/en_US/rbot-dict.po +0 -0
  152. data/po/en_US/rbot-dictclient.po +124 -0
  153. data/po/en_US/rbot-digg.po +0 -0
  154. data/po/en_US/rbot-eightball.po +0 -0
  155. data/po/en_US/rbot-excuse.po +0 -0
  156. data/po/en_US/rbot-factoids.po +107 -0
  157. data/po/en_US/rbot-figlet.po +36 -0
  158. data/po/en_US/rbot-fish.po +0 -0
  159. data/po/en_US/rbot-forecast.po +0 -0
  160. data/po/en_US/rbot-fortune.po +0 -0
  161. data/po/en_US/rbot-freshmeat.po +0 -0
  162. data/po/en_US/rbot-grouphug.po +18 -0
  163. data/po/en_US/rbot-hl2.po +0 -0
  164. data/po/en_US/rbot-host.po +3 -0
  165. data/po/en_US/rbot-imdb.po +0 -0
  166. data/po/en_US/rbot-insult.po +0 -0
  167. data/po/en_US/rbot-iplookup.po +0 -0
  168. data/po/en_US/rbot-karma.po +0 -0
  169. data/po/en_US/rbot-keywords.po +24 -0
  170. data/po/en_US/rbot-lart.po +0 -0
  171. data/po/en_US/rbot-lastfm.po +172 -0
  172. data/po/en_US/rbot-linkbot.po +0 -0
  173. data/po/en_US/rbot-markov.po +20 -0
  174. data/po/en_US/rbot-math.po +0 -0
  175. data/po/en_US/rbot-modes.po +0 -0
  176. data/po/en_US/rbot-nickrecover.po +40 -0
  177. data/po/en_US/rbot-nickserv.po +104 -0
  178. data/po/en_US/rbot-nslookup.po +0 -0
  179. data/po/en_US/rbot-quakeauth.po +0 -0
  180. data/po/en_US/rbot-quiz.po +0 -0
  181. data/po/en_US/rbot-quotes.po +108 -0
  182. data/po/en_US/rbot-reaction.po +0 -0
  183. data/po/en_US/rbot-remind.po +0 -0
  184. data/po/en_US/rbot-remotectl.po +0 -0
  185. data/po/en_US/rbot-ri.po +0 -0
  186. data/po/en_US/rbot-roshambo.po +0 -0
  187. data/po/en_US/rbot-rot13.po +0 -0
  188. data/po/en_US/rbot-roulette.po +0 -0
  189. data/po/en_US/rbot-rss.po +20 -0
  190. data/po/en_US/rbot-salut.po +0 -0
  191. data/po/en_US/rbot-script.po +0 -0
  192. data/po/en_US/rbot-search.po +0 -0
  193. data/po/en_US/rbot-seen.po +0 -0
  194. data/po/en_US/rbot-shiritori.po +113 -0
  195. data/po/en_US/rbot-shortenurls.po +0 -0
  196. data/po/en_US/rbot-slashdot.po +0 -0
  197. data/po/en_US/rbot-spell.po +54 -0
  198. data/po/en_US/rbot-theyfightcrime.po +0 -0
  199. data/po/en_US/rbot-threat.po +0 -0
  200. data/po/en_US/rbot-time.po +0 -0
  201. data/po/en_US/rbot-topic.po +0 -0
  202. data/po/en_US/rbot-translator.po +77 -0
  203. data/po/en_US/rbot-tube.po +0 -0
  204. data/po/en_US/rbot-twitter.po +24 -0
  205. data/po/en_US/rbot-uno.po +512 -0
  206. data/po/en_US/rbot-urban.po +0 -0
  207. data/po/en_US/rbot-url.po +0 -0
  208. data/po/en_US/rbot-usermodes.po +0 -0
  209. data/po/en_US/rbot-wall.po +33 -0
  210. data/po/en_US/rbot-weather.po +0 -0
  211. data/po/en_US/rbot-wheelfortune.po +205 -0
  212. data/po/en_US/rbot-wow.po +0 -0
  213. data/po/en_US/rbot-wserver.po +0 -0
  214. data/po/en_US/rbot-youtube.po +58 -0
  215. data/po/en_US/rbot.po +1097 -0
  216. data/po/fr/rbot-alias.po +97 -0
  217. data/po/fr/rbot-autoop.po +0 -0
  218. data/po/fr/rbot-autorejoin.po +0 -0
  219. data/po/fr/rbot-azgame.po +204 -0
  220. data/po/fr/rbot-bans.po +0 -0
  221. data/po/fr/rbot-bash.po +0 -0
  222. data/po/fr/rbot-botsnack.po +0 -0
  223. data/po/fr/rbot-cal.po +3 -0
  224. data/po/fr/rbot-chanserv.po +0 -0
  225. data/po/fr/rbot-chucknorris.po +0 -0
  226. data/po/fr/rbot-debugger.po +0 -0
  227. data/po/fr/rbot-deepthoughts.po +0 -0
  228. data/po/fr/rbot-delicious.po +0 -0
  229. data/po/fr/rbot-dice.po +0 -0
  230. data/po/fr/rbot-dict.po +0 -0
  231. data/po/fr/rbot-dictclient.po +134 -0
  232. data/po/fr/rbot-digg.po +0 -0
  233. data/po/fr/rbot-eightball.po +0 -0
  234. data/po/fr/rbot-excuse.po +0 -0
  235. data/po/fr/rbot-factoids.po +111 -0
  236. data/po/fr/rbot-figlet.po +37 -0
  237. data/po/fr/rbot-fish.po +0 -0
  238. data/po/fr/rbot-forecast.po +0 -0
  239. data/po/fr/rbot-fortune.po +0 -0
  240. data/po/fr/rbot-freshmeat.po +0 -0
  241. data/po/fr/rbot-grouphug.po +18 -0
  242. data/po/fr/rbot-hl2.po +0 -0
  243. data/po/fr/rbot-host.po +3 -0
  244. data/po/fr/rbot-imdb.po +0 -0
  245. data/po/fr/rbot-insult.po +0 -0
  246. data/po/fr/rbot-iplookup.po +0 -0
  247. data/po/fr/rbot-karma.po +0 -0
  248. data/po/fr/rbot-keywords.po +24 -0
  249. data/po/fr/rbot-lart.po +0 -0
  250. data/po/fr/rbot-lastfm.po +172 -0
  251. data/po/fr/rbot-linkbot.po +0 -0
  252. data/po/fr/rbot-markov.po +20 -0
  253. data/po/fr/rbot-math.po +0 -0
  254. data/po/fr/rbot-modes.po +0 -0
  255. data/po/fr/rbot-nickrecover.po +36 -0
  256. data/po/fr/rbot-nickserv.po +116 -0
  257. data/po/fr/rbot-nslookup.po +0 -0
  258. data/po/fr/rbot-quakeauth.po +0 -0
  259. data/po/fr/rbot-quiz.po +0 -0
  260. data/po/fr/rbot-quotes.po +138 -0
  261. data/po/fr/rbot-reaction.po +0 -0
  262. data/po/fr/rbot-remind.po +0 -0
  263. data/po/fr/rbot-remotectl.po +0 -0
  264. data/po/fr/rbot-ri.po +0 -0
  265. data/po/fr/rbot-roshambo.po +0 -0
  266. data/po/fr/rbot-rot13.po +0 -0
  267. data/po/fr/rbot-roulette.po +0 -0
  268. data/po/fr/rbot-rss.po +20 -0
  269. data/po/fr/rbot-salut.po +0 -0
  270. data/po/fr/rbot-script.po +0 -0
  271. data/po/fr/rbot-search.po +0 -0
  272. data/po/fr/rbot-seen.po +0 -0
  273. data/po/fr/rbot-shiritori.po +119 -0
  274. data/po/fr/rbot-shortenurls.po +0 -0
  275. data/po/fr/rbot-slashdot.po +0 -0
  276. data/po/fr/rbot-spell.po +56 -0
  277. data/po/fr/rbot-theyfightcrime.po +0 -0
  278. data/po/fr/rbot-threat.po +0 -0
  279. data/po/fr/rbot-time.po +0 -0
  280. data/po/fr/rbot-topic.po +0 -0
  281. data/po/fr/rbot-translator.po +90 -0
  282. data/po/fr/rbot-tube.po +0 -0
  283. data/po/fr/rbot-twitter.po +24 -0
  284. data/po/fr/rbot-uno.po +521 -0
  285. data/po/fr/rbot-urban.po +0 -0
  286. data/po/fr/rbot-url.po +0 -0
  287. data/po/fr/rbot-usermodes.po +0 -0
  288. data/po/fr/rbot-wall.po +33 -0
  289. data/po/fr/rbot-weather.po +0 -0
  290. data/po/fr/rbot-wheelfortune.po +255 -0
  291. data/po/fr/rbot-wow.po +0 -0
  292. data/po/fr/rbot-wserver.po +0 -0
  293. data/po/fr/rbot-youtube.po +64 -0
  294. data/po/fr/rbot.po +1133 -0
  295. data/po/it/rbot-alias.po +82 -0
  296. data/po/it/rbot-autoop.po +0 -0
  297. data/po/it/rbot-autorejoin.po +0 -0
  298. data/po/it/rbot-azgame.po +186 -0
  299. data/po/it/rbot-bans.po +0 -0
  300. data/po/it/rbot-bash.po +0 -0
  301. data/po/it/rbot-botsnack.po +0 -0
  302. data/po/it/rbot-cal.po +3 -0
  303. data/po/it/rbot-chanserv.po +0 -0
  304. data/po/it/rbot-chucknorris.po +0 -0
  305. data/po/it/rbot-debugger.po +0 -0
  306. data/po/it/rbot-deepthoughts.po +0 -0
  307. data/po/it/rbot-delicious.po +0 -0
  308. data/po/it/rbot-dice.po +0 -0
  309. data/po/it/rbot-dict.po +0 -0
  310. data/po/it/rbot-dictclient.po +111 -0
  311. data/po/it/rbot-digg.po +0 -0
  312. data/po/it/rbot-eightball.po +0 -0
  313. data/po/it/rbot-excuse.po +0 -0
  314. data/po/it/rbot-factoids.po +110 -0
  315. data/po/it/rbot-figlet.po +36 -0
  316. data/po/it/rbot-fish.po +0 -0
  317. data/po/it/rbot-forecast.po +0 -0
  318. data/po/it/rbot-fortune.po +0 -0
  319. data/po/it/rbot-freshmeat.po +0 -0
  320. data/po/it/rbot-grouphug.po +18 -0
  321. data/po/it/rbot-hl2.po +0 -0
  322. data/po/it/rbot-host.po +3 -0
  323. data/po/it/rbot-imdb.po +0 -0
  324. data/po/it/rbot-insult.po +0 -0
  325. data/po/it/rbot-iplookup.po +0 -0
  326. data/po/it/rbot-karma.po +0 -0
  327. data/po/it/rbot-keywords.po +24 -0
  328. data/po/it/rbot-lart.po +0 -0
  329. data/po/it/rbot-lastfm.po +172 -0
  330. data/po/it/rbot-linkbot.po +0 -0
  331. data/po/it/rbot-markov.po +20 -0
  332. data/po/it/rbot-math.po +0 -0
  333. data/po/it/rbot-modes.po +0 -0
  334. data/po/it/rbot-nickrecover.po +36 -0
  335. data/po/it/rbot-nickserv.po +104 -0
  336. data/po/it/rbot-nslookup.po +0 -0
  337. data/po/it/rbot-quakeauth.po +0 -0
  338. data/po/it/rbot-quiz.po +0 -0
  339. data/po/it/rbot-quotes.po +108 -0
  340. data/po/it/rbot-reaction.po +0 -0
  341. data/po/it/rbot-remind.po +0 -0
  342. data/po/it/rbot-remotectl.po +0 -0
  343. data/po/it/rbot-ri.po +0 -0
  344. data/po/it/rbot-roshambo.po +0 -0
  345. data/po/it/rbot-rot13.po +0 -0
  346. data/po/it/rbot-roulette.po +0 -0
  347. data/po/it/rbot-rss.po +20 -0
  348. data/po/it/rbot-salut.po +0 -0
  349. data/po/it/rbot-script.po +0 -0
  350. data/po/it/rbot-search.po +0 -0
  351. data/po/it/rbot-seen.po +0 -0
  352. data/po/it/rbot-shiritori.po +102 -0
  353. data/po/it/rbot-shortenurls.po +0 -0
  354. data/po/it/rbot-slashdot.po +0 -0
  355. data/po/it/rbot-spell.po +54 -0
  356. data/po/it/rbot-theyfightcrime.po +0 -0
  357. data/po/it/rbot-threat.po +0 -0
  358. data/po/it/rbot-time.po +0 -0
  359. data/po/it/rbot-topic.po +0 -0
  360. data/po/it/rbot-translator.po +77 -0
  361. data/po/it/rbot-tube.po +0 -0
  362. data/po/it/rbot-twitter.po +24 -0
  363. data/po/it/rbot-uno.po +564 -0
  364. data/po/it/rbot-urban.po +0 -0
  365. data/po/it/rbot-url.po +0 -0
  366. data/po/it/rbot-usermodes.po +0 -0
  367. data/po/it/rbot-wall.po +33 -0
  368. data/po/it/rbot-weather.po +0 -0
  369. data/po/it/rbot-wheelfortune.po +251 -0
  370. data/po/it/rbot-wow.po +0 -0
  371. data/po/it/rbot-wserver.po +0 -0
  372. data/po/it/rbot-youtube.po +64 -0
  373. data/po/it/rbot.po +1127 -0
  374. data/po/ja/rbot-alias.po +82 -0
  375. data/po/ja/rbot-autoop.po +0 -0
  376. data/po/ja/rbot-autorejoin.po +0 -0
  377. data/po/ja/rbot-azgame.po +194 -0
  378. data/po/ja/rbot-bans.po +0 -0
  379. data/po/ja/rbot-bash.po +0 -0
  380. data/po/ja/rbot-botsnack.po +0 -0
  381. data/po/ja/rbot-cal.po +3 -0
  382. data/po/ja/rbot-chanserv.po +0 -0
  383. data/po/ja/rbot-chucknorris.po +0 -0
  384. data/po/ja/rbot-debugger.po +0 -0
  385. data/po/ja/rbot-deepthoughts.po +0 -0
  386. data/po/ja/rbot-delicious.po +0 -0
  387. data/po/ja/rbot-dice.po +0 -0
  388. data/po/ja/rbot-dict.po +0 -0
  389. data/po/ja/rbot-dictclient.po +111 -0
  390. data/po/ja/rbot-digg.po +0 -0
  391. data/po/ja/rbot-eightball.po +0 -0
  392. data/po/ja/rbot-excuse.po +0 -0
  393. data/po/ja/rbot-factoids.po +107 -0
  394. data/po/ja/rbot-figlet.po +36 -0
  395. data/po/ja/rbot-fish.po +0 -0
  396. data/po/ja/rbot-forecast.po +0 -0
  397. data/po/ja/rbot-fortune.po +0 -0
  398. data/po/ja/rbot-freshmeat.po +0 -0
  399. data/po/ja/rbot-grouphug.po +18 -0
  400. data/po/ja/rbot-hl2.po +0 -0
  401. data/po/ja/rbot-host.po +3 -0
  402. data/po/ja/rbot-imdb.po +0 -0
  403. data/po/ja/rbot-insult.po +0 -0
  404. data/po/ja/rbot-iplookup.po +0 -0
  405. data/po/ja/rbot-karma.po +0 -0
  406. data/po/ja/rbot-keywords.po +24 -0
  407. data/po/ja/rbot-lart.po +0 -0
  408. data/po/ja/rbot-lastfm.po +172 -0
  409. data/po/ja/rbot-linkbot.po +0 -0
  410. data/po/ja/rbot-markov.po +20 -0
  411. data/po/ja/rbot-math.po +0 -0
  412. data/po/ja/rbot-modes.po +0 -0
  413. data/po/ja/rbot-nickrecover.po +36 -0
  414. data/po/ja/rbot-nickserv.po +104 -0
  415. data/po/ja/rbot-nslookup.po +0 -0
  416. data/po/ja/rbot-quakeauth.po +0 -0
  417. data/po/ja/rbot-quiz.po +0 -0
  418. data/po/ja/rbot-quotes.po +108 -0
  419. data/po/ja/rbot-reaction.po +0 -0
  420. data/po/ja/rbot-remind.po +0 -0
  421. data/po/ja/rbot-remotectl.po +0 -0
  422. data/po/ja/rbot-ri.po +0 -0
  423. data/po/ja/rbot-roshambo.po +0 -0
  424. data/po/ja/rbot-rot13.po +0 -0
  425. data/po/ja/rbot-roulette.po +0 -0
  426. data/po/ja/rbot-rss.po +20 -0
  427. data/po/ja/rbot-salut.po +0 -0
  428. data/po/ja/rbot-script.po +0 -0
  429. data/po/ja/rbot-search.po +0 -0
  430. data/po/ja/rbot-seen.po +0 -0
  431. data/po/ja/rbot-shiritori.po +115 -0
  432. data/po/ja/rbot-shortenurls.po +0 -0
  433. data/po/ja/rbot-slashdot.po +0 -0
  434. data/po/ja/rbot-spell.po +54 -0
  435. data/po/ja/rbot-theyfightcrime.po +0 -0
  436. data/po/ja/rbot-threat.po +0 -0
  437. data/po/ja/rbot-time.po +0 -0
  438. data/po/ja/rbot-topic.po +0 -0
  439. data/po/ja/rbot-translator.po +77 -0
  440. data/po/ja/rbot-tube.po +0 -0
  441. data/po/ja/rbot-twitter.po +24 -0
  442. data/po/ja/rbot-uno.po +512 -0
  443. data/po/ja/rbot-urban.po +0 -0
  444. data/po/ja/rbot-url.po +0 -0
  445. data/po/ja/rbot-usermodes.po +0 -0
  446. data/po/ja/rbot-wall.po +33 -0
  447. data/po/ja/rbot-weather.po +0 -0
  448. data/po/ja/rbot-wheelfortune.po +205 -0
  449. data/po/ja/rbot-wow.po +0 -0
  450. data/po/ja/rbot-wserver.po +0 -0
  451. data/po/ja/rbot-youtube.po +58 -0
  452. data/po/ja/rbot.po +999 -0
  453. data/po/rbot-alias.pot +83 -0
  454. data/po/rbot-autoop.pot +0 -0
  455. data/po/rbot-autorejoin.pot +0 -0
  456. data/po/rbot-azgame.pot +187 -0
  457. data/po/rbot-bans.pot +0 -0
  458. data/po/rbot-bash.pot +0 -0
  459. data/po/rbot-botsnack.pot +0 -0
  460. data/po/rbot-cal.pot +21 -0
  461. data/po/rbot-chanserv.pot +0 -0
  462. data/po/rbot-chucknorris.pot +0 -0
  463. data/po/rbot-debugger.pot +0 -0
  464. data/po/rbot-deepthoughts.pot +0 -0
  465. data/po/rbot-delicious.pot +0 -0
  466. data/po/rbot-dice.pot +0 -0
  467. data/po/rbot-dict.pot +0 -0
  468. data/po/rbot-dictclient.pot +112 -0
  469. data/po/rbot-digg.pot +0 -0
  470. data/po/rbot-eightball.pot +0 -0
  471. data/po/rbot-excuse.pot +0 -0
  472. data/po/rbot-factoids.pot +108 -0
  473. data/po/rbot-figlet.pot +37 -0
  474. data/po/rbot-fish.pot +0 -0
  475. data/po/rbot-forecast.pot +0 -0
  476. data/po/rbot-fortune.pot +0 -0
  477. data/po/rbot-freshmeat.pot +0 -0
  478. data/po/rbot-grouphug.pot +36 -0
  479. data/po/rbot-hl2.pot +0 -0
  480. data/po/rbot-host.pot +21 -0
  481. data/po/rbot-imdb.pot +0 -0
  482. data/po/rbot-insult.pot +0 -0
  483. data/po/rbot-iplookup.pot +0 -0
  484. data/po/rbot-karma.pot +0 -0
  485. data/po/rbot-keywords.pot +25 -0
  486. data/po/rbot-lart.pot +0 -0
  487. data/po/rbot-lastfm.pot +190 -0
  488. data/po/rbot-linkbot.pot +0 -0
  489. data/po/rbot-markov.pot +21 -0
  490. data/po/rbot-math.pot +0 -0
  491. data/po/rbot-modes.pot +0 -0
  492. data/po/rbot-nickrecover.pot +37 -0
  493. data/po/rbot-nickserv.pot +105 -0
  494. data/po/rbot-nslookup.pot +0 -0
  495. data/po/rbot-quakeauth.pot +0 -0
  496. data/po/rbot-quiz.pot +0 -0
  497. data/po/rbot-quotes.pot +109 -0
  498. data/po/rbot-reaction.pot +0 -0
  499. data/po/rbot-remind.pot +0 -0
  500. data/po/rbot-remotectl.pot +0 -0
  501. data/po/rbot-ri.pot +0 -0
  502. data/po/rbot-roshambo.pot +0 -0
  503. data/po/rbot-rot13.pot +0 -0
  504. data/po/rbot-roulette.pot +0 -0
  505. data/po/rbot-rss.pot +21 -0
  506. data/po/rbot-salut.pot +0 -0
  507. data/po/rbot-script.pot +0 -0
  508. data/po/rbot-search.pot +0 -0
  509. data/po/rbot-seen.pot +0 -0
  510. data/po/rbot-shiritori.pot +103 -0
  511. data/po/rbot-shortenurls.pot +0 -0
  512. data/po/rbot-slashdot.pot +0 -0
  513. data/po/rbot-spell.pot +55 -0
  514. data/po/rbot-theyfightcrime.pot +0 -0
  515. data/po/rbot-threat.pot +0 -0
  516. data/po/rbot-time.pot +0 -0
  517. data/po/rbot-topic.pot +0 -0
  518. data/po/rbot-translator.pot +78 -0
  519. data/po/rbot-tube.pot +0 -0
  520. data/po/rbot-twitter.pot +25 -0
  521. data/po/rbot-uno.pot +513 -0
  522. data/po/rbot-urban.pot +0 -0
  523. data/po/rbot-url.pot +0 -0
  524. data/po/rbot-usermodes.pot +0 -0
  525. data/po/rbot-wall.pot +33 -0
  526. data/po/rbot-weather.pot +0 -0
  527. data/po/rbot-wheelfortune.pot +206 -0
  528. data/po/rbot-wow.pot +0 -0
  529. data/po/rbot-wserver.pot +0 -0
  530. data/po/rbot-youtube.pot +59 -0
  531. data/po/rbot.pot +1004 -0
  532. data/po/zh_CN/rbot-alias.po +82 -0
  533. data/po/zh_CN/rbot-autoop.po +0 -0
  534. data/po/zh_CN/rbot-autorejoin.po +0 -0
  535. data/po/zh_CN/rbot-azgame.po +186 -0
  536. data/po/zh_CN/rbot-bans.po +0 -0
  537. data/po/zh_CN/rbot-bash.po +0 -0
  538. data/po/zh_CN/rbot-botsnack.po +0 -0
  539. data/po/zh_CN/rbot-cal.po +3 -0
  540. data/po/zh_CN/rbot-chanserv.po +0 -0
  541. data/po/zh_CN/rbot-chucknorris.po +0 -0
  542. data/po/zh_CN/rbot-debugger.po +0 -0
  543. data/po/zh_CN/rbot-deepthoughts.po +0 -0
  544. data/po/zh_CN/rbot-delicious.po +0 -0
  545. data/po/zh_CN/rbot-dice.po +0 -0
  546. data/po/zh_CN/rbot-dict.po +0 -0
  547. data/po/zh_CN/rbot-dictclient.po +111 -0
  548. data/po/zh_CN/rbot-digg.po +0 -0
  549. data/po/zh_CN/rbot-eightball.po +0 -0
  550. data/po/zh_CN/rbot-excuse.po +0 -0
  551. data/po/zh_CN/rbot-factoids.po +107 -0
  552. data/po/zh_CN/rbot-figlet.po +36 -0
  553. data/po/zh_CN/rbot-fish.po +0 -0
  554. data/po/zh_CN/rbot-forecast.po +0 -0
  555. data/po/zh_CN/rbot-fortune.po +0 -0
  556. data/po/zh_CN/rbot-freshmeat.po +0 -0
  557. data/po/zh_CN/rbot-grouphug.po +18 -0
  558. data/po/zh_CN/rbot-hl2.po +0 -0
  559. data/po/zh_CN/rbot-host.po +3 -0
  560. data/po/zh_CN/rbot-imdb.po +0 -0
  561. data/po/zh_CN/rbot-insult.po +0 -0
  562. data/po/zh_CN/rbot-iplookup.po +0 -0
  563. data/po/zh_CN/rbot-karma.po +0 -0
  564. data/po/zh_CN/rbot-keywords.po +24 -0
  565. data/po/zh_CN/rbot-lart.po +0 -0
  566. data/po/zh_CN/rbot-lastfm.po +172 -0
  567. data/po/zh_CN/rbot-linkbot.po +0 -0
  568. data/po/zh_CN/rbot-markov.po +20 -0
  569. data/po/zh_CN/rbot-math.po +0 -0
  570. data/po/zh_CN/rbot-modes.po +0 -0
  571. data/po/zh_CN/rbot-nickrecover.po +36 -0
  572. data/po/zh_CN/rbot-nickserv.po +104 -0
  573. data/po/zh_CN/rbot-nslookup.po +0 -0
  574. data/po/zh_CN/rbot-quakeauth.po +0 -0
  575. data/po/zh_CN/rbot-quiz.po +0 -0
  576. data/po/zh_CN/rbot-quotes.po +108 -0
  577. data/po/zh_CN/rbot-reaction.po +0 -0
  578. data/po/zh_CN/rbot-remind.po +0 -0
  579. data/po/zh_CN/rbot-remotectl.po +0 -0
  580. data/po/zh_CN/rbot-ri.po +0 -0
  581. data/po/zh_CN/rbot-roshambo.po +0 -0
  582. data/po/zh_CN/rbot-rot13.po +0 -0
  583. data/po/zh_CN/rbot-roulette.po +0 -0
  584. data/po/zh_CN/rbot-rss.po +20 -0
  585. data/po/zh_CN/rbot-salut.po +0 -0
  586. data/po/zh_CN/rbot-script.po +0 -0
  587. data/po/zh_CN/rbot-search.po +0 -0
  588. data/po/zh_CN/rbot-seen.po +0 -0
  589. data/po/zh_CN/rbot-shiritori.po +102 -0
  590. data/po/zh_CN/rbot-shortenurls.po +0 -0
  591. data/po/zh_CN/rbot-slashdot.po +0 -0
  592. data/po/zh_CN/rbot-spell.po +54 -0
  593. data/po/zh_CN/rbot-theyfightcrime.po +0 -0
  594. data/po/zh_CN/rbot-threat.po +0 -0
  595. data/po/zh_CN/rbot-time.po +0 -0
  596. data/po/zh_CN/rbot-topic.po +0 -0
  597. data/po/zh_CN/rbot-translator.po +77 -0
  598. data/po/zh_CN/rbot-tube.po +0 -0
  599. data/po/zh_CN/rbot-twitter.po +24 -0
  600. data/po/zh_CN/rbot-uno.po +512 -0
  601. data/po/zh_CN/rbot-urban.po +0 -0
  602. data/po/zh_CN/rbot-url.po +0 -0
  603. data/po/zh_CN/rbot-usermodes.po +0 -0
  604. data/po/zh_CN/rbot-wall.po +33 -0
  605. data/po/zh_CN/rbot-weather.po +0 -0
  606. data/po/zh_CN/rbot-wheelfortune.po +205 -0
  607. data/po/zh_CN/rbot-wow.po +0 -0
  608. data/po/zh_CN/rbot-wserver.po +0 -0
  609. data/po/zh_CN/rbot-youtube.po +58 -0
  610. data/po/zh_CN/rbot.po +1006 -0
  611. data/po/zh_TW/rbot-alias.po +82 -0
  612. data/po/zh_TW/rbot-autoop.po +0 -0
  613. data/po/zh_TW/rbot-autorejoin.po +0 -0
  614. data/po/zh_TW/rbot-azgame.po +186 -0
  615. data/po/zh_TW/rbot-bans.po +0 -0
  616. data/po/zh_TW/rbot-bash.po +0 -0
  617. data/po/zh_TW/rbot-botsnack.po +0 -0
  618. data/po/zh_TW/rbot-cal.po +3 -0
  619. data/po/zh_TW/rbot-chanserv.po +0 -0
  620. data/po/zh_TW/rbot-chucknorris.po +0 -0
  621. data/po/zh_TW/rbot-debugger.po +0 -0
  622. data/po/zh_TW/rbot-deepthoughts.po +0 -0
  623. data/po/zh_TW/rbot-delicious.po +0 -0
  624. data/po/zh_TW/rbot-dice.po +0 -0
  625. data/po/zh_TW/rbot-dict.po +0 -0
  626. data/po/zh_TW/rbot-dictclient.po +111 -0
  627. data/po/zh_TW/rbot-digg.po +0 -0
  628. data/po/zh_TW/rbot-eightball.po +0 -0
  629. data/po/zh_TW/rbot-excuse.po +0 -0
  630. data/po/zh_TW/rbot-factoids.po +107 -0
  631. data/po/zh_TW/rbot-figlet.po +36 -0
  632. data/po/zh_TW/rbot-fish.po +0 -0
  633. data/po/zh_TW/rbot-forecast.po +0 -0
  634. data/po/zh_TW/rbot-fortune.po +0 -0
  635. data/po/zh_TW/rbot-freshmeat.po +0 -0
  636. data/po/zh_TW/rbot-grouphug.po +18 -0
  637. data/po/zh_TW/rbot-hl2.po +0 -0
  638. data/po/zh_TW/rbot-host.po +3 -0
  639. data/po/zh_TW/rbot-imdb.po +0 -0
  640. data/po/zh_TW/rbot-insult.po +0 -0
  641. data/po/zh_TW/rbot-iplookup.po +0 -0
  642. data/po/zh_TW/rbot-karma.po +0 -0
  643. data/po/zh_TW/rbot-keywords.po +24 -0
  644. data/po/zh_TW/rbot-lart.po +0 -0
  645. data/po/zh_TW/rbot-lastfm.po +172 -0
  646. data/po/zh_TW/rbot-linkbot.po +0 -0
  647. data/po/zh_TW/rbot-markov.po +20 -0
  648. data/po/zh_TW/rbot-math.po +0 -0
  649. data/po/zh_TW/rbot-modes.po +0 -0
  650. data/po/zh_TW/rbot-nickrecover.po +36 -0
  651. data/po/zh_TW/rbot-nickserv.po +104 -0
  652. data/po/zh_TW/rbot-nslookup.po +0 -0
  653. data/po/zh_TW/rbot-quakeauth.po +0 -0
  654. data/po/zh_TW/rbot-quiz.po +0 -0
  655. data/po/zh_TW/rbot-quotes.po +108 -0
  656. data/po/zh_TW/rbot-reaction.po +0 -0
  657. data/po/zh_TW/rbot-remind.po +0 -0
  658. data/po/zh_TW/rbot-remotectl.po +0 -0
  659. data/po/zh_TW/rbot-ri.po +0 -0
  660. data/po/zh_TW/rbot-roshambo.po +0 -0
  661. data/po/zh_TW/rbot-rot13.po +0 -0
  662. data/po/zh_TW/rbot-roulette.po +0 -0
  663. data/po/zh_TW/rbot-rss.po +20 -0
  664. data/po/zh_TW/rbot-salut.po +0 -0
  665. data/po/zh_TW/rbot-script.po +0 -0
  666. data/po/zh_TW/rbot-search.po +0 -0
  667. data/po/zh_TW/rbot-seen.po +0 -0
  668. data/po/zh_TW/rbot-shiritori.po +102 -0
  669. data/po/zh_TW/rbot-shortenurls.po +0 -0
  670. data/po/zh_TW/rbot-slashdot.po +0 -0
  671. data/po/zh_TW/rbot-spell.po +54 -0
  672. data/po/zh_TW/rbot-theyfightcrime.po +0 -0
  673. data/po/zh_TW/rbot-threat.po +0 -0
  674. data/po/zh_TW/rbot-time.po +0 -0
  675. data/po/zh_TW/rbot-topic.po +0 -0
  676. data/po/zh_TW/rbot-translator.po +77 -0
  677. data/po/zh_TW/rbot-tube.po +0 -0
  678. data/po/zh_TW/rbot-twitter.po +24 -0
  679. data/po/zh_TW/rbot-uno.po +512 -0
  680. data/po/zh_TW/rbot-urban.po +0 -0
  681. data/po/zh_TW/rbot-url.po +0 -0
  682. data/po/zh_TW/rbot-usermodes.po +0 -0
  683. data/po/zh_TW/rbot-wall.po +33 -0
  684. data/po/zh_TW/rbot-weather.po +0 -0
  685. data/po/zh_TW/rbot-wheelfortune.po +205 -0
  686. data/po/zh_TW/rbot-wow.po +0 -0
  687. data/po/zh_TW/rbot-wserver.po +0 -0
  688. data/po/zh_TW/rbot-youtube.po +58 -0
  689. data/po/zh_TW/rbot.po +1034 -0
  690. data/setup.rb +800 -574
  691. metadata +723 -108
  692. data/data/rbot/contrib/plugins/figlet.rb +0 -20
  693. data/data/rbot/contrib/plugins/ri.rb +0 -83
  694. data/data/rbot/plugins/demauro.rb +0 -95
  695. data/data/rbot/plugins/google.rb +0 -53
  696. data/data/rbot/plugins/opme.rb +0 -19
  697. data/data/rbot/plugins/roshambo.rb +0 -54
  698. data/data/rbot/plugins/rubyurl.rb +0 -39
  699. data/data/rbot/plugins/tinyurl.rb +0 -39
  700. data/data/rbot/plugins/xmlrpc.rb.disabled +0 -52
  701. data/data/rbot/templates/levels.rbot +0 -32
  702. data/data/rbot/templates/users.rbot +0 -1
  703. data/lib/rbot/auth.rb +0 -314
  704. data/lib/rbot/channel.rb +0 -54
  705. data/lib/rbot/httputil.rb +0 -309
  706. data/lib/rbot/utils.rb +0 -83
@@ -1,27 +1,61 @@
1
+ #-- vim:sw=2:et
2
+ #++
3
+ #
4
+ # :title: Freshmeat plugin for rbot
5
+
1
6
  require 'rexml/document'
2
- require 'uri/common'
3
7
 
4
8
  class FreshmeatPlugin < Plugin
5
9
  include REXML
6
10
  def help(plugin, topic="")
7
11
  "freshmeat search [<max>=4] <string> => search freshmeat for <string>, freshmeat [<max>=4] => return up to <max> freshmeat headlines"
8
12
  end
9
-
13
+
14
+ REL_ENTRY = %r{<a href="/(release)s/(\d+)/"><font color="#000000">(.*?)</font></a>}
15
+ PRJ_ENTRY = %r{<a href="/(project)s/(\S+?)/"><b>(.*?)</b></a>}
16
+
17
+ # This method defines a filter for fm pages. It's needed because the generic
18
+ # summarization grabs a comment, not the actual article.
19
+ #
20
+ def freshmeat_filter(s)
21
+ loc = Utils.check_location(s, /freshmeat\.net/)
22
+ return nil unless loc
23
+ entries = []
24
+ s[:text].scan(/#{REL_ENTRY}|#{PRJ_ENTRY}/) { |m|
25
+ entry = {
26
+ :type => ($1 || $4).dup,
27
+ :code => ($2 || $5).dup,
28
+ :name => ($3 || $6).dup
29
+ }
30
+ entries << entry
31
+ }
32
+ return nil if entries.empty?
33
+ title = s[:text].ircify_html_title
34
+ content = entries.inject([]) { |l, e| l << e[:name] }.join(" | ")
35
+ return {:title => title, :content => content}
36
+ end
37
+
38
+ def initialize
39
+ super
40
+ @bot.register_filter(:freshmeat, :htmlinfo) { |s| freshmeat_filter(s) }
41
+ end
42
+
10
43
  def search_freshmeat(m, params)
11
44
  max = params[:limit].to_i
12
45
  search = params[:search].to_s
13
46
  max = 8 if max > 8
14
- begin
15
- xml = @bot.httputil.get(URI.parse("http://freshmeat.net/search-xml/?orderby=locate_projectname_full_DESC&q=#{URI.escape(search)}"))
16
- rescue URI::InvalidURIError, URI::BadURIError => e
17
- m.reply "illegal search string #{search}"
18
- return
19
- end
47
+ xml = @bot.httputil.get("http://freshmeat.net/search-xml/?orderby=locate_projectname_full_DESC&q=#{CGI.escape(search)}")
20
48
  unless xml
21
49
  m.reply "search for #{search} failed"
22
50
  return
23
51
  end
24
- doc = Document.new xml
52
+ doc = nil
53
+ begin
54
+ doc = Document.new xml
55
+ rescue
56
+ debug xml
57
+ error $!
58
+ end
25
59
  unless doc
26
60
  m.reply "search for #{search} failed"
27
61
  return
@@ -59,7 +93,7 @@ class FreshmeatPlugin < Plugin
59
93
  max = params[:limit].to_i
60
94
  max = 8 if max > 8
61
95
  begin
62
- xml = @bot.httputil.get(URI.parse("http://images.feedstermedia.com/feedcache/ostg/freshmeat/fm-releases-global.xml"))
96
+ xml = @bot.httputil.get('http://freshmeat.net/backend/fm-releases-global.xml')
63
97
  unless xml
64
98
  m.reply "freshmeat news parse failed"
65
99
  return
@@ -79,8 +113,8 @@ class FreshmeatPlugin < Plugin
79
113
  title_width = 0
80
114
  done = 0
81
115
  doc.elements.each("*/channel/item") {|e|
82
- desc = e.elements["description"].text
83
- title = e.elements["title"].text
116
+ desc = e.elements["description"].text.ircify_html
117
+ title = e.elements["title"].text.ircify_html
84
118
  #title.gsub!(/\s+\(.*\)\s*$/, "")
85
119
  title.strip!
86
120
  title_width = title.length if title.length > title_width
@@ -0,0 +1,565 @@
1
+ #-- vim:sw=2:et
2
+ #++
3
+ #
4
+ # :title: A-Z Game Plugin for rbot
5
+ #
6
+ # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
7
+ # Author:: Yaohan Chen <yaohan.chen@gmail.com>: Japanese support
8
+ #
9
+ # Copyright:: (C) 2006 Giuseppe Bilotta
10
+ # Copyright:: (C) 2007 GIuseppe Bilotta, Yaohan Chen
11
+ #
12
+ # License:: GPL v2
13
+ #
14
+ # A-Z Game: guess the word by reducing the interval of allowed ones
15
+ #
16
+ # TODO allow manual addition of words
17
+
18
+ class AzGame
19
+
20
+ attr_reader :range, :word
21
+ attr_reader :lang, :rules, :listener
22
+ attr_accessor :tries, :total_tries, :total_failed, :failed, :winner
23
+ def initialize(plugin, lang, rules, word)
24
+ @plugin = plugin
25
+ @lang = lang.to_sym
26
+ @word = word.downcase
27
+ @rules = rules
28
+ @range = [@rules[:first].dup, @rules[:last].dup]
29
+ @listener = @rules[:listener]
30
+ @total_tries = 0
31
+ @total_failed = 0 # not used, reported, updated
32
+ @tries = Hash.new(0)
33
+ @failed = Hash.new(0) # not used, not reported, updated
34
+ @winner = nil
35
+ def @range.to_s
36
+ return "%s -- %s" % self
37
+ end
38
+ end
39
+
40
+ def check(word)
41
+ w = word.downcase
42
+ debug "checking #{w} for #{@word} in #{@range}"
43
+ # Since we're called threaded, bail out early if a winner
44
+ # was assigned already
45
+ return [:ignore, nil] if @winner
46
+ return [:bingo, nil] if w == @word
47
+ return [:out, @range] if w < @range.first or w > @range.last
48
+ return [:ignore, @range] if w == @range.first or w == @range.last
49
+ # This is potentially slow (for languages that check online)
50
+ return [:noexist, @range] unless @plugin.send("is_#{@lang}?", w)
51
+ debug "we like it"
52
+ # Check again if there was a winner in the mean time,
53
+ # and bail out if there was
54
+ return [:ignore, nil] if @winner
55
+ if w < @word and w > @range.first
56
+ @range.first.replace(w)
57
+ return [:in, @range]
58
+ elsif w > @word and w < @range.last
59
+ @range.last.replace(w)
60
+ return [:in, @range]
61
+ end
62
+ return [:out, @range]
63
+ end
64
+
65
+ # TODO scoring: base score is t = ceil(100*exp(-((n-1)^2)/(50^2)))+p for n attempts
66
+ # done by p players; players that didn't win but contributed
67
+ # with a attempts will get t*a/n points
68
+
69
+ include Math
70
+
71
+ def score
72
+ n = @total_tries
73
+ p = @tries.keys.length
74
+ t = (100*exp(-((n-1)**2)/(50.0**2))).ceil + p
75
+ debug "Total score: #{t}"
76
+ ret = Hash.new
77
+ @tries.each { |k, a|
78
+ ret[k] = [t*a/n, n_("%{count} try", "%{count} tries", a) % {:count => a}]
79
+ }
80
+ if @winner
81
+ debug "replacing winner score of %d with %d" % [ret[@winner].first, t]
82
+ tries = ret[@winner].last
83
+ ret[@winner] = [t, _("winner, %{tries}") % {:tries => tries}]
84
+ end
85
+ return ret.sort_by { |h| h.last.first }.reverse
86
+ end
87
+
88
+ end
89
+
90
+ class AzGamePlugin < Plugin
91
+
92
+ def initialize
93
+ super
94
+ # if @registry.has_key?(:games)
95
+ # @games = @registry[:games]
96
+ # else
97
+ @games = Hash.new
98
+ # end
99
+ if @registry.has_key?(:wordcache) and @registry[:wordcache]
100
+ @wordcache = @registry[:wordcache]
101
+ else
102
+ @wordcache = Hash.new
103
+ end
104
+ debug "A-Z wordcache: #{@wordcache.pretty_inspect}"
105
+
106
+ @rules = {
107
+ :italian => {
108
+ :good => /s\.f\.|s\.m\.|agg\.|v\.tr\.|v\.(pronom\.)?intr\./, # avv\.|pron\.|cong\.
109
+ :bad => /var\./,
110
+ :first => 'abaco',
111
+ :last => 'zuzzurellone',
112
+ :url => "http://www.demauroparavia.it/%s",
113
+ :wapurl => "http://wap.demauroparavia.it/index.php?lemma=%s",
114
+ :listener => /^[a-z]+$/
115
+ },
116
+ :english => {
117
+ :good => /(?:singular )?noun|verb|adj/,
118
+ :first => 'abacus',
119
+ :last => 'zuni',
120
+ :url => "http://www.chambersharrap.co.uk/chambers/features/chref/chref.py/main?query=%s&title=21st",
121
+ :listener => /^[a-z]+$/
122
+ },
123
+ }
124
+
125
+ japanese_wordlist = "#{@bot.botclass}/azgame/wordlist-japanese"
126
+ if File.exist?(japanese_wordlist)
127
+ words = File.readlines(japanese_wordlist) \
128
+ .map {|line| line.strip} .uniq
129
+ if(words.length >= 4) # something to guess
130
+ @rules[:japanese] = {
131
+ :good => /^\S+$/,
132
+ :list => words,
133
+ :first => words[0],
134
+ :last => words[-1],
135
+ :listener => /^\S+$/
136
+ }
137
+ debug "Japanese wordlist loaded, #{@rules[:japanese][:list].length} lines; first word: #{@rules[:japanese][:first]}, last word: #{@rules[:japanese][:last]}"
138
+ end
139
+ end
140
+ end
141
+
142
+ def save
143
+ # @registry[:games] = @games
144
+ @registry[:wordcache] = @wordcache
145
+ end
146
+
147
+ def message(m)
148
+ return if m.channel.nil? or m.address?
149
+ k = m.channel.downcase.to_s # to_sym?
150
+ return unless @games.key?(k)
151
+ return if m.params
152
+ word = m.plugin.downcase
153
+ return unless word =~ @games[k].listener
154
+ word_check(m, k, word)
155
+ end
156
+
157
+ def word_check(m, k, word)
158
+ # Not really safe ... what happens
159
+ Thread.new {
160
+ isit = @games[k].check(word)
161
+ case isit.first
162
+ when :bingo
163
+ m.reply _("%{bold}BINGO!%{bold} the word was %{underline}%{word}%{underline}. Congrats, %{bold}%{player}%{bold}!") % {:bold => Bold, :underline => Underline, :word => word, :player => m.sourcenick}
164
+ @games[k].total_tries += 1
165
+ @games[k].tries[m.source] += 1
166
+ @games[k].winner = m.source
167
+ ar = @games[k].score.inject([]) { |res, kv|
168
+ res.push("%s: %d (%s)" % kv.flatten)
169
+ }
170
+ m.reply _("The game was won after %{tries} tries. Scores for this game: %{scores}") % {:tries => @games[k].total_tries, :scores => ar.join('; ')}
171
+ @games.delete(k)
172
+ when :out
173
+ m.reply _("%{word} is not in the range %{bold}%{range}%{bold}") % {:word => word, :bold => Bold, :range => isit.last} if m.address?
174
+ when :noexist
175
+ # bail out early if the game was won in the mean time
176
+ return if !@games[k] or @games[k].winner
177
+ m.reply _("%{word} doesn't exist or is not acceptable for the game") % {:word => word}
178
+ @games[k].total_failed += 1
179
+ @games[k].failed[m.source] += 1
180
+ when :in
181
+ # bail out early if the game was won in the mean time
182
+ return if !@games[k] or @games[k].winner
183
+ m.reply _("close, but no cigar. New range: %{bold}%{range}%{bold}") % {:bold => Bold, :range => isit.last}
184
+ @games[k].total_tries += 1
185
+ @games[k].tries[m.source] += 1
186
+ when :ignore
187
+ m.reply _("%{word} is already one of the range extrema: %{range}") % {:word => word, :range => isit.last} if m.address?
188
+ else
189
+ m.reply _("hm, something went wrong while verifying %{word}")
190
+ end
191
+ }
192
+ end
193
+
194
+ def manual_word_check(m, params)
195
+ k = m.channel.downcase.to_s
196
+ word = params[:word].downcase
197
+ if not @games.key?(k)
198
+ m.reply _("no A-Z game running here, can't check if %{word} is valid, can I?")
199
+ return
200
+ end
201
+ if word !~ /^\S+$/
202
+ m.reply _("I only accept single words composed by letters only, sorry")
203
+ return
204
+ end
205
+ word_check(m, k, word)
206
+ end
207
+
208
+ def stop_game(m, params)
209
+ return if m.channel.nil? # Shouldn't happen, but you never know
210
+ k = m.channel.downcase.to_s # to_sym?
211
+ if @games.key?(k)
212
+ m.reply _("the word in %{bold}%{range}%{bold} was: %{bold}%{word}%{bold}") % {:bold => Bold, :range => @games[k].range, :word => @games[k].word}
213
+ ar = @games[k].score.inject([]) { |res, kv|
214
+ res.push("%s: %d (%s)" % kv.flatten)
215
+ }
216
+ m.reply _("The game was cancelled after %{tries} tries. Scores for this game would have been: %{scores}") % {:tries => @games[k].total_tries, :scores => ar.join('; ')}
217
+ @games.delete(k)
218
+ else
219
+ m.reply _("no A-Z game running in this channel ...")
220
+ end
221
+ end
222
+
223
+ def start_game(m, params)
224
+ return if m.channel.nil? # Shouldn't happen, but you never know
225
+ k = m.channel.downcase.to_s # to_sym?
226
+ unless @games.key?(k)
227
+ lang = (params[:lang] || @bot.config['core.language']).to_sym
228
+ method = 'random_pick_'+lang.to_s
229
+ m.reply _("let me think ...")
230
+ if @rules.has_key?(lang) and self.respond_to?(method)
231
+ word = self.send(method)
232
+ if word.empty?
233
+ m.reply _("couldn't think of anything ...")
234
+ return
235
+ end
236
+ else
237
+ m.reply _("I can't play A-Z in %{lang}, sorry") % {:lang => lang}
238
+ return
239
+ end
240
+ m.reply _("got it!")
241
+ @games[k] = AzGame.new(self, lang, @rules[lang], word)
242
+ end
243
+ tr = @games[k].total_tries
244
+ # this message building code is rewritten to make translation easier
245
+ if tr == 0
246
+ tr_msg = ''
247
+ else
248
+ f_tr = @games[k].total_failed
249
+ if f_tr > 0
250
+ tr_msg = _(" (after %{total_tries} and %{invalid_tries})") %
251
+ { :total_tries => n_("%{count} try", "%{count} tries", tr) %
252
+ {:count => tr},
253
+ :invalid_tries => n_("%{count} invalid try", "%{count} invalid tries", tr) %
254
+ {:count => f_tr} }
255
+ else
256
+ tr_msg = _(" (after %{total_tries})") %
257
+ { :total_tries => n_("%{count} try", "%{count} tries", tr) %
258
+ {:count => tr}}
259
+ end
260
+ end
261
+
262
+ m.reply _("A-Z: %{bold}%{range}%{bold}") % {:bold => Bold, :range => @games[k].range} + tr_msg
263
+ return
264
+ end
265
+
266
+ def wordlist(m, params)
267
+ pars = params[:params]
268
+ lang = (params[:lang] || @bot.config['core.language']).to_sym
269
+ wc = @wordcache[lang] || Hash.new rescue Hash.new
270
+ cmd = params[:cmd].to_sym rescue :count
271
+ case cmd
272
+ when :count
273
+ m.reply n_("I have %{count} %{lang} word in my cache", "I have %{count} %{lang} words in my cache", wc.size) % {:count => wc.size, :lang => lang}
274
+ when :show, :list
275
+ if pars.empty?
276
+ m.reply _("provide a regexp to match")
277
+ return
278
+ end
279
+ begin
280
+ regex = /#{pars[0]}/
281
+ matches = wc.keys.map { |k|
282
+ k.to_s
283
+ }.grep(regex)
284
+ rescue
285
+ matches = []
286
+ end
287
+ if matches.size == 0
288
+ m.reply _("no %{lang} word I know match %{pattern}") % {:lang => lang, :pattern => pars[0]}
289
+ elsif matches.size > 25
290
+ m.reply _("more than 25 %{lang} words I know match %{pattern}, try a stricter matching") % {:lang => lang, :pattern => pars[0]}
291
+ else
292
+ m.reply "#{matches.join(', ')}"
293
+ end
294
+ when :info
295
+ if pars.empty?
296
+ m.reply _("provide a word")
297
+ return
298
+ end
299
+ word = pars[0].downcase.to_sym
300
+ if not wc.key?(word)
301
+ m.reply _("I don't know any %{lang} word %{word}") % {:lang => lang, :word => word}
302
+ return
303
+ end
304
+ if wc[word].key?(:when)
305
+ tr = _("%{word} learned from %{user} on %{date}") % {:word => word, :user => wc[word][:who], :date => wc[word][:when]}
306
+ else
307
+ tr = _("%{word} learned from %{user}") % {:word => word, :user => wc[word][:who]}
308
+ end
309
+ m.reply tr
310
+ when :delete
311
+ if pars.empty?
312
+ m.reply _("provide a word")
313
+ return
314
+ end
315
+ word = pars[0].downcase.to_sym
316
+ if not wc.key?(word)
317
+ m.reply _("I don't know any %{lang} word %{word}") % {:lang => lang, :word => word}
318
+ return
319
+ end
320
+ wc.delete(word)
321
+ @bot.okay m.replyto
322
+ when :add
323
+ if pars.empty?
324
+ m.reply _("provide a word")
325
+ return
326
+ end
327
+ word = pars[0].downcase.to_sym
328
+ if wc.key?(word)
329
+ m.reply _("I already know the %{lang} word %{word}")
330
+ return
331
+ end
332
+ wc[word] = { :who => m.sourcenick, :when => Time.now }
333
+ @bot.okay m.replyto
334
+ else
335
+ end
336
+ end
337
+
338
+ def is_japanese?(word)
339
+ @rules[:japanese][:list].include?(word)
340
+ end
341
+
342
+ # return integer between min and max, inclusive
343
+ def rand_between(min, max)
344
+ rand(max - min + 1) + min
345
+ end
346
+
347
+ def random_pick_japanese(min=nil, max=nil)
348
+ rules = @rules[:japanese]
349
+ min = rules[:first] if min.nil_or_empty?
350
+ max = rules[:last] if max.nil_or_empty?
351
+ debug "Randomly picking word between #{min} and #{max}"
352
+ min_index = rules[:list].index(min)
353
+ max_index = rules[:list].index(max)
354
+ debug "Index between #{min_index} and #{max_index}"
355
+ index = rand_between(min_index + 1, max_index - 1)
356
+ debug "Index generated: #{index}"
357
+ word = rules[:list][index]
358
+ debug "Randomly picked #{word}"
359
+ word
360
+ end
361
+
362
+ def is_italian?(word)
363
+ unless @wordcache.key?(:italian)
364
+ @wordcache[:italian] = Hash.new
365
+ end
366
+ wc = @wordcache[:italian]
367
+ return true if wc.key?(word.to_sym)
368
+ rules = @rules[:italian]
369
+ p = @bot.httputil.get(rules[:wapurl] % word, :open_timeout => 60, :read_timeout => 60)
370
+ if not p
371
+ error "could not connect!"
372
+ return false
373
+ end
374
+ debug p
375
+ p.scan(/<anchor>#{word} - (.*?)<go href="lemma.php\?ID=([^"]*?)"/) { |qual, url|
376
+ debug "new word #{word} of type #{qual}"
377
+ if qual =~ rules[:good] and qual !~ rules[:bad]
378
+ wc[word.to_sym] = {:who => :dict}
379
+ return true
380
+ end
381
+ next
382
+ }
383
+ return false
384
+ end
385
+
386
+ def random_pick_italian(min=nil,max=nil)
387
+ # Try to pick a random word between min and max
388
+ word = String.new
389
+ min = min.to_s
390
+ max = max.to_s
391
+ if min > max
392
+ m.reply "#{min} > #{max}"
393
+ return word
394
+ end
395
+ rules = @rules[:italian]
396
+ min = rules[:first] if min.empty?
397
+ max = rules[:last] if max.empty?
398
+ debug "looking for word between #{min.inspect} and #{max.inspect}"
399
+ return word if min.empty? or max.empty?
400
+ begin
401
+ while (word <= min or word >= max or word !~ /^[a-z]+$/)
402
+ debug "looking for word between #{min} and #{max} (prev: #{word.inspect})"
403
+ # TODO for the time being, skip words with extended characters
404
+ unless @wordcache.key?(:italian)
405
+ @wordcache[:italian] = Hash.new
406
+ end
407
+ wc = @wordcache[:italian]
408
+
409
+ if wc.size > 0
410
+ cache_or_url = rand(2)
411
+ if cache_or_url == 0
412
+ debug "getting word from wordcache"
413
+ word = wc.keys[rand(wc.size)].to_s
414
+ next
415
+ end
416
+ end
417
+
418
+ # TODO when doing ranges, adapt this choice
419
+ l = ('a'..'z').to_a[rand(26)]
420
+ debug "getting random word from dictionary, starting with letter #{l}"
421
+ first = rules[:url] % "lettera_#{l}_0_50"
422
+ p = @bot.httputil.get(first)
423
+ max_page = p.match(/ \/ (\d+)<\/label>/)[1].to_i
424
+ pp = rand(max_page)+1
425
+ debug "getting random word from dictionary, starting with letter #{l}, page #{pp}"
426
+ p = @bot.httputil.get(first+"&pagina=#{pp}") if pp > 1
427
+ lemmi = Array.new
428
+ good = rules[:good]
429
+ bad = rules[:bad]
430
+ # We look for a lemma composed by a single word and of length at least two
431
+ p.scan(/<li><a href="([^"]+?)" title="consulta il lemma ([^ "][^ "]+?)">.*?&nbsp;(.+?)<\/li>/) { |url, prelemma, tipo|
432
+ lemma = prelemma.downcase.to_sym
433
+ debug "checking lemma #{lemma} (#{prelemma}) of type #{tipo} from url #{url}"
434
+ next if wc.key?(lemma)
435
+ case tipo
436
+ when good
437
+ if tipo =~ bad
438
+ debug "refusing, #{bad}"
439
+ next
440
+ end
441
+ debug "good one"
442
+ lemmi << lemma
443
+ wc[lemma] = {:who => :dict}
444
+ else
445
+ debug "refusing, not #{good}"
446
+ end
447
+ }
448
+ word = lemmi[rand(lemmi.length)].to_s
449
+ end
450
+ rescue => e
451
+ error "error #{e.inspect} while looking up a word"
452
+ error e.backtrace.join("\n")
453
+ end
454
+ return word
455
+ end
456
+
457
+ def is_english?(word)
458
+ unless @wordcache.key?(:english)
459
+ @wordcache[:english] = Hash.new
460
+ end
461
+ wc = @wordcache[:english]
462
+ return true if wc.key?(word.to_sym)
463
+ rules = @rules[:english]
464
+ p = @bot.httputil.get(rules[:url] % CGI.escape(word))
465
+ if not p
466
+ error "could not connect!"
467
+ return false
468
+ end
469
+ debug p
470
+ if p =~ /<span class="(?:hwd|srch)">#{word}<\/span>([^\n]+?)<span class="psa">#{rules[:good]}<\/span>/i
471
+ debug "new word #{word}"
472
+ wc[word.to_sym] = {:who => :dict}
473
+ return true
474
+ end
475
+ return false
476
+ end
477
+
478
+ def random_pick_english(min=nil,max=nil)
479
+ # Try to pick a random word between min and max
480
+ word = String.new
481
+ min = min.to_s
482
+ max = max.to_s
483
+ if min > max
484
+ m.reply "#{min} > #{max}"
485
+ return word
486
+ end
487
+ rules = @rules[:english]
488
+ min = rules[:first] if min.empty?
489
+ max = rules[:last] if max.empty?
490
+ debug "looking for word between #{min.inspect} and #{max.inspect}"
491
+ return word if min.empty? or max.empty?
492
+ begin
493
+ while (word <= min or word >= max or word !~ /^[a-z]+$/)
494
+ debug "looking for word between #{min} and #{max} (prev: #{word.inspect})"
495
+ # TODO for the time being, skip words with extended characters
496
+ unless @wordcache.key?(:english)
497
+ @wordcache[:english] = Hash.new
498
+ end
499
+ wc = @wordcache[:english]
500
+
501
+ if wc.size > 0
502
+ cache_or_url = rand(2)
503
+ if cache_or_url == 0
504
+ debug "getting word from wordcache"
505
+ word = wc.keys[rand(wc.size)].to_s
506
+ next
507
+ end
508
+ end
509
+
510
+ # TODO when doing ranges, adapt this choice
511
+ l = ('a'..'z').to_a[rand(26)]
512
+ ll = ('a'..'z').to_a[rand(26)]
513
+ random = [l,ll].join('*') + '*'
514
+ debug "getting random word from dictionary, matching #{random}"
515
+ p = @bot.httputil.get(rules[:url] % CGI.escape(random))
516
+ debug p
517
+ lemmi = Array.new
518
+ good = rules[:good]
519
+ # We look for a lemma composed by a single word and of length at least two
520
+ p.scan(/<span class="(?:hwd|srch)">(.*?)<\/span>([^\n]+?)<span class="psa">#{rules[:good]}<\/span>/i) { |prelemma, discard|
521
+ lemma = prelemma.downcase
522
+ debug "checking lemma #{lemma} (#{prelemma}) and discarding #{discard}"
523
+ next if wc.key?(lemma.to_sym)
524
+ if lemma =~ /^[a-z]+$/
525
+ debug "good one"
526
+ lemmi << lemma
527
+ wc[lemma.to_sym] = {:who => :dict}
528
+ else
529
+ debug "funky characters, not good"
530
+ end
531
+ }
532
+ next if lemmi.empty?
533
+ word = lemmi[rand(lemmi.length)]
534
+ end
535
+ rescue => e
536
+ error "error #{e.inspect} while looking up a word"
537
+ error e.backtrace.join("\n")
538
+ end
539
+ return word
540
+ end
541
+
542
+ def help(plugin, topic="")
543
+ case topic
544
+ when 'manage'
545
+ return _("az [lang] word [count|list|add|delete] => manage the az wordlist for language lang (defaults to current bot language)")
546
+ when 'cancel'
547
+ return _("az cancel => abort current game")
548
+ when 'check'
549
+ return _('az check <word> => checks <word> against current game')
550
+ when 'rules'
551
+ return _("try to guess the word the bot is thinking of; if you guess wrong, the bot will use the new word to restrict the range of allowed words: eventually, the range will be so small around the correct word that you can't miss it")
552
+ when 'play'
553
+ return _("az => start a game if none is running, show the current word range otherwise; you can say 'az <language>' if you want to play in a language different from the current bot default")
554
+ end
555
+ return _("az topics: play, rules, cancel, manage, check")
556
+ end
557
+
558
+ end
559
+
560
+ plugin = AzGamePlugin.new
561
+ plugin.map 'az [:lang] word :cmd *params', :action=>'wordlist', :defaults => { :lang => nil, :cmd => 'count', :params => [] }, :auth_path => '!az::edit!'
562
+ plugin.map 'az cancel', :action=>'stop_game', :private => false
563
+ plugin.map 'az check :word', :action => 'manual_word_check', :private => false
564
+ plugin.map 'az [play] [:lang]', :action=>'start_game', :private => false, :defaults => { :lang => nil }
565
+