public function render()
	{
		$tag = "ListUlDrafter: render()";
		Log::debug("$tag");
		
		// convenience pointer
		$id = $this->id;
		$entityBP = $this->entityBlueprint;
		$listBP = $this->listBlueprint;
		$listRows = $this->listRows;
		$params = $this->params;
		
		// encode params for inclusion in html
		$encodedParams = ParamEncoder::encode($params);
		
		// turn on output buffering
		@ob_end_flush();
		ob_start();
		
		?><div class="bp-draft-rendering" id="<?= $id ?>" type="list" renderer="ListUlDrafter" entitySignature="<?= $entityBP->signature(); ?>" listSignature="<?= ($listBP) ? $listBP->signature() : ""; ?>" params="<?= $encodedParams ?>"><?

			if((is_array($listRows)) && (count($listRows > 0)) )
			{
				?><ul><?
					foreach($listRows as $row)
					{
						?><li entityId="<?= $row->id ?>"><?
							foreach($row->columns as $key=>$listColumn)
							{
								$value = $listColumn->value;
								$href = $listColumn->href;
								
								if(!empty($href))
								{
									?><a href="<?= $href ?>"><?= $value ?></a> <?
								}
								else
								{
									?><?= $value ?> <?
								}
								
							}
						?></li><?
					}	
				?></ul><?
			}
			else
			{
				?>
				Empty
				<?
			}
		
		?></div><?
		
		// return contents of output buffer
		$html = ob_get_contents();
		ob_end_clean();
		return $html;
	}
	public function render()
	{
		$tag = "FormDrafter: render()";
		Log::debug("$tag");
		
		// convenience pointers
		$id = $this->id;
		$entityId = $this->entityId;
		$entityBP = $this->entityBlueprint;
		$formBP = $this->formBlueprint;
		$fields = $this->formFields;
		$params = $this->params;
		
		// encode params for inclusion in html
		$encodedParams = ParamEncoder::encode($params);
		
		// translate buttonPlacement into html element
		$buttonContainer = "tfoot";
		if( array_key_exists("buttonPlacement", $params) )
		{
			if($params["buttonPlacement"] == "thead")
				$buttonContainer = "thead";
			else
				$buttonContainer = "tfoot";
		}
		
		// turn on output buffering
		@ob_end_flush();
		ob_start();
		
		?>
		<div class="bp-draft-rendering" id="<?= $id ?>" type="form" renderer="FormDrafter" entitySignature="<?= $entityBP->signature(); ?>" formSignature="<?= ($formBP) ? $formBP->signature() : ""; ?>" entityId="<?= $entityId ?>" params="<?= $encodedParams ?>">
			<form class="bp-form" method="POST" <?= (array_key_exists("action", $params)) ? "action='" . $params["action"] . "'" : "" ?>>
				<table class="bp-form-table">
					<?
					if( array_key_exists("buttons", $params) )
					{
						echo "<" . $buttonContainer . ">"; // OPEN: <thead> or <tfoot>
							?>
							<tr>
								<td colspan="2" align="<?= $params["buttonAlignment"] ?>" class="bp-form-buttons">
									<?
									$buttonKeys = array_keys($params["buttons"]);
									foreach($buttonKeys as $b)
									{
										?>
										<input type="button" class="bp-form-button" value="<?= $b ?>" onClick="<?= $params["buttons"]["$b"] ?>" />
										<?
									}
									?>
								</td>
							</tr>
							<?
						echo "</" . $buttonContainer. ">";	// CLOSE: </thead> or </tfoot>
					}
					?>
					<tbody>
						<?
						foreach($fields as $f)
						{
							$key = $f->getKey();
							$entityField = $entityBP->get($key);
							
							if($f->display != "hidden")
							{
								?>
								<tr>
									<td class="bp-form-label"><?= $f->displayName; ?></td>
									<td class="bp-form-input">
										<?
										if(!$entityField->isForeignKey())
										{
											switch($f->dataType)
											{
												case "string":
													if($entityField->getEncType() == "plain")
													{
														?><input type="text" name="<?= $key ?>" value="<?= $f->value; ?>" class="<?= ($f->err) ? "bp-validation-error" : "" ?>" <?= ($f->err) ? "title='" . $f->err . "'" : "" ?> /><?
													}
													else
													{
														?>
														<input type="password" name="<?= $key ?>" value="********" class="<?= ($f->err) ? "bp-validation-error" : "" ?>" <?= ($f->err) ? "title='" . $f->err . "'" : "" ?> disabled="true" size="10" />&nbsp;
														<button class="bp-form-encoded-clear" href="<?= $key ?>">Edit</button>
														<?
													}
													break;
												case "text":
													?><textarea name="<?= $key ?>" class="<?= ($f->err) ? "bp-validation-error" : "" ?>" <?= ($f->err) ? "title='" . $f->err . "'" : "" ?>><?= $f->value; ?></textarea><?
													break;
												case "int":
												case "decimal":
													?><input type="text" name="<?= $key ?>" value="<?= $f->value ?>" class="<?= ($f->err) ? "bp-validation-error" : "" ?>" /><?
													break;
												case "date":
													?><input type="text" name="<?= $key ?>" value="<?= $f->value ?>" class="bp-form-input-date <?= ($f->err) ? "bp-validation-error" : "" ?>" /><?
													break;
												case "datetime":
													?><input type="text" name="<?= $key ?>" value="<?= $f->value ?>" class="bp-form-input-datetime <?= ($f->err) ? "bp-validation-error" : "" ?>" /><?
													break;
												case "time":
													?><input type="text" name="<?= $key ?>" value="<?= $f->value ?>" class="bp-form-input-time <?= ($f->err) ? "bp-validation-error" : "" ?>" /><?
													break;
												case "enum":
													$enumOptions = $entityField->getEnumOptions();
													if(count($enumOptions) <= 2)
													{
														?><div class="<?= ($f->err) ? "bp-validation-error" : "" ?>" <?= ($f->err) ? "title='" . $f->err . "'" : "" ?>><?		
															foreach($enumOptions as $e)
															{
																?><input type="radio" name="<?= $key ?>" value="<?= $e ?>" <?= ($f->value==$e) ? "CHECKED" : "" ?>><?= $e ?><?
															}
														?></div><?
													}
													else
													{
														?>
														<select name="<?= $key ?>" class="<?= ($f->err) ? "bp-validation-error" : "" ?>">
															<option value=""></option>
															<?
															foreach($enumOptions as $e)
															{
															?><option value="<?= $e ?>" <?= ($f->value==$e) ? "SELECTED" : "" ?>><?= $e ?></option><?
															}
														?>
														</select>
														<?
													}
													break;
												case "binary":
													?><span class="bp-form-binary"><?
													if(empty($f->value))
													{
														?>
														<input type="file" name="<?= $key ?>" />
														<?
													}
													else
													{
														?>
														<a href="/blueprints/binary/<?= $entityBP->getKey() ?>/<?= $key ?>/<?= $entityId ?>"><?= $entityField->getMimeType(); ?></a>
														<button class="bp-form-binary-clear"  href="<?= $key ?>">Clear</button>
														<?
													}
													?></span><?
													break;
											}
										} // END: if(!$f->isForeignKey())
										else
										{
											$foreignKey = substr($entityField->getForeignKey(), strpos($entityField->getForeignKey(), ".")+1);
											$foreignValue = substr($entityField->getForeignValue(), strpos($entityField->getForeignValue(), ".")+1);
											$foreignTable = substr($entityField->getForeignKey(), 0, strpos($entityField->getForeignKey(), "."));
											
											$query = "SELECT $foreignKey, $foreignValue FROM $foreignTable ORDER BY $foreignValue";
											// TODO: include WHERE cluase from formBlueprint->field:where
											$sql = new DatabaseQuery($query);
											
											try
											{
												$sql->doQuery();
												?>
												<select name="<?= $key ?>" class="<?= ($f->err) ? "bp-validation-error" : "" ?>">
													<option value=""></option>
													<?
													$num_rows = $sql->get_num_rows();
													for($i=0; $i<$num_rows; $i++)
													{
														$row = $sql->get_next_row();
														$foreignKeyResult = $row->$foreignKey;
														$foreignValueResult = $row->$foreignValue;
														?>
														<option value="<?= $foreignKeyResult ?>" <?= ($f->value==$foreignKeyResult) ? "SELECTED" : ""; ?>><?= $foreignValueResult ?></option>
														<?
													}
													?>
												</select>
												<?
											}
											catch(Exception $e)
											{
												Log::error("Caught Exception: " . $e->getMessage());
											}									
										}
										?>
									</td>
								</tr>
								<?
							} // END: if($f->display != "hidden")
							else
							{
								?>
								<input type="hidden" name="<?= $key ?>" value="<?= $f->value ?>" />
								<?
							}							
						} // END: foreach($fields as $f)
						?>
					</tbody>
				</table>
			</form>
		</div>
		<?
		
		// return contents of output buffer
		$html = ob_get_contents();
		ob_end_clean();
		return $html;
	}
	public function render()
	{
		$tag = "ReportDrafter: render()";
		Log::debug("$tag");
		
		// convenience pointers
		$id = $this->id;
		$reportBP = $this->reportBlueprint;
		$reportRows = $this->reportRows;
		$params = $this->params;
		
		// Encode Parameters
		$encodedParams = ParamEncoder::encode($params);
		
		// turn on output buffering
		@ob_end_flush();
		ob_start();
		
		?><div class="bp-draft-rendering" id="<?= $id ?>" type="report" renderer="DraftDrafter" reportSignature="<?= $reportBP->signature(); ?>" entitySignature="<?= $reportBP->getKey() ?>.entity.xml" params="<?= $encodedParams ?>"><?
		
			if((is_array($reportRows)) && (count($reportRows > 0)) )
			{	
					foreach($reportRows as $row)
					{
						$id = $row->id;
						?><?= $id ?>, <?
					}	
			}
			else
			{
				?>
				Empty
				<?
			}
		
		?></div><?	
		
		// return contents of output buffer
		$html = ob_get_contents();
		ob_end_clean();
		return $html;	
	}
	public function render()
	{
		$tag = "ListTableDrafter: render()";
		Log::debug("$tag");
		
		// convenience pointer
		$id = $this->id;
		$entityBP = $this->entityBlueprint;
		$listBP = $this->listBlueprint;
		$params = $this->params;
		$listRows = $this->listRows;
		$listColumnNames = $this->listColumnNames;
		$entityActions = $this->entityActions;
		$collectionActions = $this->collectionActions;
		
		// encode params for inclusion in html
		$encodedParams = ParamEncoder::encode($params);
		
		// turn on output buffering
		@ob_end_flush();
		ob_start();
		
		?><div class="bp-draft-rendering" id="<?= $id ?>" type="list" renderer="ListTableDrafter" entitySignature="<?= $entityBP->signature(); ?>" listSignature="<?= ($listBP) ? $listBP->signature() : ""; ?>" params="<?= $encodedParams ?>"><?

			if( (is_array($listRows)) && (count($listRows > 0)) )
			{
				?>
				<table class="bp-list-table" border="0" cellspacing="0" <?= ((array_key_exists("width", $params))&&(!empty($params["width"]))) ? ("width='" . $params["width"] . "'") : ""; ?>>
					<thead>
						<tr>
							<?
							if(count($collectionActions) > 0)
							{
								?>
								<th><input type="checkbox" class="bp-collection-select-all"/></th>
								<?
							}
							
							foreach($listColumnNames as $key=>$displayName)
							{
								?>
								<th class="bp-list-table-column" key="<?= $key ?>"><?= $displayName ?></th>
								<?
							}
							
							if(count($entityActions) > 0)
							{
								?>
								<th>&nbsp;</th>
								<?
							}
							?>
						</tr>
					</thead>
					<tfoot>
					<?
					if(count($collectionActions) > 0)
					{
						$tfootColspan = count($listColumnNames) + 1;
						if(count($entityActions) > 0) { $tfootColspan++; }
						
						?>
						<tr>
							<td colspan="<?= $tfootColspan ?>">
								<?
								foreach($collectionActions as $x)
								{
									?><input type="button" class="bp-list-action bp-target-type-collection" value="<?= $x["displayText"]; ?>" href="<?= $x["javascript"]; ?>" /><?
								}
								?>
							</td>
						</tr>
						<?
					}
					?>
					</tfoot>
					<tbody>
					<?			
					foreach($listRows as $row)
					{
						?><tr entityId=<?= $row->id; ?>><?

							if(count($collectionActions) > 0)
							{
								?>
								<td><input type="checkbox" class="bp-collection-select"/></td>
								<?
							}
							
							foreach($row->columns as $key=>$listColumn)
							{
								$value = $listColumn->value;
								$href = $listColumn->href;
									
								if(!empty($href))
								{
									?><td><a href="<?= $href ?>"><?= $value ?></a></td><?
								}
								else
								{
									?><td><?= $value ?></td><?
								}
							}
							
							if(count($entityActions) > 0)
							{
								?><td><?
									foreach($entityActions as $x)
									{
										?>
										<a class="bp-list-action bp-target-type-entity" icon="<?= $x["icon"] ?>" href="javascript:<?= $x["javascript"] ?>"><?= $x["displayText"] ?></a>
										<?
									}
								?></td><?
							}
						?></tr><?
					}
					?>
					</tbody>
				</table>
				<?
			}
			else
			{
				?>
				Empty
				<?
			}
			
		?></div><?
		
		// return contents of output buffer
		$html = ob_get_contents();
		ob_end_clean();
		return $html;
	}
	public function render()
	{
		$tag = "FilterDrafter: render()";
		Log::debug("$tag");
		
		// convenience pointers
		$id = $this->id;
		$entityBP = $this->entityBlueprint;
		$filterBP = $this->filterBlueprint;
		$filters = $this->filters;
		$params = $this->params;
		
		// encode params for inclusion in html
		$encodedParams = ParamEncoder::encode($params);
		
		// translate buttonPlacement into html element
		$buttonContainer = "tfoot";
		if( array_key_exists("buttonPlacement", $params) )
		{
			if($params["buttonPlacement"] == "thead")
				$buttonContainer = "thead";
			else
				$buttonContainer = "tfoot";
		}
		
		// turn on output buffering
		@ob_end_flush();
		ob_start();
		
		?>
		<div class="bp-draft-rendering" id="<?= $id ?>" type="filter" renderer="FilterDrafter" entitySignature="<?= $entityBP->signature(); ?>" filterSignature="<?= ($filterBP) ? $filterBP->signature() : ""; ?>" params="<?= $encodedParams ?>">
			<form class="bp-filter-form">
				<table class="bp-filter-table">
					<?
					if( array_key_exists("buttons", $params) )
					{
						echo "<" . $buttonContainer . ">"; // OPEN: <thead> or <tfoot>
							?>
							<tr>
								<td colspan="2" align="<?= $params["buttonAlignment"] ?>" class="bp-form-buttons">
									<?
									$buttonKeys = array_keys($params["buttons"]);
									foreach($buttonKeys as $b)
									{
										?>
										<input type="button" class="bp-form-button" value="<?= $b ?>" onClick="<?= $params["buttons"]["$b"] ?>" />
										<?
									}
									?>
								</td>
							</tr>
							<?
						echo "</" . $buttonContainer. ">";	// CLOSE: </thead> or </tfoot>
					}
					?>
					<tbody>
						<?
						foreach($filters as $f)
						{
							$key = $f->getKey();
							$type = $f->type;
							
							?>
							<tr>
								<td class="bp-filter-label"><?= $f->displayName; ?></td>
								<td class="bp-filter-input">
									<?
									if(!$f->isForeignKey())
									{
										switch($f->dataType)
										{
											case "string":
											case "text":
												?><input type="text" key="<?= $key ?>" name="<?= $key . "_" . $type ?>" value="<?= $f->value["$type"]; ?>" /><?
												break;
											case "int":
											case "decimal":
											case "date":
											case "datetime":
												switch($type)
												{
													case "min":
													case "max":
													case "equals":
														?><input type="text" key="<?= $key ?>" name="<?= $key . "_" . $type ?>" value="<?= $f->value["$type"]; ?>" /><?
														break;
													case "range":
														?><input type="text" key="<?= $key ?>" name="<?= $key . "_min" ?>" value="<?= $f->value["min"]; ?>" />&nbsp;to&nbsp;<input type="text" key="<?= $key ?>" name="<?= $key . "_max" ?>" value="<?= $f->value["max"]; ?>" /><?
														break;
												}
												break;
											case "enum":
												$entityField = $entityBP->get($key);
												$enumOptions = $entityField->getEnumOptions();
																				
												?>
												<select key="<?= $key ?>" name="<?= $key . "_" . $type ?>">
													<option value=""></option>
													<?
													foreach($enumOptions as $e)
													{
													?><option value="<?= $e ?>" <?= ($f->value["$type"]==$e) ? "SELECTED" : "" ?>><?= $e ?></option><?
													}
												?>
												</select>
												<?								
												break;
											case "binary":
												// TODO: render; type=not null|size
												break;
										} // END: switch($f->dataType)
									} // END: if(!$f->isForeignKey())
									else
									{
										$foreignKey = substr($f->foreignKey, strpos($f->foreignKey, ".")+1);
										$foreignValue = substr($f->foreignValue, strpos($f->foreignValue, ".")+1);
										$foreignTable = substr($f->foreignKey, 0, strpos($f->foreignKey, "."));
										
										$query = "SELECT $foreignKey, $foreignValue FROM $foreignTable";
										// TODO: include WHERE cluase from filterBlueprint->field:where
										$sql = new DatabaseQuery($query);
										
										try
										{
											$sql->doQuery();
											?>
											<select key="<?= $key ?>" name="<?= $key . "_equals" ?>">
												<option value=""></option>
												<?
												$num_rows = $sql->get_num_rows();
												for($i=0; $i<$num_rows; $i++)
												{
													$row = $sql->get_next_row();
													$foreignKeyResult = $row->$foreignKey;
													$foreignValueResult = $row->$foreignValue;
													?>
													<option value="<?= $foreignKeyResult ?>" <?= ($f->value["equals"]==$foreignKeyResult) ? "SELECTED" : ""; ?>><?= $foreignValueResult ?></option>
													<?
												}
												?>
											</select>
											<?
										}
										catch(Exception $e)
										{
											Log::error("Caught Exception: " . $e->getMessage());
										}
									}
									?>
								</td>
							</tr>
							<?
						}
						?>
					</tbody>
				</table>
			</form>
		</div>
		<?
		
		// return contents of output buffer
		$html = ob_get_contents();
		ob_end_clean();
		return $html;
	}
