.
		echo $cmsText->processTextLine($text);
		echo $cmsText->processTextBlock($text);
//--------------------------------------------------
// End of example setup
***************************************************/
class cmsText {
	var $preservedInlineTags;
	var $indentLevel;
	var $config;
	function __construct($config = NULL) {
		$this->preservedInlineTags = array();
		$this->indentLevel = 1;
		$this->setConfig($config);
	}
	function setConfig($config) {
		//--------------------------------------------------
		// If this class was not initialised with a config
		// array parameter.
			if ($config === NULL) {
				$config = array();
			}
		//--------------------------------------------------
		// The config setup is an array
			$this->config = array();
		//--------------------------------------------------
		// Boolean (permission) values - default to false
			$this->config['allowHtmlCode']      = (isset($config['allowHtmlCode'])      && $config['allowHtmlCode']      === true);
			$this->config['allowPopupLinks']    = (isset($config['allowPopupLinks'])    && $config['allowPopupLinks']    === true);
			$this->config['allowMailLinks']     = (isset($config['allowMailLinks'])     && $config['allowMailLinks']     === true);
			$this->config['allowImgTags']       = (isset($config['allowImgTags'])       && $config['allowImgTags']       === true);
			$this->config['allowParaAlign']     = (isset($config['allowParaAlign'])     && $config['allowParaAlign']     === true);
			$this->config['allowListTags']      = (isset($config['allowListTags'])      && $config['allowListTags']      === true);
			$this->config['allowTableTags']     = (isset($config['allowTableTags'])     && $config['allowTableTags']     === true);
			$this->config['allowHeadingTags']   = (isset($config['allowHeadingTags'])   && $config['allowHeadingTags']   === true);
			$this->config['noFollowLinks']      = (isset($config['noFollowLinks'])      && $config['noFollowLinks']      === true);
			$this->config['hideCmsComments']    = (isset($config['hideCmsComments'])    && $config['hideCmsComments']    === true);
			$this->config['plainTextMailLinks'] = (isset($config['plainTextMailLinks']) && $config['plainTextMailLinks'] === true);
		//--------------------------------------------------
		// General config
			if (isset($config['headingLevel'])) {
				$this->config['headingLevel'] = $config['headingLevel']; // Valid number checked later
			} else {
				$this->config['headingLevel'] = NULL;
			}
	}
	function changeConfig($key, $value) {
		if ($key == 'headingLevel') {
			$this->config['headingLevel'] = $value;
		} else if (isset($this->config[$key])) {
			$this->config[$key] = ($value === true);
		}
	}
	function processTextLine($string, $preserveOpenTags = false, $childOfTag = NULL) { // Do not set 'childOfTag', its considered PRIVATE
		//--------------------------------------------------
		// Make the string HTML safe and remove whitespace
		// at the end.
 				// NOTE: If this is a child of a tag,
				// then the content would have already
				// been html encoded.
			if ($childOfTag === NULL) {
				$string = rtrim(html($string));
			}
		//--------------------------------------------------
		// Defaults
			$inTagText = NULL;
			$inTagAttribute = NULL;
			$escapingStack = 0;
			$tagStack = array();
			$outputHtml = '';
			$inlineTags = array();
			$inlineTags['b']['open'] = '
';
			$inlineTags['b']['close'] = '';
			$inlineTags['i']['open'] = '
';
			$inlineTags['i']['close'] = '';
		//--------------------------------------------------
		// If any tags were preserved from the last run,
		// then re-open them
			if ($preserveOpenTags === true) {
				while ($tag = array_pop($this->preservedInlineTags)) {
					$tagStack[] = $tag;
					$outputHtml .= $inlineTags[$tag]['open'];
				}
			}
		//--------------------------------------------------
		// Loop though each of the characters in the string
			$stringLength = strlen($string);
			for ($i = 0; $i < $stringLength; $i++) {
				$char = $string[$i];
				if ($char == '[' && $inTagAttribute === NULL) {
					//--------------------------------------------------
					// If we are already collecting data for a tag, which
					// has not finished yet, then then its not really a
					// tag... the user has just used "["
						if ($inTagText !== NULL) {
							$tmp = str_repeat('\\', $escapingStack) . '[' . $inTagText;
							$result = preg_match('/^(.*?)(\\\\*)$/', $tmp, $matches);
							if ($result) {
								$outputHtml .= $matches[1];
								$escapingStack = strlen($matches[2]); // Slashes before the new "["
							} else {
								$outputHtml .= $tmp;
								$escapingStack = 0;
							}
						}
					//--------------------------------------------------
					// Remember we are now in tag mode (not NULL)
						$inTagText = '';
				} else if ($inTagText !== NULL) {
					if ($char == ']' && $inTagAttribute === NULL) {
						//--------------------------------------------------
						// The tag text has been collected, so now extract
						// the tag parts
							$result = preg_match('/^(\/?)([^ ]*)( +.*)?$/', $inTagText, $matches);
							if ($result) {
								$tagTypeOpener = ($matches[1] == '');
								$tagNameLower = strtolower($matches[2]);
								$tagAttributes = (isset($matches[3]) ? $matches[3] : '');
							} else {
								$tagTypeOpener = false;
								$tagNameLower = '';
								$tagAttributes = '';
							}
						//--------------------------------------------------
						// Process the tag (if ness) by setting the
						// $tagOutput to something other than NULL
							$tagOutput = NULL;
							$tagEscaped = (($escapingStack % 2) != 0);
							$tagValid = isset($inlineTags[$tagNameLower]);
							if ($tagValid && $tagAttributes != '') {
								$tagValid = false; // Inline tags arn't allowed attributes
							}
							if ($tagValid && $tagEscaped != true) {
								if ($tagTypeOpener) {
									//--------------------------------------------------
									// This this is an opening tag, if it is not already
									// open AND this is not at the end of the string,
									// then open it now... otherwise we cannot open it
									// again, so silently ignore it.
										if (!in_array($tagNameLower, $tagStack) && (($i + 1) < $stringLength)) {
											$tagOutput = $inlineTags[$tagNameLower]['open'];
											$tagStack[] = $tagNameLower;
										} else {
											$tagOutput = '';
										}
								} else if (!in_array($tagNameLower, $tagStack)) {
									//--------------------------------------------------
									// This is a CLOSING tag that is NOT open, so
									// silently ignore it.
										$tagOutput = '';
								} else {
									//--------------------------------------------------
									// This is a CLOSING tag that is already open
										$tagOutput = '';
										$tempStack = array();
									//--------------------------------------------------
									// Close all of the tags which are currently open,
									// until we find the one the user has requested that
									// we close (XML formatting).
										$processing = true;
										while ($processing) {
											$tag = array_pop($tagStack);
											$tagOutput .= $inlineTags[$tag]['close'];
											if ($tag == $tagNameLower) {
												$processing = false;
											} else {
												$tempStack[] = $tag;
											}
										}
									//--------------------------------------------------
									// Reopen any of the tags which were closed in order
									// to meet the users requested tag close.
										while ($tag = array_pop($tempStack)) {
											$tagStack[] = $tag;
											$tagOutput .= $inlineTags[$tag]['open'];
										}
								}
							} else {
								//--------------------------------------------------
								// This might be an inline element, so extract
								// the attributes
									$tagAttrib1 = '';
									$tagAttrib2 = '';
									$tagAttrib3 = '';
									$found = preg_match('/^ +("|')(.*?)\1(?: +\1(.*?)\1)?(?: +\1(.*?)\1)?$/', $tagAttributes, $matches);
									if ($found) {
										//--------------------------------------------------
										// Attribute 1
											$tagAttrib1 = $matches[2];
										//--------------------------------------------------
										// Attribute 2
												// NOTE: Due to inTagAttribute, a child tag might
												// appear within this attribute. However, we cannot
												// preserveOpenTags, as we would need to re-open
												// them blindly, potentially creating XML errors.
											if (isset($matches[3])) {
												$tagAttrib2 = $matches[3];
												if ($tagNameLower == 'link' || $tagNameLower == 'open' || $tagNameLower == 'mail') {
													$tagAttrib2 = $this->processTextLine($tagAttrib2, false, true);
												}
											}
										//--------------------------------------------------
										// Attribute 3
											if (isset($matches[4])) {
												$tagAttrib3 = $matches[4];
											}
									}
								//--------------------------------------------------
								// If this is a recognised inline element, replace
								// it with the relevant HTML
										// NOTE: If we are processing some text which is
										// a child of a tag, then it should be a child
										// of a link... and as such, we don't to allow
										// and of the following link tags.
									if ($tagAttrib1 != '') {
										if ($tagAttrib3 != '') {
											$classHtml = ' class="' . $tagAttrib3 . '"';
										} else {
											$classHtml = '';
										}
										if ($tagNameLower == 'link' && $childOfTag === NULL) {
											$tagValid = true;
											if ($tagEscaped != true) {
												if ($tagAttrib2 == '') {
													$tagOutput = '
config['noFollowLinks'] ? ' rel="nofollow"' : '') . '>' . $tagAttrib1 . '';
												} else {
													$tagOutput = '
config['noFollowLinks'] ? ' rel="nofollow"' : '') . '>' . $tagAttrib2 . '';
												}
											}
										} else if ($tagNameLower == 'open' && $this->config['allowPopupLinks'] && $childOfTag === NULL) {
											$tagValid = true;
											if ($tagEscaped != true) {
												if ($tagAttrib2 == '') {
													$tagOutput = '
config['noFollowLinks'] ? ' rel="nofollow"' : '') . '>' . $tagAttrib1 . '';
												} else {
													$tagOutput = '
config['noFollowLinks'] ? ' rel="nofollow"' : '') . '>' . $tagAttrib2 . '';
												}
											}
										} else if ($tagNameLower == 'mail' && $this->config['allowMailLinks'] && $childOfTag === NULL) {
											$tagValid = true;
											if ($tagEscaped != true) {
												if ($this->config['plainTextMailLinks']) {
													if ($tagAttrib2 == '') {
														$tagOutput = '
' . $tagAttrib1 . '';
													} else {
														$tagOutput = '
' . $tagAttrib2 . '';
													}
												} else {
													if ($tagAttrib2 == '') {
														$tagOutput = '
' . $tagAttrib1 . '';
													} else {
														$tagOutput = '
' . $tagAttrib2 . '';
													}
												}
											}
										} else if ($tagNameLower == 'img' && $this->config['allowImgTags']) {
											$tagValid = true;
											if ($tagEscaped != true) {
												if ($tagAttrib2 == '' && $tagAttrib3 == '') {
													$tagOutput = '

';
												} else if ($tagAttrib3 == '') {
													$tagOutput = '

';
												} else {
													$tagOutput = '

';
												}
											}
										}
									} else if ($tagNameLower == 'hr') {
										$tagValid = true;
										$tagOutput = '
';
									}
							}
						//--------------------------------------------------
						// If the tag is invalid, or was escaped, return
						// its text value to the $outputHtml
							if ($tagValid) {
								$escapingStack = floor($escapingStack / 2);
							}
							if ($tagOutput === NULL) {
								$tagOutput = '[' . $inTagText . ']'; // Invalid tag, or escaped tag
							}
							$outputHtml .= str_repeat('\\', $escapingStack) . $tagOutput;
						//--------------------------------------------------
						// Reset the tag tracking variables
							$inTagText = NULL;
							$escapingStack = 0;
					} else {
						//--------------------------------------------------
						// The tag has not finished yet, so keep stacking
						// its contents up.
							$inTagText .= $char;
						//--------------------------------------------------
						// Detect if we are in an attribute
							$marker = substr($inTagText, -6);
							if ($marker == '"') $marker = '"';
							if ($marker == ''') $marker = "'";
							if ($inTagAttribute === NULL) {
								if ($marker == '"' || $marker == "'") {
									$inTagAttribute = $marker;
								}
							} else {
								if ($inTagAttribute == $marker) {
									$inTagAttribute = NULL;
								}
							}
					}
				} else if ($char == '\\') {
					//--------------------------------------------------
					// Add to the escaping string stack... these should
					// be added to the $outputHtml later
						$escapingStack++;
				} else {
					//--------------------------------------------------
					// We are looking at an ordinary character which
					// is not part of a tag, so add the relevant number
					// of escaping characters which have been "ignored"
					// just incase we could hit a tag.
						if ($escapingStack > 0) {
							$outputHtml .= str_repeat('\\', $escapingStack);
							$escapingStack = 0;
						}
					//--------------------------------------------------
					// Store the character into the output buffer,
					// although if a new line is being generated, use
					// a simple 
... if its a double newline that
					// should have been handled by blockLevelTagClose()
						if ($char == "\n") {
							if ($i > 0 && ($i + 1) < $stringLength) { // Don't process the first and last "\n"
								$outputHtml .= "
\n";
							}
						} else {
							$outputHtml .= $char;
						}
				}
			}
		//--------------------------------------------------
		// If requested, remember the tags which were left
		// open (about to be closed) so they can be reopened
		// next time this function is called.
			$this->preservedInlineTags = $tagStack;
		//--------------------------------------------------
		// If there is any text remaining in the tag buffer,
		// dump it into $outputHtml
			if ($escapingStack > 0) {
				$outputHtml .= str_repeat('\\', $escapingStack);
			}
			if ($inTagText !== NULL) {
				$outputHtml .= '[' . $inTagText;
			}
			while ($tag = array_pop($tagStack)) {
				$outputHtml .= $inlineTags[$tag]['close'];
			}
		//--------------------------------------------------
		// Post process - remove any tags which have no
		// effect on the output (surround white-space). Not
		// ness, but it keeps the output cleaner and stops
		// upsetting a few code checkers
			$reRun = 0;
			$reRunMax = count($inlineTags);
			while ($reRun++ < $reRunMax) {
				foreach ($inlineTags as $tagInfo) {
					$regExpOpen = preg_quote($tagInfo['open'], '/');
					$regExpClose = preg_quote($tagInfo['close'], '/');
					$outputHtml = preg_replace('/' . $regExpOpen . '(\s*)' . $regExpClose . '/i', '$1', $outputHtml, -1);
					$outputHtml = preg_replace('/' . $regExpClose . '(\s*)' . $regExpOpen . '/i', '$1', $outputHtml, -1);
				}
			}
		//--------------------------------------------------
		// Encode the whitespace characters so browsers
		// will render them
			$outputHtml = str_replace('  ', '  ', $outputHtml); // 2 spaces
			$outputHtml = str_replace(chr(9), '    ', $outputHtml);
		//--------------------------------------------------
		// Set the indent level - again, for code checkers
			$outputHtml = str_replace("\n", "\n" . str_repeat("\t", $this->indentLevel), $outputHtml);
		//--------------------------------------------------
		// Return the output
			return $outputHtml;
	}
	function processTextBlock($string, $preserveOpenTags = false) {
		//--------------------------------------------------
		// Ensure were using use the proper UNIX "\n"
			$string = str_replace("\r\n", "\n", $string);
		//--------------------------------------------------
		// A new block, so we should not care about the
		// previous indent level
			$this->indentLevel = 1;
		//--------------------------------------------------
		// Defaults
			$inTagText = NULL;
			$escapingStack = 0;
			$currentBlockTag = 'p';
			$outputBuffer = '';
			$outputHtml = '';
			$blockLevelTags = array();
			$blockLevelTags[] = 'p';
			if ($this->config['allowParaAlign']) {
				$blockLevelTags[] = 'left';
				$blockLevelTags[] = 'center';
				$blockLevelTags[] = 'right';
			}
			if ($this->config['allowHeadingTags']) {
				$blockLevelTags[] = 'h';
				$blockLevelTags[] = 'h1';
				$blockLevelTags[] = 'h2';
				$blockLevelTags[] = 'h3';
				$blockLevelTags[] = 'h4';
				$blockLevelTags[] = 'h5';
				$blockLevelTags[] = 'h6';
			}
			if ($this->config['allowListTags']) {
				$blockLevelTags[] = 'list';
			}
			if ($this->config['allowTableTags']) {
				$blockLevelTags[] = 'table';
			}
			if ($this->config['allowHtmlCode']) {
				$blockLevelTags[] = 'html';
			}
		//--------------------------------------------------
		// Loop though each of the characters in the string
			$stringLength = strlen($string);
			for ($i = 0; $i < $stringLength; $i++) {
				$char = $string[$i];
				if ($char == '[') {
					//--------------------------------------------------
					// If we are already collecting data for a tag, which
					// has not finished yet, then then its not really a
					// tag... the user has just used "["
						if ($inTagText !== NULL) {
							$tmp = str_repeat('\\', $escapingStack) . '[' . $inTagText;
							$result = preg_match('/^(.*?)(\\\\*)$/', $tmp, $matches);
							if ($result) {
								$outputBuffer .= $matches[1];
								$escapingStack = strlen($matches[2]); // Slashes before the new "["
							} else {
								$outputBuffer .= $tmp;
								$escapingStack = 0;
							}
						}
					//--------------------------------------------------
					// Remember we are now in tag mode (not NULL)
						$inTagText = '';
				} else if ($inTagText !== NULL) {
					if ($char == ']') {
						//--------------------------------------------------
						// Extract the tag parts
							$result = preg_match('/^(\/?)([^ ]*)$/', $inTagText, $matches);
							if ($result) {
								$tagTypeOpener = ($matches[1] == '');
								$tagNameLower = strtolower($matches[2]);
							} else {
								$tagTypeOpener = false;
								$tagNameLower = '';
							}
						//--------------------------------------------------
						// Default processing variables
							$tagOutput = NULL;
							$tagIgnored = false;
							if (in_array($tagNameLower, $blockLevelTags)) { // If this is a valid tag
								if (($escapingStack % 2) == 0) { // Tag not escaped, with an odd number of slashes
									if ($tagTypeOpener == true) {
										if ($tagNameLower != $currentBlockTag) {
											$tagOutput .= $this->blockLevelTagClose($currentBlockTag, $outputBuffer, true);
											$currentBlockTag = $tagNameLower;
										} else {
											$tagIgnored = true; // Already open
										}
									} else {
										if ($tagNameLower == $currentBlockTag) {
											$tagOutput = $this->blockLevelTagClose($currentBlockTag, $outputBuffer, true);
											$currentBlockTag = 'p'; // Return to default
										} else {
											$tagIgnored = true; // Already closed
										}
									}
								}
								$escapingStack = floor($escapingStack / 2);
							}
						//--------------------------------------------------
						// If tag output was generated add it to outputHtml,
						// otherwise dump the (invalid) tag back in to the
						// outputBuffer
							if ($tagOutput === NULL) {
								$outputBuffer .= str_repeat('\\', $escapingStack) . ($tagIgnored ? '' : '[' . $inTagText . ']'); // Invalid tag, or escaped tag
							} else {
								$outputHtml .= str_repeat('\\', $escapingStack) . $tagOutput;
								$outputBuffer = '';
							}
						//--------------------------------------------------
						// Reset the tag tracking variables
							$inTagText = NULL;
							$escapingStack = 0;
					} else {
						//--------------------------------------------------
						// The tag has not finished yet, so keep stacking
						// its contents up.
							$inTagText .= $char;
					}
				} else if ($char == '\\') {
					//--------------------------------------------------
					// Add to the escaping string stack... these should
					// be added to the $outputBuffer later
						$escapingStack++;
				} else {
					//--------------------------------------------------
					// We are looking at an ordinary character which
					// is not part of a tag, so add the relevant number
					// of escaping characters which have been "ignored"
					// just incase we could hit a tag.
						if ($escapingStack > 0) {
							$outputBuffer .= str_repeat('\\', $escapingStack);
							$escapingStack = 0;
						}
					//--------------------------------------------------
					// Store the character into the output buffer.
						$outputBuffer .= $char;
				}
			}
		//--------------------------------------------------
		// If there is any text remaining in the tag buffer,
		// dump it into $outputHtml
			if ($escapingStack > 0) {
				$outputBuffer .= str_repeat('\\', $escapingStack);
			}
			if ($inTagText !== NULL) {
				$outputBuffer .= '[' . $inTagText;
			}
			$outputHtml .= $this->blockLevelTagClose($currentBlockTag, $outputBuffer, $preserveOpenTags); // By default, tags are not preserved
		//--------------------------------------------------
		// Return the output
			if ($this->config['hideCmsComments']) {
				return $outputHtml;
			} else {
				return "\n" . $outputHtml . "\n\n";
			}
	}
	function blockLevelTagClose($currentBlockTag, $content, $preserveOpenTags = false) {
		//--------------------------------------------------
		// If the tag is empty, there is no point generating
		// any html output
			if (trim($content) == '') {
				return '';
			}
		//--------------------------------------------------
		// Process the relevant tags
			if ($currentBlockTag == 'p' || $currentBlockTag == 'left' || $currentBlockTag == 'center' || $currentBlockTag == 'right') {
				//--------------------------------------------------
				// Determine text alignment (none by default)
					if ($currentBlockTag == 'p') {
						$align = NULL;
					} else {
						$align = $currentBlockTag;
					}
				//--------------------------------------------------
				// If double newlines are used, split into
				// multiple paragraphs
					$htmlOutput = '';
					$subParas = explode("\n\n", $content);
					$subParasLength = count($subParas);
					$k = 1;
					foreach ($subParas as $subPara) {
						if (trim($subPara) != '') {
							$htmlOutput .= "\n" . $this->processParagraph($subPara, ($k == 1 ? $preserveOpenTags : true), $align);
						}
						$k++;
					}
				//--------------------------------------------------
				// Return the output
					return $htmlOutput;
			} else if (preg_match('/^h([1-6])?$/', $currentBlockTag, $matches)) {
				$level = intval($this->config['headingLevel']);
				if (isset($matches[1])) {
					$level += (intval($matches[1]) - 1);
				}
				if ($level < 1) $level = 1;
				if ($level > 6) $level = 6;
				return "\n" . $this->processHeading($content, $preserveOpenTags, $level);
			} else if ($currentBlockTag == 'list') {
				return "\n" . $this->processList($content, $preserveOpenTags);
			} else if ($currentBlockTag == 'table') {
				return "\n" . $this->processTable($content, $preserveOpenTags);
			} else if ($currentBlockTag == 'html') {
				if ($this->config['hideCmsComments']) {
					return $content;
				} else {
					return "\n\n" . $content . "\n";
				}
			}
	}
	function processParagraph($content, $preserveOpenTags, $align = NULL) {
		//--------------------------------------------------
		// Process the content, but have it correctly
		// indented if its multi-lined
			$itemHtml = $this->processTextLine($content, $preserveOpenTags);
			if (strpos($itemHtml, "\n") !== false) {
				$itemHtml = "\n\t" . $itemHtml . "\n";
			}
		//--------------------------------------------------
		// Return the output in its wrapper
			return '
' . $itemHtml . '
';
	}
	function processHeading($content, $preserveOpenTags, $level) {
		//--------------------------------------------------
		// Process the content, but have it correctly
		// indented if its multi-lined
			$itemHtml = $this->processTextLine($content, $preserveOpenTags);
			if (strpos($itemHtml, "\n") !== false) {
				$itemHtml = "\n\t" . $itemHtml . "\n";
			}
		//--------------------------------------------------
		// Return the output in its wrapper
			return '
' . $itemHtml . '';
	}
	function processList($content, $preserveOpenTags) {
		//--------------------------------------------------
		// Increase the indent level
			$this->indentLevel++;
		//--------------------------------------------------
		// Process each item in the list
			$outputHtml = '';
			$items = preg_split('/\n(\*|#)/', $content);
			foreach ($items as $item) {
				$item = trim($item);
				if ($item != '') {
					$itemHtml = $this->processTextLine($item, $preserveOpenTags);
					if (strpos($itemHtml, "\n") !== false) {
						$itemHtml = "\n\t\t" . $itemHtml . "\n\t";
					}
					$outputHtml .= "\n\t" . '
' . $itemHtml . '';
				}
			}
		//--------------------------------------------------
		// Restore the indent level
			$this->indentLevel--;
		//--------------------------------------------------
		// Return the output in its wrapper
			if (preg_match('/^\s*#/', $content)) {
				return '
' . $outputHtml . "\n" . '
';
			} else {
				return '
' . $outputHtml . "\n" . '
';
			}
	}
	function processTable($content, $preserveOpenTags) {
		//--------------------------------------------------
		// Split the data into a multi-dimensional array
			$tableColumns = 1;
			$tableData = array();
			$tableRowCells = array();
			$k = 0;
			$rows = explode("\n", $content);
			foreach ($rows as $row) {
				if ($row != '') {
					$cells = explode('|', $row);
					$tableData[$k] = $cells;
					$tableRowCells[$k] = count($cells);
					if ($tableRowCells[$k] > $tableColumns) {
						$tableColumns = $tableRowCells[$k];
					}
					$k++;
				}
			}
		//--------------------------------------------------
		// Build the html output
			$k = 0;
			$inHead = true;
			$outputHeadHtml = '';
			$outputBodyHtml = '';
			foreach ($tableData as $cells) {
				$rowHtml = "\n\t\t
";
				$i = 0;
				foreach ($cells as $cellData) {
					$i++;
					if ($i == 1 && $inHead) {
						if (substr($cellData, 0, 1) == '#') {
							$cellData = substr($cellData, 1);
						} else {
							$inHead = false;
						}
					}
					$colSpan = (($tableColumns + 1) - $tableRowCells[$k]);
					$rowHtml .= "\n\t\t\t" . '<' . ($inHead ? 'th' : 'td') . ($colSpan > 1 && $i == $tableRowCells[$k] ? ' colspan="' . intval($colSpan) . '"' : '') . '>' . $this->processTextLine($cellData, $preserveOpenTags) . ($inHead ? '' : '');
				}
				$rowHtml .= "\n\t\t
";
				if ($inHead) {
					$outputHeadHtml .= $rowHtml;
				} else {
					$outputBodyHtml .= $rowHtml;
				}
				$k++;
			}
		//--------------------------------------------------
		// Return the output in its wrapper
			return "
\n" . ($outputHeadHtml == '' ? '' : "\t" . $outputHeadHtml . "\n\t\n") . ($outputBodyHtml == '' ? '' : "\t" . $outputBodyHtml . "\n\t\n") . "
";
	}
}
//--------------------------------------------------
// Copyright (c) 2006, Craig Francis All rights
// reserved.
//
// Redistribution and use in source and binary forms,
// with or without modification, are permitted provided
// that the following conditions are met:
//
//  * Redistributions of source code must retain the
//    above copyright notice, this list of
//    conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce
//    the above copyright notice, this list of
//    conditions and the following disclaimer in the
//    documentation and/or other materials provided
//    with the distribution.
//  * Neither the name of the copyright holder nor the
//    names of its contributors may be used to endorse
//    or promote products derived from this software
//    without specific prior written permission.
//
// This software is provided by the copyright holders
// and contributors "as is" and any express or implied
// warranties, including, but not limited to, the
// implied warranties of merchantability and fitness
// for a particular purpose are disclaimed. In no event
// shall the copyright holder or contributors be liable
// for any direct, indirect, incidental, special,
// exemplary, or consequential damages (including, but
// not limited to, procurement of substitute goods or
// services; loss of use, data, or profits; or business
// interruption) however caused and on any theory of
// liability, whether in contract, strict liability, or
// tort (including negligence or otherwise) arising in
// any way out of the use of this software, even if
// advised of the possibility of such damage.
//--------------------------------------------------
?>