 #####################################################################
#	Routines for Image Loop Webpage
#	10.3.2005
#	David Carey
#	
#####################################################################

import cgi, os, os.path, glob, re, string

#	points to web root from os side
base_directory_path = '/home/disk/user_www/'

# points to web root from browser side
base_URL = 'http://www.atmos.washington.edu/~'


######################################################################
# condition path
######################################################################

def condition_path(url):
	# strip leading/trailing whitespace
	url = url.rstrip()
	strings = []
	# convert URL to path relative to web server root
	if url.count('~') != 0:
		url = url.split('~')
		strings.append(base_directory_path)
		strings.append(url[1])
	elif url.count('home/disk/user_www') != 0:
		# already in correct format
		strings.append(url)
	else:
		# url is empty or unreadable
		strings ='no url'
	return ''.join(strings)
	
			
######################################################################
# validate path
######################################################################

def validate_path(url):
	strings = []
	# is this a valid path?
	if not os.path.isdir(url):
		strings.append('not a valid directory')	
	else:
		if not is_loop(url):
			strings.append('not a loopable directory')
		else:
			strings.append('is a loopable directory')
	return ''.join(strings)	
	

######################################################################
# get path given URL
######################################################################

def path_from_url(url):
	path = base_directory_path+os.path.abspath(url)
	return path

######################################################################
# get URL given path
######################################################################

def url_from_path(path):
	path = os.path.abspath(path)
	url = path.replace(str(base_directory_path),str(base_URL))
	return url	


######################################################################
# validate query string
######################################################################

def validate_query_string(query_string):

	return query_string


######################################################################
#    count files
######################################################################

def count_files(path,filetype):
	"""
	return the number of files (of a specified type) in a directory
	"""
	files = glob.glob1(path,filetype)
	return len(files)


######################################################################
#    first image in array
######################################################################

def get_first_image(path,filetype):
	"""
	return the first file in the looping directory for pre-loading into the page 
	"""
	files = glob.glob1(path,filetype)
	files.sort()
	
	# number of files in directory
	num_files = count_files(path,filetype)

	# file number index for generating array
	image_number=0
	
	# hold strings for constructing array code
	strings = []
	if num_files > 0:
			strings.append(url_from_path(path +'/'+ files[0]))
	else: strings.append('						// ERROR: no image files found\n')
	results = "".join(strings)
	return results

######################################################################
#    last image in array (most recent)
######################################################################

def get_last_image(path,filetype):
	"""
	return the last file (newest) in the looping directory for pre-loading into the page 
	"""
	files = glob.glob1(path,filetype)
	files.sort()
	
	# number of files in directory
	num_files = count_files(path,filetype)

	# file number index for generating array
	image_number=0
	
	# hold strings for constructing array code
	strings = []
	if num_files > 0:
			strings.append(url_from_path(path +'/'+ files[num_files-1]))
	else: strings.append('						// ERROR: no image files found\n')
	results = "".join(strings)
	return results


######################################################################
#    draw image and control bar
######################################################################

def draw_controlbar(name):
	strings.append('								<table class="grayBorder">\n')
	strings.append('								<tr>\n')
	strings.append('								<td class="controlLabelText">onMouseOver=document.'+name+'Form.'+name+'.src="animation_buttons/'+name+'Play()\');\n')
	strings.append('								tmp += '+name+'DrawButton(\''+name+'Play\', \'Play\', \''+name+'StartPlay()\');\n')
	strings.append('								tmp += '+name+'DrawButton(\''+name+'Pause\', \'Pause\', \''+name+'StopPlay()\');\n')
	strings.append('								tmp += '+name+'DrawButton(\''+name+'First\', \'First image\', \''+name+'FirstImage()\');\n')
	strings.append('								tmp += '+name+'DrawButton(\''+name+'Prev\', \'Previous image\', \''+name+'StepBackward()\');\n')
	strings.append('								tmp += '+name+'DrawButton(\''+name+'Next\', \'Next image\', \''+name+'StepForward()\');\n')
	strings.append('								tmp += '+name+'DrawButton(\''+name+'Last\', \'Last image\', \''+name+'LastImage()\');\n')
	strings.append('								tmp += \'<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Speed:</td>\';\n')
	strings.append('								tmp += '+name+'DrawButton(\''+name+'Slowdown\', \'Slower\', \''+name+'Slower()\');\n')
	strings.append('								tmp += '+name+'DrawButton(\''+name+'Speedup\', \'Faster\', \''+name+'Faster()\');\n')
	strings.append('								tmp += '+name+'DrawButton(\''+name+'Speedreset_en\', \'Reset\', \''+name+'SpeedReset()\');\n')
	strings.append('							\n')
	strings.append('									tmp += \'onMouseOver=document.'+name+'Form.\' + targetName + \'.src="animation_buttons/\' + targetName + \'_over.png" \';\n')
	strings.append('									tmp += \'onMouseOut=document.'+name+'Form.\' + targetName + \'.src="animation_buttons/\' + targetName + \'.png" \';\n')
	strings.append('								} else {\n')
	strings.append('									tmp = \'<td><a href="javascript:\'+ clickFunction+ \'"><img name="\' + targetName + \'" src="animation_buttons/\' + name + \'_greyed.png" alt="\' + alt + \'" \';\n')
	strings.append('								}\n')
	strings.append('								tmp += \'onClick="\' + clickFunction + \'" border="0"></a></td>\';\n')


