#!/usr/bin/env python2 # -*- coding: utf-8 -*- import os import re import string import sys import regex import datetime gridheader=r"""\documentclass[10pt]{article} \pagestyle{empty} \usepackage[text={7.5in,10.25in}]{geometry} \newcommand{\session}[3]{ \textbf{#1} & #3 & #2\\} \newcommand{\blocks}[1]{ Session & #1 & Room(s) \\} \newcommand{\blocktotal}[1]{\textbf{Sessions:} & #1 & \\} \newcommand{\speakerstotal}[1]{\textbf{Invited:} & #1 & \\} \newcommand{\invitedcount}[1]{\begin{tabular}[t]{r|lllllll|l} \cline{2-8} There are & #1 & Sessions \\ With & 0 & 1 & 2 & 3 & 4 & 5 & 6+ & Invited Talks \\ Symbol: & \tzero & \tone & \ttwo & \tthree & \tfour & \tfive & \tsix\\ \cline{2-8} \end{tabular} } \newcommand{\ns}{ } \newcommand{\tzero}{$\circ$} \newcommand{\tone}{$\star$} \newcommand{\ttwo}{$\star$} \newcommand{\tthree}{$\star$} \newcommand{\tfour}{$\bullet$} \newcommand{\tfive}{$\bullet$} \newcommand{\tsix}{$\diamond$} \renewcommand{\arraystretch}{0.9} \setlength{\parindent}{0pt} """ #%% epitomeheader="""\\documentclass[10pt]{article} \\usepackage[text={7.5in,9.3in},centering]{geometry} \\usepackage{mhchem} \\setlength{\\parindent}{0pt} \setlength{\\tabcolsep}{.2ex} \\newcommand{\\focus}[1]{\\textit{#1}} \\newcommand{\\invited}[1]{\\textbf{#1}} \\newcommand{\\sessioncount}[1]{\\normalsize Total Sessions:#1} """ #%% talksheader=r"""\documentclass[10pt]{article} \usepackage[text={6.5in,9in},centering]{geometry} \usepackage{mhchem} \newcommand{\talk}[6]{\item[#1#2.#3] #4: #5 \textsc{#6}} \newcommand{\sessionskip}{\paragraph*{}\par} \newcommand{\blockskip}{\newpage\section*{}\par} \newcommand{\sessiontitle}[3]{\small \item \textbf{#1: #2}\quad Room:~\textsc{#3}} \newcommand{\specialtitle}[3]{\small \item \textbf{Special Session \ #1: #2}\quad Room:~\textsc{#3}\ \\ \textit{Start times after first talk are approximate}} \newcommand{\focus}[1]{\textit{#1}} \newcommand{\invited}[1]{\textbf{#1}} \makeatletter \newcommand{\ps@invited}{% \renewcommand{\@oddhead}{March Meeting Invited Talks. \hfil} \renewcommand{\@evenhead}{\@oddhead} \renewcommand{\@oddfoot}{ \hfil \focus{Focus Sessions} in italics, \invited{Invited Sessions} in bold.} \renewcommand{\@evenfoot}{\@oddfoot}} \makeatother \pagestyle{invited} \newcommand{\talklabel}[1]{\hfil\normalsize\textbf{#1}} \newenvironment{talklist}{% \begin{list}{}{\renewcommand{\makelabel}{\talklabel}% \setlength{\labelwidth}{5em} \setlength{\labelsep}{1ex} \setlength{\leftmargin}{0pt} % \setlength{\rightmargin}{0pt} \setlength{\parsep}{0pt} \setlength{\itemsep}{0pt} }} % {\end{list}} \begin{document} \begin{talklist} \small """ totalsessioncount=0 regularsessioncount=0 invitedcount=0 focussessioncount=0 # The sessioncounts are used in summary after grid sessiongridlist=[] #sessiongridlist is the list of session numbers. Occasionally there have been no sessions of a particular number #can handle alphanumeric sessions, and is used for indexing roomArray and looping through session numbers #to make the grid maxsessions=0 #Used as the upper bound in the loop to fill in any missing session numbers regularsession=False newsession=False clockstring="%I:%M%p" fieldsepmarker=" & " roomsubtext=[] #roomsubtext will be the list of room abbreviations to be used currentblock="" regularsessions=[] #is a list of regular session blocks. Used for several looping operations. Formerly, blocklist #duplicated this but these have been combined specialsessions=[] #Stores a list of block+session for non-regular sessions that are not ignored. Used in compiling invited # talk list. Formerly duplicate of usefulspecialsessions, now combined, so the elements are indices # to thetimes{} and sessionlist{} for the Epitome usefulblocks=[] # a list of regular session blocks and non-ignored, non-regular block+sessions. For some looping # essentially combines regularsessions and specialsessions # used as looping for speakers file to combine all sessions (regular+special) in chronological order invcount={} #invcount: how many sessions have n invited talks, n=0..6, n-indexed dict starttime={} #starttime is block-indexed dict of datetime.datetime objects used for calculating invited talk start times thetimes={} #block-indexed dict of starting times and days of week of each regular block and special block+session. #Used to write epitome block headings and speakers block page headings sessiontitles={} #sessiontitles is a block+session indexed dict of lists consisting of block+session, cleaned #session title, and cleaned room number. Each represents a field for a TeX macro to write the #session info on the invited speaker list, which will be sorted by session sessionlist={} #sessionlist is a block-indexed dict consisting of a list of lists for each block of the sessions. #primary output for the Epitome. #each block's outer list has as its contents a list for each session #each session's inner list is a list of fields to be the inputs to a TeX macro, specifically, #the block+session, the number of invited talks, the cleaned title, and the cleaned room sessionArray={} #a block-indexed dict that counts how many session are occuring in each block, to be output in the grid invitedArray={} #a block-indexed dict that counts how many invited talks in each schedule block roomArray={} # a session-number-indexed dict that, for each session number n, holds a list of all the rooms that # sessions [A-Z]n are held in. Usually, e.g., B28, C28, E28, ... are in the same room, but there are # some swaps. Used as output in the grid talkarray={} # a block+session-indexed dict counting the invited speakers in each individual session. Each is capped # at six, this is the main array for constructing the grid romanArray={} #romanArray dict, indexed by roman numberal, tracks how many sessions have each roman numeral (or #equivalent arabic number) as a part indicator romanMax=0 romanDisplayMax=20 #Maximum number of multi-part sessions to display after the grid multititle={} #multititle is a title-indexed dict of all the roman numerals associated with a title invitedtalklist=[] # a list of block+session+talknumber of all invited talks, gleaned from the invited talk list # apparently used only to find duplicate invited talk entries, which I guess has happened # on occation talklist={} # a block-indexed dict of lists of lists. The inner lists are the fields that will be fed # to a TeX macro for each invited talk: the block, session, talk number, speaker, title, and time # the outer list is the list of each of these talks in an entire block. # each outer list is sorted primarily by session number and secondarily by talk number, for output # we step through the list and make session breaks where necessary marchdirectory=os.getcwd() for i in range(7): invcount[i]=0 numwords=["zero","one","two","three","four","five","six","seven","eight"] #%% epitomere=re.compile('Mar([0-9]+)_epitome\.txt') invitedre=re.compile('Mar[0-9]+_invited\.txt') textsubre=re.compile('Mar[0-9]+_textsub\.txt') blockre=re.compile('(Feb|Mar) [0-9]+ 20[0-9][0-9] ([1-9][012]?:[0-9][0-9][AP]M), ([MTWFS][a-z]+)') blockidre=re.compile('([1-9]?[A-Za-z])([0-9]+[A-Za-z]?) (.+)\n') roomre=re.compile('Room: (.+)') sponsorre=re.compile('(.+?) [A-Z][a-z]+:.*') speakersre=re.compile('Invited Speakers: (.*)') ignorere=re.compile('Poster|Business') regulartimes=("8:00AM", "11:15AM", "2:30PM") focusre=re.compile('Focus (?:Session)?:?(.+)') invitedsessionre=re.compile('Invited (?:Session)?:?(.+)') multisessionre=re.compile(r'\b[IVX]+(?!-[Rr])(?=:|-|\Z|\))') numeralsessionre=re.compile('(?','$>$'), ('<','$<$'), (r'\s"',' ``')] # textsublist is substitutions to make TeX look nicer chemformulare=regex.compile(r'''(?x) (?(DEFINE) (?He|Li|Be|Ne|Na|Mg|Al|Si|Cl|Ar|Ca|Sc|Ti|Cr|Mn|Fe|Co|Ni|Cu|Zn|Ga|Ge|As|Se|Br|Kr|Rb|Sr|Zr|Nb|Mo|Tc|Ru|Rh|Pd|Ag|Cd|In|Sn|Sb|Te|Xe|Cs|Ba|La|Ce|Pr|Nd|Pm|Sm|Eu|Gd|Tb|Dy|Ho|Er|Tm|Yb|Lu|Hf|Ta|Re|Os|Ir|Pt|Au|Hg|Tl|Pb|Bi|Po|At|Rn|Fr|Ra|Ac|Th|Pa|Np|Pu|Am|Cm|Bk|Cf|Es|Fm|Md|No|Lr|Rf|Db|Sg|Bh|Hs|Mt|Ds|Rg|Cn|Nh|Fl|Mc|Lv|Ts|Og|H|B|C|N|O|F|P|S|V|K|Y|I|W|U) (?[1-9]\d*) (?(?&Element)(?&Num)?) ) (?P\b(?&ElementGroup)+(?!\.)\b) ''') alphanumsessionre=re.compile('([1-9][0-9]*)([A-Za-z]*)') def alphanumsessionkey(s): t=alphanumsessionre.search(s).groups() u=int(t[0]) v=t[1].upper() return (u,v) #%% def texstringclean(s): # texspecial=("\\", "#", "$", "%", "&", "~", "_", "^", "{", "}") texspecial=("#", "%", "&", "~", "^") # There are occasionally authors who still use TeX $ and _ in their titles as TeX directives # and we want to use these and not print them literally. Also, for manual edits of invited talk # titles with super/sub scripts, want to add $, _, {, }, for a in texspecial: s=s.replace(a, '\\'+a) return s #%% cwdfilelist=os.listdir(marchdirectory) epitomefilelist=[f for f in cwdfilelist if epitomere.match(f)] invitedfilelist=[f for f in cwdfilelist if invitedre.match(f)] roomsubfilelist=[f for f in cwdfilelist if textsubre.match(f)] if epitomefilelist and invitedfilelist: epitomefile=os.path.join(marchdirectory, epitomefilelist[0]) invitedfile=os.path.join(marchdirectory, invitedfilelist[0]) conferenceyear=epitomere.match(epitomefilelist[0]).group(1) else: if not epitomefilelist: print "No Epitome File" if not invitedfilelist: print "No Invited Talk File" if roomsubfilelist: with open(os.path.join(marchdirectory,roomsubfilelist[0]), 'r') as roomsubfile: roomsublist=[tuple(sub.split(',')) for sub in roomsubfile.read().splitlines()] roomsubtext=", ".join([textlong+"="+textshort for textlong,textshort in roomsublist if textshort != '']) # ============================================================================= # I'm combining what might need to be two separate ideas: substitutions to make # the TeX come out better, as the default textsublist item, and items to make # the room names take up less space, which has been a problem in some years # when the entire convention center name is spelled out # ============================================================================= #%% with open(epitomefile, 'r') as content_file: epitometext= content_file.read().split('\n\n') content_file.close() def makeroomset(): '''this would be a program run before the data processing to assist with compiling the text substitution list. Not sure how we'll run this eventually (shell or Sypder) so not sure what all to include.''' roomlist=[] for f in epitometext: room=roomre.search(f) sponsormatch=sponsorre.match(room) if sponsormatch: room=sponsormatch.group(1) roomlist.append(room) return set(roomlist).union() for s in epitometext: focusSession=False invitedSession=False blocktime=blockre.search(s) if blocktime: month, thetime, dayofweek=blocktime.groups() newsession=True blockmatch=blockidre.search(s) roommatch=roomre.search(s) speakersmatch=speakersre.search(s) if blockmatch and roommatch: block, session, title=blockmatch.groups() if not ignorere.search(title): if block != currentblock: newsession=True currentblock=block if newsession: specialsession=False ignoresession=False regularsession=False if thetime in regulartimes: regularsession=True regularsessions.append(block) else: specialsession=True currentblock=block+session specialsessions.append(currentblock) usefulblocks.append(currentblock) thetimes[currentblock]=thetime.lower() + ' ' + dayofweek starttime[currentblock]=datetime.datetime.strptime(thetime,clockstring) room=roommatch.group(1) sponsormatch=sponsorre.match(room) if sponsormatch: room=sponsormatch.group(1) speakernum=0 if speakersmatch: speakernum=len(speakersmatch.group(1).split(',')) invitedcount+=speakernum focus=focusre.match(title) if focus: title=focus.group(1) focussessioncount+=1 focusSession=True invited=invitedsessionre.match(title) if invited: title=invited.group(1) invitedSession=True title=texstringclean(title).strip(' "') for sub in textsubrelist: title=re.sub(sub[0],sub[1],title) multisession=multisessionre.search(title) if multisession: romanNumber=multisession.group(0) if romanNumber in romanArray: romanArray[romanNumber]+=1 else: romanArray[romanNumber]=1 arabicNumber=romanlist.index(romanNumber) romanMax=max(romanMax,arabicNumber) noRomanTitle=title[0:multisession.start()].strip() noRomanTitle=noRomanTitle.replace('Focus','').strip() noRomanTitle=' '.join([w.title() if w.islower() else w for w in noRomanTitle.split()]) if noRomanTitle in multititle: multititle[noRomanTitle].append(romanNumber) else: multititle[noRomanTitle]=[romanNumber] chemtitle=title[0:multisession.start()] title=chemformulare.sub(r'\ce{\g}',chemtitle)+title[multisession.start():] else: title=chemformulare.sub(r'\ce{\g}',title) # We need to parse roman numbers before chemicals, because many Roman numbers match as chemical formulas, but # for some reason, some multisession series use Arabic numbers instead of the much more common Roman numerals numeralsession=numeralsessionre.search(title) if numeralsession: romanNumber=romanlist[int(numeralsession.group(0))] arabicNumber=romanlist.index(romanNumber) romanMax=max(romanMax,arabicNumber) if romanNumber in romanArray: romanArray[romanNumber]+=1 else: romanArray[romanNumber]=1 noRomanTitle=title[0:numeralsession.start()].strip() noRomanTitle=noRomanTitle.replace('Focus','').strip() noRomanTitle=' '.join([w.title() if w.islower() else w for w in noRomanTitle.split()]) if noRomanTitle in multititle: multititle[noRomanTitle].append(romanNumber) else: multititle[noRomanTitle]=[romanNumber] if not title[-1] in '.!?': title+='.' for sub in roomsublist: room=room.replace(sub[0],sub[1]) if focusSession: title=r'\focus{'+title+'}' if invitedSession: title=r'\invited{'+title+'}' room=room.strip().replace(' ','~') sessiontitles[currentblock+session]=[block+session, title, room] title +=' \\textsc{'+room+'}' speakertext='\\tiny('+str(speakernum)+')' if currentblock in sessionlist: sessionlist[currentblock].append([block+session, speakertext, title]) else: sessionlist[currentblock]=[[block+session, speakertext, title]] totalsessioncount +=1 if block in invitedArray: invitedArray[block]+=speakernum else: invitedArray[block]=speakernum speakernum=min(speakernum,6) invcount[speakernum]+=1 # Comments from tcl: # There are only one or two sessions each year with more than 5 speakers, # usually a panel or something. To simplify the counting, we're using 6 to # denote 6+, but all speakers are added to invited speaker count # invcount(n) counts the number of sessions with n invited # speakers #we will count invited speakers and sessions for the special #sessions but only want to build the grid for regular sessions if regularsession: if not session in sessiongridlist: sessiongridlist.append(session) regularsessioncount+=1 if block in sessionArray: sessionArray[block]+=1 else: sessionArray[block]=1 if session in roomArray: if not room in roomArray[session]: roomArray[session].append(room) else: roomArray[session]=[room] talkarray[block+session]=speakernum if session.isdigit(): maxsessions=max(maxsessions,int(session)) newsession=False epitomefilepath=os.path.join(marchdirectory,"Mar"+conferenceyear+"_Epitomepy.tex") epitometexfile=open(epitomefilepath, 'w') epitometexfile.write(epitomeheader) epitometexfile.write("""\\makeatletter \\newcommand{\\ps@epitome}{%\r""") epitometexfile.write("\\renewcommand{\\@oddhead}{March Meeting 20"+conferenceyear +". \\hfil \\textit{Focus Sessions} in italics \\textbf{Invited Sessions} in bold {\\tiny(Invited talk \\# in parenthesis)} }\r") epitometexfile.write("\\renewcommand{\\@evenhead}{\\@oddhead}\r") epitometexfile.write("\\renewcommand{\\@oddfoot}{{\\scriptsize "+roomsubtext+ "}\\hfil}\r") epitometexfile.write("""\\renewcommand{\\@evenfoot}{\\@oddfoot} } \\makeatother \\makeatletter \\newcommand{\\ps@specialepitome}{% """) epitometexfile.write("\\renewcommand{\\@oddhead}{March Meeting 20"+conferenceyear+ "\\hfil Special Sessions {\\tiny(Invited talk \\# in parenthesis)} }\r") epitometexfile.write("\\renewcommand{\\@evenhead}{\\@oddhead}\r") epitometexfile.write("\\renewcommand{\\@oddfoot}{{\\scriptsize "+roomsubtext+ "}\\hfil}\r") epitometexfile.write("""\\renewcommand{\\@evenfoot}{\\@oddfoot} } \\makeatother \\pagestyle{epitome} \\begin{document} \\small """) for block in regularsessions: epitometexfile.write("\\begin{tabular}{rrp{6.5in}l}\r") epitometexfile.write("\\multicolumn{4}{l}{\\textsc{"+ thetimes[block]+ "}} \\\\ \r") for session in sessionlist[block]: epitometexfile.write(fieldsepmarker.join(session)+" \\\\ \r") epitometexfile.write("""\\end{tabular}\r\r \\smallskip \\bigskip """) epitometexfile.write("""\\newpage \\pagestyle{specialepitome} """) for block in specialsessions: epitometexfile.write("\\begin{tabular}{rrp{6.5in}l}\r") epitometexfile.write("\\multicolumn{4}{l}{\\textsc{"+ thetimes[block]+ "}} \\\\ \r") for session in sessionlist[block]: epitometexfile.write(fieldsepmarker.join(session)+" \\\\ \r") epitometexfile.write("""\\end{tabular}\r\r \\smallskip \\bigskip """) epitometexfile.write("\\end{document}\r") epitometexfile.close() #%% ### ### Invited Speaker List ### with open(invitedfile, 'r') as content_file: invitedtext= content_file.read().splitlines() content_file.close() invitedtext=[invitedtext[i:i+2] for i in range(0,len(invitedtext),2)] for talk in invitedtext: author=talk[0].strip() block,session,talknumber,title,room=talkre.search(talk[1]).groups() room=room.strip().replace(' ','~') for sub in roomsublist: room=room.replace(sub[0],sub[1]) title=texstringclean(title).strip(' ".') for sub in textsubrelist: title=re.sub(sub[0],sub[1],title) title=chemformulare.sub(r'\ce{\g}',title) if not title[-1] in '.?!': title=title+'.' talkID=block+session+'.'+talknumber bls=block+session talkEntry=[block,session,talknumber,author,title] # Below is the minimalist version if not talkID in invitedtalklist: invitedtalklist.append(talkID) if bls in specialsessions: if bls in talklist: talklist[bls].append(talkEntry) else: talklist[bls]=[talkEntry] elif block in regularsessions: if block in talklist: talklist[block].append(talkEntry) else: talklist[block]=[talkEntry] else: print "Neither special nor regular "+talkID else: print "Duplicate "+talkID+"in invitedtalklist" for block in usefulblocks: if block in talklist: talklist[block].sort(key=lambda x:(x[1],x[2])) speakersfilepath=os.path.join(marchdirectory,"Mar"+conferenceyear+"_Invitedpy.tex") speakerstexfile=open(speakersfilepath, 'w') speakerstexfile.write(talksheader) for currentblock in usefulblocks: if currentblock in regularsessions: regularsession=True outputline=r'\sessiontitle' else: regularsession=False outputline=r'\specialtitle' if currentblock in talklist: speakerstexfile.write(r'''\makeatletter \renewcommand{\ps@invited}{% ''') speakerstexfile.write(r'\renewcommand{\@oddhead}{March Meeting 20'+conferenceyear+ r' Invited Talks. \hfil \textbf{'+currentblock+r'} \textsc{'+ thetimes[currentblock]+'}}\r') speakerstexfile.write(r'''\renewcommand{\@evenhead}{\@oddhead} \renewcommand{\@oddfoot}{{\scriptsize ''') speakerstexfile.write(roomsubtext+'}\hfil}\r') speakerstexfile.write(r'''\renewcommand{\@evenfoot}{\@oddfoot} } \makeatother \pagestyle{invited} ''') currentsession=talklist[currentblock][0][1] speakerstexfile.write(outputline) for field in sessiontitles[currentblock+currentsession]: speakerstexfile.write('{'+field+'}') speakerstexfile.write('\r') invited=0 for talk in talklist[currentblock]: if talk[1] != currentsession: speakerstexfile.write('\\sessionskip\r') currentsession=talk[1] speakerstexfile.write(outputline) for field in sessiontitles[currentblock+currentsession]: speakerstexfile.write('{'+field+'}') speakerstexfile.write('\r') invited=0 speakerstexfile.write(r'\talk') index=int(talk[2]) offset=12*(index-1)+(36-12)*invited talk.append((starttime[currentblock]+datetime.timedelta(minutes=offset)).strftime(clockstring).lower()) invited+=1 for field in talk: speakerstexfile.write('{'+field+'}') speakerstexfile.write('\r') speakerstexfile.write('\\blockskip\r') speakerstexfile.write(r'''\end{talklist} \end{document} ''') speakerstexfile.close() #%% ### ### Grid Output ### gridfilepath=os.path.join(marchdirectory,"Mar"+conferenceyear+"_Gridpy.tex") gridtexfile=open(gridfilepath, 'w') gridtexfile.write(gridheader) gridtexfile.write(r'''\begin{document} \begin{center} ''') gridtexfile.write('March Meeting 20'+str(conferenceyear)+' Rooms and Sessions\r') gridtexfile.write(r'''\end{center} \medskip \begin{tabular}[t]{r|ccc|ccc|ccc|ccc|cc|l} ''') gridtexfile.write(r'\blocks{'+fieldsepmarker.join(regularsessions)+'}\r') gridtexfile.write('\\hline\r') #Occasionally, a session number is skipped over all the sessions. Here we add any missing #session numbers to sessiongridlist sessionnumlist=[int(s) for s in sessiongridlist if s.isdigit()] for i in range(1,maxsessions+1): if not i in sessionnumlist: sessiongridlist.append(str(i)) # We'll need a sort of natural sorting key or function if we have alphanumeric sessions sessiongridlist.sort(key=alphanumsessionkey) for labeledsession in sessiongridlist: if labeledsession in roomArray: gridtexfile.write(r'\session{'+labeledsession+'}{'+ ', '.join(roomArray[labeledsession])+'}') else: gridtexfile.write(r'\session{'+labeledsession+'}{}') sessionout=[] for block in regularsessions: if block+labeledsession in talkarray: sessionout.append(r'\t'+numwords[talkarray[block+labeledsession]]) else: sessionout.append(r'\ns') gridtexfile.write('{'+fieldsepmarker.join(sessionout)+'}\r') gridtexfile.write('\\hline\r') gridtexfile.write(r'\blocktotal{'+fieldsepmarker.join( [str(sessionArray[s]) for s in regularsessions])+'}\r') gridtexfile.write(r'\speakerstotal{'+fieldsepmarker.join( [str(invitedArray[b]) for b in regularsessions])+'}\r') gridtexfile.write('\\end{tabular}\r\r') gridtexfile.write(roomsubtext+'\r\r') gridtexfile.write('Sessions: '+str(regularsessioncount)+' Regular, '+ str(focussessioncount)+ ' Focus, '+ str(totalsessioncount)+ ' Total.\r') gridtexfile.write('Invited Speakers: '+str(invitedcount)+' (Epitome), '+ str(len(invitedtalklist))+' (Invited List)\r\r') gridtexfile.write(r'\invitedcount{'+fieldsepmarker.join( [str(invcount[i]) for i in range(7)])+'}\r') #The invited count can easily be handled by a macro because there always 0-5 plus 6+ invited talks #however with the roman numerals we don't know how far they'll go so we need to construct our own #grid here with python gridtexfile.write('\r\r') gridtexfile.write(r'''\bigskip \begin{tabular}[t]{r|''') gridtexfile.write('l'*romanMax) gridtexfile.write('|l}\r') gridtexfile.write(r'\cline{2-'+str(romanMax+1)+'}\r') gridtexfile.write('There are & ') gridtexfile.write(fieldsepmarker.join([str(romanArray[romanlist[i]]) for i in range(1,romanMax+1)])) gridtexfile.write(r''' & Multi-part sessions with \\ a part of & ''') gridtexfile.write(fieldsepmarker.join([str(r) for r in romanlist[1:romanMax+1]])) gridtexfile.write(r''' & \\ \cline{2-''') gridtexfile.write(str(romanMax+1)+'}\r') gridtexfile.write(r'''\end{tabular} \bigskip ''') romanDisplayList=[romanlist.index(i) for i in romanlist[1:romanMax+1] if romanArray[i]