header("Content-Type: text/xml");
$dom = new DomDocument();
$responseNode = $dom->createElement("response");
$dom->appendChild($responseNode);
// Retrieve request parameters
$renderer = @$_POST["renderer"];
$entitySignature = @$_POST["entitySignature"];
$filterSignature = @$_POST["filterSignature"];
$params = @$_POST["params"];
// encoded with ParamEncoder::encode()
if (!empty($renderer) && !empty($entitySignature)) {
    Log::debug("* renderer = {$renderer}");
    Log::debug("* entitySignature = {$entitySignature}");
    Log::debug("* filterSignature = {$filterSignature}");
    // Decode params
    $params = ParamEncoder::decode($params);
    /*
    // Read Blueprints
    */
    // Read Entity Blueprint
    try {
        $entityBP = BlueprintReader::read($entitySignature);
    } catch (Exception $e) {
        Log::error("{$tag}: Caught Exception reading entity blueprint " . $entitySignature);
        // TODO: return error response; do not continue
    }
    // Read Filter Blueprint
    if ($filterSignature != null) {
        try {
            $filterBP = BlueprintReader::read($filterSignature);
        } catch (Exception $e) {
 public function render()
 {
     $tag = "FilterXMLDrafter: render()";
     Log::debug("{$tag}");
     // convenience pointers
     $id = $this->id;
     $entityBP = $this->entityBlueprint;
     $filterBP = $this->filterBlueprint;
     $filters = $this->filters;
     $params = $this->params;
     // encode params for inclusion in html
     $encodedParams = ParamEncoder::encode($params);
     // init xml respose
     $xml = new SimpleXmlElement("<bpXmlDraftRendering />");
     $rendering = $xml;
     $rendering->addAttribute("id", $id);
     $rendering->addAttribute("type", "filter");
     $rendering->addAttribute("entitySignature", $entityBP->signature());
     if ($filterBP) {
         $rendering->addAttribute("filterSignature", $filterBP->signature());
     }
     $rendering->addAttribute("params", $encodedParams);
     foreach ($filters as $f) {
         // collect data for this field
         $key = $f->getKey();
         $type = $f->type;
         // add new <field> to xml response
         $fieldPtr = $rendering->addChild("field");
         $fieldPtr->addAttribute("key", $key);
         $fieldPtr->addChild("type", $type);
         $fieldPtr->addChild("dataType", $f->dataType);
         $fieldPtr->addChild("displayName", $f->displayName);
         // enum options
         if ($f->dataType == "enum") {
             $enumPtr = $fieldPtr->addChild("enumOptions");
             $entityField = $entityBP->get($key);
             $enumOptions = $entityField->getEnumOptions();
             foreach ($enumOptions as $e) {
                 $enumPtr->addChild("option", $e);
             }
         }
         // value
         if (!$f->isForeignKey()) {
             if ($f->hasValue()) {
                 $filterValue = $f->value;
                 // an array
                 $valuePtr = $fieldPtr->addChild("value");
                 if (array_key_exists("equals", $filterValue)) {
                     $ptr = $valuePtr->addChild("equals", $filterValue["equals"]);
                     $ptr->addAttribute("name", $key . "_equals");
                 }
                 if (array_key_exists("like", $filterValue)) {
                     $ptr = $valuePtr->addChild("like", $filterValue["like"]);
                     $ptr->addAttribute("name", $key . "_like");
                 }
                 if (array_key_exists("min", $filterValue)) {
                     $ptr = $valuePtr->addChild("min", $filterValue["min"]);
                     $ptr->addAttribute("name", $key . "_min");
                 }
                 if (array_key_exists("max", $filterValue)) {
                     $ptr = $valuePtr->addChild("max", $filterValue["max"]);
                     $ptr->addAttribute("name", $key . "_max");
                 }
             }
         } else {
             $enumPtr = $fieldPtr->addChild("foreignOptions");
             $foreignKey = substr($f->foreignKey, strpos($f->foreignKey, ".") + 1);
             $foreignValue = substr($f->foreignValue, strpos($f->foreignValue, ".") + 1);
             $foreignTable = substr($f->foreignKey, 0, strpos($f->foreignKey, "."));
             $query = "SELECT {$foreignKey}, {$foreignValue} FROM {$foreignTable}";
             // TODO: include WHERE clause from filterBlueprint->field:where
             $sql = new DatabaseQuery($query);
             try {
                 $sql->doQuery();
                 $num_rows = $sql->get_num_rows();
                 for ($i = 0; $i < $num_rows; $i++) {
                     $row = $sql->get_next_row();
                     $foreignKeyResult = $row->{$foreignKey};
                     $foreignValueResult = $row->{$foreignValue};
                     $optionPtr = $enumPtr->addChild("option");
                     $optionPtr->addAttribute("key", $foreignKeyResult);
                     $optionPtr->addChild("value", $foreignValueResult);
                 }
             } catch (Exception $e) {
                 Log::error("Caught Exception: " . $e->getMessage());
             }
         }
     }
     // END: foreach($filters as $f)
     // Return XML string
     // NOTE: using DomDocument provides more flexibility (supressing empty tags, and removing xml declaration)
     // This xml cannot contain an xml declaration, because we plan on embedding it in another xml document
     $dom = new DomDocument();
     $dom->loadXML($xml->asXML());
     $node = $dom->getElementsByTagName("bpXmlDraftRendering")->item(0);
     return $dom->saveXML($node, LIBXML_NOEMPTYTAG);
 }
 public function render()
 {
     $tag = "FormXMLDrafter: render()";
     Log::debug("{$tag}");
     // convenience pointers
     $id = $this->id;
     $entityId = $this->entityId;
     $entityBP = $this->entityBlueprint;
     $formBP = $this->formBlueprint;
     $fields = $this->formFields;
     $params = $this->params;
     // encode params for inclusion in html
     $encodedParams = ParamEncoder::encode($params);
     // init xml respose
     $xml = new SimpleXmlElement("<bpXmlDraftRendering></bpXmlDraftRendering>");
     $rendering = $xml;
     $rendering->addAttribute("id", $id);
     $rendering->addAttribute("type", "form");
     $rendering->addAttribute("entitySignature", $entityBP->signature());
     if ($formBP) {
         $rendering->addAttribute("formSignature", $formBP->signature());
     }
     $rendering->addAttribute("entityId", $entityId);
     $rendering->addAttribute("params", $encodedParams);
     foreach ($fields as $f) {
         // collect data for this field
         $key = $f->getKey();
         $entityField = $entityBP->get($key);
         // add new <field> to xml response
         $fieldPtr = $rendering->addChild("field");
         $fieldPtr->addAttribute("key", $key);
         /*
         // add details for this <field>
         */
         // displayName
         $fieldPtr->addChild("displayName", $f->displayName);
         // dataType
         $fieldPtr->addChild("dataType", $f->dataType);
         // value
         // replace "&" with "&amp;" to prevent xml errors
         $f->value = str_replace("&", "&amp;", $f->value);
         switch ($f->dataType) {
             case "string":
                 if ($entityField->getEncType() != "plain") {
                     $fieldPtr->addChild("value", "********");
                 } else {
                     $fieldPtr->addChild("value", $f->value);
                 }
                 break;
             case "binary":
                 $binaryValue = !empty($f->value) ? "/blueprints/binary/" . $entityBP->getKey() . "/" . $key . "/" . $entityId : "";
                 $binaryValuePtr = $fieldPtr->addChild("value", $binaryValue);
                 $binaryValuePtr->addAttribute("mimeType", $entityField->getMimeType());
                 break;
             default:
                 $fieldPtr->addChild("value", $f->value);
         }
         // foreign value options
         if ($entityField->isForeignKey()) {
             $enumPtr = $fieldPtr->addChild("foreignOptions");
             $foreignKey = substr($entityField->getForeignKey(), strpos($entityField->getForeignKey(), ".") + 1);
             $foreignValue = substr($entityField->getForeignValue(), strpos($entityField->getForeignValue(), ".") + 1);
             $foreignTable = substr($entityField->getForeignKey(), 0, strpos($entityField->getForeignKey(), "."));
             $query = "SELECT {$foreignKey}, {$foreignValue} FROM {$foreignTable} ORDER BY {$foreignValue}";
             // TODO: include WHERE cluase from formBlueprint->field:where
             $sql = new DatabaseQuery($query);
             try {
                 $sql->doQuery();
                 $num_rows = $sql->get_num_rows();
                 for ($i = 0; $i < $num_rows; $i++) {
                     $row = $sql->get_next_row();
                     $foreignKeyResult = $row->{$foreignKey};
                     $foreignValueResult = $row->{$foreignValue};
                     // clean
                     $foreignValueResult = htmlentities($foreignValueResult);
                     $optionPtr = $enumPtr->addChild("foreignOption", $foreignValueResult);
                     $optionPtr->addAttribute("key", $foreignKeyResult);
                 }
             } catch (Exception $e) {
                 Log::error("Caught Exception: " . $e->getMessage());
             }
         }
         // enumOptions
         if ($f->dataType == "enum") {
             $enumPtr = $fieldPtr->addChild("enumOptions");
             $enumOptions = $entityField->getEnumOptions();
             foreach ($enumOptions as $e) {
                 $enumPtr->addChild("enumOption", $e);
             }
         }
         // validation errors
         if ($f->err) {
             $errPtr = $fieldPtr->addChild("validationError");
             $errPtr->addChild("message", $f->err);
         }
     }
     // END: foreach($fields as $f)
     // Return XML string
     // NOTE: using DomDocument provides more flexibility (supressing empty tags, and removing xml declaration)
     // This xml cannot contain an xml declaration, because we plan on embedding it in another xml document
     $dom = new DomDocument();
     $dom->loadXML($xml->asXML());
     $node = $dom->getElementsByTagName("bpXmlDraftRendering")->item(0);
     return $dom->saveXML($node, LIBXML_NOEMPTYTAG);
 }
	public function render()
	{
		$tag = "ReportTableDrafter: render()";
		Log::debug("$tag");
		
		// convenience pointers
		$id = $this->id;
		$reportBP = $this->reportBlueprint;
		$query = $this->query;
		$params = $this->params;
		$reportRows = $this->reportRows;
		$reportColumnNames = $this->reportColumnNames;
		$rowActions = $this->rowActions;
		$collectionActions = $this->collectionActions;
		
		// encode params
		$encodedParams = ParamEncoder::encode($params);
		
		// turn on output buffering
		@ob_end_flush();
		ob_start();

		?><div class="bp-draft-rendering" id="<?= $id ?>" type="report" renderer="ReportTableDrafter" reportSignature="<?= $reportBP->signature() ?>" entitySignature="<?= $reportBP->getKey() ?>.entity.xml" params="<?= $encodedParams ?>"><?
			
			if( (is_array($reportRows)) && (count($reportRows > 0)) )
			{
				?>
				<table class="bp-list-table" border="0" cellspacing="0">
					<thead>
						<tr>
							<?
							
							if(count($collectionActions) > 0)
							{
								?>
								<th><input type="checkbox" class="bp-collection-select-all" /></th>
								<?
							}
							
							foreach($reportColumnNames as $key=>$displayName)
							{
								?>
								<th class="bp-list-table-column" key="<?= $key ?>"><?= $displayName ?></th>
								<?
							}
							
							if(count($rowActions) > 0)
							{
								?>
								<th>&nbsp;</th>
								<?
							}
							
							?>
						</tr>
					</thead>
					<tfoot>
					<?
					if(count($collectionActions) > 0)
					{
						$tfootColspan = count($reportColumnNames) + 1;
						if(count($rowActions) > 0) { $tfootColspan++; }
						
						?>
						<tr>
							<td colspan="<?= $tfootColspan ?>">
							<?
							foreach($collectionActions as $x)
							{
								?><input type="button" value="<?= $x["displayText"] ?>" href="<?= $x["javascript"] ?>" /><?
							}
							?>
							</td>
						</tr>
						<?
					}
					?>
					</tfoot>
					<tbody>
					<?
					foreach($reportRows as $row)
					{
						?><tr rowId="<?= $row->id; ?>"><?
						
						if(count($collectionActions) > 0)
						{
							?>
							<td><input type="checkbox" class="bp-collection-select" /></td>
							<?
						}
						
						foreach($row->columns as $key=>$rowColumn)
						{
							$value = $rowColumn->value;
							$href = $rowColumn->href;
							
							if(!empty($href))
							{
								?><td><a href="<?= $href ?>"><?= $value ?></a></td><?
							}
							else
							{
								?><td><?= $value ?></td><?
							}
						}
						
						if(count($rowActions) > 0)
						{
							?><td><?
								foreach($rowActions as $x)
								{
									?><a class="bp-list-action" href="javascript:<?= $x["javascript"] ?>"><?= $x["displayText"] ?></a><?
								}
							?></td><?
						}
						?></tr><?
					}
					?>
					</tbody>
				</table>
				<?
			}
			else
			{
				?>Empty<?
			}
			
		?></div><?
		
		// return contents of output buffer
		$html = ob_get_contents();
		ob_end_clean();
		return $html;
	}