######################################################################
#   create common javascript code for entire page	8.26.2005
######################################################################

def get_common_javascript_code():

	strings = []
	strings.append('							<SCRIPT language="JavaScript">\n')
	strings.append('							<!--\n')	
	strings.append('\n')
	strings.append('							//--------------------------------------------------------------------------\n')
	strings.append('							//     c o m m o n   c o d e \n')
	strings.append('							//--------------------------------------------------------------------------\n')
	strings.append('\n')
	strings.append('								var preloadedImages=new Array();\n')
	strings.append('\n')
	strings.append('								function preloadimages(){\n')
	strings.append('									//\n')
	strings.append('									// pre-load button graphics\n')
	strings.append('									//\n')
	strings.append('\n')
	strings.append('									for (i=0;i<preloadimages.arguments.length;i++){\n')
	strings.append('										preloadedImages[i]=new Image();\n')
	strings.append('										preloadedImages[i].src=preloadimages.arguments[i];\n')
	strings.append('									}\n')
	strings.append('								}\n')
	strings.append('\n')
	strings.append('								// variables\n')
	strings.append('								icon_dir = \'animation_buttons\';\n')
	strings.append('\n')
	strings.append('								// text box label\n')
	strings.append('								textBoxLabel = \'<span class="control_label"><!-- caption here --></span>\';\n')
	strings.append('\n')
	strings.append('														//-->\n')
	strings.append('								</SCRIPT>\n')
	result = ''.join(strings)
	return result


######################################################################
#   create javascript code for each pane	8.26.2005
######################################################################

def get_javascript_code(path,filetype,name):

	# enforce initial capitalization of name
	name = string.capitalize(name)
	
	strings = []
	strings.append('						<SCRIPT language="JavaScript">\n')
	strings.append('							<!--\n')
	strings.append('							//--- '+name+' -------------------------------------------------------------\n')
	strings.append('							//--------------------------------------------------------------------------\n')
	strings.append('							//     p a n e   s p e c i f i c   v a r i a b l e s \n')
	strings.append('							//--------------------------------------------------------------------------\n')
	strings.append('\n')	
	strings.append('\n')	
	strings.append('								// number of individual '+name+'Speed steps\n')
	strings.append('								numberOf'+name+'Speeds = 20;\n')
	strings.append('\n')	
	strings.append('								// init'+name+'Speed: initial animation '+name+'Speed\n')
	strings.append('								init'+name+'Speed = 16;\n')
	strings.append('								'+name+'Speed = init'+name+'Speed;\n')
	strings.append('\n')	
	strings.append('								// initial '+name+'Delay value\n')
	strings.append('								'+name+'Delay=800;\n')
	strings.append('\n')
	strings.append('\n')
	strings.append('							//--------------------------------------------------------------------------\n')
	strings.append('							//     p a n e   s p e c i f i c    f u n c t i o n s\n')
	strings.append('							//--------------------------------------------------------------------------\n')
	strings.append('\n')
	strings.append('								function '+name+'Startup() {\n')
	strings.append('									//\n')
	strings.append('									// startup: update the '+name+' speed and frame text widgets\n')
	strings.append('									//\n')
	strings.append('\n')			
	strings.append('									set'+name+'Images(0);\n')
	strings.append('									set'+name+'Delay();\n')
	strings.append('\n')	
	strings.append('								}\n')
	strings.append('\n')
	strings.append('							//---------------------------------------------------------------------\n')
	strings.append('\n')	
	strings.append('								function draw'+name+'ImageTextbox() {\n')
	strings.append('									// \n')
	strings.append('									// draw '+name+' text box\n')
	strings.append('									//\n')
	strings.append('\n')
	strings.append('									tmp = \'\';\n')
	strings.append('									tmp = \'<div align="center" class="contol_label">\';\n')
