Compare commits
No commits in common. "catalyst" and "master" have entirely different histories.
16 changed files with 26319 additions and 347 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -2,3 +2,4 @@
|
|||
*.log
|
||||
/*.db
|
||||
/*.conf
|
||||
/env
|
||||
|
|
|
|||
31
README.md
Normal file
31
README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
LolBot
|
||||
======
|
||||
|
||||
A naff IRC bot I rattled off in a hurry once, for folks stuck behind censor
|
||||
walls at work. Logs a channel and collects up all the URLs for later.
|
||||
It was refactored for Twisted in 2011, then again to use pypi irc in 2015.
|
||||
Has recently grown a quiz feature based on MoxQuizz, which might actually turn
|
||||
into something useful one day.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
To get started, set up a Python virtual environment, and install the stuff in
|
||||
`requirements.txt`.
|
||||
|
||||
apt-get install python-virtualenv
|
||||
|
||||
Clone this git repository, and in the directory:
|
||||
|
||||
virtualenv env
|
||||
env/bin/pip install -r requirements.txt
|
||||
|
||||
Then you can run the bot like so:
|
||||
|
||||
env/bin/python lolbot.py --help
|
||||
|
||||
Development
|
||||
-----------
|
||||
|
||||
Patches welcome! Development currently happens on the New Zealand Open Source
|
||||
Society [GitLab](https://git.nzoss.org.nz/moxquizz-fans/lolbot).
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
irc.server = irc.wgtn.cat-it.co.nz
|
||||
irc.server = irc.freenode.net
|
||||
irc.channel = #lolbottest
|
||||
|
||||
# defaults:
|
||||
# irc.port = 6667
|
||||
# irc.nickname = lolbot
|
||||
|
||||
# sqlite database filename
|
||||
db.file = lolbot.db
|
||||
|
||||
|
|
|
|||
704
lolbot.py
Executable file → Normal file
704
lolbot.py
Executable file → Normal file
|
|
@ -1,253 +1,339 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# LolBot
|
||||
#
|
||||
# New version based on Twisted IRC.
|
||||
|
||||
#! /usr/bin/env python
|
||||
"""
|
||||
Useful bot for folks stuck behind censor walls at work
|
||||
Logs a channel and collects URLs for later.
|
||||
LOLBOT 2
|
||||
|
||||
- die: Let the bot cease to exist.
|
||||
- ask: Ask a MoxQuizz question.
|
||||
- list: list some URLs
|
||||
"""
|
||||
|
||||
try:
|
||||
import sys
|
||||
import os
|
||||
import string
|
||||
import re
|
||||
import random
|
||||
import time
|
||||
import getopt
|
||||
import sqlite3
|
||||
from twisted.words.protocols import irc
|
||||
from twisted.internet import protocol
|
||||
from twisted.internet import reactor
|
||||
from datetime import datetime
|
||||
from mechanize import Browser
|
||||
from sqlalchemy import MetaData, Table, Column, String, Text, Integer, DateTime, create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
except ImportError:
|
||||
print "Some modules missing: Lolbot relies on Twisted IRC, Mechanize and SQLAlchemy.\n"
|
||||
sys.exit
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
SqlBase = declarative_base()
|
||||
import sys
|
||||
import os
|
||||
import sqlite3
|
||||
import random
|
||||
import time
|
||||
import getopt
|
||||
import irc.strings
|
||||
from irc.bot import SingleServerIRCBot
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from models import Log, Url, Model
|
||||
from pymoxquizz import QuestionBank, Question
|
||||
from os import listdir, path
|
||||
|
||||
class Log(SqlBase):
|
||||
|
||||
DEBUG = True
|
||||
|
||||
|
||||
def debug(msg):
|
||||
if DEBUG:
|
||||
print(msg)
|
||||
|
||||
|
||||
class LolBot(SingleServerIRCBot):
|
||||
"""
|
||||
This class represents an event in the log table and inherits from a SQLAlchemy
|
||||
convenience ORM class.
|
||||
An IRC bot to entertain the troops with MoxQuizz questions, log URLs, and
|
||||
other shenanigans.
|
||||
"""
|
||||
|
||||
__tablename__ = "log"
|
||||
qb = list()
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
timestamp = Column(DateTime)
|
||||
nickname = Column(String(20))
|
||||
text = Column(Text)
|
||||
|
||||
def __init__(self, nickname, text, timestamp=None):
|
||||
def __init__(self, config=None):
|
||||
"""
|
||||
Creates an event log for the IRC logger.
|
||||
"""
|
||||
if timestamp is None:
|
||||
timestamp = datetime.now()
|
||||
self.timestamp = timestamp
|
||||
self.nickname = nickname
|
||||
self.text = text
|
||||
|
||||
def __repr__(self):
|
||||
return "(%s) %s: %s" % (self.timestamp.strftime("%Y-%m-%d %H:%M:%S"), self.nickname, self.text)
|
||||
|
||||
class Url(SqlBase):
|
||||
"""
|
||||
This class represents a saved URL and inherits from a SQLAlchemy convenience
|
||||
ORM class.
|
||||
Constructor. Instantiates a lolbot with a configuration dictionary,
|
||||
or from command-line options if none is specified.
|
||||
"""
|
||||
|
||||
__tablename__ = "url"
|
||||
if not config:
|
||||
config = LolBot.get_options()
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
timestamp = Column(DateTime)
|
||||
nickname = Column(String(20))
|
||||
url = Column(String(200), unique=True)
|
||||
title = Column(Text)
|
||||
if not self.validate_config(config):
|
||||
sys.exit(1)
|
||||
|
||||
def __init__(self, nickname, url, title=None, timestamp=None):
|
||||
if timestamp is None:
|
||||
timestamp = datetime.now()
|
||||
self.timestamp = timestamp
|
||||
self.nickname = nickname
|
||||
self.url = url
|
||||
self.title = title
|
||||
self.config = config
|
||||
(server, port, channel, nickname, database) = (
|
||||
config['irc.server'],
|
||||
config['irc.port'],
|
||||
config['irc.channel'],
|
||||
config['irc.nickname'],
|
||||
config['db.file'])
|
||||
|
||||
# populate the title from the URL if not given.
|
||||
if title is None:
|
||||
try:
|
||||
br = Browser()
|
||||
br.open(self.url)
|
||||
self.title = br.title()
|
||||
except Exception as ex:
|
||||
self.title = ''
|
||||
debug("Instantiating SingleServerIRCBot")
|
||||
irc.client.ServerConnection.buffer_class = irc.buffer.LenientDecodingLineBuffer
|
||||
SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
|
||||
self.channel = channel
|
||||
|
||||
def __repr__(self):
|
||||
if not self.title:
|
||||
return "%s: %s" % (self.nickname, self.url)
|
||||
else:
|
||||
return "%s: %s - %s" % (self.nickname, self.url, self.title)
|
||||
# load some MoxQuizz questions
|
||||
qfiles = [f for f in listdir('questions') if path.isfile(path.join('questions', f))]
|
||||
debug("Loading MoxQuizz questions")
|
||||
for f in qfiles:
|
||||
qfile = path.abspath(path.join('questions', f))
|
||||
debug(" - from MoxQuizz bank '%s'" % qfile)
|
||||
self.qb += QuestionBank(qfile).questions
|
||||
random.shuffle(self.qb)
|
||||
self.quiz = 0
|
||||
self.question = None
|
||||
|
||||
class LolBot(irc.IRCClient):
|
||||
"""
|
||||
The Lolbot itself.
|
||||
"""
|
||||
# connect to the database
|
||||
debug("Connecting to SQLite database '%s'" % database)
|
||||
self.dbfile = database
|
||||
self.dbengine = create_engine('sqlite+pysqlite://', creator=self._get_connection)
|
||||
Model.metadata.bind = self.dbengine
|
||||
Model.metadata.create_all()
|
||||
self.get_db = sessionmaker(bind=self.dbengine)
|
||||
|
||||
self.helptext = "Keeps a list of URLs. Commands: list [n|x-y] - prints the last 10 URLs (or n URLs, or x through y); <url> - adds the URL to the list; help - this message."
|
||||
debug("Exiting lolbot constructor")
|
||||
|
||||
def _get_connection(self):
|
||||
connection = sqlite3.Connection(self.config['db.file'])
|
||||
"""Creator function for SQLAlchemy."""
|
||||
connection = sqlite3.Connection(self.dbfile)
|
||||
connection.text_factory = str
|
||||
debug("Creating SQLAlchemy connection")
|
||||
return connection
|
||||
|
||||
def created(self, when):
|
||||
# connect to the database
|
||||
self.dbengine = create_engine('sqlite+pysqlite://', creator=self._get_connection)
|
||||
SqlBase.metadata.bind = self.dbengine
|
||||
SqlBase.metadata.create_all()
|
||||
self.get_session = sessionmaker(bind=self.dbengine)
|
||||
@property
|
||||
def nickname(self):
|
||||
return self.connection.get_nickname()
|
||||
|
||||
self.helptext = "Keeps a list of URLs. Commands: list [n|x-y] - prints the last 10 URLs (or n URLs, or x through y); clear - clears the list; <url> - adds the URL to the list; help - this message."
|
||||
def say_public(self, text):
|
||||
"""
|
||||
Say text in the public channel for all to see.
|
||||
"""
|
||||
self.connection.privmsg(self.channel, text)
|
||||
self.log_event(self.nickname, text)
|
||||
|
||||
def now(self):
|
||||
return datetime.today().strftime("%Y-%m-%d %H:%M:%S")
|
||||
def say_private(self, nick, text):
|
||||
"""
|
||||
Say text in a private message to nick.
|
||||
"""
|
||||
self.connection.privmsg(nick, text)
|
||||
|
||||
def reply(self, text, to_private=None):
|
||||
"""
|
||||
Say text in either public channel or a private message (if to_private
|
||||
supplied).
|
||||
"""
|
||||
if to_private is not None:
|
||||
self.say_private(to_private, text)
|
||||
else:
|
||||
self.say_public(text)
|
||||
|
||||
def on_nicknameinuse(self, connection, event):
|
||||
debug("Nick '%s' in use, trying '%s_'" % (self.nickname, self.nickname))
|
||||
connection.nick(self.nickname + "_")
|
||||
|
||||
def on_welcome(self, connection, event):
|
||||
debug("Joining channel '%s' as %s" % (self.channel, self.nickname))
|
||||
connection.join(self.channel)
|
||||
|
||||
def on_privmsg(self, connection, event):
|
||||
"""
|
||||
Handle a /msg from a user.
|
||||
Handle commands addressed to the bot.
|
||||
"""
|
||||
message = event.arguments[0]
|
||||
self.do_command(event, message)
|
||||
|
||||
def on_pubmsg(self, connection, event):
|
||||
"""
|
||||
Handle an event on the channel.
|
||||
Handle commands addressed to the bot.
|
||||
If there's a question, see if it's been answered.
|
||||
"""
|
||||
|
||||
# Handle bot commands if addressed by nick or using ! shortcut.
|
||||
try:
|
||||
(nick, message) = event.arguments[0].split(": ", 1)
|
||||
if irc.strings.lower(nick) == irc.strings.lower(self.connection.get_nickname()):
|
||||
self.do_command(event, message.strip())
|
||||
except ValueError:
|
||||
message = event.arguments[0]
|
||||
nick = event.source.nick
|
||||
if message.startswith('!'):
|
||||
self.do_command(event, message.lstrip('!'))
|
||||
|
||||
# Log it.
|
||||
self.log_event(nick, message)
|
||||
|
||||
# Deal with MoxQuizz question.
|
||||
if self.quiz:
|
||||
self.handle_quiz(nick, message)
|
||||
|
||||
# Record URLs.
|
||||
words = message.split(" ")
|
||||
for w in words:
|
||||
if w.startswith('http://') or w.startswith('https://'):
|
||||
title = self.save_url(nick, w)
|
||||
if title is False:
|
||||
self.say_public("Failed to record URL, or no title found.")
|
||||
else:
|
||||
self.say_public("URL added. %s" % title)
|
||||
|
||||
def save_url(self, nickname, url):
|
||||
title = False
|
||||
try:
|
||||
db = self.get_session()
|
||||
db = self.get_db()
|
||||
if not db.query(Url).filter(Url.url == url).count():
|
||||
theurl = Url(nickname, url)
|
||||
db.add(theurl)
|
||||
db.commit()
|
||||
else:
|
||||
theurl = db.query(Url).filter(Url.url == url).one()
|
||||
print theurl
|
||||
print(theurl)
|
||||
title = theurl.title
|
||||
except Exception, ex:
|
||||
print "Exception caught saving URL: %s" % ex
|
||||
except Exception as ex:
|
||||
print("Exception caught saving URL: %s" % ex)
|
||||
return title
|
||||
|
||||
def log_event(self, nick, text):
|
||||
try:
|
||||
entry = Log(nick, text)
|
||||
db = self.get_session()
|
||||
db = self.get_db()
|
||||
db.add(entry)
|
||||
db.commit()
|
||||
print entry
|
||||
except Exception, ex:
|
||||
print "Exception caught logging event: %s" % ex
|
||||
print(entry)
|
||||
except Exception as ex:
|
||||
print("Exception caught logging event: %s" % ex)
|
||||
|
||||
def _get_nickname(self):
|
||||
return self.factory.nickname
|
||||
nickname = property(_get_nickname)
|
||||
def start_quiz(self, nick):
|
||||
self.quiz = 0
|
||||
self.quiz_scores = dict()
|
||||
self.connection.notice(self.channel, 'Quiz begun by %s.' % nick)
|
||||
self.quiz_get_next()
|
||||
|
||||
def _get_channel(self):
|
||||
return self.factory.channel
|
||||
channel = property(_get_channel)
|
||||
def stop_quiz(self):
|
||||
self.quiz = 0
|
||||
self.quiz_scores = None
|
||||
self.question = None
|
||||
|
||||
def _get_config(self):
|
||||
return self.factory.config
|
||||
config = property(_get_config)
|
||||
def quiz_get_next(self):
|
||||
self.quiz += 1
|
||||
self.tip = 0
|
||||
self.question = random.choice(self.qb)
|
||||
print(self.question.question)
|
||||
self.connection.notice(self.channel, "Question %s: %s" % (self.quiz, self.question.question))
|
||||
|
||||
def signedOn(self):
|
||||
self.join(self.channel)
|
||||
print "Signed on as %s." % (self.nickname,)
|
||||
|
||||
def joined(self, channel):
|
||||
print "Joined %s." % (channel,)
|
||||
|
||||
def privmsg(self, user, channel, msg):
|
||||
user = user.split('!')[0]
|
||||
if channel == self.nickname:
|
||||
# Private /msg from a user
|
||||
self.do_command(msg, user)
|
||||
def quiz_tip(self):
|
||||
if len(self.question.tip) > self.tip:
|
||||
self.connection.notice(self.channel, "Tip: %s" % self.question.tip[self.tip])
|
||||
self.tip += 1
|
||||
else:
|
||||
# log it
|
||||
self.log_event(user, msg)
|
||||
self.connection.notice(self.channel, "No more tips.")
|
||||
|
||||
args = string.split(msg, ":", 1)
|
||||
if len(args) > 1 and args[0] == self.nickname:
|
||||
self.do_command(string.strip(args[1]))
|
||||
else:
|
||||
# parse it for links, add URLs to the list
|
||||
words = msg.split(" ")
|
||||
for w in words:
|
||||
def quiz_award_points(self, nick):
|
||||
if nick not in self.quiz_scores.keys():
|
||||
self.quiz_scores[nick] = 0
|
||||
self.quiz_scores[nick] += self.question.score
|
||||
|
||||
# URL
|
||||
if w.startswith('http://') or w.startswith('https://'):
|
||||
title = self.save_url(user, w)
|
||||
if title != False:
|
||||
self.say_public("URL added. %s" % title)
|
||||
score = "%s point" % self.quiz_scores[nick]
|
||||
if self.quiz_scores[nick] != 1:
|
||||
score += "s"
|
||||
|
||||
# Moodle tracker bugs
|
||||
elif w.startswith('MDL-'):
|
||||
m = re.search('^MDL-([0-9]+)$', w)
|
||||
if m:
|
||||
trackerurl = 'https://tracker.moodle.org/browse/%s' % w
|
||||
title = self.save_url(user, trackerurl)
|
||||
if title != False:
|
||||
self.say_public("%s - %s" % (trackerurl, title))
|
||||
|
||||
# Work requests
|
||||
elif w.startswith('WR'):
|
||||
m = re.search('^WR#?([0-9]+)$', w)
|
||||
if m:
|
||||
wrmsurl = 'https://wrms.catalyst.net.nz/%s' % m.groups()[0]
|
||||
title = self.save_url(user, wrmsurl)
|
||||
if title != False:
|
||||
self.say_public("%s - %s" % (wrmsurl, title))
|
||||
|
||||
# Bugzilla
|
||||
elif w.startswith('BUG'):
|
||||
m = re.search('^BUG#?([0-9]+)$', w)
|
||||
if m:
|
||||
wrmsurl = 'http://bugzilla.catalyst.net.nz/show_bug.cgi?id=%s' % m.groups()[0]
|
||||
title = self.save_url(user, wrmsurl)
|
||||
if title != False:
|
||||
self.say_public("%s - %s" % (wrmsurl, title))
|
||||
|
||||
def say_public(self, text):
|
||||
"Print TEXT into public channel, for all to see."
|
||||
self.notice(self.channel, text)
|
||||
self.log_event(self.nickname, text)
|
||||
|
||||
def say_private(self, nick, text):
|
||||
"Send private message of TEXT to NICK."
|
||||
self.notice(nick, text)
|
||||
|
||||
def reply(self, text, to_private=None):
|
||||
"Send TEXT to either public channel or TO_PRIVATE nick (if defined)."
|
||||
if to_private is not None:
|
||||
self.say_private(to_private, text)
|
||||
else:
|
||||
self.say_public(text)
|
||||
|
||||
def do_command(self, cmd, target=None):
|
||||
"""
|
||||
This is the function called whenever someone sends a public or
|
||||
private message addressed to the bot. (e.g. "bot: blah").
|
||||
"""
|
||||
|
||||
try:
|
||||
if cmd == 'help':
|
||||
self.reply(self.helptext, target)
|
||||
|
||||
elif cmd == 'urls' or cmd == 'list':
|
||||
db = self.get_session()
|
||||
for url in db.query(Url).order_by(Url.timestamp.desc())[:10]:
|
||||
line = "%s %s" % (url.url, url.title)
|
||||
self.reply(line, target)
|
||||
self.connection.notice(self.channel, 'Correct! The answer was %s.' % self.question.answer)
|
||||
time.sleep(1)
|
||||
self.connection.notice(self.channel, '%s is on %s.' % (nick, score))
|
||||
|
||||
elif cmd.startswith('urls ') or cmd.startswith('list '):
|
||||
db = self.get_session()
|
||||
def quiz_check_win(self, nick):
|
||||
if self.quiz_scores[nick] == 10:
|
||||
self.connection.notice(self.channel, '%s wins with 10 points!' % nick)
|
||||
self.quiz_scoreboard()
|
||||
self.stop_quiz()
|
||||
|
||||
def quiz_scoreboard(self):
|
||||
if not self.quiz:
|
||||
self.connection.notice(self.channel, 'Quiz not running.')
|
||||
return
|
||||
|
||||
self.connection.notice(self.channel, 'Scoreboard:')
|
||||
for nick in self.quiz_scores.keys():
|
||||
score = "%s point" % self.quiz_scores[nick]
|
||||
if self.quiz_scores[nick] != 1:
|
||||
score += "s"
|
||||
self.connection.notice(self.channel, '%s has %s.' % (nick, score))
|
||||
if not len(self.quiz_scores):
|
||||
self.connection.notice(self.channel, 'So far, nobody has got anything right.')
|
||||
|
||||
def handle_quiz(self, nick, message):
|
||||
# bail if there's no quiz or unanswered question.
|
||||
if not self.quiz or not isinstance(self.question, Question):
|
||||
return
|
||||
|
||||
# see if anyone answered correctly.
|
||||
if self.question.attempt(message):
|
||||
self.quiz_award_points(nick)
|
||||
time.sleep(1)
|
||||
self.quiz_check_win(nick)
|
||||
|
||||
# if nobody has won, carry on
|
||||
if self.quiz:
|
||||
|
||||
# scores every 10 questions.
|
||||
if self.quiz % 10 == 0:
|
||||
self.quiz_scoreboard()
|
||||
|
||||
time.sleep(1)
|
||||
self.quiz_get_next()
|
||||
|
||||
def do_command(self, e, cmd):
|
||||
"""
|
||||
Handle bot commands.
|
||||
"""
|
||||
nick = e.source.nick
|
||||
c = self.connection
|
||||
|
||||
if cmd == "die":
|
||||
self.die()
|
||||
|
||||
elif cmd == 'help':
|
||||
c.notice(nick, self.helptext)
|
||||
|
||||
elif cmd == 'status':
|
||||
c.notice(self.channel, "I know %s questions." % len(self.qb))
|
||||
if self.quiz:
|
||||
c.notice(self.channel, "I am currently running a quiz.")
|
||||
self.quiz_scoreboard()
|
||||
|
||||
elif cmd == 'halt' or cmd == 'quit':
|
||||
if self.quiz:
|
||||
self.quiz_scoreboard()
|
||||
self.stop_quiz()
|
||||
c.notice(self.channel, "Quiz halted by %s. Use ask to start a new one." % nick)
|
||||
else:
|
||||
c.notice(self.channel, "No quiz running.")
|
||||
|
||||
elif cmd == 'scores':
|
||||
if self.quiz:
|
||||
self.quiz_scoreboard()
|
||||
|
||||
elif cmd == 'tip' or cmd == 'hint':
|
||||
if self.quiz:
|
||||
self.quiz_tip()
|
||||
|
||||
elif cmd == 'ask':
|
||||
if self.quiz:
|
||||
c.notice(self.channel, "Quiz is running. Use halt or quit to stop.")
|
||||
c.notice(self.channel, self.question.question)
|
||||
elif isinstance(self.question, Question):
|
||||
c.notice(self.channel, "There is an unanswered question.")
|
||||
c.notice(self.channel, self.question.question)
|
||||
else:
|
||||
self.start_quiz(nick)
|
||||
|
||||
elif cmd == 'revolt':
|
||||
if isinstance(self.question, Question):
|
||||
c.notice(self.channel, "Fine, the answer is: %s" % self.question.answer)
|
||||
self.quiz_get_next()
|
||||
|
||||
elif cmd.startswith('urls') or cmd.startswith('list'):
|
||||
db = self.get_db()
|
||||
try:
|
||||
(listcmd, n) = cmd.split(" ", 1)
|
||||
except ValueError:
|
||||
n = '5'
|
||||
|
||||
n = n.strip()
|
||||
if n == "all":
|
||||
rows = db.query(Url).order_by(Url.timestamp.desc())
|
||||
|
|
@ -258,91 +344,118 @@ class LolBot(irc.IRCClient):
|
|||
y = abs(int(y))
|
||||
if y < x:
|
||||
x, y = y, x
|
||||
except ValueError, ex:
|
||||
self.reply("Give me a number or a range of numbers, e.g. list 5 or list 11-20", target)
|
||||
except ValueError as ex:
|
||||
c.notice(nick, "Give me a number or a range of numbers, e.g. list 5 or list 11-20")
|
||||
raise ex
|
||||
rows = db.query(Url).order_by(Url.timestamp.desc())[x-1:y]
|
||||
rows = db.query(Url).order_by(Url.timestamp.desc())[x - 1: y]
|
||||
else:
|
||||
try:
|
||||
n = abs(int(n))
|
||||
except ValueError, ex:
|
||||
self.reply("Give me a number or a range of numbers, e.g. list 5 or list 11-20", target)
|
||||
except ValueError as ex:
|
||||
c.notice(nick, "Give me a number or a range of numbers, e.g. list 5 or list 11-20")
|
||||
raise ex
|
||||
rows = db.query(Url).order_by(Url.timestamp.desc())[:n]
|
||||
|
||||
for url in rows:
|
||||
line = "%s %s" % (url.url, url.title)
|
||||
self.reply(line, target)
|
||||
c.notice(nick, line)
|
||||
time.sleep(1)
|
||||
|
||||
elif cmd.startswith('http:') or cmd.startswith('https:'):
|
||||
title = self.save_url(from_private, cmd)
|
||||
if title == False:
|
||||
self.say_public("Sorry, I'm useless at UTF-8.")
|
||||
else:
|
||||
self.reply('URL added. %s' % title, target)
|
||||
c.notice(nick, "Not understood: " + cmd)
|
||||
|
||||
else:
|
||||
self.reply("I'm a bot of little brain. Try help for more information.", target)
|
||||
def validate_config(self, config):
|
||||
"""
|
||||
Basic checks for configuration parameters. Returns a Boolean indicating
|
||||
success or failure.
|
||||
"""
|
||||
|
||||
except Exception, ex:
|
||||
print "Exception caught processing command: %s" % ex
|
||||
print " command was '%s' from %s" % (cmd, target)
|
||||
self.reply("Sorry, I didn't understand: %s" % cmd, target)
|
||||
self.reply(self.helptext, target)
|
||||
# validate IRC host
|
||||
if 'irc.server' not in config.keys():
|
||||
print("Error: the IRC server was not specified. Use --help for more information.")
|
||||
return False
|
||||
|
||||
class LolBotFactory(protocol.ClientFactory):
|
||||
protocol = LolBot
|
||||
|
||||
def __init__(self, config_path):
|
||||
self.config = get_config(config_path)
|
||||
self.server = self.config['irc.server']
|
||||
self.port = self.config['irc.port']
|
||||
self.nickname = self.config['irc.nickname']
|
||||
self.channel = self.config['irc.channel']
|
||||
|
||||
def clientConnectionLost(self, connector, reason):
|
||||
print "Lost connection (%s), reconnecting." % (reason,)
|
||||
connector.connect()
|
||||
|
||||
def clientConnectionFailed(self, connector, reason):
|
||||
print "Could not connect: %s" % (reason,)
|
||||
|
||||
def get_options():
|
||||
# validate IRC port
|
||||
if 'irc.port' not in config.keys():
|
||||
config['irc.port'] = '6667'
|
||||
try:
|
||||
(options, args) = getopt.getopt(sys.argv[1:], "hc:", ["help", "config=", ])
|
||||
except getopt.GetoptError, err:
|
||||
print str(err)
|
||||
usage()
|
||||
config['irc.port'] = int(config['irc.port'])
|
||||
except ValueError:
|
||||
print("Error: the IRC port must be an integer. If not specified, lolbot will use the default IRC port value 6667. Use --help for more information.")
|
||||
return False
|
||||
|
||||
# validate IRC channel
|
||||
if 'irc.channel' not in config.keys() or not config['irc.channel'].startswith('#'):
|
||||
print("Error: the IRC channel is not specified or incorrect. It must begin with a # - e.g. #mychatchannel. Use --help for more information.")
|
||||
return False
|
||||
|
||||
# validate bot nickname
|
||||
if 'irc.nickname' not in config.keys():
|
||||
config['irc.nickname'] = 'lolbot'
|
||||
|
||||
# validate bot nickname
|
||||
if 'db.file' not in config.keys():
|
||||
config['db.file'] = 'lolbot.db'
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def get_options():
|
||||
"""
|
||||
Set up configuration from the script arguments.
|
||||
"""
|
||||
|
||||
try:
|
||||
(options, args) = getopt.getopt(sys.argv[1:], 'hc:s:p:j:n:d:', ['help', 'config=', 'server=', 'port=', 'join=', 'nick=', 'database=', ])
|
||||
except getopt.GetoptError as err:
|
||||
print(err)
|
||||
LolBot.usage()
|
||||
sys.exit(2)
|
||||
|
||||
config_path = ""
|
||||
for option,value in options:
|
||||
if option in ("-h", "--help"):
|
||||
usage()
|
||||
config = {}
|
||||
for option, value in options:
|
||||
# Display help text.
|
||||
if option in ('-h', '--help'):
|
||||
LolBot.usage()
|
||||
sys.exit(2)
|
||||
if option in ("-c", "--config"):
|
||||
config_path = value
|
||||
return { 'config_path': config_path }
|
||||
|
||||
def get_config(config_path):
|
||||
# Get configuration from a file.
|
||||
if option in ('-c', '--config'):
|
||||
config = LolBot.load_config(value)
|
||||
break
|
||||
|
||||
# Individually specified settings.
|
||||
if option in ('-s', '--server'):
|
||||
config['irc.server'] = value
|
||||
if option in ('-p', '--port'):
|
||||
config['irc.port'] = value
|
||||
if option in ('-j', '--join', '--channel', '--join-channel'):
|
||||
config['irc.channel'] = value
|
||||
if option in ('-n', '--nickname'):
|
||||
config['irc.nickname'] = value
|
||||
if option in ('-d', '--database'):
|
||||
config['db.file'] = value
|
||||
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def load_config(config_path=''):
|
||||
"""
|
||||
This method loads configuration options from a lolbot.conf file. The file
|
||||
should look like this:
|
||||
should look something like this::
|
||||
|
||||
irc.server = irc.freenode.net
|
||||
irc.server = irc.yourdomain.com
|
||||
irc.port = 6667
|
||||
irc.channel = #lolbottest
|
||||
irc.nickname = lolbot
|
||||
db.url = sqlite:///lolbot.db
|
||||
|
||||
db.file = lolbot.db
|
||||
"""
|
||||
|
||||
if not config_path:
|
||||
config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "lolbot.conf")
|
||||
if config_path == '':
|
||||
config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'lolbot.conf')
|
||||
if not os.path.exists(config_path):
|
||||
print "Error: configuration file not found. By default lolbot will look for a lolbot.conf file in the same directory as the lolbot script, but you can override this by specifying a path on the command line with the --config option."
|
||||
usage()
|
||||
print("Error: configuration file not found. By default lolbot will look for a lolbot.conf file in the same directory as the lolbot script, but you can override this by specifying a path on the command line with the --config option.")
|
||||
LolBot.usage()
|
||||
sys.exit(1)
|
||||
|
||||
# open the configuration file and grab all param=value declarations.
|
||||
|
|
@ -350,79 +463,64 @@ def get_config(config_path):
|
|||
with open(config_path) as f:
|
||||
for line in f:
|
||||
# skip comments
|
||||
if line.strip().startswith("#") or line.strip() == "":
|
||||
if line.strip().startswith('#') or line.strip() == '':
|
||||
continue
|
||||
|
||||
# collect up param = value
|
||||
try:
|
||||
(param, value) = line.strip().split("=", 1)
|
||||
if param.strip() != "":
|
||||
(param, value) = line.strip().split('=', 1)
|
||||
if param.strip() != '':
|
||||
config[param.strip()] = value.strip()
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
# validate IRC host
|
||||
if "irc.server" not in config.keys():
|
||||
print "Error: the IRC server was not specified. Use --help for more information."
|
||||
sys.exit(1)
|
||||
|
||||
# validate IRC port
|
||||
if "irc.port" not in config.keys():
|
||||
config["irc.port"] = "6667"
|
||||
try:
|
||||
config["irc.port"] = int(config["irc.port"])
|
||||
except ValueError:
|
||||
print "Error: the IRC port must be an integer. If not specified, lolbot will use the default IRC port value 6667. Use --help for more information."
|
||||
sys.exit(1)
|
||||
|
||||
# validate IRC channel
|
||||
if "irc.channel" not in config.keys() or not config["irc.channel"].startswith("#"):
|
||||
print "Error: the IRC channel is not specified or incorrect. It must begin with a # - e.g. #mychatchannel. Use --help for more information."
|
||||
sys.exit(1)
|
||||
|
||||
# validate bot nickname
|
||||
if "irc.nickname" not in config.keys():
|
||||
config["irc.nickname"] = "lolbot"
|
||||
|
||||
return config
|
||||
|
||||
def usage():
|
||||
print """Run a lolbot.
|
||||
@staticmethod
|
||||
def usage():
|
||||
"""
|
||||
Spits out CLI help.
|
||||
"""
|
||||
|
||||
print("""Run a lolbot.
|
||||
|
||||
-h, --help
|
||||
This message.
|
||||
|
||||
-c, --config=<filename>
|
||||
Specify a configuration file. Defaults to lolbot.conf in the same
|
||||
directory as the script.
|
||||
|
||||
Configuration:
|
||||
|
||||
irc.server = <host>
|
||||
-s, --server=<hostname>
|
||||
The IRC server, e.g. irc.freenode.net
|
||||
|
||||
irc.port = <port>
|
||||
-p, --port=<port>
|
||||
The IRC server port. Default: 6667
|
||||
|
||||
irc.channel = <channel>
|
||||
-j, --join=<channel>
|
||||
The chat channel to join, e.g. #trainspotting
|
||||
|
||||
irc.nickname = <nickname>
|
||||
-n, --nickname=<nickname>
|
||||
The nickname for your lolbot. Default: "lolbot"
|
||||
|
||||
db.url = <url>
|
||||
The URL to your lolbot database. This can be any valid URL accepted
|
||||
by SQL Alchemy. If not specified, lolbot will attempt to use a
|
||||
SQLite database called lolbot.db in the same directory as the
|
||||
script.
|
||||
"""
|
||||
-d, --database=<path>
|
||||
The path to a SQLite lolbot database. If not specified, lolbot will
|
||||
attempt to use a SQLite database called lolbot.db in the same
|
||||
directory as the script.
|
||||
|
||||
Configuration file:
|
||||
|
||||
-c, --config=<filename>
|
||||
Specify a configuration file. Ignores any options specified from the
|
||||
command-line. Defaults to lolbot.conf in the same directory as the
|
||||
script. File layout:
|
||||
|
||||
irc.server = <host>
|
||||
irc.port = <port>
|
||||
irc.channel = <channel>
|
||||
irc.nickname = <nickname>
|
||||
db.file = <path>
|
||||
""".strip())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = get_options()
|
||||
config = get_config(args['config_path'])
|
||||
try:
|
||||
reactor.connectTCP(config['irc.server'], config['irc.port'], LolBotFactory(args['config_path']))
|
||||
reactor.run()
|
||||
LolBot().start()
|
||||
except KeyboardInterrupt:
|
||||
print "Shutting down."
|
||||
|
||||
pass
|
||||
|
|
|
|||
83
models.py
Normal file
83
models.py
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#! /usr/bin/env python
|
||||
"""
|
||||
Database models for lolbot.
|
||||
"""
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from bs4 import BeautifulSoup
|
||||
from sqlalchemy import (Column, String, Text, Integer, DateTime)
|
||||
from sqlalchemy.ext.declarative import (declarative_base)
|
||||
|
||||
|
||||
Model = declarative_base()
|
||||
|
||||
|
||||
class Log(Model):
|
||||
"""
|
||||
This class represents an event in the log table and inherits from a SQLAlchemy
|
||||
convenience ORM class.
|
||||
"""
|
||||
|
||||
__tablename__ = "log"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
timestamp = Column(DateTime)
|
||||
nickname = Column(String(20))
|
||||
text = Column(Text)
|
||||
|
||||
def __init__(self, nickname, text, timestamp=None):
|
||||
"""
|
||||
Creates an event log for the IRC logger.
|
||||
"""
|
||||
if timestamp is None:
|
||||
timestamp = datetime.now()
|
||||
self.timestamp = timestamp
|
||||
self.nickname = nickname
|
||||
self.text = text
|
||||
|
||||
def __repr__(self):
|
||||
return "(%s) %s: %s" % (self.timestamp.strftime("%Y-%m-%d %H:%M:%S"), self.nickname, self.text)
|
||||
|
||||
|
||||
class Url(Model):
|
||||
"""
|
||||
This class represents a saved URL and inherits from a SQLAlchemy convenience
|
||||
ORM class.
|
||||
"""
|
||||
|
||||
__tablename__ = "url"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
timestamp = Column(DateTime)
|
||||
nickname = Column(String(20))
|
||||
url = Column(String(200), unique=True)
|
||||
title = Column(Text)
|
||||
|
||||
def __init__(self, nickname, url, title=None, timestamp=None):
|
||||
if timestamp is None:
|
||||
timestamp = datetime.now()
|
||||
self.timestamp = timestamp
|
||||
self.nickname = nickname
|
||||
self.url = url
|
||||
self.title = title
|
||||
|
||||
# populate the title from the URL if not given.
|
||||
if title is None:
|
||||
r = requests.get(url)
|
||||
if r.status_code == 200:
|
||||
if 'text/html' in r.headers['content-type']:
|
||||
dom = BeautifulSoup(r.content, 'html.parser')
|
||||
self.title = dom.title.string
|
||||
else:
|
||||
self.title = r.headers['content-type']
|
||||
else:
|
||||
self.title = "Error: HTTP %s" % r.status_code
|
||||
|
||||
def __repr__(self):
|
||||
if not self.title:
|
||||
return "%s: %s" % (self.nickname, self.url)
|
||||
else:
|
||||
return "%s: %s - %s" % (self.nickname, self.url, self.title)
|
||||
300
pymoxquizz.py
Normal file
300
pymoxquizz.py
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
#!/usr/bin/env python
|
||||
## -*- coding: utf-8 -*-
|
||||
"""
|
||||
A MozQuizz question library for Python.
|
||||
See http://moxquizz.de/ for the original implementation in TCL.
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, print_function
|
||||
from io import open
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
class Question:
|
||||
"""
|
||||
Represents one MoxQuizz question.
|
||||
"""
|
||||
|
||||
category = None
|
||||
"""
|
||||
The question category. Arbitrary text; optional.
|
||||
"""
|
||||
|
||||
question = None
|
||||
"""
|
||||
The question. Arbitrary text; required.
|
||||
"""
|
||||
|
||||
answer = None
|
||||
"""
|
||||
The answer. Arbitrary text; required. Correct answers can also be covered
|
||||
by the :attr:`regexp` property.
|
||||
"""
|
||||
|
||||
regexp = None
|
||||
"""
|
||||
A regular expression that will generate correct answers. Optional. See
|
||||
also the :attr:`answer` property.
|
||||
"""
|
||||
|
||||
author = None
|
||||
"""
|
||||
The question author. Arbitrary text; optional.
|
||||
"""
|
||||
|
||||
level = None # Default: NORMAL (constructor)
|
||||
"""
|
||||
The difficulty level. Value must be from the :attr:`LEVELS` tuple.
|
||||
The default value is :attr:`NORMAL`.
|
||||
"""
|
||||
|
||||
comment = None
|
||||
"""
|
||||
A comment. Arbitrary text; optional.
|
||||
"""
|
||||
|
||||
score = 1
|
||||
"""
|
||||
The points scored for the correct answer. Integer value; default is 1.
|
||||
"""
|
||||
tip = list()
|
||||
"""
|
||||
An ordered list of tips (hints) to display to users. Optional.
|
||||
"""
|
||||
|
||||
tipcycle = 0
|
||||
"""
|
||||
Indicates which tip is to be displayed next, if any.
|
||||
"""
|
||||
|
||||
TRIVIAL = 1
|
||||
"""
|
||||
A value for :attr:`level` that indicates a question of trivial difficulty.
|
||||
"""
|
||||
|
||||
EASY = 2
|
||||
"""
|
||||
A value for :attr:`level` that indicates a question of easy difficulty.
|
||||
"""
|
||||
|
||||
NORMAL = 3
|
||||
"""
|
||||
A value for :attr:`level` that indicates a question of average or normal
|
||||
difficulty.
|
||||
"""
|
||||
|
||||
HARD = 4
|
||||
"""
|
||||
A value for :attr:`level` that indicates a question of hard difficulty.
|
||||
"""
|
||||
|
||||
EXTREME = 5
|
||||
"""
|
||||
A value for :attr:`level` that indicates a question of extreme difficulty
|
||||
or obscurity.
|
||||
"""
|
||||
|
||||
LEVELS = (TRIVIAL, EASY, NORMAL, HARD, EXTREME)
|
||||
"""
|
||||
The available :attr:`level` difficulty values, :attr:`TRIVIAL`, :attr:`EASY`,
|
||||
:attr:`NORMAL`, :attr:`HARD` and :attr:`EXTREME`.
|
||||
"""
|
||||
|
||||
def __init__(self, attributes_dict):
|
||||
"""
|
||||
Constructor that takes a dictionary of MoxQuizz key-value pairs. Usually
|
||||
called from a :class:`QuestionBank`.
|
||||
"""
|
||||
# Set defaults first.
|
||||
self.level = self.NORMAL
|
||||
self.parse(attributes_dict)
|
||||
|
||||
def parse(self, attributes_dict):
|
||||
"""
|
||||
Populate fields from a dictionary of attributes, usually provided by a
|
||||
:class:`QuestionBank` :attr:`~QuestionBank.parse` call.
|
||||
"""
|
||||
|
||||
## Valid keys:
|
||||
# ----------
|
||||
# Category? (should always be on top!)
|
||||
# Question (should always stand after Category)
|
||||
# Answer (will be matched if no regexp is provided)
|
||||
# Regexp? (use UNIX-style expressions)
|
||||
# Author? (the brain behind this question)
|
||||
# Level? [baby|easy|normal|hard|extreme] (difficulty)
|
||||
# Comment? (comment line)
|
||||
# Score? [#] (credits for answering this question)
|
||||
# Tip* (provide one or more hints)
|
||||
# TipCycle? [#] (Specify number of generated tips)
|
||||
|
||||
if 'Question' in attributes_dict.keys():
|
||||
self.question = attributes_dict['Question']
|
||||
else:
|
||||
raise Exception("Cannot instantiate Question: 'Question' attribute required.")
|
||||
|
||||
if 'Category' in attributes_dict.keys():
|
||||
self.category = attributes_dict['Category']
|
||||
|
||||
if 'Answer' in attributes_dict.keys():
|
||||
self.answer = attributes_dict['Answer']
|
||||
else:
|
||||
raise Exception("Cannot instantiate Question: 'Answer' attribute required.")
|
||||
|
||||
if 'Regexp' in attributes_dict.keys():
|
||||
self.regexp = attributes_dict['Regexp']
|
||||
|
||||
if 'Author' in attributes_dict.keys():
|
||||
self.category = attributes_dict['Author']
|
||||
|
||||
if 'Level' in attributes_dict.keys() and attributes_dict['Level'] in self.LEVELS:
|
||||
self.level = attributes_dict['Level']
|
||||
elif 'Level' in attributes_dict.keys() and attributes_dict['Level'] in QuestionBank.LEVEL_VALUES.keys():
|
||||
self.level = QuestionBank.LEVEL_VALUES[attributes_dict['Level']]
|
||||
|
||||
if 'Comment' in attributes_dict.keys():
|
||||
self.comment = attributes_dict['Comment']
|
||||
|
||||
if 'Score' in attributes_dict.keys():
|
||||
self.score = attributes_dict['Score']
|
||||
|
||||
if 'Tip' in attributes_dict.keys():
|
||||
self.tip = attributes_dict['Tip']
|
||||
|
||||
if 'Tipcycle' in attributes_dict.keys():
|
||||
self.tipcycle = attributes_dict['Tipcycle']
|
||||
|
||||
def attempt(self, answer):
|
||||
return (self.answer is not None and self.answer.lower() == answer.lower()) or (
|
||||
self.regexp is not None and re.search(self.regexp, answer, re.IGNORECASE) is not None)
|
||||
|
||||
class QuestionBank:
|
||||
"""
|
||||
Represents a MoxQuizz question bank.
|
||||
"""
|
||||
|
||||
filename = ''
|
||||
"""
|
||||
The path or filename of the question bank file.
|
||||
"""
|
||||
|
||||
questions = list()
|
||||
"""
|
||||
A list of :class:`Question` objects, constituting the questions in the
|
||||
question bank.
|
||||
"""
|
||||
|
||||
# Case sensitive, to remain backwards-compatible with MoxQuizz.
|
||||
KEYS = ('Answer',
|
||||
'Author',
|
||||
'Category',
|
||||
'Comment',
|
||||
'Level',
|
||||
'Question',
|
||||
'Regexp',
|
||||
'Score',
|
||||
'Tip',
|
||||
'Tipcycle',
|
||||
)
|
||||
"""
|
||||
The valid attributes available in a MoxQuizz question bank file.
|
||||
"""
|
||||
|
||||
LEVEL_VALUES = {
|
||||
'trivial': Question.TRIVIAL,
|
||||
'baby': Question.TRIVIAL,
|
||||
'easy': Question.EASY,
|
||||
'normal': Question.NORMAL,
|
||||
'hard': Question.HARD,
|
||||
'difficult': Question.HARD,
|
||||
'extreme': Question.EXTREME
|
||||
}
|
||||
"""
|
||||
Text labels for the :attr:`Question.level` difficulty values.
|
||||
"""
|
||||
|
||||
def __init__(self, filename):
|
||||
"""
|
||||
Constructor, takes a MozQuizz-formatted question bank filename.
|
||||
"""
|
||||
self.filename = filename
|
||||
self.questions = self.parse(filename)
|
||||
|
||||
def parse(self, filename):
|
||||
"""
|
||||
Read a MoxQuizz-formatted question bank file. Returns a ``list`` of
|
||||
:class:`Question` objects found in the file.
|
||||
"""
|
||||
questions = list()
|
||||
|
||||
with open(filename) as f:
|
||||
key = ''
|
||||
i = 0
|
||||
|
||||
# new question
|
||||
q = dict()
|
||||
q['Tip'] = list()
|
||||
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
i += 1
|
||||
|
||||
# Ignore comments.
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
|
||||
# A blank line starts a new question.
|
||||
if line == '':
|
||||
# Store the previous question, if valid.
|
||||
if 'Question' in q.keys() and 'Answer' in q.keys():
|
||||
question = Question(q)
|
||||
questions.append(question)
|
||||
|
||||
# Start a new question.
|
||||
q = dict()
|
||||
q['Tip'] = list()
|
||||
continue
|
||||
|
||||
# Fetch the next parameter.
|
||||
try:
|
||||
(key, value) = line.split(':', 1)
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
except ValueError:
|
||||
print("Unexpected weirdness in MoxQuizz questionbank '%s', line %s." % (self.filename, i))
|
||||
continue
|
||||
# break # TODO: is it appropriate to bail on broken bank files?
|
||||
|
||||
# Ignore bad parameters.
|
||||
if key not in self.KEYS:
|
||||
print("Unexpected key '%s' in MoxQuizz questionbank '%s', line %s." % (key, self.filename, i))
|
||||
continue
|
||||
|
||||
# Enumerate the Tips.
|
||||
if key == 'Tip':
|
||||
q['Tip'].append(value.strip())
|
||||
elif key == 'Level':
|
||||
if value not in self.LEVEL_VALUES:
|
||||
print("Unexpected Level value '%s' in MoxQuizz questionbank '%s', line '%s'." % (value, self.filename, i))
|
||||
else:
|
||||
q['Level'] = self.LEVEL_VALUES[value]
|
||||
else:
|
||||
q[key] = value.strip()
|
||||
|
||||
return questions
|
||||
|
||||
|
||||
# A crappy test.
|
||||
if __name__ == '__main__':
|
||||
qb = QuestionBank('questions/questions.doctorlard.en')
|
||||
for q in qb.questions:
|
||||
print(q.question)
|
||||
if sys.version.startswith('2'):
|
||||
a = unicode(raw_input('A: '), 'utf8')
|
||||
else:
|
||||
a = input('A: ')
|
||||
if q.attempt(a):
|
||||
print("Correct!")
|
||||
else:
|
||||
print("Incorrect - the answer is '%s'" % q.answer)
|
||||
175
questions/questions.doctorlard.en
Normal file
175
questions/questions.doctorlard.en
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
########################################################
|
||||
# DoctorLard's collection of random Moxquizz questions
|
||||
########################################################
|
||||
|
||||
## Demo-Entry:
|
||||
# ----------
|
||||
# Category: History
|
||||
# Question: Chinese philosopher (um 500 v. Chr.) ?
|
||||
# Answer: Konfuzius
|
||||
# Regexp: [ck]onfu(ts|z)ius
|
||||
# Author: anonymous
|
||||
# Level: hard
|
||||
# Comment: demo-entry, ÄÖÜäöüß ^° !"§$%&/()=? `Ž
|
||||
# Score: 5
|
||||
# Tip: Kon......
|
||||
# Tip: ...fuz...
|
||||
# Tip: ......ius
|
||||
|
||||
## valid keys:
|
||||
# ----------
|
||||
# Category? (should always be on top!)
|
||||
# Question (should always stand after Category)
|
||||
# Answer (will be matched if no regexp is provided)
|
||||
# Regexp? (use UNIX-style expressions)
|
||||
# Author? (the brain behind this question)
|
||||
# Level? [baby|easy|normal|hard|extreme] (difficulty)
|
||||
# Comment? (comment line)
|
||||
# Score? [#] (credits for answering this question)
|
||||
# Tip* (provide one or more hints)
|
||||
# TipCycle? [#] (Specify number of generated tips)
|
||||
|
||||
## WARNING:
|
||||
# -------
|
||||
# DO NOT ADD COMMENTS BEYOND THIS LINE, since they might get lost.
|
||||
# you may add as much comments as you want into the part above
|
||||
|
||||
Category: Units
|
||||
Question: What does the SI unit weber (Wb) measure?
|
||||
Tip: m....... f...
|
||||
Answer: magnetic flux
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Units
|
||||
Question: Four gills in a ....?
|
||||
Tip: It's an Imperial unit.
|
||||
Tip: You might ask for one at the pub.
|
||||
Tip: p...
|
||||
Answer: pint
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Units
|
||||
Question: Ten chains in a ....?
|
||||
Tip: It's an Imperial unit of length.
|
||||
Tip: f......
|
||||
Answer: furlong
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Units
|
||||
Question: Four .... in a chain?
|
||||
Tip: An obscure Imperial unit of length.
|
||||
Tip: Equal to 5½ yards.
|
||||
Tip: r..
|
||||
RegExp: (rod|pole|perch)
|
||||
Answer: Rod (or Pole, or Perch)
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Units
|
||||
Question: Eight .... in a mile?
|
||||
Tip: An Imperial unit of length.
|
||||
Tip: Equal to 220 yards.
|
||||
Tip: f......
|
||||
Answer: Furlong
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Units
|
||||
Question: A perch is unit of area equivalent to a square pole. A pole is another name for a rod, and there are ten chains to a furlong and four rods to a chain. A rood is a quarter acre, and there are 160 perches to an acre. If a property area is one rood and half a furlong on one side, how long is the other side, in rods?
|
||||
Tip: Less than you might think.
|
||||
Tip: Whatever. Google won't help you either.
|
||||
Level: hard
|
||||
Answer: 2
|
||||
Author: DoctorLard
|
||||
|
||||
Question: How many pennies in a half crown?
|
||||
Answer: 30
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Units
|
||||
Question: What is the old English surveying unit of area, defined as one furlong by one rod?
|
||||
Tip: There are four of them to an acre.
|
||||
Tip: r...
|
||||
Answer: rood
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Units
|
||||
Question: What is the SI prefix that denotes a multiplier of ten to the negative eighteenth power (10¯¹⁸)?
|
||||
Tip: It's used really really small quantities.
|
||||
Tip: a...
|
||||
Answer: atto
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Temporal anomalies
|
||||
Question: How many times do the minute and hour hands on a clockface overlap in a 24 hour period?
|
||||
Answer: 22
|
||||
Author: DoctorLard
|
||||
|
||||
Category: xG
|
||||
Question: Which country did hell- visit in August 2014?
|
||||
Answer: USA
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Music
|
||||
Question: A traditional Arabian and Turkish string instrument, distinguished from the lute by having no frets.
|
||||
Answer: oud
|
||||
Author: Bill Bailey
|
||||
|
||||
Category: Pharmacology
|
||||
Question: In Breaking Bad, Walter and Jesse used a "P2P cook" process to make very pure methamphetamine (by reduction with methylamine over aluminium). What does P2P stand for?
|
||||
Answer: phenyl-2-propanone
|
||||
Author: DoctorLard
|
||||
|
||||
Category: General ignorance
|
||||
Question: What are igloos normally made of?
|
||||
Answer: animal skins
|
||||
Regexp: (animal )?skins
|
||||
Tip: It isn't snow.
|
||||
Tip: It isn't any form of frozen water.
|
||||
Author: DoctorLard
|
||||
|
||||
Category: New Zealand
|
||||
Question: In what year did New Zealand become self-governing (by gaining its own representative government, separate from the United Kingdom)?
|
||||
Answer: 1852
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Geography
|
||||
Question: How many of the Commonwealth of Nations' member states are Realms?
|
||||
Answer: 16
|
||||
Level: hard
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Sculpture
|
||||
Question: Which Lord of the Rings actor, in an interview with Jay Leno, admitted to urinating in Wellington's Bucket Fountain sculpture while filming in New Zealand?
|
||||
Answer: Elijah Wood
|
||||
Author: DoctorLard
|
||||
|
||||
Category: TV
|
||||
Question: Which British comedy actor played Richmond in The IT Crowd, and Vincent Noir in The Mighty Boosh?
|
||||
Answer: Noel Fielding
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Video Games
|
||||
Question: Who composed the music for the Elder Scrolls and Guild Wars games, thinks he's God's gift to composers, and takes fucking ages to ship CDs of his soundtracks?
|
||||
Answer: Jeremy Soule
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Video Games
|
||||
Question: In the Guild Wars world of Tyria, name the once great human kingdom, laid waste by the Charr?
|
||||
Answer: Ascalon
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Video Games
|
||||
Question: In Mass Effect 2 and 3, which Oscar-nominated American actor provided the voice for The Illusive Man?
|
||||
Answer: Martin Sheen
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Cuisine
|
||||
Question: Which spice is made from the dried and ground aril that surrounds a nutmeg (Myristica fragrans) seed?
|
||||
Answer: Mace
|
||||
Author: DoctorLard
|
||||
|
||||
Category: Cuisine
|
||||
Question: What is the main ingredient of borscht?
|
||||
Answer: beetroot
|
||||
Author: DoctorLard
|
||||
|
||||
|
||||
182
questions/questions.dtron.en
Normal file
182
questions/questions.dtron.en
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
# ------------------------------------------------------------------------------
|
||||
#
|
||||
# Author: Lee Clarke, 1st April 2002
|
||||
# Editor:
|
||||
# Last edited: 2002/07/05 19:09:11
|
||||
#
|
||||
# Comment: many mixed quiz questions, Authors nick removed on request
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
## Demo-Entry:
|
||||
# ----------
|
||||
# Category: History
|
||||
# Question: Chinese philosopher (um 500 v. Chr.) ?
|
||||
# Answer: Konfuzius
|
||||
# Regexp: [ck]onfu(ts|z)ius
|
||||
# Author: anonymous
|
||||
# Level: hard
|
||||
# Comment: demo-entry, ÄÖÜäöüß ^° !"§$%&/()=? `Ž
|
||||
# Score: 5
|
||||
# Tip: Kon......
|
||||
# Tip: ...fuz...
|
||||
# Tip: ......ius
|
||||
|
||||
## valid keys:
|
||||
# ----------
|
||||
# Category? (should always be on top!)
|
||||
# Question (should always stand after Category)
|
||||
# Answer (will be matched if no regexp is provided)
|
||||
# Regexp? (use UNIX-style expressions)
|
||||
# Author? (the brain behind this question)
|
||||
# Level? [baby|easy|normal|hard|extreme] (difficulty)
|
||||
# Comment? (comment line)
|
||||
# Score? [#] (credits for answering this question)
|
||||
# Tip* (provide one or more hints)
|
||||
# TipCycle? [#] (Specify number of generated tips)
|
||||
|
||||
## WARNING:
|
||||
# -------
|
||||
# DO NOT ADD COMMENTS BEYOND THIS LINE, since they might get lost.
|
||||
# you may add as much comments as you want into the part above
|
||||
# <!========================================================!>
|
||||
|
||||
Category: Animals
|
||||
Question: What is the only animal, other than a human that can catch leprosy?
|
||||
Answer: The Armadillo
|
||||
|
||||
Category: Computer Games
|
||||
Question: Which legendary games designer/producer created the Super Mario Brothers franchise for Nintendo?
|
||||
Answer: Shigeru Miyamoto
|
||||
|
||||
Category: General
|
||||
Question: Aesthetic principles derived from the literature and art of ancient Greece & Rome, but found as ideals in all ages is called?
|
||||
Answer: Classicism
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: General
|
||||
Question: North American Indian language family including languages of Alaska and north-western Canada, the Pacific coast and the south-western United States.
|
||||
Answer: Athapascan
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: General
|
||||
Question: What is the literal translation of the Latin word 'video'?
|
||||
Answer: I See
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: General
|
||||
Question: Which 1946 Louis Reard creation, was nicknamed "four triangles of nothing"?
|
||||
Answer: The Bikini
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: General
|
||||
Question: Who is the supreme head of the Church Of England?
|
||||
Answer: Queen Elizabeth II
|
||||
|
||||
Category: General
|
||||
Question: Whose picture was on the first adhesive nickel postage stamp in the US?
|
||||
Answer: Benjamin Franklin
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: General
|
||||
Question: One of the twelve members of the administrative council of the Mormon church, is called a(n) .......?
|
||||
Answer: Apostle
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: General
|
||||
Question: The process of adding a number to itself a certain number of times is called?
|
||||
Answer: Multiplication
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Literature
|
||||
Question: Which novel by Mary Shelley was subtitled 'The Modern Prometheus'?
|
||||
Answer: Frankenstein
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Magazines
|
||||
Question: Which magazine always features an obituary on its last page?
|
||||
Answer: Rolling Stone
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Magazines
|
||||
Question: Who was the first male to appear on the cover of Playboy in 1964?
|
||||
Answer: Peter Sellers
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Movies
|
||||
Question: In which movie did Bruce Willis play the role of Corben Dallas?
|
||||
Answer: The Fifth Element
|
||||
|
||||
Category: Movies
|
||||
Question: What does Steven Spielberg try to include in every film he makes, claiming it is for luck?
|
||||
Answer: Scene With A Shooting Star
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Movies
|
||||
Question: Which actor played the role of Chewbacca in the Star Wars trilogy?
|
||||
Answer: Peter Mayhew
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Movies
|
||||
Question: Which actress won the 2002 Academy Award for best actress in a leading role, for her part in the movie, 'Monster's Ball'?
|
||||
Answer: Halle Berry
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Music
|
||||
Question: The theme tune for 'Monty Python's Flying Circus' was written by which composer?
|
||||
Answer: John Philip Sousa
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Music
|
||||
Question: What was the working title for The Beatles' song, 'Yesterday'?
|
||||
Answer: Scrambled Eggs
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Music
|
||||
Question: Which native of Flint, Michigan, once advised us to "drive your Chevrolet through the USA"?
|
||||
Answer: Pat Boone
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Quotes
|
||||
Question: Which tennis player , when asked if he had learned anything from his US Open loss said, "Yeah...I learned I needed to lose 15 pounds"?
|
||||
Answer: Andre Agassi
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Quotes
|
||||
Question: Who said, "People don't credit me with much of a brain, so why should I disillusion them."?
|
||||
Answer: Sylvester Stallone
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Soccer
|
||||
Question: Which English Premier League team plays their home games at Elland Road?
|
||||
Answer: Leeds United
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Sports
|
||||
Question: According to Olympic rules, what number of feathers must a badminton bird (shuttlecock) have?
|
||||
Answer: Fourteen
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Sports
|
||||
Question: What is the name of the oldest National Hockey League team in the US?
|
||||
Answer: The Boston Bruins
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: Star Trek
|
||||
Question: What is Mr Spock's pulse rate?
|
||||
Answer: 242 Beats Per Minute
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: TV
|
||||
Question: What is the address of The Munsters?
|
||||
Answer: 1313 Mockingbird Lane
|
||||
Author: DonkeyTron
|
||||
|
||||
Category: The Simpsons
|
||||
Question: Who has starred in such movies as 'The Erotic Adventures Of Hercules' & 'Dial M For Murderousness'?
|
||||
Answer: Troy McClure
|
||||
|
||||
Category: Weights & Measures
|
||||
Question: The liquid measure of a capacity equal to 1/8 of a fluid ounce is a(n) ..........?
|
||||
Answer: Fluid Dram
|
||||
Author: DonkeyTron
|
||||
3209
questions/questions.imran.en
Normal file
3209
questions/questions.imran.en
Normal file
File diff suppressed because it is too large
Load diff
618
questions/questions.ollypomm.en
Normal file
618
questions/questions.ollypomm.en
Normal file
|
|
@ -0,0 +1,618 @@
|
|||
# ------------------------------------------------------------------------------
|
||||
#
|
||||
# Author: OllyPomm
|
||||
# Editor: stanstime
|
||||
# Last edited: 2002/07/05 19:09:10
|
||||
#
|
||||
# Comment: OllyPomm has submitted about 200 questions with more to come
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
## Demo-Entry:
|
||||
# ----------
|
||||
# Category: History
|
||||
# Question: Chinese philosopher (um 500 v. Chr.) ?
|
||||
# Answer: Konfuzius
|
||||
# Regexp: [ck]onfu(ts|z)ius
|
||||
# Author: anonymous
|
||||
# Level: hard
|
||||
# Comment: demo-entry, ÄÖÜäöüß ^° !"§$%&/()=? `Ž
|
||||
# Score: 5
|
||||
# Tip: Kon......
|
||||
# Tip: ...fuz...
|
||||
# Tip: ......ius
|
||||
|
||||
## valid keys:
|
||||
# ----------
|
||||
# Category? (should always be on top!)
|
||||
# Question (should always stand after Category)
|
||||
# Answer (will be matched if no regexp is provided)
|
||||
# Regexp? (use UNIX-style expressions)
|
||||
# Author? (the brain behind this question)
|
||||
# Level? [baby|easy|normal|hard|extreme] (difficulty)
|
||||
# Comment? (comment line)
|
||||
# Score? [#] (credits for answering this question)
|
||||
# Tip* (provide one or more hints)
|
||||
# TipCycle? [#] (Specify number of generated tips)
|
||||
|
||||
## WARNING:
|
||||
# -------
|
||||
# DO NOT ADD COMMENTS BEYOND THIS LINE, since they might get lost.
|
||||
# you may add as much comments as you want into the part above
|
||||
# <!========================================================!>
|
||||
|
||||
Category: Animals
|
||||
Question: An unusual feature of the wombats pouch is that it .......?
|
||||
Answer: faces backwards
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Animals
|
||||
Question: How many nipples does an echidna have?
|
||||
Answer: None
|
||||
Regexp: (None|0|Zero|Nill)
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Animals
|
||||
Question: The thylacine (considered extinct) is more commonly know as the?
|
||||
Answer: Tasmanian Tiger
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Animals
|
||||
Question: What is a monotreme?
|
||||
Answer: An egg laying mammal
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Morse Code
|
||||
Question: What letter of the alphabet does 'dash dash' represent?
|
||||
Answer: M
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Morse Code
|
||||
Question: What letter of the alphabet does 'dash dot' represent?
|
||||
Answer: N
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Morse Code
|
||||
Question: What letter of the alphabet does 'dash dash dot' represent?
|
||||
Answer: G
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Morse Code
|
||||
Question: What letter of the alphabet does 'dash dash dot dot' represent?
|
||||
Answer: Z
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Morse Code
|
||||
Question: What letter of the alphabet does 'dot dot' represent?
|
||||
Answer: I
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: The Melbourne Cup horse race is held on the first ------- in November.?
|
||||
Answer: Tuesday
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: Over what distance is the Melbourne Cup horse race ran (in metres)?
|
||||
Answer: 3200
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Pot Pourri
|
||||
Question: How many weeks until Christmas Day if it is the 25th September?
|
||||
Answer: 13 weeks
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: What famous race was established in 1903?
|
||||
Answer: The Tour de France
|
||||
Author: OllyPomm
|
||||
|
||||
Category: History
|
||||
Question: In 1893, this country was the first to give women the vote.?
|
||||
Answer: New Zealand
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Metals
|
||||
Question: The largest pure gold nugget (weighing 70.92kg) ever discovered was called...?
|
||||
Answer: The Welcome Stranger
|
||||
Regexp: (The )?Welcome Stranger
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Medicine
|
||||
Question: In 1665 the first ----- ----------- was performed by Dr Richard Lower.?
|
||||
Answer: Blood Transfusion
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Pot Pourri
|
||||
Question: If it's 12.00 noon GMT - what time is it in Sydney, Australia?
|
||||
Answer: 10.00pm
|
||||
Author: OllyPomm
|
||||
|
||||
Category: History
|
||||
Question: Considered to be the last full blooded Tasmanian aborigine, (died 1876 - aged 73), her name is.....?
|
||||
Answer: Truganini
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Olympics
|
||||
Question: In what city is the Olympic torch first lit?
|
||||
Answer: Olympia
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Olympics
|
||||
Question: What is the latin Olympic motto?
|
||||
Answer: Citius Altius Fortius
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Olympics
|
||||
Question: What does the latin Olympic motto - Citius Altius Fortius stand for?
|
||||
Answer: Faster Higher Stronger
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Olympics
|
||||
Question: What are the colours of the Olympics rings (in order).?
|
||||
Answer: Blue Yellow Black Green Red
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Olympics
|
||||
Question: How many mascots did the Sydney Olympics have?
|
||||
Answer: 3
|
||||
Regexp: (3|Three)
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Olympics
|
||||
Question: The Sydney Olympics had 3 mascots. What type of animals were they?
|
||||
Answer: Kookaburra Echidna Platypus
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Olympics
|
||||
Question: What were the names of the 3 mascots at the Sydney Olympic Games?
|
||||
Answer: Ollie Millie Syd
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Quotes
|
||||
Question: Who said "Come up and see me sometime"?
|
||||
Answer: Mae West
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Quotes
|
||||
Question: Who said "Tha tha that's all folks"?
|
||||
Answer: Porky Pig
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Quotes
|
||||
Question: Who said "Go ahead - make my day" (character name)?
|
||||
Answer: Harry Callaghan
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: What sport do the following terms belong to - "Tight End & Wide Receiver"?
|
||||
Answer: #American Football# (Gridiron)
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: What sport do the following terms belong to - "Pull & Lolly"?
|
||||
Answer: Cricket
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: What sport do the following terms belong to - "Jerk & Snatch"?
|
||||
Answer: Weightlifting
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: What sport do the following terms belong to - "Hotdog & Bottom Trun"?
|
||||
Answer: Surfing
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: What sport do the following terms belong to - "Toucher & Dead Length"?
|
||||
Answer: Lawn or Indoor Bowls
|
||||
Regexp: (Lawn)?(Indoor Bowls)?
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: What sport do the following terms belong to - "Pist & Telemark"?
|
||||
Answer: Skiing
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: What sport do the following terms belong to - "Touches & Lunges"?
|
||||
Answer: Fencing
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: What sport do the following terms belong to - "Behind & Banana Kick"?
|
||||
Answer: Australian Football League
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Sport
|
||||
Question: What sport do the following terms belong to - "Sweeper & Advantage Rule"?
|
||||
Answer: Soccer
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Astronomy
|
||||
Question: How many stars make up the 'Southern Cross'?
|
||||
Answer: 5
|
||||
Regexp: (5|Five)
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Astronomy
|
||||
Question: How many Earths would it take to match the size of the sun? Over 1000, 100,000 or 1,000,000?
|
||||
Answer: 1,000,000
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Astronomy
|
||||
Question: What planet position is the Earth from the Sun?
|
||||
Answer: 3rd
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Astronomy
|
||||
Question: How long does it take for Earth to travel around the Sun?
|
||||
Answer: 1 Year
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Astronomy
|
||||
Question: The Moon orbits around the Earth -Tue or False.?
|
||||
Answer: True
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Famous Aliases
|
||||
Question: By what name is Maurice Micklewhite better known as?
|
||||
Answer: Michael Caine
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Famous Aliases
|
||||
Question: By what name is Arthur Leech better known as?
|
||||
Answer: Cary Grant
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Famous Aliases
|
||||
Question: By what name is Robert Zimmerman better known as?
|
||||
Answer: Bob Dylan
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Famous Aliases
|
||||
Question: By what name is Francis Gumm better known as?
|
||||
Answer: Judy Garland
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Famous Aliases
|
||||
Question: By what name is Richard Starkey better known as?
|
||||
Answer: Ringo Starr
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Famous Aliases
|
||||
Question: By what name is Allan Stewart Konisburg better known as?
|
||||
Answer: Woody Allan
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Famous Aliases
|
||||
Question: By what name is Marion Morrison better known as?
|
||||
Answer: John Wayne
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Famous Aliases
|
||||
Question: By what name is Reginald Dwight better known as?
|
||||
Answer: Elton John
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Famous Aliases
|
||||
Question: By what name is Norma Jean Baker better known as?
|
||||
Answer: Marilyn Monroe
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Food & Drink
|
||||
Question: What is the main ingredient in the soup Borscht?
|
||||
Answer: Beetroot
|
||||
Author: OllyPomm
|
||||
|
||||
Category: General
|
||||
Question: How many axles does an 18 wheeler truck have?
|
||||
Answer: 5
|
||||
Regexp: (5|Five)
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Animals
|
||||
Question: What bird has the biggest wingspan?
|
||||
Answer: Albatross
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Animals
|
||||
Question: What do you call a group of rhinocerus?
|
||||
Answer: A Crash
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Geography
|
||||
Question: What country is Mt Etna in?
|
||||
Answer: Italy
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Plants
|
||||
Question: What genus of tree does the wattle belong?
|
||||
Answer: Acacia
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Plants
|
||||
Question: What do you offer someone as a peace gesture?
|
||||
Answer: An Olive Branch
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Plants
|
||||
Question: What word describes part of your hand and a type of tree?
|
||||
Answer: Palm
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Plants
|
||||
Question: What is the name given to the art of miniaturising trees and maintaining their small size?
|
||||
Answer: Bonsai
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Plants
|
||||
Question: What part of a rhubarb plant is poisonous?
|
||||
Answer: The Leaves
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Flags
|
||||
Question: What are the 2 background colours of the Welsh flag?
|
||||
Answer: Green and White
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Flags
|
||||
Question: What creature is depicted on the Welsh Flag?
|
||||
Answer: A Red Dragon
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Emblems
|
||||
Question: What is the flower emblem of Wales?
|
||||
Answer: Daffodil
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Saints
|
||||
Question: Who is the patron saint of Wales?
|
||||
Answer: St David
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Food & Drink
|
||||
Question: What nut is used to make marzipan?
|
||||
Answer: Almond
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Flags
|
||||
Question: What 3 colours are featured on the Australian Aboriginal flag?
|
||||
Answer: Black Red Yellow
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: What other well known singer shares the same birthday as Elvis Presley (Jan 8)?
|
||||
Answer: David Bowie
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Add It Up, Blister In The Sun, Kiss Off"?
|
||||
Answer: Violet Femmes
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Baby I Don't Care, I Want Your Love"?
|
||||
Answer: Transvision Vamp
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Strange Brew, White Room"?
|
||||
Answer: Cream
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Anniversaries
|
||||
Question: What gift is associated with the 60th Wedding Anniversary?
|
||||
Answer: Diamonds
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Anniversaries
|
||||
Question: What gift is associated with the 20th Wedding Anniversary?
|
||||
Answer: China
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Anniversaries
|
||||
Question: What gift is associated with the 30th Wedding Anniversary?
|
||||
Answer: Pearls
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Anniversaries
|
||||
Question: What gift is associated with the 40th Wedding Anniversary?
|
||||
Answer: Rubies
|
||||
Author: OllyPomm
|
||||
|
||||
Category: General
|
||||
Question: Bowline, Figure Eight & Square are all types of what?
|
||||
Answer: Knots
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Honours & Awards
|
||||
Question: What does OBE stand for?
|
||||
Answer: Officer of the Order of the British Empire
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What is celebrated on April 1st?
|
||||
Answer: April Fools Day
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What famous playwrite has his birthday on 23rd April?
|
||||
Answer: William Shakespeare
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 17th May?
|
||||
Answer: Norway
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What famous battle was fought on 4th June 1942?
|
||||
Answer: The Battle of Midway
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 6th June?
|
||||
Answer: Sweden
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 2nd June?
|
||||
Answer: Italy
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 17th June?
|
||||
Answer: Iceland
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 25th June?
|
||||
Answer: Slovenia
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What was signed on 15th June 1215?
|
||||
Answer: The Magna Carta
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 14th July?
|
||||
Answer: France
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 21st July?
|
||||
Answer: Belgium
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Date
|
||||
Question: This date is the date in the middle of the year.?
|
||||
Answer: 2nd July
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 25th August?
|
||||
Answer: Uruguay
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 29th October?
|
||||
Answer: Turkey
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 12th October?
|
||||
Answer: Spain
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 26th October?
|
||||
Answer: Austria
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Flags
|
||||
Question: What 3 flags does the Union Jack comprise of?
|
||||
Answer: England Scotland Ireland
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrates its National Day on 29th October?
|
||||
Answer: Turkey
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrated its National Day on 1st March?
|
||||
Answer: Wales
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What country celebrated its National Day on 15th March?
|
||||
Answer: Hungary
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Dates
|
||||
Question: What well known bard (poems & songs) was born on 25th January 1759?
|
||||
Answer: Robert Burns
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Aqualung, Thick as a Brick"?
|
||||
Answer: Jethro Tull
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Mystify, Listen Like Thieves, Original Sin"?
|
||||
Answer: INXS
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Heart of Glass, The Tide is High"?
|
||||
Answer: Blondie
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the singer - songs include "Me & Bobby McGee, Mercedes Benz"?
|
||||
Answer: Janis Joplin
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Black Night, Smoke On The Water"?
|
||||
Answer: Deep Purple
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Monday Monday, California Dreamin'"?
|
||||
Answer: The Mamas and the Papas
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Light My Fire, Love Her Madly"?
|
||||
Answer: The Doors
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Let's Stick Together, The Price of Love"?
|
||||
Answer: Bryan Ferry
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Psycho Killer, Road To Nowhere"?
|
||||
Answer: Talkingheads
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Get Down & Get With It, Mama We're All Crazy Now"?
|
||||
Answer: Slade
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Forgiven Not Forgotten, Runaway"?
|
||||
Answer: The Coors
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Doctor Doctor, Hold Me Now, Don't Mess With Dr Dream"?
|
||||
Answer: Thompson Twins
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: Name the band - songs include "Sex & Drugs & Rock & Roll, I Want To Be Straight"?
|
||||
Answer: Ian Drury and The Blockheads
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Music
|
||||
Question: A graphical representation of the guitar fingerboard, used to teach someone to play a guitar without actually learning how to read musical notes.?
|
||||
Answer: Tablature
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Riddles?
|
||||
Question: How do you name 3 consecutive days without saying Monday, Tuesday, Wednesday, Thursday, Friday, Saturday or Sunday?
|
||||
Answer: Yesterday Today and Tomorrow
|
||||
Author: OllyPomm
|
||||
|
||||
Category: Riddles?
|
||||
Question: What was the highest mountain before Mt Everest was discovered?
|
||||
Answer: Mt Everest
|
||||
Author: OllyPomm
|
||||
2415
questions/questions.serv.en
Normal file
2415
questions/questions.serv.en
Normal file
File diff suppressed because it is too large
Load diff
5748
questions/questions.trivia.en
Normal file
5748
questions/questions.trivia.en
Normal file
File diff suppressed because it is too large
Load diff
6867
questions/questions.trivia2.en
Normal file
6867
questions/questions.trivia2.en
Normal file
File diff suppressed because it is too large
Load diff
6223
questions/questions.user.en
Normal file
6223
questions/questions.user.en
Normal file
File diff suppressed because it is too large
Load diff
4
requirements.txt
Normal file
4
requirements.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
SQLAlchemy==1.0.9
|
||||
beautifulsoup4==4.4.1
|
||||
irc==13.2
|
||||
requests==2.8.1
|
||||
22
runbot
Executable file
22
runbot
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
|
||||
NOW=`date +%Y-%m-%d_%H%M`
|
||||
if [ "x$1" = "x" ]; then
|
||||
CONFIG=""
|
||||
else
|
||||
CONFIG="--config $1"
|
||||
fi
|
||||
|
||||
LOLBOTS=`ps -ef|grep 'lolbot.py'|grep -v grep|awk '{print $2}'`
|
||||
if [ "$LOLBOTS" != "" ]; then
|
||||
kill $LOLBOTS
|
||||
fi
|
||||
|
||||
cd `dirname $0`
|
||||
APP_PATH=`pwd`
|
||||
while true; do
|
||||
/usr/bin/python $APP_PATH/lolbot.py $CONFIG > logs/server-$NOW.log 2> logs/error-$NOW.log
|
||||
done
|
||||
|
||||
Loading…
Add table
Reference in a new issue