Browse Source

use jsonify rather than dumps

master
wes 8 years ago
parent
commit
163cd32f3b
  1. 47
      src/mcmaster/classes.py
  2. 358
      src/mcmaster/classes2.py
  3. 50
      src/mcmaster/errors2.log
  4. 2172
      src/mcmaster/errors3.log
  5. BIN
      src/mcmaster/requests3.pcap
  6. 12
      src/mcmaster/sylla.py
  7. 117
      src/mcmaster/sylla2.py
  8. 0
      src/mcmaster/texbooks.csv
  9. 0
      src/mcmaster/textbooks.csv
  10. 1
      src/mcmaster/wtf.xml
  11. 18
      src/website.py

47
src/mcmaster/classes.py

@ -1,7 +1,7 @@
#! /usr/bin/python2 #! /usr/bin/python3
from sys import argv from sys import argv
from itertools import chain, islice, izip as zip from itertools import chain, islice
from re import search, sub from re import search, sub
from functools import total_ordering from functools import total_ordering
@ -11,6 +11,7 @@ from collections import MutableMapping
import datetime as dt import datetime as dt
import lxml.html as lxh import lxml.html as lxh
import requests import requests
import logging
import sys import sys
import copy import copy
@ -19,7 +20,7 @@ spring_summer = "2175"
winter = "2171" winter = "2171"
# threading stuff # threading stuff
import Queue as q import queue as q
import threading as thd import threading as thd
baseurl = "https://applicants.mcmaster.ca/psp/prepprd/EMPLOYEE/PSFT_LS/c/COMMUNITY_ACCESS.CLASS_SEARCH.GBL" baseurl = "https://applicants.mcmaster.ca/psp/prepprd/EMPLOYEE/PSFT_LS/c/COMMUNITY_ACCESS.CLASS_SEARCH.GBL"
@ -31,6 +32,11 @@ custom_headers = {
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8", "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
} }
get_headers = {
"User-Agent" : "Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0",
"Content-Type" : "text/html; charset=UTF-8",
}
courseCodes1 = "ICAJAX=1&ICNAVTYPEDROPDOWN=1&ICType=Panel&ICElementNum=0&ICStateNum={0}&ICAction=CLASS_SRCH_WRK2_SSR_PB_SUBJ_SRCH%240&ICXPos=0&ICYPos=0&ResponsetoDiffFrame=-1&TargetFrameName=None&FacetPath=None&ICFocus=&ICSaveWarningFilter=0&ICChanged=-1&ICResubmit=0&ICSID=5tq9x%2Fjt42mf62Sh5z%2BrjxT0gT15kiIyQ2cecCSmRB4%3D&ICActionPrompt=false&ICFind=&ICAddCount=&ICAPPCLSDATA=&CLASS_SRCH_WRK2_STRM$45$={1}" courseCodes1 = "ICAJAX=1&ICNAVTYPEDROPDOWN=1&ICType=Panel&ICElementNum=0&ICStateNum={0}&ICAction=CLASS_SRCH_WRK2_SSR_PB_SUBJ_SRCH%240&ICXPos=0&ICYPos=0&ResponsetoDiffFrame=-1&TargetFrameName=None&FacetPath=None&ICFocus=&ICSaveWarningFilter=0&ICChanged=-1&ICResubmit=0&ICSID=5tq9x%2Fjt42mf62Sh5z%2BrjxT0gT15kiIyQ2cecCSmRB4%3D&ICActionPrompt=false&ICFind=&ICAddCount=&ICAPPCLSDATA=&CLASS_SRCH_WRK2_STRM$45$={1}"
courseCodes2 = "ICAJAX=1&ICNAVTYPEDROPDOWN=1&ICType=Panel&ICElementNum=0&ICStateNum={0}&ICAction=SSR_CLSRCH_WRK2_SSR_ALPHANUM_{1}&ICXPos=0&ICYPos=0&ResponsetoDiffFrame=-1&TargetFrameName=None&FacetPath=None&ICFocus=&ICSaveWarningFilter=0&ICChanged=-1&ICResubmit=0&ICSID=vIUgl6ZXw045S07EPbQw4RDzv7NmKCDdJFdT4CTRQNM%3D&ICActionPrompt=false&ICFind=&ICAddCount=&ICAPPCLSDATA=&CLASS_SRCH_WRK2_STRM$45$={2}" courseCodes2 = "ICAJAX=1&ICNAVTYPEDROPDOWN=1&ICType=Panel&ICElementNum=0&ICStateNum={0}&ICAction=SSR_CLSRCH_WRK2_SSR_ALPHANUM_{1}&ICXPos=0&ICYPos=0&ResponsetoDiffFrame=-1&TargetFrameName=None&FacetPath=None&ICFocus=&ICSaveWarningFilter=0&ICChanged=-1&ICResubmit=0&ICSID=vIUgl6ZXw045S07EPbQw4RDzv7NmKCDdJFdT4CTRQNM%3D&ICActionPrompt=false&ICFind=&ICAddCount=&ICAPPCLSDATA=&CLASS_SRCH_WRK2_STRM$45$={2}"
@ -140,7 +146,7 @@ class Section(dict):
assert len(self._day) == 2 assert len(self._day) == 2
day = self._day day = self._day
else: else:
day = [day[n:n+2] for n in xrange(0, len(day)-1, 2)] day = [day[n:n+2] for n in range(0, len(day)-1, 2)]
self._date = (day, timeparse(start), timeparse(end)) self._date = (day, timeparse(start), timeparse(end))
@ -213,7 +219,7 @@ def parseColumns(subject, html):
if span.xpath("@id") and if span.xpath("@id") and
search(r"DERIVED_CLSRCH_DESCR", span.xpath("@id")[0])) search(r"DERIVED_CLSRCH_DESCR", span.xpath("@id")[0]))
return zip(classNames, classInfo) return list(zip(classNames, classInfo))
def getCodes(html): def getCodes(html):
parsed = lxh.fromstring(html) parsed = lxh.fromstring(html)
@ -231,7 +237,7 @@ class MosReq(object):
# Let the server set some cookies before doing the searching # Let the server set some cookies before doing the searching
cookies = {} cookies = {}
for key, val in s.cookies.iteritems(): for key, val in list(s.cookies.items()):
cookies[key] = val cookies[key] = val
self.cookies = cookies self.cookies = cookies
self.statenum = False self.statenum = False
@ -239,17 +245,20 @@ class MosReq(object):
def getlist(self, subject): def getlist(self, subject):
sys.stderr.write("Getting %s\n" % subject.decode("UTF-8")) sys.stderr.write("Getting %s\n" % subject.decode("UTF-8"))
first_req = requests.get(searchurl, cookies=self.cookies).content first_req = requests.get(searchurl, cookies=self.cookies, headers=get_headers)
# for some reason Mosaic wants us to request it twice, ?????????????????? # for some reason Mosaic wants us to request it twice, ??????????????????
self.statenum = getStateNum(first_req) self.statenum = getStateNum(first_req.content)
first_req = requests.post(searchurl, first_req = requests.post(searchurl,
data=payload.format(self.statenum, subject, self.semester), data=payload.format(self.statenum, subject, self.semester),
cookies=self.cookies, cookies=self.cookies,
allow_redirects=False, allow_redirects=False,
headers=custom_headers).content headers=custom_headers)
print("HEADERS")
print(first_req.request.headers)
# we make a first request to get the ICStateNum in case it thinks there are too many results # we make a first request to get the ICStateNum in case it thinks there are too many results
try: try:
self.statenum = getStateNum(first_req) self.statenum = getStateNum(first_req.content)
except IndexError: except IndexError:
pass pass
if b"Your search will return over" in first_req: if b"Your search will return over" in first_req:
@ -263,11 +272,13 @@ class MosReq(object):
return first_req return first_req
def classes(self, subject): def classes(self, subject):
print("Trying to get classes")
print(subject)
return list(parseColumns(subject, self.getlist(subject))) return list(parseColumns(subject, self.getlist(subject)))
def getCodes(self, letter): def getCodes(self, letter):
sys.stderr.write("Getting letter " + letter + "\n") sys.stderr.write("Getting letter %s\n" % letter)
first_req = requests.get(searchurl, cookies=self.cookies).content first_req = requests.get(searchurl, cookies=self.cookies, headers=get_headers).content
self.statenum = getStateNum(first_req) self.statenum = getStateNum(first_req)
self.statenum = getStateNum(requests.post(searchurl, self.statenum = getStateNum(requests.post(searchurl,
@ -284,9 +295,9 @@ class MosReq(object):
def codes(self): def codes(self):
if not self.codes_: if not self.codes_:
self.codes_ = list(chain.from_iterable( self.codes_ = list(chain.from_iterable(
map((lambda l: list(map((lambda l:
self.getCodes(chr(l))), self.getCodes(chr(l))),
xrange(65, 91)))) list(range(65, 91))))))
return self.codes_ return self.codes_
def request(codes, lists, semester): def request(codes, lists, semester):
@ -295,8 +306,8 @@ def request(codes, lists, semester):
code = codes.get() code = codes.get()
try: try:
lists.put(requester.classes(code)) lists.put(requester.classes(code))
except exception: except Exception as e:
print(exception) print(e)
codes.task_done() codes.task_done()
return return
codes.task_done() codes.task_done()
@ -321,7 +332,7 @@ class CourseInfo(object):
lists = q.Queue() lists = q.Queue()
threads = [] threads = []
thread = None thread = None
for i in xrange(self.threadcount): for i in range(self.threadcount):
thread = thd.Thread(group=None, target=request, args=(qcodes, lists, self.semester)) thread = thd.Thread(group=None, target=request, args=(qcodes, lists, self.semester))
threads.append(thread) threads.append(thread)
thread.start() thread.start()
@ -357,4 +368,4 @@ def allCourses():
if __name__ == "__main__": if __name__ == "__main__":
for course in allCourses(): for course in allCourses():
sys.stdout.write("%s, %s, %s, %s\n" % (course.title, course.code, course.dept, list(chain.from_iterable(course.books)))) sys.stdout.write("%s, %s, %s, %s\n" % (course.title, course.code, course.dept, list(chain.from_iterable(course.books))))
print course.sections print((course.sections))

358
src/mcmaster/classes2.py

@ -0,0 +1,358 @@
#! /usr/bin/python2
from sys import argv
from itertools import chain, islice
from re import search, sub
from functools import total_ordering
from sylla2 import textbookInfo
from collections import MutableMapping
import datetime as dt
import lxml.html as lxh
import requests
import logging
import sys
import copy
fall = "2169"
spring_summer = "2175"
winter = "2171"
# threading stuff
import Queue as q
import threading as thd
baseurl = "https://applicants.mcmaster.ca/psp/prepprd/EMPLOYEE/PSFT_LS/c/COMMUNITY_ACCESS.CLASS_SEARCH.GBL"
searchurl = "https://csprd.mcmaster.ca/psc/prcsprd/EMPLOYEE/PSFT_LS/c/COMMUNITY_ACCESS.CLASS_SEARCH.GBL"
custom_headers = {
"User-Agent" : "Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0",
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
}
courseCodes1 = "ICAJAX=1&ICNAVTYPEDROPDOWN=1&ICType=Panel&ICElementNum=0&ICStateNum={0}&ICAction=CLASS_SRCH_WRK2_SSR_PB_SUBJ_SRCH%240&ICXPos=0&ICYPos=0&ResponsetoDiffFrame=-1&TargetFrameName=None&FacetPath=None&ICFocus=&ICSaveWarningFilter=0&ICChanged=-1&ICResubmit=0&ICSID=5tq9x%2Fjt42mf62Sh5z%2BrjxT0gT15kiIyQ2cecCSmRB4%3D&ICActionPrompt=false&ICFind=&ICAddCount=&ICAPPCLSDATA=&CLASS_SRCH_WRK2_STRM$45$={1}"
courseCodes2 = "ICAJAX=1&ICNAVTYPEDROPDOWN=1&ICType=Panel&ICElementNum=0&ICStateNum={0}&ICAction=SSR_CLSRCH_WRK2_SSR_ALPHANUM_{1}&ICXPos=0&ICYPos=0&ResponsetoDiffFrame=-1&TargetFrameName=None&FacetPath=None&ICFocus=&ICSaveWarningFilter=0&ICChanged=-1&ICResubmit=0&ICSID=vIUgl6ZXw045S07EPbQw4RDzv7NmKCDdJFdT4CTRQNM%3D&ICActionPrompt=false&ICFind=&ICAddCount=&ICAPPCLSDATA=&CLASS_SRCH_WRK2_STRM$45$={2}"
payload2 = "ICAJAX=1&ICNAVTYPEDROPDOWN=1&ICType=Panel&ICElementNum=0&ICStateNum={0}&ICAction=%23ICSave&ICXPos=0&ICYPos=0&ResponsetoDiffFrame=-1&TargetFrameName=None&FacetPath=None&ICFocus=&ICSaveWarningFilter=0&ICChanged=-1&ICResubmit=0&ICSID=aWx3w6lJ6d2wZui6hwRVSEnzsPgCA3afYJEFBLLkxe4%3D&ICActionPrompt=false&ICFind=&ICAddCount=&ICAPPCLSDATA=&CLASS_SRCH_WRK2_STRM$45$={1}"
payload = "ICAJAX=1&ICNAVTYPEDROPDOWN=1&ICType=Panel&ICElementNum=0&ICStateNum={0}&ICAction=CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH&ICXPos=0&ICYPos=0&ResponsetoDiffFrame=-1&TargetFrameName=None&FacetPath=None&ICFocus=&ICSaveWarningFilter=0&ICChanged=-1&ICResubmit=0&ICSID=aWx3w6lJ6d2wZui6hwRVSEnzsPgCA3afYJEFBLLkxe4%3D&ICActionPrompt=false&ICFind=&ICAddCount=&ICAPPCLSDATA=&SSR_CLSRCH_WRK_SUBJECT$75$$0={1}&CLASS_SRCH_WRK2_STRM$45$={2}"
year = dt.date.today().year
month = dt.date.today().month
days = {
"Mo" : 0,
"Tu" : 1,
"We" : 2,
"Th" : 3,
"Fr" : 4,
"Sa" : 5,
"Su" : 6
}
day_descs = {
"Mo" : "Monday Mon Mo",
"Tu" : "Tuesday Tues Tu Tue",
"We" : "Wednesday Wed We",
"Th" : "Thursday Th Thurs",
"Fr" : "Friday Fr Fri",
"Sa" : "Saturday Sat Sa",
"Su" : "Sunday Su Sun",
"T" : "TBA"
}
def timeparse(time):
"""
Parse the time into numbers
"""
if len(time) == 7:
hour = int(time[0:2])
minutes = int(time[3:5])
half = time[5:7]
else:
hour = int(time[0])
minutes = int(time[2:4])
half = time[4:6]
if half == "PM":
if hour < 12:
hour = hour + 12
return (str(hour), str(minutes), half)
class Class(object):
def __init__(self, dept, title, sections):
self.title = title.encode("UTF-8")
self.sections = sections
self.dept = dept
def __repr__(self):
return repr((self.title, self.sections))
def __iter__(self):
return iter((self.title, sec) for sec in self.sections)
def hasCode(self):
splitted = self.title.strip().split(" ")
return ((len(splitted) >= 2) and
(splitted[0].upper() == splitted[0]) and
(splitted[1].upper() == splitted[1]))
@property
def code(self):
if self.hasCode():
return self.title.strip().split(" ")[1].strip()
return False
@property
def books(self):
if self.dept and self.code:
return textbookInfo(self.dept, self.code, withPrices=True)
return False
@total_ordering
class Section(dict):
def __init__(self, time, loc, prof, sem):
self.time = time.encode("UTF-8")
self.loc = loc.encode("UTF-8")
self.prof = prof.encode("UTF-8")
self._sem = sem.encode("UTF-8")
self._date = False
self._day = False
@property
def sem(self):
if self._sem == fall:
return "Fall"
elif self._sem == winter:
return "Winter"
else:
return "Spring/Summer"
@property
def date(self):
if self.time != "TBA":
day, start, _, end = self.time.split()
if self._day:
assert len(self._day) == 2
day = self._day
else:
day = [day[n:n+2] for n in range(0, len(day)-1, 2)]
self._date = (day, timeparse(start), timeparse(end))
return self._date
return self.time
@property
def day(self):
return self.date[0]
@property
def start(self):
return self.date[1][0] + self.date[1][1]
def __repr__(self):
return ("""
Time = %s, Location = %s, Instructor = %s, Semester Running = %s
""" % (self.date, self.loc, self.prof, self.sem))
def __gt__(self, x):
if isinstance(self.day, list):
raise NotImplementedError
if (self.date == "TBA" or
x.date == "TBA"):
return False
return ((days[self.day] > days[x.day]) or
((self.day == x.day) and
(self.start > x.start)))
def __eq__(self, x):
return (x.date == self.date and
x.prof == self.prof and
x.loc == self.loc and
x.sem == self.sem)
def getStateNum(html):
"""
Get the state num from Mosaic
This is unique to each requester
"""
parsed = lxh.fromstring(html)
return parsed.xpath(".//input[@name=\"ICStateNum\"]")[0].value
def parseSection(section):
cols = section.xpath(".//td")
assert len(cols) == 4
time, loc, prof, sem = [col.text_content().encode("UTF-8").strip() for col in cols]
classinfo = Section(time, loc, prof, sem)
return classinfo
def getSectionInfo(table):
trs = table.xpath(".//tr")
for tr in trs:
if tr.xpath("@id") and search(r"SSR_CLSRCH", tr.xpath("@id")[0]):
yield parseSection(tr)
def parseColumns(subject, html):
parsed = lxh.fromstring(html)
classInfo = (list(getSectionInfo(table)) for table in
islice((table for table in parsed.xpath(".//table")
if table.xpath("@id") and
search(r"ICField[0-9]+\$scroll", table.xpath("@id")[0])), 1, sys.maxsize))
classNames = ((subject, span.text_content().strip()) for span in parsed.xpath(".//span")
if span.xpath("@id") and
search(r"DERIVED_CLSRCH_DESCR", span.xpath("@id")[0]))
return list(zip(classNames, classInfo))
def getCodes(html):
parsed = lxh.fromstring(html)
return (code.text_content().encode("UTF-8") for code in
parsed.xpath("//span")
if code.xpath("@id") and
search(r"SSR_CLSRCH_SUBJ_SUBJECT\$[0-9]+", code.xpath("@id")[0]))
class MosReq(object):
def __init__(self, semester):
self.semester = semester
s = requests.Session()
resp = s.get(baseurl, allow_redirects=True, headers=custom_headers).content
# Let the server set some cookies before doing the searching
cookies = {}
for key, val in s.cookies.items():
cookies[key] = val
self.cookies = cookies
self.statenum = False
self.codes_ = []
def getlist(self, subject):
sys.stderr.write("Getting %s\n" % subject.decode("UTF-8"))
first_req = requests.get(searchurl, cookies=self.cookies)
# for some reason Mosaic wants us to request it twice, ??????????????????
self.statenum = getStateNum(first_req.content)
first_req = requests.post(searchurl,
data=payload.format(self.statenum, subject, self.semester),
cookies=self.cookies,
allow_redirects=False,
headers=custom_headers)
print("HEADERS")
print(first_req.request.headers)
# we make a first request to get the ICStateNum in case it thinks there are too many results
try:
self.statenum = getStateNum(first_req.content)
except IndexError:
pass
if b"Your search will return over" in first_req:
return requests.post(searchurl,
data=payload2.format(self.statenum, self.semester),
cookies=self.cookies,
allow_redirects=False,
headers=custom_headers).content
else:
return first_req
def classes(self, subject):
return list(parseColumns(subject, self.getlist(subject)))
def getCodes(self, letter):
sys.stderr.write("Getting letter " + letter + "\n")
first_req = requests.get(searchurl, cookies=self.cookies).content
self.statenum = getStateNum(first_req)
self.statenum = getStateNum(requests.post(searchurl,
data=courseCodes1.format(self.statenum, self.semester),
cookies=self.cookies,
headers=custom_headers).content)
return getCodes(requests.post(searchurl,
data=courseCodes2.format(self.statenum, letter, self.semester),
cookies=self.cookies,
allow_redirects=False,
headers=custom_headers).content)
@property
def codes(self):
if not self.codes_:
self.codes_ = list(chain.from_iterable(
list(map((lambda l:
self.getCodes(chr(l))),
range(65, 91)))))
return self.codes_
def request(codes, lists, semester):
requester = MosReq(semester)
while not codes.empty():
code = codes.get()
lists.put(requester.classes(code))
codes.task_done()
class CourseInfo(object):
def __init__(self, threadcount, semester):
self._codes = False
self.threadcount = threadcount
self.semester = semester
@property
def codes(self):
if not self._codes:
req = MosReq(self.semester)
self._codes = req.codes
return self._codes
def classes(self):
qcodes = q.Queue()
for code in self.codes:
qcodes.put(code)
lists = q.Queue()
threads = []
thread = None
for i in range(self.threadcount):
thread = thd.Thread(group=None, target=request, args=(qcodes, lists, self.semester))
threads.append(thread)
thread.start()
qcodes.join()
for t in threads:
t.join()
sections = []
while not lists.empty():
sections.append(lists.get())
for cl in chain.from_iterable(sections):
new_sections = []
for sec in cl[1]:
print(sec)
if len(sec.day) > 1:
for day in sec.day:
new_sections.append(copy.deepcopy(sec))
new_sections[-1]._day = day
else:
sec._day = sec.day[0]
new_sections.append(sec)
yield Class(cl[0][0], sub("\xa0+", "", cl[0][1]), sorted(new_sections))
def getCourses(semester, threadcount=10):
return CourseInfo(threadcount, semester).classes()
def allCourses():
return chain.from_iterable(
(getCourses(sem, threadcount=25)
for sem in (fall, winter, spring_summer)))
if __name__ == "__main__":
for course in allCourses():
sys.stdout.write("%s, %s, %s, %s\n" % (course.title, course.code, course.dept, list(chain.from_iterable(course.books) if course.books else [])))
print(course.sections)

50
src/mcmaster/errors2.log

@ -0,0 +1,50 @@
HEADERS
{'Content-Length': '417', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=xduoMvTAUgA7lPvyWdZde0Bl7Byb_2J1!-1839177281; PS_TOKEN=qQAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABRFKduLPmKmYqWIluxqMZGQ1zdhnWkAAAAFAFNkYXRhXXicHYlLDkBAEAVrEEsHcAfiM4ilyLAiEqznIK7mcJ7pRdWr9AMkcWSM/EaEyzdmNjynPMsrN051kTp2ZXaoFrXnYMI2VNT0FGItNgxht5R0chn+P3ssYzAfZUENsw==; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=TQB9Y7xGbS1LTKr8MFWz2rlv59g1BnP8!531660376; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9d45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '417', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=BOuoMvUPHqPy0LjXeW8EBpO7BlbM-MKl!-1839177281; PS_TOKEN=qgAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABR+G9/wkfk8H4KY3xx0dTtEoQj4bGoAAAAFAFNkYXRhXnicHYlNDkAwGESfEksHcAeN+l2LYFVpgnUP4moOZ9JvMW/efC9Q5CbLxM+QrvaseCKXuIoHD5vsptw4pVWQ7fJIYGHoaHFMNEqn7JhT77GMok1/q32Sj9od/GVIDbA=; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=4MpRY7xGyQtLtLZwQYGyXrV1fdcHjX5m!-1080248884; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9e45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '421', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=pI-oMvS9Ibt75xltbVqBUWjlnCJGoKDc!1679552918; PS_TOKEN=qwAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABSJfBd8pFfkOh5f2FAvW/R9aC3TMGsAAAAFAFNkYXRhX3icHYnLCYAwFATHDx4twB4Mxr9HEfUUCahnC7E1i3PJg7ezw75AmsRRJH4x4QrHguPhFBdx52aVXWQrhzT3sk3+4JlpayosPaXSKmuG0BsMnWjCbhiZtDX6CX5loQ27; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=1pQvY7xG7S59yPhLGcLcBdvtDppTnBl7!297042307; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9f45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9c45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '417', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=jV2oMvScU3Ws7kM6WGcit63w2-bZLD1d!1679552918; PS_TOKEN=rQAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABSEs++BTGGPtSKM/EQIIoWVaIt6Qm0AAAAFAFNkYXRhYXicHYq5DYAwEASHR4QUQA9YPOZJkWWIQEhA7EJojeJY+YKdm7t9gTxLk0T8UuJUO46dwCU6cePBy24KzyEtT9kqD5ws2I6GlpFa2So7prj3GAbRxL/Rdcaq18v5AWWaDbY=; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=TJgVY7xGRD9zHB3vhLdnfTLCLpy230pH!-1080248884; PS_TOKENEXPIRE=27_Nov_2016_23:51:02_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9e45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9c45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '417', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=hoeoMvSJRaBLJZ2VDW48XWM5SypNEgTf!-1839177281; PS_TOKEN=qwAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABTDtIThLzRoGTByZlNKVU2PPpb6GmsAAAAFAFNkYXRhX3icHYpLDkBAEAXLEEsHcAdiZnzWIlgRCdZzEFdzOM90J6+60u8BstQkifga4pQbExuBU5zElZtZdpHP7NLikC3ywMFI62iw9FRKq3QM8fbUdGId/3/+Ta+18AFkxw2j; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=FfK8Y7xGlm0n5hD839tGFHNnZWMyHx9w!-675472577; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9845525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '421', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=QQWoMvVfAvglhWPIjZUDw95oEOEv1EhY!-1839177281; PS_TOKEN=qgAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABTl9T9nndclvjWPRHx4ZuAf6kvLJWoAAAAFAFNkYXRhXnicHYlNDkAwGERfSywdwB00foq1SFkRCdY9iKs5nEm/SebNy/cCeWaNET9LumpnYSdyiYu48RBkN0XgkJanbJVHTmZ8R0PLSK1u1R1T2j2OQXTp7+QTXssr/GVJDbE=; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=mZNvY7xGdZ6VGqYc4r2lYLnnLknXdQ40!-1851985177; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9a45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '419', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=_omoMvSQwLtwMWWynzPs-6hVel8NRvKU!-1839177281; PS_TOKEN=qwAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABSx+qh8pW4t7OK6WrrPKzvXfzSoK2sAAAAFAFNkYXRhX3icHYlLDkBAFARrEEsHcAcTY3xiKYLViARrB3E1h9OZl3RXV94LZGlijPglxCsDM4GHU5zFjZtFdpEv7NLikK3yh4OJtqHG0VOpnbphiNtj6UQb/5aWUekVDz9ljA24; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=Cq2cY7xGdnctTZwD3PpF2Y9jpwCvnp08!-1344051968; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9b45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '419', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=gceoMvTxE85prx6BpYYAnZTiatNw1_RI!1679552918; PS_TOKEN=qwAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABSbiEEKOKJeKHPsaJaPfR8vaJkkM2sAAAAFAFNkYXRhX3icHYlLDkBAEAXLJ5YO4A4mxjeWMhlWRIK1g7iaw3mmk37V1e8B0iSOIvGNCVOsOFZuDtGJCxdedpJ5Nmm+y2b5zc5EW1Nh6SmVVlkzhLvB0Ikm9H+O+vVaCx9lRA2w; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=29PQY7xGg9rWjWqkQGxJHCQgzQHFvRNc!-1851985177; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9a45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9c45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '420', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=gCmoMvWIaXees8rdh9lNpisMOaQTe-5e!-1839177281; PS_TOKEN=rAAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABRj9LO046eWZkTNPbuNg1rEAbN1vGwAAAAFAFNkYXRhYHicHYpLDkBAEAVrEEsHcAcTnxnWIliNSLCeg7iaw3mZXrzq6n4vUOSZMeKXkaYOLAQil7iIOw+r7KZcOaTVKdvkkZMZ19PSMdIoO2XPlPYBixdt+luc6HTxavADZSQNrg==; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=0fHwY7xGQZZNwCmQ26yDYFTGyFRNz7tF!-1080248884; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9e45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
HEADERS{'Content-Length': '417', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=3XeoMvS0I0AKjt9hNR0h_Q2PCkOPSBBm!1679552918; PS_TOKEN=qwAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABRDtHDfWEeGAgRMXPyCiu/HBPzg/msAAAAFAFNkYXRhX3icHYpLDkBAFARrEEsHcAcT4zNsRbAiEqwdxNUcTpu36OpKvwdI4sgY8Y0Il6+MrNwc4iguXEyyk3Rik2a7bJbf7Aw0FSUOT6F0yoou9BpLK9qwW/4/r83TwwdlQQ23; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=BhddY7xGwRSt5TJWBVghBCGjlF1qQJrP!-1851985177; PS_TOKENEXPIRE=27_Nov_2016_23:51:02_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9a45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9c45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
{'Content-Length': '421', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=8YqoMvT2-wgensT2w3mjTLx9pq8bkKy0!-1839177281; PS_TOKEN=rAAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABSWnSi7Ra5yxsbhpo/RDNRZubdtkmwAAAAFAFNkYXRhYHicHYpLDkBAEAVrEEsHcAfiMz5bkWFFJFjPQVzN4TzTnbx6le4HSOLIGPGNCJNvzGx4TnEWV26c7CJ17NLskC1yz8GEbaio6SmUtbJhCL2lpBPLcP+7ZdT2+uADZZsNuw==; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=0cL7Y7xGnLvvQm2jbBz2wSdQNsp2ZrbG!297042307; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9f45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '420', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=4SGoMvWvMuwQfAEVstSjqs6EEje5G_bD!1679552918; PS_TOKEN=qwAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABQ9RowUj9KFjDdjF4lHANVZ4kQxhGsAAAAFAFNkYXRhX3icHYpNDkAwGERfEUsHcAeNqp+1CFYVCdY9iKs5nEm/xbx5me8FijwzRvwy0tWBhUDkEhdx52GV3ZQrh7Q6ZZs8cjLTd7Q4RhqlU3ZMqXssg2jTbun147R6NX5lMg2u; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=pBJlY7xG6hhjMLLPcDzTmq0f8YHJ5Tqp!-1851985177; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9a45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9c45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '417', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=3DOoMvW4Svql1cvvIsMyS0Qp6VSQPqDe!-1839177281; PS_TOKEN=rAAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABSABEDPRcVjlM5XzKI1YIBxKI6JFmwAAAAFAFNkYXRhYHicHYpLDkBAEAVrEEsHcAcT4ze2IliNSLB2EFdzOC/Ti1dd3e8FsjQxRvwS4pSBmcDDKc7ixs0iu8gXdmlxyFb5w8FE11DjGKiUTtng495i6UUb/5ZRF6+ek/MDZYENsw==; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=PlsxY7xHz9QWS1x2BfdWVqWjmKB2GJQX!297042307; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9f45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '422', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=wyqoMvWWYIdoyv_pTEdtWBQBxwKw9Iby!1679552918; PS_TOKEN=qwAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABRKfxHYuCPVPwlU0rlic94pvJ13h2sAAAAFAFNkYXRhX3icHYlLDkBAFATLJ5YO4A4mjEEsRbAik2A9B3E1h9OZTl7Xq/QL5FmaJOKXElMdLBwELnERdx5W2U2xckpLL9vkAc+MszS0DNTqVm0Z499h6EUTd8Mkc7pRxg9low25; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=bB1MY7xGnNXqyhzyDb6M0ypCg310SvJZ!-675472577; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9845525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9c45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '420', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=uneoMvTqjh7TWpenIofy6ckoE-o_AOCl!1679552918; PS_TOKEN=rAAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABSLxDKrAQnoDTukMVG+LDouZRlMoWwAAAAFAFNkYXRhYHicHYpLDkBAEAVrEEsHcAcT4zPWIliNSLCeg7iaw3mZXrzq6tcvUOSZMeKXkaYOLAQil7iIOw+r7KZcOaTVKdvkkZOZoaPF4WmUTtkxpb3HMoo29VYfXt2gm4cfZXMNtw==; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=RnYkY7xG2ppJhDZh62ys5KR9hKynG0xM!297042307; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9f45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9c45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '421', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=UtWoMvWZC5Vy2ATqPc1he_e5_fE_8J07!-1839177281; PS_TOKEN=qwAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABQKe6x0IQngm7QjAaGw6iNX3qL86GsAAAAFAFNkYXRhX3icHYlLDkBAFARrEEsHcAcT428pgtWIBGsHcTWH05m36Orq9wJJHBkjfhHhcs+M5+EUZ3HjZpFdpAu7NDtkq/zhYKKpKHF0FEqnrOhDr7G0og1/q9XRMGof4Adleg26; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=pHXyY7xGggytCgKhPnBGrQngdKn4qGrH!531660376; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9d45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '421', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=heCoMvXvm18xDJecdbtltSUtmQOFTuxC!-1839177281; PS_TOKEN=qgAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABQsFcmHlYRGjE7GWPUaojnid3QsE2oAAAAFAFNkYXRhXnicHYlLDkAwAESfTywdwB001K9bacqKSLB2EFdzOJPOYt68zAvkWZok4pcSU214Nh5O0YsrN0F2UQR2aXnIFvnDwUxvaWgZqdWt2jLF3WEYRBN/g5M5bSvjB2V+DbI=; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=ytLNY7xHZds8wv4XzH7YyVJQ9dQgMY1M!297042307; PS_TOKENEXPIRE=27_Nov_2016_23:51:04_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9f45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '420', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=PiOoMvX6ULIMy5pdEo-GE64kHLrYkTYv!1679552918; PS_TOKEN=qwAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABS8curVc9Vwlkhg7XcswvKHbXV0E2sAAAAFAFNkYXRhX3icHYpLDkBAEAVrEEsHcAcT4xtLEaxGJFg7iKs5nGd68aqr+z1AEkfGiG9EmNwz4bk5xElcuZhlJ+nMJs122SK/2RlpKkocHYXSKSv6sNdYWtGGv9X9bzkGJR9lKw2z; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=TxmzY7xHXLR6PLmKLQh29McdXkz1Gn6s!-1344051968; PS_TOKENEXPIRE=27_Nov_2016_23:51:04_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9b45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9c45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '417', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=M66oMvXALSSBCkHVm10rmVhf23yBAAcA!-1839177281; PS_TOKEN=rAAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABSpw7fcCqgCK/lgv+nVx0KN5K6rRmwAAAAFAFNkYXRhYHicHYrLCYAwEAXHDx4twB4MGqM5i6gnJaCeU4itWZyPLOybHd6+QFnkWSZ+OWmag4WDyCUu4s7DKrupVk5pHWSbPBKYcZaOnolW2SstPt0DhlE0qTfaTo3Tp4cfZSUNsw==; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=p16CY7xHJmDJk1wHdp0D1mZXfycG2ywq!-1080248884; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9e45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '421', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=BYmoMvXRMDuzDOMAb4P2iVhHeMP7GpKB!-1839177281; PS_TOKEN=qgAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABRUi8sAfMgDStjEKeHLUNZpoTISaWoAAAAFAFNkYXRhXnicHYlJDkBAAARrEEcP8AcT+3IUwYlIcJ6H+JrHadOHrq70A0RhYIz4BvikGxMbjlOcxJWbWXYRz+zS5JAtcsfBSF2SU9CSqQt1Sed3haURrf//neup6BngA2ViDbo=; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=cSJrY7xHcBkQznTyqQy0c41wlp9QDVHn!-675472577; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9845525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '422', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=OMioMvYQ4SFm-QcU8PEcNwa1sMyGgl5j!-1839177281; PS_TOKEN=qwAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABStyPfVuQPDDbFZj7C2hw3a53BiKmsAAAAFAFNkYXRhX3icHYlLDkBAFATLJ5YO4A4mZvyXMsGKSLB2EFdzOJ15i65X3S+QJnEUiV9MuGLDs/Fwil5cuZllF9nMLs0P2SJ/OJhoHBWWjlJplY4+/DWGVjRhN+pHBm2dWn5lrQ2/; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=qBhJY7xHWNQvrKvMPyVcSl1tGy2p7hJR!-1344051968; PS_TOKENEXPIRE=27_Nov_2016_23:51:04_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9b45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9d45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '421', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=aWqoMvV1vf0XNk5PxfHjA5CX1ajSl6E8!1679552918; PS_TOKEN=qgAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABS95BJZ+bsocqIKMKQ6+uKGkLYBfmoAAAAFAFNkYXRhXnicHYlLDkAwAERfEUsHcAeNX5WlCFZEgrWDuJrDmXQW8+ZlXiCJI2PELyIk35jYeDjFSVy5mWUX6cwuzQ7ZIn84GGlrSio6CnWlrvFhN1icaMNvGejlXnTwA2XxDcU=; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=qlJYY7xGGBYy53ZQND4nDc1Nn1dv6CXD!-1344051968; PS_TOKENEXPIRE=27_Nov_2016_23:51:03_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9b45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9c45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '421', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=8Y2oMvXk9U32aTOvEL7lcCuyBMNkhGgJ!1679552918; PS_TOKEN=qgAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABQr24cbH8H2oFG7MscDE4WN0fi3EWoAAAAFAFNkYXRhXnicHYlLDkBAFARrEEsHcAfC+C9FhhWRYO0gruZw2rxFV1e/B4jCwBjxDfCXrkys3BziJC5cONlJ7NikyS6b5Tc7I7WloKQlU5ZKS+d7RU4j5v7/d8ug1dLDB2VpDbc=; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=DqJTY7xH1n0pb3fRP2yGgnmGQbQ5Jl84!-1080248884; PS_TOKENEXPIRE=27_Nov_2016_23:51:04_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9e45525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9c45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '421', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=bxGoMvYBXtTwRPnwqwrLLRIauwH7jWbt!1679552918; PS_TOKEN=qwAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABSNBSrOPEVZNFl5HJwQuZvjx90qlGsAAAAFAFNkYXRhX3icHYpLDkBAFARrEEsHcAcT45tZimBFJFg7iKs5nDZv0dWV1w+QxJEx4hsRLl8ZWbk5xFFcuJhkJ+nEJs122Sy/2RloKkocHYXSKSv60GssrWjD32rhxX/t4QNlbQ21; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femployee%2fempl%2frefresh=list: %3ftab%3dmcm_tab_app_signin|%3frp%3dmcm_tab_app_signin|%3ftab%3dmcm_tab_app_signin_grad|%3frp%3dmcm_tab_app_signin_grad|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; PS_LOGINLIST=https://csprd.mcmaster.ca/prcsprd https://applicants.mcmaster.ca/prepprd; csprd-8000-PORTAL-PSJSESSIONID=ky4xY7xHhX2bjBbrngg9sTJdMh0H1GvF!-675472577; PS_TOKENEXPIRE=27_Nov_2016_23:51:04_GMT; SignOnDefault=MCM_SCC_GUEST; NSC_qh-dtqseqjb=ffffffffaf122a9845525d5f4f58455e445a4a422970; ps_theme=node:EMPL portal:EMPLOYEE theme_id:MCM_GUEST_THEME css:MCM_PT_BRAND_CLASSIC_FLUID css_f:PT_BRAND_FLUID_TEMPLATE accessibility:A macroset:MCM_MYMAC_THEME formfactor:3 piamode:2; https%3a%2f%2fcsprd.mcmaster.ca%2fpsp%2fprcsprd%2femployee%2fhrms%2frefresh=list: %3ftab%3ddefault|%3frp%3ddefault|%3ftab%3dremoteunifieddashboard|%3frp%3dremoteunifieddashboard; NSC_qh-fqqsebqqmjdbout=ffffffffaf122b9c45525d5f4f58455e445a4a422970', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
HEADERS
{'Content-Length': '421', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0', 'Connection': 'keep-alive', 'Cookie': 'PS_DEVICEFEATURES=new:1; epprd-8000-PORTAL-PSJSESSIONID=QzKoMvWjImoy2rcwi9bm9XHf0-YdNF_l!1679552918; PS_TOKEN=qQAAAAQDAgEBAAAAvAIAAAAAAAAsAAAABABTaGRyAk4Aewg4AC4AMQAwABQKh/Kkz1qgnd394kPa2EuiFKjaYmkAAAAFAFNkYXRhXXicJYlLDkBAEAXLJ5YO4A4E47eVybAik2DtIK7mcF5GL6pepR8gTeIokt+YcMWGZePmkK28cuFUJ5ljV+ZetahvPDNdS03DQCk2YssYtqGil6vw/2mYxBE+ZQINrg==; ExpirePage=https://applicants.mcmaster.ca/psp/prepprd/; https%3a%2f%2fapplicants.mcmaster.ca%2fpsp%2fprepprd%2femplo

2172
src/mcmaster/errors3.log

File diff suppressed because it is too large

BIN
src/mcmaster/requests3.pcap

Binary file not shown.

12
src/mcmaster/sylla.py

@ -1,7 +1,7 @@
#! /usr/bin/python2 #! /usr/bin/python3
from sys import argv from sys import argv
from itertools import chain, islice, izip_longest, izip as zip from itertools import chain, islice, zip_longest
from re import search, sub from re import search, sub
from functools import total_ordering from functools import total_ordering
from re import sub from re import sub
@ -34,7 +34,7 @@ class Book(object):
def grouper(n, iterable, fillvalue=None): def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args) return zip_longest(fillvalue=fillvalue, *args)
searchUrl = "https://campusstore.mcmaster.ca/cgi-mcm/ws/txsub.pl?wsDEPTG1=%s&wsDEPTDESC1=&wsCOURSEG1=%s&crit_cnt=1" searchUrl = "https://campusstore.mcmaster.ca/cgi-mcm/ws/txsub.pl?wsDEPTG1=%s&wsDEPTDESC1=&wsCOURSEG1=%s&crit_cnt=1"
@ -70,7 +70,7 @@ def books(dept, code, withPrices):
pricelist = prices(parsed) pricelist = prices(parsed)
for div in parsed.xpath(".//div"): for div in parsed.xpath(".//div"):
if (div.attrib.has_key("id") and if ("id" in div.attrib and
"prodDesc" in div.attrib["id"]): "prodDesc" in div.attrib["id"]):
textbook = div.text_content() textbook = div.text_content()
@ -96,8 +96,8 @@ def prices(html):
] ]
try: try:
amts, stats = zip(*list(reversed(list(grouper(2, ps))))) amts, stats = list(zip(*list(reversed(list(grouper(2, ps))))))
return map(Price, amts, stats) return list(map(Price, amts, stats))
except ValueError: except ValueError:
return [] return []

117
src/mcmaster/sylla2.py

@ -0,0 +1,117 @@
#! /usr/bin/python2
from sys import argv
from itertools import chain, islice, izip_longest, izip as zip
from re import search, sub
from functools import total_ordering
from re import sub
import datetime as dt
import lxml.html as lxh
import requests
# Purpose of this module is to download and parse syllabi from various departments
# In order to be corellated with individual courses
class Price(object):
def __init__(self, amnt, status):
self.dollars = float(amnt[1:])
self.status = status
def __repr__(self):
return "$%s %s" % (repr(self.dollars), self.status)
class Book(object):
def __init__(self, title, price):
self.title = title
self.price = price
def __repr__(self):
return '["%s", "%s"]' % (self.title, repr(self.price))
def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
searchUrl = "https://campusstore.mcmaster.ca/cgi-mcm/ws/txsub.pl?wsDEPTG1=%s&wsDEPTDESC1=&wsCOURSEG1=%s&crit_cnt=1"
def normalize(word):
if len(word) > 1:
return ("%s%s" %
(word[0].upper(),
"".join(word[1:]).lower()))
return word
def parseAuthor(author):
split = author.split(" ")
if len(split) <= 1:
return author
lastname = split[0]
firstname = split[1]
return "%s %s" % (firstname, lastname)
def normwords(phrase):
words = phrase.split(" ")
return " ".join(map(normalize, words))
def books(dept, code, withPrices):
"""
Snatch me up a book title or three
"""
req = searchUrl % (dept, code)
html = requests.get(req).text
parsed = lxh.fromstring(html)
pricelist = prices(parsed)
for div in parsed.xpath(".//div"):
if (div.attrib.has_key("id") and
"prodDesc" in div.attrib["id"]):
textbook = div.text_content()
author = sub(r',', '',
"".join(
(div.getparent()
.xpath(".//span[@class='inline']")
[0].text_content()
.split(":")[1:])).strip())
price = pricelist.pop()
if withPrices:
yield (normwords(textbook), normwords(author), repr(price))
else:
yield (normwords(textbook), normwords(author))
def prices(html):
"""
Get the prices from a search result page
"""
ps = [
p.getparent().text_content().split()[0]
for p in html.xpath("//p/input[@type='checkbox']")
]
try:
amts, stats = zip(*list(reversed(list(grouper(2, ps)))))
return map(Price, amts, stats)
except ValueError:
return []
def textbookInfo(dept, code, withPrices=False):
"""
Return all the textbooks for a course
"""
return list(books(dept, code, withPrices))
def humanities():
"""
Download humanities syllabi
"""
return []
# Example, getting the course info for Personality Theory (PSYCH = Department, 2B03 = Course code)
# print list(courseInfo("PSYCH", "2B03"))

0
src/mcmaster/texbooks.csv

0
src/mcmaster/textbooks.csv

1
src/mcmaster/wtf.xml

File diff suppressed because one or more lines are too long

18
src/website.py

@ -1,7 +1,7 @@
#! /usr/bin/python3 #! /usr/bin/python3
from functools import partial from functools import partial
from flask import Blueprint, abort, Flask, render_template, flash, request, send_from_directory from flask import Blueprint, abort, Flask, render_template, flash, request, send_from_directory, jsonify
from flask_bootstrap import Bootstrap from flask_bootstrap import Bootstrap
from flask_appconfig import AppConfig from flask_appconfig import AppConfig
@ -13,7 +13,7 @@ from syslog import syslog
from archive import searchIA from archive import searchIA
from urllib.parse import quote, unquote from urllib.parse import quote, unquote
from json import dumps, loads from json import loads
from werkzeug.contrib.cache import MemcachedCache from werkzeug.contrib.cache import MemcachedCache
cache = MemcachedCache(['127.0.0.1:11211']) cache = MemcachedCache(['127.0.0.1:11211'])
@ -24,15 +24,15 @@ def predict(fieldtype, term):
print(fieldtype) print(fieldtype)
print(term) print(term)
if not term: if not term:
return "[]" return jsonify([])
else: else:
try: try:
cs = completers[fieldtype](term.lower()) cs = completers[fieldtype](term.lower())
except KeyError: except KeyError:
return "[]" return jsonify([])
if cs: if cs:
return cs return cs
return "[]" return jsonify([])
def predictor(fieldtype): def predictor(fieldtype):
def inner(request): def inner(request):
@ -106,14 +106,14 @@ def ClassSearch(configfile=None):
try: try:
params = loads(unquote(dict(request.args.items())["data"])) params = loads(unquote(dict(request.args.items())["data"]))
except KeyError: except KeyError:
return dumps("false") return jsonify("false")
print(params) print(params)
author = params["author"] author = params["author"]
title = params["title"] title = params["title"]
if ("No Textbooks" in title or if ("No Textbooks" in title or
"No Adoption" in title): "No Adoption" in title):
return dumps("false") return jsonify("false")
# Cache the result of the open library search # Cache the result of the open library search
openlib = cacheit("openlib"+title+author, lambda : bookUrls(title, author)) openlib = cacheit("openlib"+title+author, lambda : bookUrls(title, author))
@ -125,9 +125,9 @@ def ClassSearch(configfile=None):
if not (any(openlib) or any(iarchive)): if not (any(openlib) or any(iarchive)):
# We literally could not find ANYTHING # We literally could not find ANYTHING
return dumps("false") return jsonify("false")
return dumps({ return jsonify({
"iarchive" : iarchive, "iarchive" : iarchive,
"openlib" : openlib "openlib" : openlib
}) })

Loading…
Cancel
Save