#	strings.append('		tmp += \'<span class="control_label">\';\n')
	strings.append('									tmp += textBoxLabel;\n')
#	strings.append('		tmp += \'</span>\';\n')
#	strings.append('									tmp += \'<INPUT TYPE="text" SIZE="21" MAXLENGTH="21" Name="'+name+'ImageText" Value="" onChange="update'+name+'ImageText()" >\';\n')
	strings.append('									tmp += \'<INPUT TYPE="text" SIZE="21" MAXLENGTH="21" Name="'+name+'ImageText" Value="" >\';\n')
	strings.append('									tmp += \'</div>\';\n')
	strings.append('									return tmp;\n')
	strings.append('								} \n')
	strings.append('\n')
	strings.append('							//---------------------------------------------------------------------\n')
	strings.append('\n')	
	strings.append('								function set'+name+'MouseOver(img) {\n')
	strings.append('									if ('+name+'ClickPlay == 1) {\n')
	strings.append('										img.src=\'animation_buttons/\' + img.name + \'_over.gif\';\n')
	strings.append('									} else {\n')
	strings.append('										img.src=\'animation_buttons/\' + img.name + \'_greyed.gif\';\n')
	strings.append('									}\n')
	strings.append('								}\n')
	strings.append('\n')
	strings.append('							//---------------------------------------------------------------------\n')
	strings.append('\n')
	strings.append('							        function set'+name+'MouseOut(img) {\n')
	strings.append('								        if ('+name+'ClickPlay == 1) {\n')
	strings.append('									        img.src=\'animation_buttons/\' + img.name + \'.gif\';\n')
	strings.append('								        } else {\n')
	strings.append('									        img.src=\'animation_buttons/\' + img.name + \'_greyed.gif\';\n')
	strings.append('								        }\n')
	strings.append('							        }\n')
	strings.append('\n')
	strings.append('						        //---------------------------------------------------------------------\n')
	strings.append('\n')	
	strings.append('								function draw'+name+'Button(name, alt, clickFunction, over_img) {\n')
	strings.append('									// NS 4 doesn\t support image button\n')
	strings.append('									var browser = navigator.appName;\n')
	strings.append('									var version = parseInt(navigator.appVersion);\n')
	strings.append('									\n')
	strings.append('\n')
	strings.append('									if ((browser==\'Netscape\') &&  (version == 4)) {     // Netscape 4\n')
	strings.append('										if(name == \'play\') {\n')
	strings.append('											tmp = \'<td><a href="javascript:\'+ clickFunction+ \'"><img name="\' + name + \'" src="animation_buttons/\' + name + \'.gif" alt="\' + alt + \'" \';\n')
	strings.append('											tmp += \'onMouseOver=document.'+name+'Form \' + name + \'.src="animation_buttons/\' + name + \'_over.gif" \';\n')
	strings.append('											tmp += \'onMouseOut=document.'+name+'Form.\' + name + \'.src="animation_buttons/\' + name + \'.gif" \';\n')
	strings.append('										} else {\n')
	strings.append('											tmp = \'<td><a href="javascript:\'+ clickFunction+ \'">')
	strings.append('											<img name="\' + name + \'" src="animation_buttons/\' + name + \'_greyed.gif" alt="\' + alt + \'"\'; \n')
	strings.append('										}\n')
	strings.append('										tmp += \'onClick="\' + clickFunction + \'" border="0"></a></td>\';\n')
	strings.append('									} else {     // NOT Netscape\n')
	strings.append('										if(name == \'play\') {\n')
	strings.append('											tmp = \'<td><img name="\' + name + \'" src="animation_buttons/\' + name + \'.gif" alt="\' + alt + \'" \';\n')
	strings.append('											tmp += \'onMouseOver=document.'+name+'Form \' + name + \'.src="animation_buttons/\' + name + \'_over.gif" \';\n')
	strings.append('											tmp += \'onMouseOut=document.'+name+'Form.\' + name + \'.src="animation_buttons/\' + name + \'.gif" \';\n')
	strings.append('										} else {\n')
	strings.append('											tmp = \'<td><img name="\' + name + \'" src="animation_buttons/\' + name + \'_greyed.gif" alt="\' + alt + \'"\';\n')
	strings.append('											tmp += \'onMouseOver="javascript:set'+name+'MouseOver(this)"; \';\n')
	strings.append('											tmp += \'onMouseOut="javascript:set'+name+'MouseOut(this)"; \';\n')
	strings.append('										}\n')
	strings.append('										tmp += \'onClick="\' + clickFunction + \'"></td>\';\n')
	strings.append('									}\n')
	strings.append('									return tmp;\n')
	strings.append('								}\n')
	strings.append('\n')
	strings.append('							//---------------------------------------------------------------------\n')
	strings.append('\n')	
	strings.append('							function draw'+name+'ControlButtons() {\n')
	strings.append('\n')
	strings.append('									tmp = \'<table border="0" class="controlButtons">\';\n')
	strings.append('									tmp += \'<tr>\';\n')
	strings.append('									tmp += draw'+name+'Button(\'play\', \'Play\', \'start'+name+'Play()\');\n')
	strings.append('									tmp += draw'+name+'Button(\'pause\', \'Pause\', \'stop'+name+'Play()\');\n')
	strings.append('									tmp += draw'+name+'Button(\'first\',\'First image\', \''+name+'FirstImage()\');\n')
	strings.append('									tmp += draw'+name+'Button(\'prev\', \'Previous image\', \''+name+'StepBackward()\');\n')
	strings.append('									tmp += draw'+name+'Button(\'next\', \'Next image\', \''+name+'StepForward()\');\n')
	strings.append('									tmp += draw'+name+'Button(\'last\', \'Last image\', \''+name+'LastImage()\');\n')
	strings.append('									tmp += \'<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="controlLabelText">Speed:</span></td>\';\n')
	strings.append('									tmp += draw'+name+'Button(\'slowdown\', \'Slower\', \''+name+'Slower()\');\n')
	strings.append('									tmp += draw'+name+'Button(\'speedup\', \'Faster\', \''+name+'Faster()\');\n')
	strings.append('									tmp += draw'+name+'Button(\'speedreset\', \'Reset\', \''+name+'SpeedReset()\');\n')
	strings.append('									tmp += \'<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>\';\n')
	strings.append('									tmp += \'<td>\';\n')
	strings.append('									tmp += draw'+name+'ImageTextbox();\n')
	strings.append('									tmp += \'</td>\';\n')
	strings.append('									tmp += \'</tr>\';\n')
	strings.append('									tmp += \'</table>\';\n')
