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
|
*.log
|
||||||
/*.db
|
/*.db
|
||||||
/*.conf
|
/*.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
|
irc.channel = #lolbottest
|
||||||
|
|
||||||
# defaults:
|
|
||||||
# irc.port = 6667
|
|
||||||
# irc.nickname = lolbot
|
|
||||||
|
|
||||||
# sqlite database filename
|
# sqlite database filename
|
||||||
db.file = lolbot.db
|
db.file = lolbot.db
|
||||||
|
|
||||||
|
|
|
||||||
782
lolbot.py
Executable file → Normal file
782
lolbot.py
Executable file → Normal file
|
|
@ -1,428 +1,526 @@
|
||||||
#!/usr/bin/env python
|
#! /usr/bin/env python
|
||||||
#
|
|
||||||
# LolBot
|
|
||||||
#
|
|
||||||
# New version based on Twisted IRC.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Useful bot for folks stuck behind censor walls at work
|
LOLBOT 2
|
||||||
Logs a channel and collects URLs for later.
|
|
||||||
|
- die: Let the bot cease to exist.
|
||||||
|
- ask: Ask a MoxQuizz question.
|
||||||
|
- list: list some URLs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
from __future__ import print_function, unicode_literals
|
||||||
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
|
|
||||||
|
|
||||||
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
|
An IRC bot to entertain the troops with MoxQuizz questions, log URLs, and
|
||||||
convenience ORM class.
|
other shenanigans.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__tablename__ = "log"
|
qb = list()
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
def __init__(self, config=None):
|
||||||
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.
|
Constructor. Instantiates a lolbot with a configuration dictionary,
|
||||||
|
or from command-line options if none is specified.
|
||||||
"""
|
"""
|
||||||
if timestamp is None:
|
|
||||||
timestamp = datetime.now()
|
|
||||||
self.timestamp = timestamp
|
|
||||||
self.nickname = nickname
|
|
||||||
self.text = text
|
|
||||||
|
|
||||||
def __repr__(self):
|
if not config:
|
||||||
return "(%s) %s: %s" % (self.timestamp.strftime("%Y-%m-%d %H:%M:%S"), self.nickname, self.text)
|
config = LolBot.get_options()
|
||||||
|
|
||||||
class Url(SqlBase):
|
if not self.validate_config(config):
|
||||||
"""
|
sys.exit(1)
|
||||||
This class represents a saved URL and inherits from a SQLAlchemy convenience
|
|
||||||
ORM class.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__tablename__ = "url"
|
self.config = config
|
||||||
|
(server, port, channel, nickname, database) = (
|
||||||
|
config['irc.server'],
|
||||||
|
config['irc.port'],
|
||||||
|
config['irc.channel'],
|
||||||
|
config['irc.nickname'],
|
||||||
|
config['db.file'])
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
debug("Instantiating SingleServerIRCBot")
|
||||||
timestamp = Column(DateTime)
|
irc.client.ServerConnection.buffer_class = irc.buffer.LenientDecodingLineBuffer
|
||||||
nickname = Column(String(20))
|
SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
|
||||||
url = Column(String(200), unique=True)
|
self.channel = channel
|
||||||
title = Column(Text)
|
|
||||||
|
|
||||||
def __init__(self, nickname, url, title=None, timestamp=None):
|
# load some MoxQuizz questions
|
||||||
if timestamp is None:
|
qfiles = [f for f in listdir('questions') if path.isfile(path.join('questions', f))]
|
||||||
timestamp = datetime.now()
|
debug("Loading MoxQuizz questions")
|
||||||
self.timestamp = timestamp
|
for f in qfiles:
|
||||||
self.nickname = nickname
|
qfile = path.abspath(path.join('questions', f))
|
||||||
self.url = url
|
debug(" - from MoxQuizz bank '%s'" % qfile)
|
||||||
self.title = title
|
self.qb += QuestionBank(qfile).questions
|
||||||
|
random.shuffle(self.qb)
|
||||||
|
self.quiz = 0
|
||||||
|
self.question = None
|
||||||
|
|
||||||
# populate the title from the URL if not given.
|
# connect to the database
|
||||||
if title is None:
|
debug("Connecting to SQLite database '%s'" % database)
|
||||||
try:
|
self.dbfile = database
|
||||||
br = Browser()
|
self.dbengine = create_engine('sqlite+pysqlite://', creator=self._get_connection)
|
||||||
br.open(self.url)
|
Model.metadata.bind = self.dbengine
|
||||||
self.title = br.title()
|
Model.metadata.create_all()
|
||||||
except Exception as ex:
|
self.get_db = sessionmaker(bind=self.dbengine)
|
||||||
self.title = ''
|
|
||||||
|
|
||||||
def __repr__(self):
|
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."
|
||||||
if not self.title:
|
debug("Exiting lolbot constructor")
|
||||||
return "%s: %s" % (self.nickname, self.url)
|
|
||||||
else:
|
|
||||||
return "%s: %s - %s" % (self.nickname, self.url, self.title)
|
|
||||||
|
|
||||||
class LolBot(irc.IRCClient):
|
|
||||||
"""
|
|
||||||
The Lolbot itself.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _get_connection(self):
|
def _get_connection(self):
|
||||||
connection = sqlite3.Connection(self.config['db.file'])
|
"""Creator function for SQLAlchemy."""
|
||||||
|
connection = sqlite3.Connection(self.dbfile)
|
||||||
connection.text_factory = str
|
connection.text_factory = str
|
||||||
|
debug("Creating SQLAlchemy connection")
|
||||||
return connection
|
return connection
|
||||||
|
|
||||||
def created(self, when):
|
@property
|
||||||
# connect to the database
|
def nickname(self):
|
||||||
self.dbengine = create_engine('sqlite+pysqlite://', creator=self._get_connection)
|
return self.connection.get_nickname()
|
||||||
SqlBase.metadata.bind = self.dbengine
|
|
||||||
SqlBase.metadata.create_all()
|
|
||||||
self.get_session = 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); 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):
|
def say_private(self, nick, text):
|
||||||
return datetime.today().strftime("%Y-%m-%d %H:%M:%S")
|
"""
|
||||||
|
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):
|
def save_url(self, nickname, url):
|
||||||
title = False
|
title = False
|
||||||
try:
|
try:
|
||||||
db = self.get_session()
|
db = self.get_db()
|
||||||
if not db.query(Url).filter(Url.url == url).count():
|
if not db.query(Url).filter(Url.url == url).count():
|
||||||
theurl = Url(nickname, url)
|
theurl = Url(nickname, url)
|
||||||
db.add(theurl)
|
db.add(theurl)
|
||||||
db.commit()
|
db.commit()
|
||||||
else:
|
else:
|
||||||
theurl = db.query(Url).filter(Url.url == url).one()
|
theurl = db.query(Url).filter(Url.url == url).one()
|
||||||
print theurl
|
print(theurl)
|
||||||
title = theurl.title
|
title = theurl.title
|
||||||
except Exception, ex:
|
except Exception as ex:
|
||||||
print "Exception caught saving URL: %s" % ex
|
print("Exception caught saving URL: %s" % ex)
|
||||||
return title
|
return title
|
||||||
|
|
||||||
def log_event(self, nick, text):
|
def log_event(self, nick, text):
|
||||||
try:
|
try:
|
||||||
entry = Log(nick, text)
|
entry = Log(nick, text)
|
||||||
db = self.get_session()
|
db = self.get_db()
|
||||||
db.add(entry)
|
db.add(entry)
|
||||||
db.commit()
|
db.commit()
|
||||||
print entry
|
print(entry)
|
||||||
except Exception, ex:
|
except Exception as ex:
|
||||||
print "Exception caught logging event: %s" % ex
|
print("Exception caught logging event: %s" % ex)
|
||||||
|
|
||||||
def _get_nickname(self):
|
def start_quiz(self, nick):
|
||||||
return self.factory.nickname
|
self.quiz = 0
|
||||||
nickname = property(_get_nickname)
|
self.quiz_scores = dict()
|
||||||
|
self.connection.notice(self.channel, 'Quiz begun by %s.' % nick)
|
||||||
|
self.quiz_get_next()
|
||||||
|
|
||||||
def _get_channel(self):
|
def stop_quiz(self):
|
||||||
return self.factory.channel
|
self.quiz = 0
|
||||||
channel = property(_get_channel)
|
self.quiz_scores = None
|
||||||
|
self.question = None
|
||||||
|
|
||||||
def _get_config(self):
|
def quiz_get_next(self):
|
||||||
return self.factory.config
|
self.quiz += 1
|
||||||
config = property(_get_config)
|
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):
|
def quiz_tip(self):
|
||||||
self.join(self.channel)
|
if len(self.question.tip) > self.tip:
|
||||||
print "Signed on as %s." % (self.nickname,)
|
self.connection.notice(self.channel, "Tip: %s" % self.question.tip[self.tip])
|
||||||
|
self.tip += 1
|
||||||
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)
|
|
||||||
else:
|
else:
|
||||||
# log it
|
self.connection.notice(self.channel, "No more tips.")
|
||||||
self.log_event(user, msg)
|
|
||||||
|
|
||||||
args = string.split(msg, ":", 1)
|
def quiz_award_points(self, nick):
|
||||||
if len(args) > 1 and args[0] == self.nickname:
|
if nick not in self.quiz_scores.keys():
|
||||||
self.do_command(string.strip(args[1]))
|
self.quiz_scores[nick] = 0
|
||||||
else:
|
self.quiz_scores[nick] += self.question.score
|
||||||
# parse it for links, add URLs to the list
|
|
||||||
words = msg.split(" ")
|
|
||||||
for w in words:
|
|
||||||
|
|
||||||
# URL
|
score = "%s point" % self.quiz_scores[nick]
|
||||||
if w.startswith('http://') or w.startswith('https://'):
|
if self.quiz_scores[nick] != 1:
|
||||||
title = self.save_url(user, w)
|
score += "s"
|
||||||
if title != False:
|
|
||||||
self.say_public("URL added. %s" % title)
|
|
||||||
|
|
||||||
# Moodle tracker bugs
|
self.connection.notice(self.channel, 'Correct! The answer was %s.' % self.question.answer)
|
||||||
elif w.startswith('MDL-'):
|
time.sleep(1)
|
||||||
m = re.search('^MDL-([0-9]+)$', w)
|
self.connection.notice(self.channel, '%s is on %s.' % (nick, score))
|
||||||
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
|
def quiz_check_win(self, nick):
|
||||||
elif w.startswith('WR'):
|
if self.quiz_scores[nick] == 10:
|
||||||
m = re.search('^WR#?([0-9]+)$', w)
|
self.connection.notice(self.channel, '%s wins with 10 points!' % nick)
|
||||||
if m:
|
self.quiz_scoreboard()
|
||||||
wrmsurl = 'https://wrms.catalyst.net.nz/%s' % m.groups()[0]
|
self.stop_quiz()
|
||||||
title = self.save_url(user, wrmsurl)
|
|
||||||
if title != False:
|
|
||||||
self.say_public("%s - %s" % (wrmsurl, title))
|
|
||||||
|
|
||||||
# Bugzilla
|
def quiz_scoreboard(self):
|
||||||
elif w.startswith('BUG'):
|
if not self.quiz:
|
||||||
m = re.search('^BUG#?([0-9]+)$', w)
|
self.connection.notice(self.channel, 'Quiz not running.')
|
||||||
if m:
|
return
|
||||||
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):
|
self.connection.notice(self.channel, 'Scoreboard:')
|
||||||
"Print TEXT into public channel, for all to see."
|
for nick in self.quiz_scores.keys():
|
||||||
self.notice(self.channel, text)
|
score = "%s point" % self.quiz_scores[nick]
|
||||||
self.log_event(self.nickname, text)
|
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 say_private(self, nick, text):
|
def handle_quiz(self, nick, message):
|
||||||
"Send private message of TEXT to NICK."
|
# bail if there's no quiz or unanswered question.
|
||||||
self.notice(nick, text)
|
if not self.quiz or not isinstance(self.question, Question):
|
||||||
|
return
|
||||||
|
|
||||||
def reply(self, text, to_private=None):
|
# see if anyone answered correctly.
|
||||||
"Send TEXT to either public channel or TO_PRIVATE nick (if defined)."
|
if self.question.attempt(message):
|
||||||
if to_private is not None:
|
self.quiz_award_points(nick)
|
||||||
self.say_private(to_private, text)
|
time.sleep(1)
|
||||||
else:
|
self.quiz_check_win(nick)
|
||||||
self.say_public(text)
|
|
||||||
|
|
||||||
def do_command(self, cmd, target=None):
|
# 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):
|
||||||
"""
|
"""
|
||||||
This is the function called whenever someone sends a public or
|
Handle bot commands.
|
||||||
private message addressed to the bot. (e.g. "bot: blah").
|
"""
|
||||||
|
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())
|
||||||
|
elif n.find("-") > 0:
|
||||||
|
(x, y) = n.split("-", 1)
|
||||||
|
try:
|
||||||
|
x = abs(int(x))
|
||||||
|
y = abs(int(y))
|
||||||
|
if y < x:
|
||||||
|
x, y = y, x
|
||||||
|
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]
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
n = abs(int(n))
|
||||||
|
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)
|
||||||
|
c.notice(nick, line)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
else:
|
||||||
|
c.notice(nick, "Not understood: " + cmd)
|
||||||
|
|
||||||
|
def validate_config(self, config):
|
||||||
|
"""
|
||||||
|
Basic checks for configuration parameters. Returns a Boolean indicating
|
||||||
|
success or failure.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# 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.")
|
||||||
|
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:
|
try:
|
||||||
if cmd == 'help':
|
(options, args) = getopt.getopt(sys.argv[1:], 'hc:s:p:j:n:d:', ['help', 'config=', 'server=', 'port=', 'join=', 'nick=', 'database=', ])
|
||||||
self.reply(self.helptext, target)
|
except getopt.GetoptError as err:
|
||||||
|
print(err)
|
||||||
elif cmd == 'urls' or cmd == 'list':
|
LolBot.usage()
|
||||||
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)
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
elif cmd.startswith('urls ') or cmd.startswith('list '):
|
|
||||||
db = self.get_session()
|
|
||||||
(listcmd, n) = cmd.split(" ", 1)
|
|
||||||
n = n.strip()
|
|
||||||
if n == "all":
|
|
||||||
rows = db.query(Url).order_by(Url.timestamp.desc())
|
|
||||||
elif n.find("-") > 0:
|
|
||||||
(x, y) = n.split("-", 1)
|
|
||||||
try:
|
|
||||||
x = abs(int(x))
|
|
||||||
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)
|
|
||||||
raise ex
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
|
|
||||||
else:
|
|
||||||
self.reply("I'm a bot of little brain. Try help for more information.", target)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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():
|
|
||||||
try:
|
|
||||||
(options, args) = getopt.getopt(sys.argv[1:], "hc:", ["help", "config=", ])
|
|
||||||
except getopt.GetoptError, err:
|
|
||||||
print str(err)
|
|
||||||
usage()
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
config_path = ""
|
|
||||||
for option,value in options:
|
|
||||||
if option in ("-h", "--help"):
|
|
||||||
usage()
|
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
if option in ("-c", "--config"):
|
|
||||||
config_path = value
|
|
||||||
return { 'config_path': config_path }
|
|
||||||
|
|
||||||
def get_config(config_path):
|
config = {}
|
||||||
"""
|
for option, value in options:
|
||||||
This method loads configuration options from a lolbot.conf file. The file
|
# Display help text.
|
||||||
should look like this:
|
if option in ('-h', '--help'):
|
||||||
|
LolBot.usage()
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
irc.server = irc.freenode.net
|
# Get configuration from a file.
|
||||||
irc.port = 6667
|
if option in ('-c', '--config'):
|
||||||
irc.channel = #lolbottest
|
config = LolBot.load_config(value)
|
||||||
irc.nickname = lolbot
|
break
|
||||||
db.url = sqlite:///lolbot.db
|
|
||||||
|
|
||||||
"""
|
# 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
|
||||||
|
|
||||||
if not config_path:
|
return config
|
||||||
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()
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# open the configuration file and grab all param=value declarations.
|
@staticmethod
|
||||||
config = {}
|
def load_config(config_path=''):
|
||||||
with open(config_path) as f:
|
"""
|
||||||
for line in f:
|
This method loads configuration options from a lolbot.conf file. The file
|
||||||
# skip comments
|
should look something like this::
|
||||||
if line.strip().startswith("#") or line.strip() == "":
|
|
||||||
continue
|
|
||||||
|
|
||||||
# collect up param = value
|
irc.server = irc.yourdomain.com
|
||||||
try:
|
irc.port = 6667
|
||||||
(param, value) = line.strip().split("=", 1)
|
irc.channel = #lolbottest
|
||||||
if param.strip() != "":
|
irc.nickname = lolbot
|
||||||
config[param.strip()] = value.strip()
|
db.file = lolbot.db
|
||||||
except ValueError:
|
"""
|
||||||
continue
|
|
||||||
|
|
||||||
# validate IRC host
|
if config_path == '':
|
||||||
if "irc.server" not in config.keys():
|
config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'lolbot.conf')
|
||||||
print "Error: the IRC server was not specified. Use --help for more information."
|
if not os.path.exists(config_path):
|
||||||
sys.exit(1)
|
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)
|
||||||
|
|
||||||
# validate IRC port
|
# open the configuration file and grab all param=value declarations.
|
||||||
if "irc.port" not in config.keys():
|
config = {}
|
||||||
config["irc.port"] = "6667"
|
with open(config_path) as f:
|
||||||
try:
|
for line in f:
|
||||||
config["irc.port"] = int(config["irc.port"])
|
# skip comments
|
||||||
except ValueError:
|
if line.strip().startswith('#') or line.strip() == '':
|
||||||
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."
|
continue
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# validate IRC channel
|
# collect up param = value
|
||||||
if "irc.channel" not in config.keys() or not config["irc.channel"].startswith("#"):
|
try:
|
||||||
print "Error: the IRC channel is not specified or incorrect. It must begin with a # - e.g. #mychatchannel. Use --help for more information."
|
(param, value) = line.strip().split('=', 1)
|
||||||
sys.exit(1)
|
if param.strip() != '':
|
||||||
|
config[param.strip()] = value.strip()
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
|
||||||
# validate bot nickname
|
return config
|
||||||
if "irc.nickname" not in config.keys():
|
|
||||||
config["irc.nickname"] = "lolbot"
|
|
||||||
|
|
||||||
return config
|
@staticmethod
|
||||||
|
def usage():
|
||||||
|
"""
|
||||||
|
Spits out CLI help.
|
||||||
|
"""
|
||||||
|
|
||||||
def usage():
|
print("""Run a lolbot.
|
||||||
print """Run a lolbot.
|
|
||||||
|
|
||||||
-h, --help
|
-h, --help
|
||||||
This message.
|
This message.
|
||||||
|
|
||||||
-c, --config=<filename>
|
-s, --server=<hostname>
|
||||||
Specify a configuration file. Defaults to lolbot.conf in the same
|
The IRC server, e.g. irc.freenode.net
|
||||||
directory as the script.
|
|
||||||
|
|
||||||
Configuration:
|
-p, --port=<port>
|
||||||
|
The IRC server port. Default: 6667
|
||||||
|
|
||||||
irc.server = <host>
|
-j, --join=<channel>
|
||||||
The IRC server, e.g. irc.freenode.net
|
The chat channel to join, e.g. #trainspotting
|
||||||
|
|
||||||
irc.port = <port>
|
-n, --nickname=<nickname>
|
||||||
The IRC server port. Default: 6667
|
The nickname for your lolbot. Default: "lolbot"
|
||||||
|
|
||||||
irc.channel = <channel>
|
-d, --database=<path>
|
||||||
The chat channel to join, e.g. #trainspotting
|
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.
|
||||||
|
|
||||||
irc.nickname = <nickname>
|
Configuration file:
|
||||||
The nickname for your lolbot. Default: "lolbot"
|
|
||||||
|
-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())
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
args = get_options()
|
|
||||||
config = get_config(args['config_path'])
|
|
||||||
try:
|
try:
|
||||||
reactor.connectTCP(config['irc.server'], config['irc.port'], LolBotFactory(args['config_path']))
|
LolBot().start()
|
||||||
reactor.run()
|
|
||||||
except KeyboardInterrupt:
|
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