summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Tools/faqwiz/faqmain.py858
1 files changed, 0 insertions, 858 deletions
diff --git a/Tools/faqwiz/faqmain.py b/Tools/faqwiz/faqmain.py
deleted file mode 100644
index 7550bd0..0000000
--- a/Tools/faqwiz/faqmain.py
+++ /dev/null
@@ -1,858 +0,0 @@
-"""Interactive FAQ project.
-
-Note that this is not an executable script; it's an importable module.
-The actual CGI script can be kept minimal; it's appended at the end of
-this file as a string constant.
-
-XXX TO DO
-
-XXX User Features TO DO
-
-- next/prev/index links in do_show???
-- explanation of editing somewhere
-- embellishments, GIFs, hints, etc.
-- support adding annotations, too
-- restrict recent changes to last week (or make it an option)
-- extended search capabilities
-
-XXX Management Features TO DO
-
-- username/password for authors
-- create new sections
-- rearrange entries
-- delete entries
-- freeze entries
-- send email on changes?
-- send email on ERRORS!
-- optional staging of entries until reviewed?
- (could be done using rcs branches!)
-- prevent race conditions on nearly simultaneous commits
-
-XXX Performance
-
-- could cache generated HTML
-- could speed up searches with a separate index file
-
-XXX Code organization TO DO
-
-- read section titles from a file (could be a Python file: import faqcustom)
-- customize rcs command pathnames (and everything else)
-- make it more generic (so you can create your own FAQ)
-- more OO structure, e.g. add a class representing one FAQ entry
-
-"""
-
-# NB for timing purposes, the imports are at the end of this file
-
-PASSWORD = "Spam"
-
-NAMEPAT = "faq??.???.htp"
-NAMEREG = "^faq\([0-9][0-9]\)\.\([0-9][0-9][0-9]\)\.htp$"
-
-SECTIONS = {
- "1": "General information and availability",
- "2": "Python in the real world",
- "3": "Building Python and Other Known Bugs",
- "4": "Programming in Python",
- "5": "Extending Python",
- "6": "Python's design",
- "7": "Using Python on non-UNIX platforms",
-}
-
-class FAQServer:
-
- def __init__(self):
- pass
-
- def main(self):
- self.form = cgi.FieldStorage()
- req = self.req or 'frontpage'
- try:
- method = getattr(self, 'do_%s' % req)
- except AttributeError:
- print "Unrecognized request type", req
- else:
- method()
- self.epilogue()
-
- KEYS = ['req', 'query', 'name', 'text', 'commit', 'title',
- 'author', 'email', 'log', 'section', 'number', 'add',
- 'version', 'edit', 'password']
-
- def __getattr__(self, key):
- if key not in self.KEYS:
- raise AttributeError
- try:
- form = self.form
- try:
- item = form[key]
- except TypeError, msg:
- raise KeyError, msg, sys.exc_traceback
- except KeyError:
- return ''
- value = self.form[key].value
- value = string.strip(value)
- setattr(self, key, value)
- return value
-
- def do_frontpage(self):
- self.prologue("Python FAQ Wizard (beta test)")
- print """
- <UL>
- <LI><A HREF="faq.py?req=index">FAQ index</A>
- <LI><A HREF="faq.py?req=all">The whole FAQ</A>
- <LI><A HREF="faq.py?req=roulette">FAQ roulette</A>
- <LI><A HREF="faq.py?req=recent">Recently changed FAQ entries</A>
- <LI><A HREF="faq.py?req=add">Add a new FAQ entry</A>
- <LI><A HREF="faq.py?req=delete">Delete a FAQ entry</A>
- </UL>
-
- <HR>
-
- <H2>Search the FAQ</H2>
-
- <FORM ACTION="faq.py">
- <INPUT TYPE=text NAME=query>
- <INPUT TYPE=submit VALUE="Search"><BR>
- (Case insensitive regular expressions.)
- <INPUT TYPE=hidden NAME=req VALUE=query>
- </FORM>
- <HR>
- <P>
- Disclaimer: these pages are intended to be edited by anyone.
- Please exercise discretion when editing, don't be rude, etc.
- """
-
- def do_index(self):
- self.prologue("Python FAQ Index")
- names = os.listdir(os.curdir)
- names.sort()
- section = None
- for name in names:
- headers, text = self.read(name)
- if headers:
- title = headers['title']
- i = string.find(title, '.')
- nsec = title[:i]
- if nsec != section:
- if section:
- print """
- <P>
- <LI><A HREF="faq.py?req=add&amp;section=%s"
- >Add new entry</A> (at this point)
- </UL>
- """ % section
- section = nsec
- if SECTIONS.has_key(section):
- stitle = SECTIONS[section]
- else:
- stitle = ""
- print "<H2>Section %s. %s</H2>" % (section, stitle)
- print "<UL>"
- print '<LI><A HREF="faq.py?req=show&name=%s">%s</A>' % (
- name, cgi.escape(title))
- if section:
- print """
- <P>
- <LI><A HREF="faq.py?req=add&amp;section=%s">Add new entry</A>
- (at this point)
- </UL>
- """ % section
- else:
- print "No FAQ entries?!?!"
-
- def do_show(self):
- self.prologue("Python FAQ Entry")
- print "<HR>"
- name = self.name
- headers, text = self.read(name)
- if not headers:
- self.error("Invalid file name", name)
- return
- self.show(name, headers['title'], text)
-
- def do_all(self):
- import fnmatch, stat
- self.prologue("The Whole Python FAQ")
- names = os.listdir(os.curdir)
- lastmtime = 0
- for name in names:
- if not fnmatch.fnmatch(name, NAMEPAT):
- continue
- try:
- st = os.stat(name)
- except os.error:
- continue
- lastmtime = max(lastmtime, st[stat.ST_MTIME])
- if lastmtime:
- print time.strftime("Last changed on %c %Z",
- time.localtime(lastmtime))
- names.sort()
- section = None
- print "<HR>"
- for name in names:
- headers, text = self.read(name)
- if headers:
- title = headers['title']
- i = string.find(title, '.')
- nsec = title[:i]
- if nsec != section:
- section = nsec
- if SECTIONS.has_key(section):
- stitle = SECTIONS[section]
- else:
- stitle = ""
- print "<H1>Section %s. %s</H1>" % (section, stitle)
- print "<HR>"
- self.show(name, title, text, edit=(self.edit != 'no'))
- if not section:
- print "No FAQ entries?!?!"
-
- def do_roulette(self):
- import whrandom
- self.prologue("Python FAQ Roulette")
- print """
- Please check the correctness of the entry below.
- If you find any problems, please edit the entry.
- <P>
- <HR>
- """
- names = os.listdir(os.curdir)
- while names:
- name = whrandom.choice(names)
- headers, text = self.read(name)
- if headers:
- self.show(name, headers['title'], text)
- print "<P>Use `Reload' to show another one."
- break
- else:
- names.remove(name)
- else:
- print "No FAQ entries?!?!"
-
- def do_recent(self):
- import fnmatch, stat
- names = os.listdir(os.curdir)
- now = time.time()
- list = []
- for name in names:
- if not fnmatch.fnmatch(name, NAMEPAT):
- continue
- try:
- st = os.stat(name)
- except os.error:
- continue
- tuple = (st[stat.ST_MTIME], name)
- list.append(tuple)
- list.sort()
- list.reverse()
- self.prologue("Python FAQ, Most Recently Modified First")
- print "<HR>"
- n = 0
- for (mtime, name) in list:
- headers, text = self.read(name)
- if headers and headers.has_key('last-changed-date'):
- self.show(name, headers['title'], text)
- n = n+1
- if not n:
- print "No FAQ entries?!?!"
-
- def do_query(self):
- query = self.query
- if not query:
- self.error("No query string")
- return
- import regex
- self.prologue("Python FAQ Query Results")
- p = regex.compile(query, regex.casefold)
- names = os.listdir(os.curdir)
- names.sort()
- print "<HR>"
- n = 0
- for name in names:
- headers, text = self.read(name)
- if headers:
- title = headers['title']
- if p.search(title) >= 0 or p.search(text) >= 0:
- self.show(name, title, text)
- n = n+1
- if not n:
- print "No hits."
-
- def do_add(self):
- section = self.section
- if not section:
- self.prologue("How to add a new FAQ entry")
- print """
- Go to the <A HREF="faq.py?req=index">FAQ index</A>
- and click on the "Add new entry" link at the end
- of the section to which you want to add the entry.
- """
- return
- try:
- nsec = string.atoi(section)
- except ValueError:
- print "Bad section number", nsec
- names = os.listdir(os.curdir)
- max = 0
- import regex
- prog = regex.compile(NAMEREG)
- for name in names:
- if prog.match(name) >= 0:
- s1, s2 = prog.group(1, 2)
- n1, n2 = string.atoi(s1), string.atoi(s2)
- if n1 == nsec:
- if n2 > max:
- max = n2
- if not max:
- self.error("Can't add new sections yet.")
- return
- num = max+1
- name = "faq%02d.%03d.htp" % (nsec, num)
- self.name = name
- self.add = "yes"
- self.number = str(num)
- self.do_edit()
-
- def do_delete(self):
- self.prologue("How to delete a FAQ entry")
- print """
- At the moment, there's no direct way to delete entries.
- This is because the entry numbers are also their
- unique identifiers -- it's a bad idea to renumber entries.
- <P>
- If you really think an entry needs to be deleted,
- change the title to "(deleted)" and make the body
- empty (keep the entry number in the title though).
- """
-
- def do_edit(self):
- name = self.name
- headers, text = self.read(name)
- if not headers:
- self.error("Invalid file name", name)
- return
- self.prologue("Python FAQ Edit Wizard - Edit Form")
- print '<A HREF="/python/faqhelp.html">Click for Help</A>'
- title = headers['title']
- version = self.getversion(name)
- print "<FORM METHOD=POST ACTION=faq.py>"
- self.showedit(name, title, text)
- if self.add:
- print """
- <INPUT TYPE=hidden NAME=add VALUE=%s>
- <INPUT TYPE=hidden NAME=section VALUE=%s>
- <INPUT TYPE=hidden NAME=number VALUE=%s>
- """ % (self.add, self.section, self.number)
- print """
- <INPUT TYPE=submit VALUE="Review Edit">
- <INPUT TYPE=hidden NAME=req VALUE=review>
- <INPUT TYPE=hidden NAME=name VALUE=%s>
- <INPUT TYPE=hidden NAME=version VALUE=%s>
- </FORM>
- <HR>
- """ % (name, version)
- self.show(name, title, text, edit=0)
-
- def do_review(self):
- if self.commit:
- self.checkin()
- return
- name = self.name
- text = self.text
- title = self.title
- headers, oldtext = self.read(name)
- if not headers:
- self.error("Invalid file name", name)
- return
- if self.author or '@' in self.email or self.password:
- self.set_cookie(self.author, self.email, self.password)
- self.prologue("Python FAQ Edit Wizard - Review Form")
- print '<A HREF="/python/faqhelp.html">Click for Help</A>'
- print "<HR>"
- self.show(name, title, text, edit=0)
- print "<FORM METHOD=POST ACTION=faq.py>"
- if self.password == PASSWORD \
- and self.log and self.author and '@' in self.email:
- print """
- <INPUT TYPE=submit NAME=commit VALUE="Commit">
- Click this button to commit the change.
- <P>
- <HR>
- <P>
- """
- else:
- print """
- To commit this change, please enter a log message,
- your name, your email address,
- and the correct password in the form below.
- <P>
- <HR>
- <P>
- """
- self.showedit(name, title, text)
- if self.add:
- print """
- <INPUT TYPE=hidden NAME=add VALUE=%s>
- <INPUT TYPE=hidden NAME=section VALUE=%s>
- <INPUT TYPE=hidden NAME=number VALUE=%s>
- """ % (self.add, self.section, self.number)
- print """
- <BR>
- <INPUT TYPE=submit VALUE="Review Edit">
- <INPUT TYPE=hidden NAME=req VALUE=review>
- <INPUT TYPE=hidden NAME=name VALUE=%s>
- <INPUT TYPE=hidden NAME=version VALUE=%s>
- </FORM>
- <HR>
- """ % (name, self.version)
-
- def do_info(self):
- name = self.name
- headers, text = self.read(name)
- if not headers:
- self.error("Invalid file name", name)
- return
- self.prologue("Info for %s" % name)
- print '<PRE>'
- p = os.popen("/depot/gnu/plat/bin/rlog -r %s </dev/null 2>&1" %
- self.name)
- output = p.read()
- p.close()
- print cgi.escape(output)
- print '</PRE>'
- print '<A HREF="faq.py?req=rlog&name=%s">View full rcs log</A>' % name
-
- def do_rlog(self):
- name = self.name
- headers, text = self.read(name)
- if not headers:
- self.error("Invalid file name", name)
- return
- self.prologue("RCS log for %s" % name)
- print '<PRE>'
- p = os.popen("/depot/gnu/plat/bin/rlog %s </dev/null 2>&1" % self.name)
- output = p.read()
- p.close()
- print cgi.escape(output)
- print '</PRE>'
-
- def checkin(self):
- import regsub, time, tempfile
- name = self.name
- password = self.password
- if password != PASSWORD:
- self.error("Invalid password.")
- return
- if not (self.log and self.author and '@' in self.email):
- self.error("No log message, no author, or invalid email.")
- return
- headers, oldtext = self.read(name)
- if not headers:
- self.error("Invalid file name", name)
- return
- version = self.version
- curversion = self.getversion(name)
- if version != curversion:
- self.error(
- "Version conflict.",
- "You edited version %s but current version is %s." % (
- version, curversion),
- """
- <P>
- The two most common causes of this problem are:
- <UL>
- <LI>After committing a change, you went back in your browser,
- edited the entry some more, and clicked Commit again.
- <LI>Someone else started editing the same entry and committed
- before you did.
- </UL>
- <P>
- """,
- '<A HREF="faq.py?req=show&name=%s"' % name,
- '>Click here to reload the entry and try again.</A>')
- return
- text = self.text
- title = self.title
- author = self.author
- email = self.email
- log = self.log
- text = regsub.gsub("\r\n", "\n", text)
- log = regsub.gsub("\r\n", "\n", log)
- author = string.join(string.split(author))
- email = string.join(string.split(email))
- title = string.join(string.split(title))
- oldtitle = headers['title']
- oldtitle = string.join(string.split(oldtitle))
- text = string.strip(text)
- oldtext = string.strip(oldtext)
- if text == oldtext and title == oldtitle:
- self.error("No changes.")
- return
- # Check that the FAQ entry number didn't change
- if string.split(title)[:1] != string.split(oldtitle)[:1]:
- self.error("Don't change the FAQ entry number please.")
- return
- remhost = os.environ["REMOTE_HOST"]
- remaddr = os.environ["REMOTE_ADDR"]
- try:
- os.unlink(name + "~")
- except os.error:
- pass
- try:
- os.rename(name, name + "~")
- except os.error:
- pass
- try:
- os.unlink(name)
- except os.error:
- pass
- try:
- f = open(name, "w")
- except IOError, msg:
- self.error("Can't open", name, "for writing:", cgi.escape(str(msg)))
- return
- now = time.ctime(time.time())
- f.write("Title: %s\n" % title)
- f.write("Last-Changed-Date: %s\n" % now)
- f.write("Last-Changed-Author: %s\n" % author)
- f.write("Last-Changed-Email: %s\n" % email)
- f.write("Last-Changed-Remote-Host: %s\n" % remhost)
- f.write("Last-Changed-Remote-Address: %s\n" % remaddr)
- keys = headers.keys()
- keys.sort()
- keys.remove('title')
- for key in keys:
- if key[:13] != 'last-changed-':
- f.write("%s: %s\n" % (string.capwords(key, '-'),
- headers[key]))
- f.write("\n")
- f.write(text)
- f.write("\n")
- f.close()
-
- tfn = tempfile.mktemp()
- f = open(tfn, "w")
- f.write("Last-Changed-Date: %s\n" % now)
- f.write("Last-Changed-Author: %s\n" % author)
- f.write("Last-Changed-Email: %s\n" % email)
- f.write("Last-Changed-Remote-Host: %s\n" % remhost)
- f.write("Last-Changed-Remote-Address: %s\n" % remaddr)
- f.write("\n")
- f.write(log)
- f.write("\n")
- f.close()
-
- # Do this for show() below
- self.headers = {
- 'title': title,
- 'last-changed-date': now,
- 'last-changed-author': author,
- 'last-changed-email': email,
- 'last-changed-remote-host': remhost,
- 'last-changed-remote-address': remaddr,
- }
-
- p = os.popen("""
- /depot/gnu/plat/bin/rcs -l %s </dev/null 2>&1
- /depot/gnu/plat/bin/ci -u %s <%s 2>&1
- rm -f %s
- """ % (name, name, tfn, tfn))
- output = p.read()
- sts = p.close()
- if not sts:
- self.set_cookie(author, email, password)
- self.prologue("Python FAQ Entry Edited")
- print "<HR>"
- self.show(name, title, text)
- if output:
- print "<PRE>%s</PRE>" % cgi.escape(output)
- else:
- self.error("Python FAQ Entry Commit Failed",
- "Exit status 0x%04x" % sts)
- if output:
- print "<PRE>%s</PRE>" % cgi.escape(output)
-
- def set_cookie(self, author, email, password):
- name = "Python-FAQ-Wizard"
- value = "%s/%s/%s" % (author, email, password)
- import urllib
- value = urllib.quote(value)
- print "Set-Cookie: %s=%s; path=/cgi-bin/;" % (name, value),
- import time
- now = time.time()
- then = now + 28 * 24 * 3600
- gmt = time.gmtime(then)
- print time.strftime("expires=%a, %d-%b-%x %X GMT", gmt)
-
- def get_cookie(self):
- if not os.environ.has_key('HTTP_COOKIE'):
- return "", "", ""
- raw = os.environ['HTTP_COOKIE']
- words = map(string.strip, string.split(raw, ';'))
- cookies = {}
- for word in words:
- i = string.find(word, '=')
- if i >= 0:
- key, value = word[:i], word[i+1:]
- cookies[key] = value
- if not cookies.has_key('Python-FAQ-Wizard'):
- return "", "", ""
- value = cookies['Python-FAQ-Wizard']
- import urllib
- value = urllib.unquote(value)
- words = string.split(value, '/')
- while len(words) < 3:
- words.append('')
- author = string.join(words[:-2], '/')
- email = words[-2]
- password = words[-1]
- return author, email, password
-
- def showedit(self, name, title, text):
- author = self.author
- email = self.email
- password = self.password
- if not author or not email or not password:
- a, e, p = self.get_cookie()
- author = author or a
- email = email or e
- password = password or p
- print """
- Title: <INPUT TYPE=text SIZE=70 NAME=title VALUE="%s"><BR>
- <TEXTAREA COLS=80 ROWS=20 NAME=text>%s\n</TEXTAREA>""" % (
- self.escape(title), cgi.escape(string.strip(text)))
- print """<BR>
- Log message (reason for the change):<BR>
- <TEXTAREA COLS=80 ROWS=5 NAME=log>%s\n</TEXTAREA><BR>
- Please provide the following information for logging purposes:
- <TABLE FRAME=none COLS=2>
- <TR>
- <TD>Name:
- <TD><INPUT TYPE=text SIZE=40 NAME=author VALUE="%s">
- <TR>
- <TD>Email:
- <TD><INPUT TYPE=text SIZE=40 NAME=email VALUE="%s">
- <TR>
- <TD>Password:
- <TD><INPUT TYPE=password SIZE=40 NAME=password VALUE="%s">
- </TABLE>
- """ % (self.escape(self.log), self.escape(author),
- self.escape(email), self.escape(password))
-
- def escape(self, s):
- import regsub
- if '&' in s:
- s = regsub.gsub("&", "&amp;", s) # Must be done first!
- if '<' in s:
- s = regsub.gsub("<", "&lt;", s)
- if '>' in s:
- s = regsub.gsub(">", "&gt;", s)
- if '"' in s:
- s = regsub.gsub('"', "&quot;", s)
- return s
-
- def showheaders(self, headers):
- print "<UL>"
- keys = map(string.lower, headers.keys())
- keys.sort()
- for key in keys:
- print "<LI><B>%s:</B> %s" % (string.capwords(key, '-'),
- headers[key] or '')
- print "</UL>"
-
- headers = None
-
- def read(self, name):
- self.headers = None
- import fnmatch, rfc822
- if not fnmatch.fnmatch(name, NAMEPAT):
- return None, None
- if self.add:
- try:
- fname = "faq%02d.%03d.htp" % (string.atoi(self.section),
- string.atoi(self.number))
- except ValueError:
- return None, None
- if fname != name:
- return None, None
- headers = {'title': "%s.%s. " % (self.section, self.number)}
- text = ""
- else:
- f = open(name)
- headers = rfc822.Message(f)
- text = f.read()
- f.close()
- self.headers = headers
- return headers, text
-
- def show(self, name, title, text, edit=1):
- print "<H2>%s</H2>" % cgi.escape(title)
- pre = 0
- for line in string.split(text, '\n'):
- if not string.strip(line):
- if pre:
- print '</PRE>'
- pre = 0
- else:
- print '<P>'
- else:
- if line[0] not in string.whitespace:
- if pre:
- print '</PRE>'
- pre = 0
- else:
- if not pre:
- print '<PRE>'
- pre = 1
- if '/' in line or '@' in line:
- line = self.translate(line)
- elif '<' in line or '&' in line:
- line = cgi.escape(line)
- if not pre and '*' in line:
- line = self.emphasize(line)
- print line
- if pre:
- print '</PRE>'
- pre = 0
- print '<P>'
- if edit:
- print """
- <A HREF="faq.py?req=edit&name=%s">Edit this entry</A> /
- <A HREF="faq.py?req=info&name=%s" TARGET=rlog>Log info</A>
- """ % (name, name)
- if self.headers:
- try:
- date = self.headers['last-changed-date']
- author = self.headers['last-changed-author']
- email = self.headers['last-changed-email']
- except KeyError:
- pass
- else:
- s = '/ Last changed on %s by <A HREF="mailto:%s">%s</A>'
- print s % (date, email, author)
- print '<P>'
- print "<HR>"
-
- def getversion(self, name):
- p = os.popen("/depot/gnu/plat/bin/rlog -h %s </dev/null 2>&1" % name)
- head = "*new*"
- while 1:
- line = p.readline()
- if not line:
- break
- if line[:5] == 'head:':
- head = string.strip(line[5:])
- p.close()
- return head
-
- def prologue(self, title):
- title = cgi.escape(title)
- print '''
- <HTML>
- <HEAD>
- <TITLE>%s</TITLE>
- </HEAD>
- <BODY BACKGROUND="http://www.python.org/pics/RedShort.gif"
- BGCOLOR="#FFFFFF"
- TEXT="#000000"
- LINK="#AA0000"
- VLINK="#906A6A">
- <H1>%s</H1>
- ''' % (title, title)
-
- def error(self, *messages):
- self.prologue("Python FAQ error")
- print "Sorry, an error occurred:<BR>"
- for message in messages:
- print message,
- print
-
- def epilogue(self):
- if self.edit == 'no':
- global wanttime
- wanttime = 0
- else:
- print '''
- <P>
- <HR>
- <A HREF="http://www.python.org">Python home</A> /
- <A HREF="faq.py?req=frontpage">FAQ Wizard home</A> /
- Feedback to <A HREF="mailto:guido@python.org">GvR</A>
- '''
- print '''
- </BODY>
- </HTML>
- '''
-
- translate_prog = None
-
- def translate(self, text):
- if not self.translate_prog:
- import regex
- url = '\(http\|ftp\)://[^ \t\r\n]*'
- email = '\<[-a-zA-Z0-9._]+@[-a-zA-Z0-9._]+'
- self.translate_prog = prog = regex.compile(url + "\|" + email)
- else:
- prog = self.translate_prog
- i = 0
- list = []
- while 1:
- j = prog.search(text, i)
- if j < 0:
- break
- list.append(cgi.escape(text[i:j]))
- i = j
- url = prog.group(0)
- while url[-1] in ");:,.?'\"":
- url = url[:-1]
- url = self.escape(url)
- if ':' in url:
- repl = '<A HREF="%s">%s</A>' % (url, url)
- else:
- repl = '<A HREF="mailto:%s">&lt;%s&gt;</A>' % (url, url)
- list.append(repl)
- i = i + len(url)
- j = len(text)
- list.append(cgi.escape(text[i:j]))
- return string.join(list, '')
-
- emphasize_prog = None
-
- def emphasize(self, line):
- import regsub
- if not self.emphasize_prog:
- import regex
- pat = "\*\([a-zA-Z]+\)\*"
- self.emphasize_prog = prog = regex.compile(pat)
- else:
- prog = self.emphasize_prog
- return regsub.gsub(prog, "<I>\\1</I>", line)
-
-print "Content-type: text/html"
-dt = 0
-wanttime = 0
-try:
- import time
- t1 = time.time()
- import cgi, string, os, sys
- x = FAQServer()
- x.main()
- t2 = time.time()
- dt = t2-t1
- wanttime = 1
-except:
- print "\n<HR>Sorry, an error occurred"
- cgi.print_exception()
-if wanttime:
- print "<BR>(running time = %s seconds)" % str(round(dt, 3))
-
-# The following bootstrap script must be placed in cgi-bin/faq.py:
-BOOTSTRAP = """
-#! /usr/local/bin/python
-FAQDIR = "/usr/people/guido/python/FAQ"
-import os, sys
-os.chdir(FAQDIR)
-sys.path.insert(0, os.curdir)
-import faqmain
-"""