#	strings.append('									tmp += \'<br>\';\n')
	strings.append('									return tmp;\n')
	strings.append('\n')
	strings.append('								}\n')
	strings.append('\n')
	strings.append('							//---------------------------------------------------------------------\n')
	strings.append('\n')	    
	strings.append('								function draw'+name+'Image() {\n')
	strings.append('									tmp += \'<IMG NAME="'+name+'Animation" \';\n')
	strings.append('									tmp += \'SRC="\';\n')
	strings.append('									tmp +=  '+name+'FirstImageURL;\n')
	strings.append('									tmp +=  \' " ALT="Loading" BORDER="0" \';\n')
	strings.append('									tmp += \' >\';\n')
	strings.append('									tmp += \'<BR>\';\n')
	strings.append('									return tmp;\n')
	strings.append('								} \n')
	strings.append('\n')
	strings.append('							//--------------------------------------------------------------------------\n')
	
	strings.append('							//     e m b e d   c o d e\n')
	strings.append('							//--------------------------------------------------------------------------\n')
	strings.append('\n')
	strings.append('								// write '+name+' FORM code  to browser\n')
	strings.append('\n')
	strings.append('								tmp = \'<FORM NAME="'+name+'Form">\';\n')
	strings.append('								tmp += draw'+name+'Image();\n')
	strings.append('                                                                tmp += \'<br>\';\n')
	strings.append('								tmp += draw'+name+'ControlButtons();\n')
	strings.append('								tmp += \'</FORM>\';\n')
	strings.append('								document.write (tmp);\n')
	strings.append('\n')
	strings.append('								//-->\n')
	strings.append('								</SCRIPT>\n')
	result = ''.join(strings)
	return result


######################################################################
#    create looping image array       8.26.2005
######################################################################

# code based on Canadian Meteorological Office Page

def get_image_array(path,filetype,name,first):
	"""
	Create a JavaScript image array and pass it back to calling function
	Input: directory path of images, filetype to include
	Output: string representation of array for inclusion in JS code block 
	"""

	files = glob.glob1(path,filetype)
	files.sort()
	
	# enforce initial capitalization of name
	name = string.capitalize(name)
	
	# count number of files
	num_files = count_files(path,filetype)
	
	# file number index for generating array
	image_number=0
	
	# hold strings for constructing array code
	strings = []
	strings.append('						<SCRIPT language="JavaScript">\n')
	strings.append('						<!--\n')
	# build array header
	strings.append('                                                    // create '+name+' image array ------------------------------------------\n')
	strings.append('\n')
	strings.append('                                                    // '+name+'ImageTot: total images ('+name+')\n')
	strings.append('                                                    '+name+'ImageTot='+str(num_files)+';\n')
	strings.append('\n')
	# set max pause
	strings.append('                                                    // max'+name+'Pause: repeat final frame n times before restarting loop\n')
#	strings.append('                                                    max'+name+'Pause = '+str(num_files-1)+';\n')		
	strings.append('                                                    max'+name+'Pause = '+str(4)+';\n')		
	strings.append('\n')
	# determine which image to show on loading
	if first:
		strings.append('                                                    '+name+'FirstImageURL = \"'+get_first_image(path,filetype)+'\";\n')
	else:
		strings.append('                                                    '+name+'FirstImageURL = \"'+get_last_image(path,filetype)+'\";\n')
	strings.append('\n')
	strings.append('                                                    '+name+'Frames = new Array();\n')
	strings.append('\n')
	strings.append('                                                    // '+name+' array elements ------------------------------------------\n')
	strings.append('\n')
		       
	# iterate through files in directory and build array code
	for file in files:
		       strings.append('                                                 	'+name+'ImagesComplete['+str(image_number)+'] = \"' + url_from_path(path) +'/'+ get_thumbnail(file) + '\";\n')
		       strings.append('                                                 	'+name+'Frames['+str(image_number)+'] = new Object();\n')
		       strings.append('                                                 	'+name+'Frames['+str(image_number)+'].path  = \"' + url_from_path(path) +'/'+ get_thumbnail(file) + '\";\n')
		       strings.append('                                                 	'+name+'Frames['+str(image_number)+'].date  = \"''\";\n')
#		       strings.append('                                                 	'+name+'Frames['+str(image_number)+'].date  = \"'+get_timestamp(file) +'\";\n')
		       strings.append('\n')
		       image_number +=1
	
	else: strings.append('							// ERROR: no image files found\n')
        strings.append('\n')
        strings.append('							//-->\n')
        strings.append('						</SCRIPT>\n')
	results = "".join(strings)
	return results




#######################################################################		
#   filesystem navigation routines
#######################################################################
		
def get_files(path):
	"""returns files in the specified directory"""
	files=[]
	tmp = os.listdir(os.path.abspath(path)) # includes absoulte path
	#tmp = os.listdir(path) # does NOT include absolute path
	for a in tmp:
		if os.path.isfile(a):
			files.append(a)
	return files	

def get_dirs(path):
	"""returns subdirectories in the specified directory"""
	dirs=[]
	#tmp = os.listdir(os.path.abspath(path)) # includes absoulte path
	tmp = os.listdir(path) # does NOT include absolute path
	for a in tmp:
		if os.path.isdir(a):
			dirs.append(a)
	return dirs	
	
	
############################################
#    loop routines
############################################

def get_filetype(path):
	# the first filetype is default
	file_types = ['*.png','*.gif','*.jpg']
	files = []
	for file_type in file_types:
		# number of files in directory
		files.append((file_type,glob.glob1(path,file_type)))
	def cmp_(a,b):
		return cmp(len(a[1]), len(b[1]))
	files.sort(cmp_)
	files.reverse()
	
	return files[0][0]


############################################
#    loop routines
############################################

def is_loop(path):
	""" returns true/false if loop is/is not a loopable asset 
	and is completely agnostic of file type """ 
	file_types = ['*.gif','*.jpg','*.png']
	num_files = []
	for file_type in file_types:
		# number of files in directory
		files = glob.glob1(path,file_type)
		num_files.append(len(files))	
	if max(num_files) >= 2:
		return 1
	else:
		return 0 

############################################
#    return thumbnail image
############################################

def get_thumbnail(path):
	return path	
	
############################################
#    return timestamp
############################################

def get_timestamp(file):
	return ''

############################################
#    return help info
############################################

def help_string():
	strings = []
	strings.append('\n')
	strings.append('Input query string as: <code>http://www.atmos.washington.edu/~carey/loop.psp<span color="9999dd">?url=<directory relative to atmos web server root>&title=<title string here (no punctuation, spaces allowed)</span></code>\n')
	strings.append('Ex: http://www.atmos.washington.edu/~carey/loop.psp?url=~carey/test_loop&title=Test loop sequence \n')
	result = ''.join(strings)
	return result

############################################
#    return error message
############################################

def get_error(type):
	# returns formatted error - 'ype' specifies which message to display
	if type == 1:
		# URL key missing
		error_message = 'URL key missing'
		error_detail = 'Input query string as: <code>http://www.atmos.washington.edu/~carey/loop.psp<font color="dd9999">?url=</font><font color="#9999dd"><em>directory_name</em></font><font color="#dd9999">&title=</font><font color="#9999dd"><em>title_string</em></font></code>'
	elif type == 2:
		# URL value empty
		error_message = 'URL value is an empty string'
		error_detail = 'Input query string as: <code>http://www.atmos.washington.edu/~carey/loop.psp<font color="dd9999">?url=</font><font color="#9999dd"><em>directory_name</em></font><font color="#dd9999">&title=</font><font color="#9999dd"><em>title_string</em></font></code>'
	elif type == 3:
		# invalid loop directory
		error_message = 'Specified directory is invalid (or does not exist)'
		error_detail = 'Input query string as: <code>http://www.atmos.washington.edu/~carey/loop.psp<font color="dd9999">?url=</font><font color="#9999dd"><em>directory_name</em></font><font color="#dd9999">&title=</font><font color="#9999dd"><em>title_string</em></font></code>'
	elif type ==4:
		# directory content not loopable
		error_message = 'Specified directory does not contain loopable content'
		error_detail = 'Input query string as: <code>http://www.atmos.washington.edu/~carey/loop.psp<font color="dd9999">?url=</font><font color="#9999dd"><em>directory_name</em></font><font color="#dd9999">&title=</font><font color="#9999dd"><em>title_string</em></font></code>'
	else:
		# uspecified error
		error_message = 'Unspecified error'
		error_detail = 'Input query string as: <code>http://www.atmos.washington.edu/~carey/loop.psp<font color="dd9999">?url=</font><font color="#9999dd"><em>directory_name</em></font><font color="#dd9999">&title=</font><font color="#9999dd"><em>title_string</em></font></code>'	# format error output
	strings = []
	strings.append('<table class = \'grayBorder\' cellpadding = \'6\'>\n')
	strings.append('	<tr valign=\'middle\'>\n')
	strings.append('		<td  width="60" class="grayBorder" bgcolor="#cc3333">\n')
	strings.append('			<span class=\'giant\' width="60" align=\'center\'><center>&nbsp;&nbsp;!&nbsp;&nbsp;</center></span>\n')
	strings.append('		</td>\n')
	strings.append('		<td width=\'400\'>\n')
	strings.append('			<span class=\'error_message\'><p>\n')
	strings.append('			'+error_message+'\n')
	strings.append('			</span>\n')
	strings.append('			<p>\n')
	strings.append('			<span class=\'error_detail\'>\n')	
	strings.append('			'+error_detail+'<br>\n')	
	strings.append('			</span>\n')
	strings.append('		</td>\n')
	strings.append('	</tr>\n')
	strings.append('</table>\n')
	
	error_text = ''.join(strings)
	
	return error_text
