text:
<?php

/**
 * Spoon Library
 *
 * This source file is part of the Spoon Library. More information,
 * documentation and tutorials can be found @ http://www.spoon-library.be
 *
 * @package		html
 * @subpackage	datagrid
 *
 *
 * @author		Davy Hellemans <davy@spoon-library.be>
 * @author 		Tijs Verkoyen <tijs@spoon-library.be>
 * @author		Dave Lens <dave@spoon-library.be>
 * @since		1.0.0
 */

/** SpoonTemplate class */
require_once 'spoon/template/template.php';

/** SpoonFilter class */
require_once 'spoon/filter/filter.php';

/** SpoonFileSystem package */
require_once 'spoon/filesystem/filesystem.php';

/**
 * This exception is used to handle datagrid related exceptions.
 *
 * @package		html
 * @subpackage	datagrid
 *
 *
 * @author		Davy Hellemans <davy@spoon-library.be>
 * @since		0.1.1
 */
class SpoonDataGridException extends SpoonException {}

/**
 * This class is the base class used to generate datagrids from a range of sources.
 *
 * @package			html
 * @subpackage		datagrid
 *
 *
 * @author			Davy Hellemans <davy@spoon-library.be>
 * @since			1.0.0
 */
class SpoonDataGrid
{
	/**
	 * List of columns that may be sorted in, based on the query results
	 *
	 * @var	array
	 */
	private $allowedSortingColumns = array();

	/**
	 * Html attributes
	 *
	 * @var	array
	 */
	private $attributes = array('datagrid' => array(),
								'row' => array(),
								'row_even' => array(),
								'row_odd' => array(),
								'footer' => array());

	/**
	 * Table caption/description
	 *
	 * @var	string
	 */
	private $caption;

	/**
	 * Array of column functions
	 *
	 * @var	array
	 */
	private $columnFunctions = array();

	/**
	 * Array of column objects
	 *
	 * @var	array
	 */
	private $columns = array();

	/**
	 * Default compile directory
	 *
	 * @var	string
	 */
	private $compileDirectory;

	/**
	 * Final output
	 *
	 * @var	string
	 */
	private $content;

	/**
	 * Debug status
	 *
	 * @var	bool
	 */
	private $debug = false;

	/**
	 * Offset value
	 *
	 * @var	int
	 */
	private $offset;

	/**
	 * Offset start value
	 *
	 * @var	int
	 */
	private $offsetParameter;

	/**
	 * Order start value
	 *
	 * @var	string
	 */
	private $orderParameter;

	/**
	 * Separate results with pages
	 *
	 * @var	bool
	 */
	private $paging = true;

	/**
	 * Default number of results per page
	 *
	 * @var	int
	 */
	private $pagingLimit = 30;

	/**
	 * Class used to define paging
	 *
	 * @var	SpoonDataGridPaging
	 */
	private $pagingClass = 'SpoonDataGridPaging';

	/**
	 * Parse status
	 *
	 * @var	bool
	 */
	private $parsed = false;

	/**
	 * Default sorting column
	 *
	 * @var	string
	 */
	private $sortingColumn;

	/**
	 * Sorting columns (cached when requested)
	 *
	 * @var array
	 */
	private $sortingColumns = array();

	/**
	 * Sorting icons
	 *
	 * @var	array
	 */
	private $sortingIcons = array(	'asc' => null,
									'ascSelected' => null,
									'desc' => null,
									'descSelected' => null);

	/**
	 * Sorting Labels
	 *
	 * @var	array
	 */
	private $sortingLabels = array(	'asc' => 'Sort ascending',
									'ascSelected' => 'Sorted ascending',
									'desc' => 'Sort descending',
									'descSelected' => 'Sorted descending');

	/**
	 * Default sorting method
	 *
	 * @var	string
	 */
	private $sortParameter;

	/**
	 * Source of the datagrid
	 *
	 * @var	SpoonDataGridSource
	 */
	private $source;

	/**
	 * Datagrid summary
	 *
	 * @var	string
	 */
	private $summary;

	/**
	 * Default or custom template
	 *
	 * @var	string
	 */
	private $template;

	/**
	 * Template instance
	 *
	 * @var	SpoonTemplate
	 */
	protected $tpl;

	/**
	 * Basic URL
	 *
	 * @var	string
	 */
	private $URL;

	/**
	 * Class constructor.
	 *
	 * @return	void
	 * @param	SpoonDataGridSource $source
	 * @param	string[optional] $template
	 */
	public function __construct(SpoonDataGridSource $source, $template = null)
	{
		// set source
		$this->setSource($source);

		// set template
		if($template !== null) $this->setTemplate($template);

		// load template
		$this->tpl = new SpoonTemplate();

		// create default columns
		$this->createColumns();
	}

	/**
	 * Adds a new column with a couple of options such as title, URL, image, ...
	 *
	 * @return	void
	 * @param	string $name				The name for this column, later used to refer to this column.
	 * @param	string[optional] $label		The label that will be displayed in the header cell.
	 * @param	string[optional] $value		The value you wish to display.
	 * @param	string[optional] $URL		The URL to refer to.
	 * @param	string[optional] $title		The title tag, in case you've provided a URL.
	 * @param	string[optional] $image		The location to an image, used to fill the column.
	 * @param	int[optional] $sequence		The sequence for this column, by default it will be added at the back.
	 */
	public function addColumn($name, $label = null, $value = null, $URL = null, $title = null, $image = null, $sequence = null)
	{
		// redefine name
		$name = (string) $name;

		// column already exists
		if(isset($this->columns[$name])) throw new SpoonDataGridException('A column with the name "'. $name .'" already exists.');

		// redefine sequence
		if($sequence === null) $sequence = count($this->columns) + 1;

		// new column
		$this->columns[$name] = new SpoonDataGridColumn($name, $label, $value, $URL, $title, $image, $sequence);

		// add the class as an attribute to this column
		$this->columns[$name]->setAttributes(array('class' => $name));
	}

	/**
	 * Builds the requested URL.
	 *
	 * @return	string
	 * @param	int $offset
	 * @param	string $order
	 * @param	string $sort
	 */
	private function buildURL($offset, $order, $sort)
	{
		return str_replace(array('[offset]', '[order]', '[sort]'), array($offset, $order, $sort), $this->URL);
	}

	/**
	 * Clears the attributes.
	 *
	 * @return	void
	 */
	public function clearAttributes()
	{
		$this->attributes['datagrid'] = array();
	}

	/**
	 * Clears the attributes for a specific column.
	 *
	 * @return	void
	 * @param	string $column		The name of the column you want to clear the column attributes from.
	 */
	public function clearColumnAttributes($column)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// column doesn't exist
			if(!isset($this->columns[(string) $column])) throw new SpoonDataGridException('The column "'. (string) $column .'" doesn\'t exist and therefor no attributes can be removed.');

			// exists
			$this->columns[(string) $column]->clearAttributes();
		}
	}

	/**
	 * Clears the even row attributes.
	 *
	 * @return	void
	 */
	public function clearEvenRowAttributes()
	{
		$this->attributes['row_even'] = array();
	}

	/**
	 * clears the odd row attributes.
	 *
	 * @return	void
	 */
	public function clearOddRowAttributes()
	{
		$this->attributes['row_odd'] = array();
	}

	/**
	 * Clears the row attributes.
	 *
	 * @return	void
	 */
	public function clearRowAttributes()
	{
		$this->attributes['row'] = array();
	}

	/**
	 * Creates the default columns, based on the initially provided source.
	 *
	 * @return	void
	 */
	private function createColumns()
	{
		// has results
		if($this->source->getNumResults() != 0)
		{
			// fetch the column names
			foreach($this->source->getColumns() as $column)
			{
				// add column
				$this->addColumn($column, $column, '['. $column .']', null, null, null, (count($this->columns) +1));

				// by default the column name will be added as a class
				$this->columns[$column]->setAttributes(array('class' => $column));

				// may be sorted on
				$this->allowedSortingColumns[] = $column;
			}
		}
	}

	/**
	 * Shows the output & stops script execution.
	 *
	 * @return	void
	 */
	public function display()
	{
		echo $this->getContent();
		exit;
	}

	/**
	 * Generates the array with the order columns.
	 *
	 * @return	void
	 */
	private function generateOrder()
	{
		// delete current cache of sortable columns
		$this->sortingColumns = array();

		// columns present
		if(count($this->columns) != 0)
		{
			// loop columns
			foreach($this->columns as $column)
			{
				// allowed sorting, sorting enabled specifically
				if(in_array($column->getName(), $this->allowedSortingColumns) && $column->getSorting())
				{
					// add to the list
					$this->sortingColumns[] = $column->getName();

					// default
					$default = $column->getName();
				}
			}

			// no default defined
			if($this->sortingColumn === null && isset($default)) $this->sortingColumn = $default;
		}
	}

	/**
	 * Retrieve all the datagrid attributes.
	 *
	 * @return	array
	 */
	public function getAttributes()
	{
		return $this->attributes['datagrid'];
	}

	/**
	 * Fetch the column object for a specific column.
	 *
	 * @return	SpoonDataGridColumn
	 * @param	string $column
	 */
	public function getColumn($column)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// column doesnt exist
			if(!isset($this->columns[$column])) throw new SpoonDataGridException('The column "'. $column .'" doesn\'t exist.');

			// exists
			return $this->columns[$column];
		}
	}

	/**
 	 * Fetch the list of columns in this datagrid.
 	 *
 	 * @return	array
	 */
	public function getColumns()
	{
		return $this->getColumnsSequence();
	}

	/**
	 * Retrieve the columns sequence.
	 *
	 * @return	array
	 */
	private function getColumnsSequence()
	{
		// init var
		$columns = array();

		// loop all the columns
		foreach($this->columns as $column) $columns[$column->getSequence()] = $column->getName();

		// reindex
		return (!empty($columns)) ? SpoonFilter::arraySortKeys($columns) : $columns;
	}

	/**
	 * Retrieve the parsed output.
	 *
	 * @return	string
	 */
	public function getContent()
	{
		// parse if needed
		if(!$this->parsed) $this->parse();

		// fetch content
		return $this->content;
	}

	/**
	 * Fetch the debug status.
	 *
	 * @return	bool
	 */
	public function getDebug()
	{
		return $this->debug;
	}

	/**
	 * Returns the html attributes based on an array.
	 *
	 * @return	string
	 * @param	array[optional] $array
	 */
	private function getHTMLAttributes(array $array = array())
	{
		// output
		$html = '';

		// loop elements
		foreach($array as $label => $value) $html .= ' '. $label .'="'. $value .'"';
		return $html;
	}

	/**
	 * Retrieve the offset value.
	 *
	 * @return	int
	 */
	public function getOffset()
	{
		// default offset
		$offset = null;

		// paging enabled
		if($this->paging)
		{
			// has results
			if($this->source->getNumResults() != 0)
			{
				// offset parameter defined
				if($this->offsetParameter !== null) $offset = $this->offsetParameter;

				// use default
				else $offset = (isset($_GET['offset'])) ? (int) $_GET['offset'] : 0;

				// offset cant be bigger than the number of results
				if($offset >= $this->source->getNumResults()) $offset = (int) $this->source->getNumResults() - $this->pagingLimit;

				// offset divided by the per page limit should have no rest
				if(($offset % $this->pagingLimit) != 0) $offset = 0;

				// offset minus the pagina limit may not go below zero
				if(($offset - $this->pagingLimit) < 0) $offset = 0;
			}

			// no results
			else $offset = 0;
		}

		return $offset;
	}

	/**
	 * Retrieves the column that's currently being sorted on.
	 *
	 * @return	string
	 */
	public function getOrder()
	{
		// default value
		$order = null;

		// sorting enabled
		if($this->getSorting())
		{
			/**
			 * First the list of columns that can be ordered on,
			 * must be re-generated
			 */
			$this->generateOrder();

			// order parameter defined
			if($this->orderParameter !== null) $order = $this->orderParameter;

			// defaut order
			else $order = (isset($_GET['order'])) ? (string) $_GET['order'] : null;

			// retrieve order
			$order = SpoonFilter::getValue($order, $this->sortingColumns, $this->sortingColumn);
		}

		return $order;
	}

	/**
	 * Retrieve the number of results for this datagrids' source.
	 *
	 * @return	int
	 */
	public function getNumResults()
	{
		return $this->source->getNumResults();
	}

	/**
	 * Is paging enabled?
	 *
	 * @return	bool
	 */
	public function getPaging()
	{
		return $this->paging;
	}

	/**
	 * Fetch name of the class that will be used to parse the paging.
	 *
	 * @return	string
	 */
	public function getPagingClass()
	{
		return $this->pagingClass;
	}

	/**
	 * Fetch the number of items that will be shown on each page.
	 *
	 * @return	int
	 */
	public function getPagingLimit()
	{
		return ($this->paging) ? $this->pagingLimit : null;
	}

	/**
	 * Retrieve the sorting method.
	 *
	 * @return	string		The sorting method, either asc or desc.
	 */
	public function getSort()
	{
		// sort parameter defined
		if($this->sortParameter !== null) $sort = $this->sortParameter;

		// default sort
		else $sort = (isset($_GET['sort'])) ? (string) $_GET['sort'] : null;

		// retrieve sort
		return SpoonFilter::getValue($sort, array('asc', 'desc'), 'asc');
	}

	/**
	 * Retrieve the sorting status.
	 *
	 * @return	bool
	 */
	public function getSorting()
	{
		// generate order
		$this->generateOrder();

		// sorting columns exist?
		return (count($this->sortingColumns) != 0) ? true : false;
	}

	/**
	 * Retrieve the location of the template that will be used.
	 *
	 * @return	string
	 */
	private function getTemplatePath()
	{
		return ($this->template != null) ? $this->template : dirname(__FILE__) .'/datagrid.tpl';
	}

	/**
	 * Retrieve the URL.
	 *
	 * @return	string	The URL that will be used, may contain variables with square brackets.
	 */
	public function getURL()
	{
		return $this->URL;
	}

	/**
	 * Parse the datagrid.
	 *
	 * @return	void
	 */
	private function parse()
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// fetch records
			$aRecords = $this->source->getData($this->getOffset(), $this->getPagingLimit(), $this->getOrder(), $this->getSort());

			// has results
			if(count($aRecords) != 0)
			{
				// compile directory
				$compileDirectory = ($this->compileDirectory !== null) ? $this->compileDirectory : dirname(realpath(__FILE__));
				$this->tpl->setCompileDirectory($compileDirectory);

				// only force compiling when debug is enabled
				if($this->debug) $this->tpl->setForceCompile(true);

				// table attributes
				$this->parseAttributes();

				// table summary
				$this->parseSummary();

				// caption/description
				$this->parseCaption();

				// header row
				$this->parseHeader();

				// actual rows
				$this->parseBody($aRecords);

				// pagination
				$this->parseFooter();

				// parse to buffer
				ob_start();
				$this->tpl->display($this->getTemplatePath());
				$this->content = ob_get_clean();

			}
		}

		// update parsed status
		$this->parsed = true;
	}

	/**
	 * Parses the datagrid attributes.
	 *
	 * @return	void
	 */
	private function parseAttributes()
	{
		$this->tpl->assign('attributes', $this->getHtmlAttributes($this->attributes['datagrid']));
	}

	/**
	 * Parses the body.
	 *
	 * @return	void
	 * @param	array $records
	 */
	private function parseBody(array $records)
	{
		// init var
		$rows = array();

		// columns sequence
		$sequence = $this->getColumnsSequence();

		// loop records
		foreach($records as $i => &$record)
		{
			// replace possible variables
			$record = $this->parseRecord($record);

			// parse column functions
			$record = $this->parseColumnFunctions($record);

			// reset row
			$row = array('attributes' => '', 'oddAttributes' => '', 'evenAttributes' => '', 'columns' => array());

			// row attributes
			$row['attributes'] = str_replace($record['labels'], $record['values'], $this->getHtmlAttributes($this->attributes['row']));

			// odd row attributes (reversed since the first $i = 0)
			if(!SpoonFilter::isOdd($i)) $row['oddAttributes'] = str_replace($record['labels'], $record['values'], $this->getHtmlAttributes($this->attributes['row_odd']));

			// even row attributes
			else $row['evenAttributes'] = str_replace($record['labels'], $record['values'], $this->getHtmlAttributes($this->attributes['row_even']));

			// define the columns
			$columns = array();

			// loop columns
			foreach($sequence as $name)
			{
				// column
				$column = $this->columns[$name];

				// has overwrite enabled
				if($column->getOverwrite())
				{
					// fetch key
					$iKey = array_search('['. $column->getName() .']', $record['labels']);

					// parse the actual value
					$columnValue = $record['values'][$iKey];
				}

				// no overwrite status
				else
				{
					// default value
					$columnValue = '';

					// has an url
					if($column->getURL() !== null)
					{
						// open url tag
						$columnValue .= 'getURL()) .'"';

						// add title
						$columnValue .= ' title="'. str_replace($record['labels'], $record['values'], $column->getURLTitle()) .'"';

						// confirm
						if($column->getConfirm() && $column->getConfirmMessage() !== null)
						{
							// default confirm
							if($column->getConfirmCustom() == '') $columnValue .= ' onclick="return confirm(\''. str_replace($record['labels'], $record['values'], $column->getConfirmMessage()) .'\');"';

							// custom confirm
							else
							{
								// replace the message
								$tmpValue = str_replace('%message%', $column->getConfirmMessage(), $column->getConfirmCustom());

								// make vars available
								$tmpValue = str_replace($record['labels'], $record['values'], $tmpValue);

								// add id
								$columnValue .= ' '. $tmpValue;
							}
						}

						// close start tag
						$columnValue .= '>';
					}

					// has an image
					if($column->getImage() !== null)
					{
						// open img tag
						$columnValue .= 'getImage()) .'"';

						// add title & alt
						$columnValue .= ' alt="'. str_replace($record['labels'], $record['values'], $column->getImageTitle()) .'"';
						$columnValue .= ' title="'. str_replace($record['labels'], $record['values'], $column->getImageTitle()) .'"';

						// close img tag
						$columnValue .= ' />';
					}

					// regular value
					else
					{
						// fetch key
						$iKey = array_search('['. $column->getName() .']', $record['labels']);

						// parse value
						$columnValue .= $record['values'][$iKey];
					}

					// has an url (close the tag)
					if($column->getURL() !== null) $columnValue .= '';
				}

				// fetch column attributes
				$columnAttributes = $this->getHtmlAttributes($column->getAttributes());

				// visible & iteration
				if(!$column->getHidden())
				{
					// add this column
					$columns[] = array('attributes' => $columnAttributes, 'value' => $columnValue);

					// add to custom list
					$row['column'][$name] = $columnValue;
				}
			}

			// add the columns to the rows
			$row['columns'] = $columns;

			// add the row
			$rows[] = $row;
		}

		// assign body
		$this->tpl->assign('rows', $rows);

		// assign the number of columns
		$this->tpl->assign('numColumns', count($rows[0]['columns']));
	}

	/**
	 * Parses the caption tag.
	 *
	 * @return	void
	 */
	private function parseCaption()
	{
		if($this->caption !== null) $this->tpl->assign('caption', $this->caption);
	}

	/**
	 * Parses the column functions.
	 *
	 * @return	array
	 * @param	array $record
	 */
	private function parseColumnFunctions($record)
	{
		// store old error reporting settings
		$currentErrorReporting = ini_get('error_reporting');

		// ignore warnings and notices
		error_reporting(E_WARNING | E_NOTICE);

		// loop functions
		foreach($this->columnFunctions as $function)
		{
			// no arguments given
			if($function['arguments'] == null) $value = call_user_func($function['function']);

			// array
			elseif(is_array($function['arguments']))
			{
				// replace arguments
				$function['arguments'] = str_replace($record['labels'], $record['values'], $function['arguments']);

				// execute function
				$value = call_user_func_array($function['function'], $function['arguments']);
			}

			// no null/array
			else $value = call_user_func($function['function'], str_replace($record['labels'], $record['values'], $function['arguments']));

			/**
			 * Now that we have the return value of this method, we can
			 * do the actual writeback to the column(s). If overwrite was
			 * true, we're going to enable the overwrite of the writeback column(s)
			 */

			// one column, that exists
			if(is_string($function['columns']) && isset($this->columns[$function['columns']]))
			{
				// fetch key
				$iKey = array_search('['. $function['columns'] .']', $record['labels']);

				// value was set
				if($iKey !== false)
				{
					// update value
					$record['values'][$iKey] = $value;

					// update overwrite
					if($function['overwrite']) $this->columns[$function['columns']]->setOverwrite(true);
				}
			}

			// write to multiple columns
			elseif(is_array($function['columns']) && count($function['columns']) != 0)
			{
				// loop target columns
				foreach($function['columns'] as $column)
				{
					// fetch key
					$iKey = array_search('['. $column .']', $record['labels']);

					// value was set
					if($iKey !== false)
					{
						// update value
						$record['values'][$iKey] = $value;

						// update overwrite
						if($function['overwrite']) $this->columns[$column]->setOverwrite(true);
					}
				}
			}
		}

		// restore error reporting
		error_reporting($currentErrorReporting);

		return $record;
	}

	/**
	 * Parses the footer.
	 *
	 * @return	void
	 */
	private function parseFooter()
	{
		// attributes
		$this->tpl->assign('footerAttributes', $this->getHtmlAttributes($this->attributes['footer']));

		// parse paging
		$this->parsePaging();
	}

	/**
	 * Parses the header row.
	 *
	 * @return	void
	 */
	private function parseHeader()
	{
		// init vars
		$header = array();

		// sequence
		$sequence = $this->getColumnsSequence();

		// sorting enabled?
		$sorting = $this->getSorting();

		// sortable columns
		$sortingColumns = array();
		foreach($sequence as $oColumn) if($this->columns[$oColumn]->getSorting()) $sortingColumns[] = $oColumn;

		// loop columns
		foreach($sequence as $name)
		{
			// define column
			$column = array();

			// column
			$oColumn = $this->columns[$name];

			// visible
			if(!$oColumn->getHidden())
			{
				// sorting globally enabled AND for this column
				if($sorting && in_array($name, $sortingColumns))
				{
					// init var
					$column['sorting'] = true;
					$column['noSorting'] = false;

					// sorted on this column?
					if($this->getOrder() == $name)
					{
						// sorted
						$column['sorted'] = true;
						$column['notSorted'] = false;

						// asc
						if($this->getSort() == 'asc')
						{
							$column['sortedAsc'] = true;
							$column['sortedDesc'] = false;
						}

						// desc
						else
						{
							$column['sortedAsc'] = false;
							$column['sortedDesc'] = true;
						}
					}

					/**
					 * This column is sortable, but there's currently not being
					 * sorted on this column.
					 */
					elseif(in_array($name, $sortingColumns))
					{
						$column['sorted'] = false;
						$column['notSorted'] = true;
					}

					/**
					 * URL's are parsed for the opposite column, as for the asc & desc version
					 * for this column. If the sorting is currently not on this column
					 * the default sorting method (mostly asc) will be used to define the opposite/default
					 * sorting method.
					 */

					// currently not sorting on this column
					if($this->getOrder() != $name) $sortingMethod = $this->columns[$name]->getSortingMethod();

					// sorted on this column ascending
					elseif($this->getSort() == 'asc') $sortingMethod = 'desc';

					// sorting on this column descending
					else $sortingMethod = 'asc';

					// build actual urls
					$column['sortingURL'] = $this->buildURL($this->getOffset(), $name, $sortingMethod);
					$column['sortingURLAsc'] = $this->buildURL($this->getOffset(), $name, 'asc');
					$column['sortingURLDesc'] = $this->buildURL($this->getOffset(), $name, 'desc');

					/**
					 * There's no point in parsing the icon for this column if there's
					 * not being sorted on this column.
					 */

					/**
					 * To define the default icon for sorting, we need to apply
					 * the same rules as with the default url. See those comments for
					 * the necessary details.
					 */
					if($this->getOrder() != $name) $sortingIcon = $this->sortingIcons[$this->columns[$name]->getSortingMethod()];

					// sorted on this column asc/desc
					elseif($this->getSort() == 'asc') $sortingIcon = $this->sortingIcons['ascSelected'];
					else $sortingIcon = $this->sortingIcons['descSelected'];

					// asc & desc icons
					$column['sortingIcon'] = $sortingIcon;
					$column['sortingIconAsc'] = ($this->getSort() == 'asc') ? $this->sortingIcons['ascSelected'] : $this->sortingIcons['asc'];
					$column['sortingIconDesc'] = ($this->getSort() == 'desc') ? $this->sortingIcons['descSelected'] : $this->sortingIcons['desc'];

					// not sorted on this column
					if($this->getOrder() != $name) $sortingLabel = $this->sortingLabels[$this->columns[$name]->getSortingMethod()];

					// sorted on this column asc/desc
					elseif($this->getSort() == 'asc') $sortingLabel = $this->sortingLabels['ascSelected'];
					else $sortingLabel = $this->sortingLabels['descSelected'];

					// add sorting labels
					$column['sortingLabel'] = $sortingLabel;
					$column['sortingLabelAsc'] = $this->sortingLabels['asc'];
					$column['sortingLabelDesc'] = $this->sortingLabels['desc'];
				}

				// no sorting enabled for this column
				else
				{
					$column['sorting'] = false;
					$column['noSorting'] = true;
				}

				// parse vars
				$column['label'] = $oColumn->getLabel();

				// add attributes
				$column['attributes'] = $this->getHTMLAttributes($oColumn->getHeaderAttributes());

				// add to array
				$header[] = $column;
			}
		}

		// default headers
		$this->tpl->assign('headers', $header);
	}

	/**
	 * Parses the paging.
	 *
	 * @return	void
	 */
	private function parsePaging()
	{
		// enabled
		if($this->paging)
		{
			// offset, order & sort
			$this->tpl->assign(array('offset', 'order', 'sort'), array($this->getOffset(), $this->getOrder(), $this->getSort()));

			// number of results
			$this->tpl->assign('iResults', $this->source->getNumResults());

			// number of pages
			$this->tpl->assign('iPages', ceil($this->source->getNumResults() / $this->pagingLimit));

			// current page
			$this->tpl->assign('iCurrentPage', ceil($this->getOffset() / $this->pagingLimit) + 1);

			// number of items per page
			$this->tpl->assign('iPerPage', $this->pagingLimit);

			// parse paging
			$content = call_user_func(array($this->pagingClass, 'getContent'), $this->URL, $this->getOffset(), $this->getOrder(), $this->getSort(), $this->source->getNumResults(), $this->pagingLimit, $this->debug, $this->compileDirectory);

			// asign content
			$this->tpl->assign('paging', $content);
		}
	}

	/**
	 * Parses the record.
	 *
	 * @return	array
	 * @param	array $record
	 */
	private function parseRecord(array $record)
	{
		// init var
		$array = array('labels' => array(), 'values' => array());

		// create labels/values array
		foreach($record as $label => $value)
		{
			$array['labels'][] = '['. $label .']';
			$array['values'][] = $value;
		}

		// add offset?
		if($this->paging)
		{
			$array['labels'][] = '[offset]';
			$array['values'][] = $this->getOffset();
		}

		// sorting
		if(count($this->sortingColumns) != 0)
		{
			$array['labels'][] = '[order]';
			$array['labels'][] = '[sort]';
			// --
			$array['values'][] = $this->getOrder();
			$array['values'][] = $this->getSort();
		}

		// loop the record fields
		foreach($this->columns as $column)
		{
			// this column is an extra field, added in the datagrid
			if(!in_array('['. $column->getName() .']', $array['labels']))
			{

				$array['values'][] = str_replace($array['labels'], $array['values'], $column->getValue());
				$array['labels'][] = '['. $column->getName() .']';
			}
		}

		return $array;
	}

	/**
	 * Parses the summary.
	 *
	 * @return	void
	 */
	private function parseSummary()
	{
		if($this->summary !== null) $this->tpl->assign('summary', $this->summary);
	}

	/**
	 * Set main datagrid attributes.
	 *
	 * @return	void
	 * @param	array $attributes
	 */
	public function setAttributes(array $attributes)
	{
		foreach($attributes as $key => $value) $this->attributes['datagrid'][(string) $key] = (string) $value;
	}

	/**
	 * Sets the table caption or main description.
	 *
	 * @return	void
	 * @param	string $value
	 */
	public function setCaption($value)
	{
		$this->caption = (string) $value;
	}

	/**
	 * Set one or more attributes for a specific column.
	 *
	 * @return	void
	 * @param	string $column
	 * @param	array $attributes
	 */
	public function setColumnAttributes($column, array $attributes)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// column doesnt exist
			if(!isset($this->columns[$column])) throw new SpoonDataGridException('The column "'. $column .'" doesn\'t exist, therefor no attributes can be added.');

			// exists
			else $this->columns[$column]->setAttributes($attributes);
		}
	}

	/**
	 * Set a custom column confirm message.
	 *
	 * @return	void
	 * @param	string $column
	 * @param	string $message
	 * @param	string[optional] $custom
	 */
	public function setColumnConfirm($column, $message, $custom = null)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// column doesnt exist
			if(!isset($this->columns[$column])) throw new SpoonDataGridException('The column "'. $column .'" doesn\'t exist, therefor no confirm message/script can be added.');

			// exists
			else $this->columns[$column]->setConfirm($message, $custom);
		}
	}

	/**
	 * Sets the column function to be executed for every row.
	 *
	 * @return	void
	 * @param	mixed $function
	 * @param	mixed[optional] $arguments
	 * @param	mixed $columns
	 * @param	bool[optional] $overwrite
	 */
	public function setColumnFunction($function, $arguments = null, $columns, $overwrite = false)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// regular function
			if(!is_array($function))
			{
				// function checks
				if(!function_exists((string) $function)) throw new SpoonDataGridException('The function "'. (string) $function .'" doesn\'t exist.');
			}

			// class method
			else
			{
				// method checks
				if(count($function) != 2) throw new SpoonDataGridException('When providing a method for a column function it must be like array(\'class\', \'method\')');

				// method doesn't exist
				elseif(!method_exists($function[0], $function[1])) throw new SpoonDataGridException('The method '. (string) $function[0] .'::'. (string) $function[1] .' does not exist.');
			}

			// add to function stack
			$this->columnFunctions[] = array('function' => $function, 'arguments' => $arguments, 'columns' => $columns, 'overwrite' => (bool) $overwrite);
		}
	}

	/**
	 * Set one or more attributes for a columns' header.
	 *
	 * @return	void
	 * @param	string $column
	 * @param	array $attributes
	 */
	public function setColumnHeaderAttributes($column, array $attributes)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// column doesnt exist
			if(!isset($this->columns[$column])) throw new SpoonDataGridException('The column "'. $column .'" doesn\'t exist, therefor no attributes can be added to its header.');

			// exists
			else $this->columns[$column]->setHeaderAttributes($attributes);
		}
	}

	/**
	 * Sets a single column hidden.
	 *
	 * @return	void
	 * @param	string $column
	 * @param	bool[optional] $on
	 */
	public function setColumnHidden($column, $on = true)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// column doesn't exist
			if(!isset($this->columns[(string) $column])) throw new SpoonDataGridException('The column "'. (string) $column .'" doesn\'t exist and therefor can\'t be set hidden.');

			// exists
			$this->columns[(string) $column]->setHidden($on);
		}
	}

	/**
	 * Sets one or more columns hidden.
	 *
	 * @return	void
	 * @param	array $columns
	 */
	public function setColumnsHidden($columns)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// array
			if(is_array($columns)) foreach($columns as $column) $this->setColumnHidden((string) $column);

			// multiple arguments
			else
			{
				// set columns hidden
				foreach(func_get_args() as $column) $this->setColumnHidden($column);
			}
		}
	}

	/**
	 * Sets the columns sequence.
	 *
	 * @return	void
	 * @param	array $columns
	 */
	public function setColumnsSequence($columns)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// array
			if(is_array($columns)) call_user_method_array('setColumnsSequence', $this, $columns);

			// multiple arguments
			else
			{
				// current sequence
				$sequences = $this->getColumnsSequence();

				// fetch arguments
				$arguments = func_get_args();

				// build columns
				$columns = (is_array($arguments[0])) ? $arguments[0] : $arguments;

				// counter
				$i = 1;

				// loop colums
				foreach($columns as $column)
				{
					// column exists
					if(!isset($this->columns[(string) $column])) throw new SpoonDataGridException('The column "'. (string) $column .'" doesn\'t exist. Therefor its sequence can\'t be altered.');

					// update sequence
					$this->columns[(string) $column]->setSequence($i);

					// remove from the original list
					$iKey = (int) array_search((string) $column, $sequences);
					unset($sequences[$iKey]);

					// update counter
					$i++;
				}

				// reset counter
				$i = 1;

				// add remaining columns
				foreach($sequences as $sequence)
				{
					// update sequence
					$this->columns[$sequence]->setSequence(count($columns) + $i);

					// update counter
					$i++;
				}
			}
		}
	}

	/**
	 * Set the default sorting method for a column.
	 *
	 * @return	void
	 * @param	string $column
	 * @param	string[optional] $sort
	 */
	public function setColumnSortingMethod($column, $sort = 'asc')
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// column doesn't exist
			if(!isset($this->columns[(string) $column])) throw new SpoonDataGridException('The column "'. (string) $column .'" doesn\'t exist and therefor no default sorting method can be applied to it.');

			// exists
			$this->columns[(string) $column]->setSortingMethod($sort);
		}
	}

	/**
	 * Set the URL for a column.
	 *
	 * @return	void
	 * @param	string $column
	 * @param	string $URL
	 * @param	string[optional] $title
	 */
	public function setColumnURL($column, $URL, $title = null)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// column doesn't exist
			if(!isset($this->columns[(string) $column])) throw new SpoonDataGridException('The column "'. (string) $column .'" doesn\'t exist and therefor no URL can be applied.');

			// exists
			$this->columns[(string) $column]->setURL($URL, $title);
		}
	}

	/**
	 * Sets the compile directory.
	 *
	 * @return	void
	 * @param	string $path
	 */
	public function setCompileDirectory($path)
	{
		$this->compileDirectory = (string) $path;
	}

	/**
	 * Adjust the debug setting.
	 *
	 * @return	void
	 * @param	bool[optional] $on
	 */
	public function setDebug($on = true)
	{
		$this->debug = (bool) $on;
	}

	/**
	 * Set the even row attributes.
	 *
	 * @return	void
	 * @param	array $attributes
	 */
	public function setEvenRowAttributes(array $attributes)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// add to the list
			foreach($attributes as $key => $value) $this->attributes['row_even'][(string) $key] = (string) $value;
		}
	}

	/**
	 * Set the header labels.
	 *
	 * @return	void
	 * @param	array $labels
	 */
	public function setHeaderLabels(array $labels)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// loop the keys
			foreach($labels as $column => $label)
			{
				// column doesn't exist
				if(!isset($this->columns[$column])) throw new SpoonDataGridException('The column "'. $column .'" doesn\t exist, therefor no label can be assigned to it.');

				// exists
				else $this->columns[$column]->setLabel($label);
			}
		}
	}

	/**
	 * Set the odd row attributes.
	 *
	 * @return	void
	 * @param	array $attributes
	 */
	public function setOddRowAttributes(array $attributes)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// add to the list
			foreach($attributes as $key => $value) $this->attributes['row_odd'][(string) $key] = (string) $value;
		}
	}

	/**
	 * Sets the value for offset. eg from the URL.
	 *
	 * @return	void
	 * @param	int[optional] $value
	 */
	public function setOffsetParameter($value = null)
	{
		$this->offsetParameter = (int) $value;
	}

	/**
	 * Sets the value for the order. eg from the URL.
	 *
	 * @return	void
	 * @param	string[optional] $value
	 */
	public function setOrderParameter($value = null)
	{
		$this->orderParameter = (string) $value;
	}

	/**
	 * Allow/disallow showing the results on multiple pages.
	 *
	 * @return	void
	 * @param	bool[optional] $on
	 */
	public function setPaging($on = false)
	{
		$this->paging = (bool) $on;
	}

	/**
	 * Sets an alternative paging class.
	 *
	 * @return	void
	 * @param	string $class
	 */
	public function setPagingClass($class)
	{
		// class cant be found
		if(!class_exists((string) $class)) throw new SpoonDataGridException('The class "'. (string) $class .'" you provided for the alternative paging can not be found.');

		// class exists
		else
		{
			// does not impmlement the interface
			if(!in_array('iSpoonDataGridPaging', class_implements($class))) throw new SpoonDataGridException('The paging class you provided does not implement the "iSpoonDataGridPaging" interface');

			// all is fine
			else $this->pagingClass = $class;
		}
	}

	/**
	 * Sets the number of results per page.
	 *
	 * @return	void
	 * @param	int[optional] $limit
	 */
	public function setPagingLimit($limit = 30)
	{
		$this->pagingLimit = abs((int) $limit);
	}

	/**
	 * Sets the row attributes.
	 *
	 * @return	void
	 * @param	array $attributes
	 */
	public function setRowAttributes(array $attributes)
	{
		foreach($attributes as $key => $value) $this->attributes['row'][(string) $key] = (string) $value;
	}

	/**
	 * Sets the columns that may be sorted on.
	 *
	 * @return	void
	 * @param	array $columns
	 * @param	string[optional] $default
	 */
	public function setSortingColumns(array $columns, $default = null)
	{
		// has results
		if($this->source->getNumResults() > 0)
		{
			// loop columns
			foreach($columns as $column)
			{
				// column doesn't exist
				if(!isset($this->columns[(string) $column])) throw new SpoonDataGridException('The column "'. (string) $column .'" doesn\'t exist and therefor can\'t be sorted on.');

				// column exists
				else
				{
					// not sortable
					if(!in_array((string) $column, $this->allowedSortingColumns)) throw new SpoonDataGridException('The column "'. (string) $column .'" can\'t be sorted on.');

					// sortable
					else
					{
						// enable sorting
						$this->columns[(string) $column]->setSorting(true);

						// set default sorting
						if(!isset($defaultColumn)) $defaultColumn = (string) $column;
					}
				}
			}

			// default column set
			if($default !== null && in_array($defaultColumn, $columns)) $defaultColumn = (string) $default;

			// default column is not good
			if(!in_array($defaultColumn, $this->allowedSortingColumns)) throw new SpoonDataGridException('The column "'. $defaultColumn .'" can\'t be set as the default sorting column, because it doesn\'t exist or may not be sorted on.');

			// set default column
			$this->sortingColumn = $defaultColumn;
		}
	}

	/**
	 * Sets the sorting icons.
	 *
	 * @return	void
	 * @param	string[optional] $asc
	 * @param	string[optional] $ascSelected
	 * @param	string[optional] $desc
	 * @param	string[optional] $descSelected
	 */
	public function setSortingIcons($asc = null, $ascSelected = null, $desc = null, $descSelected)
	{
		if($asc !== null) $this->sortingIcons['asc'] = (string) $asc;
		if($ascSelected !== null) $this->sortingIcons['ascSelected'] = (string) $ascSelected;
		if($desc !== null) $this->sortingIcons['desc'] = (string) $desc;
		if($descSelected !== null) $this->sortingIcons['descSelected'] = (string) $descSelected;
	}

	/**
	 * Sets the sorting labels.
	 *
	 * @return	void
	 * @param	string[optional] $asc
	 * @param	string[optional] $ascSelected
	 * @param	string[optional] $desc
	 * @param	string[optional] $descSelected
	 */
	public function setSortingLabels($asc = null, $ascSelected = null, $desc = null, $descSelected = null)
	{
		if($asc !== null) $this->sortingLabels['asc'] = (string) $asc;
		if($ascSelected !== null) $this->sortingLabels['ascSelected'] = (string) $ascSelected;
		if($desc !== null) $this->sortingLabels['desc'] = (string) $desc;
		if($descSelected !== null) $this->sortingLabels['descSelected'] = (string) $descSelected;
	}

	/**
	 * Sets the value to sort.
	 *
	 * @return	void
	 * @param	string[optional] $value
	 */
	public function setSortParameter($value = 'desc')
	{
		$this->sortParameter = SpoonFilter::getValue($value, array('asc', 'desc'), 'asc');
	}

	/**
	 * Sets the source for this datagrid.
	 *
	 * @return	void
	 * @param	SpoonDataGridSource $source
	 */
	private function setSource(SpoonDataGridSource $source)
	{
		$this->source = $source;
	}

	/**
	 * Sets the table summary.
	 *
	 * @return	void
	 * @param	string $value
	 */
	public function setSummary($value)
	{
		$this->summary = (string) $value;
	}

	/**
	 * Sets the path to the template file.
	 *
	 * @return	void
	 * @param	string $template
	 */
	public function setTemplate($template)
	{
		$this->template = (string) $template;
	}

	/**
	 * Defines the default URL.
	 *
	 * @return	void
	 * @param	string $URL
	 */
	public function setURL($URL)
	{
		$this->URL = (string) $URL;
	}
}

/**
 * This class is internally used by the datagrid to hold the data
 * for every column.
 *
 * @package		html
 * @subpackage	datagrid
 *
 *
 * @author		Davy Hellemans <davy@spoon-library.be>
 * @since		1.0.0
 */
class SpoonDataGridColumn
{
	/**
	 * Main cell attributes
	 *
	 * @var	array
	 */
	private $attributes = array('general' => array(), 'header' => array());

	/**
	 * Confirmation required (via URL)
	 *
	 * @var	bool
	 */
	private $confirm = false;

	/**
	 * Custom confirmation script
	 *
	 * @var	string
	 */
	private $confirmCustom;

	/**
	 * Confirmation message
	 *
	 * @var	string
	 */
	private $confirmMessage;

	/**
	 * Is this column hidden
	 *
	 * @var	bool
	 */
	private $hidden = false;

	/**
	 * Image for this column
	 *
	 * @var	string
	 */
	private $image;

	/**
	 * Alt/title tag for the image
	 *
	 * @var	string
	 */
	private $imageTitle;

	/**
	 * Label for the header column
	 *
	 * @var	string
	 */
	private $label;

	/**
	 * Name for this column
	 *
	 * @var	string
	 */
	private $name;

	/**
	 * Does the value overwrite images & url
	 *
	 * @var	bool
	 */
	private $overwriteValue = false;

	/**
	 * Sequence of this column
	 *
	 * @var	int
	 */
	private $sequence = 0;

	/**
	 * Is this column sortable
	 *
	 * @var	bool
	 */
	private $sorting = false;

	/**
	 * The default sorting method for this column
	 *
	 * @var	string
	 */
	private $sortingMethod = 'asc';

	/**
	 * URL for this column
	 *
	 * @var	string
	 */
	private $URL;

	/**
	 * Url title tag
	 *
	 * @var	string
	 */
	private $urlTitle;

	/**
	 * The value for this column
	 *
	 * @var	string
	 */
	private $value;

	/**
	 * Class constructor.
	 *
	 * @return	void
	 * @param	string $name
	 * @param	string[optional] $label
	 * @param	string[optional] $value
	 * @param	string[optional] $URL
	 * @param	string[optional] $image
	 * @param	string[optional] $sequence
	 */
	public function __construct($name, $label = null, $value = null, $URL = null, $title = null, $image = null, $sequence = null)
	{
		// name, label & value
		$this->name = (string) $name;
		$this->label = (string) $label;
		$this->value = (string) $value;

		// url, title & image
		if($URL !== null) $this->URL = (string) $URL;
		if($title !== null) $this->urlTitle = (string) $title;
		if($image !== null) $this->image = (string) $image;

		// sequence
		$this->sequence = (int) $sequence;
	}

	/**
	 * Clears the list of attributes for this column.
	 *
	 * @return	void
	 */
	public function clearAttributes()
	{
		$this->attributes['general'] = array();
	}

	/**
	 * Retrieve the attributes.
	 *
	 * @return	array
	 */
	public function getAttributes()
	{
		return $this->attributes['general'];
	}

	/**
	 * Retrieve the confirm setting.
	 *
	 * @return	bool
	 */
	public function getConfirm()
	{
		return $this->confirm;
	}

	/**
	 * Fetch the confirm custom script.
	 *
	 * @return	string
	 */
	public function getConfirmCustom()
	{
		return $this->confirmCustom;
	}

	/**
	 * Retrieve the confirm message.
	 *
	 * @return	string
	 */
	public function getConfirmMessage()
	{
		return $this->confirmMessage;
	}

	/**
	 * Retrieve the header attributes.
	 *
	 * @return	array
	 */
	public function getHeaderAttributes()
	{
		return $this->attributes['header'];
	}

	/**
	 * Retrieve the hidden status.
	 *
	 * @return	bool
	 */
	public function getHidden()
	{
		return $this->hidden;
	}

	/**
	 * Retrieve the image.
	 *
	 * @return	string
	 */
	public function getImage()
	{
		return $this->image;
	}

	/**
	 * Retrieve the image title.
	 *
	 * @return	string
	 */
	public function getImageTitle()
	{
		return $this->imageTitle;
	}

	/**
	 * Retrieve the label.
	 *
	 * @return	string
	 */
	public function getLabel()
	{
		return $this->label;
	}

	/**
	 * Retrieve the name.
	 *
	 * @return	string
	 */
	public function getName()
	{
		return $this->name;
	}

	/**
	 * Retrieve the overwrite value setting.
	 *
	 * @return	bool
	 */
	public function getOverwrite()
	{
		return $this->overwriteValue;
	}

	/**
	 * Retrieve the sequence.
	 *
	 * @return	int
	 */
	public function getSequence()
	{
		return $this->sequence;
	}

	/**
	 * Retrieve the sorting setting.
	 *
	 * @return	bool
	 */
	public function getSorting()
	{
		return $this->sorting;
	}

	/**
	 * Retrieve the default sorting method.
	 *
	 * @return	void
	 */
	public function getSortingMethod()
	{
		return $this->sortingMethod;
	}

	/**
	 * Retrieve the URL.
	 *
	 * @return	string
	 */
	public function getURL()
	{
		return $this->URL;
	}

	/**
	 * Retrieve the URL title tag.
	 *
	 * @return	string
	 */
	public function getURLTitle()
	{
		return $this->urlTitle;
	}

	/**
	 * Retrieve the value.
	 *
	 * @return	string
	 */
	public function getValue()
	{
		return $this->value;
	}

	/**
	 * Set the attributes.
	 *
	 * @return	void
	 * @param	array $attributes
	 */
	public function setAttributes(array $attributes)
	{
		foreach($attributes as $key => $value) $this->attributes['general'][(string) $key] = (string) $value;
	}

	/**
	 * Sets the confirm message.
	 *
	 * @return	void
	 * @param	string $message
	 * @param	string[optional] $custom
	 */
	public function setConfirm($message, $custom = null)
	{
		$this->confirm = true;
		$this->confirmMessage = SpoonFilter::htmlentities((string) $message);
		$this->confirmCustom = (string) $custom;
	}

	/**
	 * Set the header attributes.
	 *
	 * @return	void
	 * @param	array $attributes
	 */
	public function setHeaderAttributes(array $attributes)
	{
		foreach($attributes as $key => $value) $this->attributes['header'][(string) $key] = (string) $value;
	}

	/**
	 * Sets the hidden status.
	 *
	 * @return	void
	 * @param	bool[optional] $on
	 */
	public function setHidden($on = true)
	{
		$this->hidden = (bool) $on;
	}

	/**
	 * Sets the image.
	 *
	 * @return	void
	 * @param	string $image
	 * @param	string $title
	 */
	public function setImage($image, $title)
	{
		$this->image = (string) $image;
		$this->imageTitle = (string) $title;
	}

	/**
	 * Sets the label.
	 *
	 * @return	void
	 * @param	string $label
	 */
	public function setLabel($label)
	{
		$this->label = (string) $label;
	}

	/**
	 * Sets the overwrite status.
	 *
	 * @return	void
	 * @param	bool[optional] $on
	 */
	public function setOverwrite($on = true)
	{
		$this->overwriteValue = (bool) $on;
	}

	/**
	 * Sets the sequence.
	 *
	 * @return	void
	 * @param	int $sequence
	 */
	public function setSequence($sequence)
	{
		$this->sequence = (int) $sequence;
	}

	/**
	 * Sets the sorting.
	 *
	 * @return	void
	 * @param	bool[optional] $on
	 */
	public function setSorting($on = true)
	{
		$this->sorting = (bool) $on;
	}

	/**
	 * Sets the default sorting method for this column.
	 *
	 * @return	void
	 * @param	string[optional] $sort
	 */
	public function setSortingMethod($sort = 'asc')
	{
		$this->sortingMethod = SpoonFilter::getValue($sort, array('asc', 'desc'), 'asc');
	}

	/**
	 * Sets the URL.
	 *
	 * @return	void
	 * @param	string $URL
	 * @param	string[optional] $title
	 */
	public function setURL($URL, $title = null)
	{
		$this->URL = (string) $URL;
		$this->urlTitle = (string) $title;
	}

	/**
	 * Sets the value & its overwrite setting.
	 *
	 * @return	void
	 * @param	string $value
	 * @param	bool[optional] $overwrite
	 */
	public function setValue($value, $overwrite = false)
	{
		$this->value = (string) $value;
		$this->overwriteValue = (bool) $overwrite;
	}
}

/**
 * This class is the base class for sources used with datagrids
 *
 * @package		html
 * @subpackage	datagrid
 *
 *
 * @author		Davy Hellemans <davy@spoon-library.be>
 * @since		1.0.0
 */
class SpoonDataGridSource
{
	/**
	 * Final data
	 *
	 * @var	array
	 */
	protected $data = array();

	/**
	 * Number of results
	 *
	 * @var	int
	 */
	protected $numResults = 0;

	/**
	 * Fetch the number of results
	 *
	 * @return	int
	 */
	public function getNumResults()
	{
		return $this->numResults;
	}
}

/**
 * This class is used for datagrids based on array sources
 *
 * @package		html
 * @subpackage	datagrid
 *
 *
 * @author		Davy Hellemans <davy@spoon-library.be>
 * @since		1.0.0
 */
class SpoonDataGridSourceArray extends SpoonDataGridSource
{
	/**
	 * Static ordering (for compare method)
	 *
	 * @var	string
	 */
	public static $order;

	/**
	 * Class constructor.
	 *
	 * @return	void
	 * @param	array $array
	 */
	public function __construct(array $array)
	{
		 // set data
		 $this->data = (array) $array;

		// set number of results
		$this->setNumResults();
	}

	/**
	 * Apply the sorting method.
	 *
	 * @return	int
	 * @param	array $firstArray
	 * @param	array $secondArray
	 */
	public static function applySorting($firstArray, $secondArray)
	{
		if($firstArray[self::$order] < $secondArray[self::$order]) return -1;
		elseif($firstArray[self::$order] > $secondArray[self::$order]) return 1;
		else return 0;
	}

	/**
	 * Retrieve the columns.
	 *
	 * @return	array
	 */
	public function getColumns()
	{
		if($this->numResults != 0) return array_keys($this->data[0]);
	}

	/**
	 * Fetch the data as an array.
	 *
	 * @return	array
	 * @param	int[optional] $offset
	 * @param	int[optional] $limit
	 * @param	string[optional] $order
	 * @param	string[optional] $sort
	 */
	public function getData($offset = null, $limit = null, $order = null, $sort = null)
	{
		// sorting ?
		if($order !== null)
		{
			// static shizzle
			self::$order = $order;

			// apply sorting
			uasort($this->data, array('SpoonDataGridSourceArray', 'applySorting'));

			// reverse if needed?
			if($sort !== null && $sort == 'desc') $this->data = array_reverse($this->data, true);
		}

		// offset & limit
		if($offset !== null && $limit !== null)
		{
			$this->data = array_slice($this->data, $offset, $limit);
		}

		return $this->data;
	}

	/**
	 * Sets the number of results.
	 *
	 * @return	void
	 */
	private function setNumResults()
	{
		$this->numResults = (int) count($this->data);
	}
}

/**
 * This class is used for datagrids based on database sources
 *
 * @package		html
 * @subpackage	datagrid
 *
 *
 * @author		Davy Hellemans <davy@spoon-library.be>
 * @since		1.0.0
 */
class SpoonDataGridSourceDB extends SpoonDataGridSource
{
	/**
	 * SpoonDatabase instance
	 *
	 * @var	SpoonDatabase
	 */
	private $db;

	/**
	 * Query to calculate the number of results
	 *
	 * @var	string
	 */
	private $numResultsQuery;

	/**
	 * Custom parameters for the numResults query
	 *
	 * @var	array
	 */
	private $numResultsQueryParameters = array();

	/**
	 * Query to fetch the results
	 *
	 * @var	string
	 */
	private $query;

	/**
	 * Custom parameters for the query
	 *
	 * @var	array
	 */
	private $queryParameters = array();

	/**
	 * Class construtor.
	 *
	 * @return	void
	 * @param	SpoonDatabase $dbConnection
	 * @param	mixed $query
	 * @param	mixed[optional] $numResultsQuery
	 */
	public function __construct(SpoonDatabase $dbConnection, $query, $numResultsQuery = null)
	{
		// database connection
		$this->db = $dbConnection;

		// set queries
		$this->setQuery($query, $numResultsQuery);
	}

	/**
	 * Get the list of columns.
	 *
	 * @return	array
	 */
	public function getColumns()
	{
		// has results
		if($this->numResults != 0)
		{
			// build query
			switch($this->db->getDriver())
			{
				case 'mysql':
					// @todo davy - this might also be LIMIT with a tab before or after instead of a space, use a decent regular expression to fix this.
					$query = (substr_count($this->query, 'LIMIT ') > 0) ? $this->query : $this->query .' LIMIT 1';
				break;

				default:
					throw new SpoonDataGridException('No datagrid support has been written for this database backend ('. $this->db->getDriver() .')');
				break;
			}

			// fetch record
			$record = $this->db->getRecord($query, $this->queryParameters);

			// fetch columns
			return array_keys($record);
		}
	}

	/**
	 * Fetch the data as an array.
	 *
	 * @return	array
	 * @param	int[optional] $offset
	 * @param	int[optional] $limit
	 * @param	string[optional] $order
	 * @param	string[optional] $sort
	 */
	public function getData($offset = null, $limit = null, $order = null, $sort = null)
	{
		// fetch query
		$query = $this->query;

		// order & sort defined
		if($order !== null && $sort !== null) $query .= " ORDER BY $order $sort";

		// offset & limit defined
		if($offset !== null && $limit !== null) $query .= " LIMIT $offset, $limit";

		// fetch data
		return (array) $this->db->getRecords($query, $this->queryParameters);
	}

	/**
	 * Set the number of results.
	 *
	 * @return	void
	 */
	private function setNumResults()
	{
		// based on resultsQuery
		if($this->numResultsQuery != '') $this->numResults = (int) $this->db->getVar($this->numResultsQuery, $this->numResultsQueryParameters);

		// based on regular query
		else $this->numResults = (int) $this->db->getNumRows($this->query, $this->queryParameters);
	}

	/**
	 * Set the queries.
	 *
	 * @return	void
	 * @param	string $query
	 * @param	string[optional] $numResultsQuery
	 */
	private function setQuery($query, $numResultsQuery = null)
	{
		// query with parameters
		if(is_array($query) && count($query) > 1 && isset($query[0]) && isset($query[1]))
		{
			$this->query = str_replace(';', '', (string) $query[0]);
			$this->queryParameters = (array) $query[1];
		}

		// no parameters
		else $this->query = str_replace(';', '', (string) $query);

		// numResults query with parameters
		if(is_array($numResultsQuery) && count($numResultsQuery) > 1 && isset($numResultsQuery[0]) && isset($numResultsQuery[1]))
		{
			$this->numResultsQuery = str_replace(';', '', (string) $numResultsQuery[0]);
			$this->numResultsQueryParameters = (array) $numResultsQuery[1];
		}

		// no paramters
		else $this->numResultsQuery = (string) $numResultsQuery;

		// set num results
		$this->setNumResults();
	}
}

interface iSpoonDataGridPaging
{
	public static function getContent($URL, $offset, $order, $sort, $numResults, $numPerPage, $debug = true, $compileDirectory = null);
}

/**
 * This class is the base class for pagination
 *
 * @package		html
 * @subpackage	datagrid
 *
 *
 * @author		Davy Hellemans <davy@spoon-library.be>
 * @since		1.0.0
 */
class SpoonDataGridPaging implements iSpoonDataGridPaging
{
	/**
	 * Next label
	 *
	 * @var	string
	 */
	private static $next = 'next';

	/**
	 * Previous label
	 *
	 * @var	string
	 */
	private static $previous = 'previous';

	/**
	 * Builds & returns the pagination.
	 *
	 * @return	string
	 * @param	string $URL
	 * @param	int $offset
	 * @param	string $order
	 * @param	string $sort
	 * @param	int $numResults
	 * @param	int $numPerPage
	 * @param	bool[optional] $debug
	 * @param	string[optional] $compileDirectory
	 */
	public static function getContent($URL, $offset, $order, $sort, $numResults, $numPerPage, $debug = true, $compileDirectory = null)
	{
		// current page
		$currentPage = ceil($offset / $numPerPage) + 1;

		// number of pages
		$numPages = ceil($numResults / $numPerPage);

		// load template
		$tpl = new SpoonTemplate();

		// compile directory
		if($compileDirectory !== null) $tpl->setCompileDirectory($compileDirectory);
		else $tpl->setCompileDirectory(dirname(__FILE__));

		// force compiling
		$tpl->setForceCompile((bool) $debug);

		// previous url
		if($currentPage > 1)
		{
			// label & url
			$previousLabel = self::$previous;
			$previousURL = str_replace(array('[offset]', '[order]', '[sort]'), array(($offset - $numPerPage), $order, $sort), $URL);
			$tpl->assign('previousLabel', $previousLabel);
			$tpl->assign('previousURL', $previousURL);
		}

		// next url
		if($currentPage < $numPages)
		{
			// label & url
			$nextLabel = self::$next;
			$nextURL = str_replace(array('[offset]', '[order]', '[sort]'), array(($offset + $numPerPage), $order, $sort), $URL);
			$tpl->assign('nextLabel', $nextLabel);
			$tpl->assign('nextURL', $nextURL);
		}

		// limit
		$limit = 7;
		$breakpoint = 4;
		$items = array();

		/**
		 * Less than or 7 pages. We know all the keys, and we put them in the array
		 * that we will use to generate the actual pagination.
		 */
		if($numPages <= $limit)
		{
			for($i = 1; $i <= $numPages; $i++) $items[$i] = $i;
		}

		// more than 7 pages
		else
		{
			// first page
			if($currentPage == 1)
			{
				// [1] 2 3 4 5 6 7 8 9 10 11 12 13
				for($i = 1; $i <= $limit; $i++) $items[$i] = $i;
				$items[$limit + 1] = '...';
			}

			// last page
			elseif($currentPage == $numPages)
			{
				// 1 2 3 4 5 6 7 8 9 10 11 12 [13]
				$items[$numPages -  $limit - 1] = '...';
				for($i = ($numPages - $limit); $i <= $numPages; $i++) $items[$i] = $i;
			}

			// other page
			else
			{
				// 1 2 3 [4] 5 6 7 8 9 10 11 12 13

				// define min & max
				$min = $currentPage - $breakpoint + 1;
				$max = $currentPage + $breakpoint - 1;

				// minimum doesnt exist
				while($min <= 0)
				{
					$min++;
					$max++;
				}

				// maximum doesnt exist
				while($max > $numPages)
				{
					$min--;
					$max--;
				}

				// create the list
				if($min != 1) $items[$min - 1] = '...';
				for($i = $min; $i <= $max; $i++) $items[$i] = $i;
				if($max != $numPages) $items[$max + 1] = '...';
			}
		}

		// init var
		$pages = array();

		// loop pages
		foreach($items as $item)
		{
			// counter
			if(!isset($i)) $i = 0;

			// base details
			$pages[$i]['page'] = false;
			$pages[$i]['currentPage'] = false;
			$pages[$i]['otherPage'] = false;
			$pages[$i]['noPage'] = false;
			$pages[$i]['url'] = '';
			$pages[$i]['pageNumber'] = $item;

			// hellips
			if($item == '...') $pages[$i]['noPage'] = true;

			// regular page
			else
			{
				// show page
				$pages[$i]['page'] = true;

				// current page ?
				if($item == $currentPage) $pages[$i]['currentPage'] = true;

				// other page
				else
				{
					// show the page
					$pages[$i]['otherPage'] = true;

					// url to this page
					$pages[$i]['url'] = str_replace(array('[offset]', '[order]', '[sort]'), array((($numPerPage * $item) - $numPerPage), $order, $sort), $URL);
				}
			}

			// update counter
			$i++;
		}

		// first key needs to be zero
		$pages = SpoonFilter::arraySortKeys($pages);

		// assign pages
		$tpl->assign('pages', $pages);

		// cough it up
		ob_start();
		$tpl->display(dirname(__FILE__) .'/paging.tpl');
		return ob_get_clean();
	}
}

?>


text:
FOUNDATION_EXPORT double KeysVersionNumber;
FOUNDATION_EXPORT const unsigned char KeysVersionString[];

redpajama_set_name: RedPajamaGithub


text:
use syntax::ast;
use syntax::codemap::DUMMY_SP;

use aster::AstBuilder;

#[test]
fn test_doc() {
    let builder = AstBuilder::new();
    assert_eq!(
        builder.attr().doc("/// doc string"),
        ast::Attribute {
            id: ast::AttrId(0),
            style: ast::AttrStyle::Outer,
            value: ast::MetaItem {
                name: builder.symbol("doc"),
                node: ast::MetaItemKind::NameValue(
                    (*builder.lit().str("/// doc string")).clone(),
                ),
                span: DUMMY_SP,
            },
            is_sugared_doc: true,
            span: DUMMY_SP,
        }
    );
}


text:
package main

import (
	"fmt"
	"io"
	"os"
	"syscall"

	"github.com/docker/docker/pkg/term"
	"github.com/opencontainers/runc/libcontainer"
)

// newTty creates a new tty for use with the container.  If a tty is not to be
// created for the process, pipes are created so that the TTY of the parent
// process are not inherited by the container.
func newTty(create bool, p *libcontainer.Process, rootuid int) (*tty, error) {
	if create {
		return createTty(p, rootuid)
	}
	return createStdioPipes(p, rootuid)
}

// setup standard pipes so that the TTY of the calling runc process
// is not inherited by the container.
func createStdioPipes(p *libcontainer.Process, rootuid int) (*tty, error) {
	var (
		t   = &tty{}
		fds []int
	)
	r, w, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	fds = append(fds, int(r.Fd()), int(w.Fd()))
	go io.Copy(w, os.Stdin)
	t.closers = append(t.closers, w)
	p.Stdin = r
	if r, w, err = os.Pipe(); err != nil {
		return nil, err
	}
	fds = append(fds, int(r.Fd()), int(w.Fd()))
	go io.Copy(os.Stdout, r)
	p.Stdout = w
	t.closers = append(t.closers, r)
	if r, w, err = os.Pipe(); err != nil {
		return nil, err
	}
	fds = append(fds, int(r.Fd()), int(w.Fd()))
	go io.Copy(os.Stderr, r)
	p.Stderr = w
	t.closers = append(t.closers, r)
	// change the ownership of the pipe fds incase we are in a user namespace.
	for _, fd := range fds {
		if err := syscall.Fchown(fd, rootuid, rootuid); err != nil {
			return nil, err
		}
	}
	return t, nil
}

func createTty(p *libcontainer.Process, rootuid int) (*tty, error) {
	console, err := p.NewConsole(rootuid)
	if err != nil {
		return nil, err
	}
	go io.Copy(console, os.Stdin)
	go io.Copy(os.Stdout, console)
	state, err := term.SetRawTerminal(os.Stdin.Fd())
	if err != nil {
		return nil, fmt.Errorf("failed to set the terminal from the stdin: %v", err)
	}
	t := &tty{
		console: console,
		state:   state,
		closers: []io.Closer{
			console,
		},
	}
	p.Stderr = nil
	p.Stdout = nil
	p.Stdin = nil
	return t, nil
}

type tty struct {
	console libcontainer.Console
	state   *term.State
	closers []io.Closer
}

func (t *tty) Close() error {
	for _, c := range t.closers {
		c.Close()
	}
	if t.state != nil {
		term.RestoreTerminal(os.Stdin.Fd(), t.state)
	}
	return nil
}

func (t *tty) resize() error {
	if t.console == nil {
		return nil
	}
	ws, err := term.GetWinsize(os.Stdin.Fd())
	if err != nil {
		return err
	}
	return term.SetWinsize(t.console.Fd(), ws)
}


text:
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false"
            aria-controls="navbar">
                Toggle navigation

            </button>
            AsTracker

Dispositivos

Mi perfil

Salir

Contactenos


text:
  Bachos est
       un village
       géographiquement positionné dans le département de Haute-Garonne en Midi-Pyrénées. Elle comptait 26 habitants en 2008.

Le parc de logements, à Bachos, était réparti en 2011 en un appartements et 36 maisons soit
 un marché plutôt équilibré.

Si vous pensez emmenager à Bachos, vous pourrez facilement trouver une maison à acheter.

À proximité de Bachos sont positionnées géographiquement les communes de
Signac à 1 km, 54 habitants,
Baren à 3 km, six habitants,
Marignac située à 3 km, 517 habitants,
Burgalays à 0 km, 124 habitants,
Binos située à 0 km, 29 habitants,
Cazaux-Layrisse située à 2 km, 70 habitants,
 entre autres. De plus, Bachos est située à seulement 25 km de Saint-Gaudens.


text:
package com.programmerr47.whitecodetesttask.api.accessoryEnums;

/**
 * @author Michael Spitsin
 * @since 2014-08-23
 */
public enum OccupationType {
    work,
    school,
    university;

    public static OccupationType optValue(String name) {
        try {
            return valueOf(name);
        } catch (NullPointerException e) {
            return null;
        } catch (IllegalArgumentException e) {
            return null;
        }
    }
}


text:
define(
	["common/demoView", "bin/util/osUtil"],
	function(Base, osUtil)
	{
		var Class = {};

		Class.events =
		{
			"click #jump" : "jump",
		};

		Class.jump = function()
		{
			bin.naviController.push("pageJumpParamsDemo/page0?a=100&c=Hello BIN", {a:10, b:"Hello", c:{}});
		}

		Class.onViewBack = function(backFrom, backData)
		{
			bin.hudManager.alertInfo("数据 "+osUtil.dump(backData), "从"+backFrom+"返回");
		}

		return Base.extend(Class);
	}
);


text:
layout: page
title: Nash Forest Air Executive Retreat
date: 2016-05-24
author: Shirley Black
tags: weekly links, java
status: published
summary: Etiam sollicitudin purus ut justo dictum, nec convallis.
banner: images/banner/wedding.jpg
booking:
  startDate: 03/07/2017
  endDate: 03/11/2017
  ctyhocn: AGSGHHX
  groupCode: NFAER
published: true
---
Suspendisse leo eros, commodo vitae eleifend eget, consectetur non nunc. Fusce vel libero sem. Sed commodo eros tempor velit dictum, sit amet suscipit nibh efficitur. Nam eget erat sodales, rutrum mauris sed, eleifend dui. Pellentesque posuere dolor ex, sed eleifend magna convallis sit amet. Vivamus eget odio nulla. Phasellus aliquam sem ut nibh luctus scelerisque. Pellentesque sodales lobortis eros et eleifend. Duis tempor ligula sem, vel ultrices mi commodo quis. Morbi eu diam imperdiet sem blandit finibus quis et quam. Morbi quis nisl id tortor pharetra facilisis et sit amet lacus. Aliquam suscipit malesuada dictum. Donec volutpat enim sem, id consequat sem mollis vel. Morbi non nulla lectus.

* Nullam porta tellus nec magna venenatis scelerisque
* Maecenas placerat felis eu nisl hendrerit congue
* Mauris nec magna egestas, pretium libero non, malesuada nibh
* Fusce malesuada felis aliquam lorem auctor sagittis.

Aenean vitae dui pellentesque massa malesuada faucibus sed nec leo. Sed orci enim, posuere sed hendrerit at, facilisis bibendum risus. Etiam fermentum leo quis tortor iaculis, quis faucibus tellus rutrum. Morbi justo mauris, sollicitudin a mollis ut, hendrerit a risus. Sed et convallis lectus. Morbi dictum aliquet diam non fringilla. In vestibulum malesuada ex et consectetur. Morbi ante lectus, dapibus a posuere quis, sagittis eu turpis. Maecenas porta molestie ornare. Sed ipsum massa, porta eget erat ac, condimentum ornare felis. Suspendisse molestie velit enim, non sagittis elit maximus sit amet. Curabitur eleifend mauris dui. Etiam non tincidunt dolor.


text:
/*jshint node:true */

"use strict";

var colors = require('chalk');

function verifyTaskSets(gulp, taskSets, skipArrays) {
	if(taskSets.length === 0) {
		throw new Error('No tasks were provided to run-sequence');
	}
	var foundTasks = {};
	taskSets.forEach(function(t) {
		var isTask = typeof t === "string",
			isArray = !skipArrays && Array.isArray(t);
		if(!isTask && !isArray) {
			throw new Error("Task "+t+" is not a valid task string.");
		}
		if(isTask && !gulp.hasTask(t)) {
			throw new Error("Task "+t+" is not configured as a task on gulp.  If this is a submodule, you may need to use require('run-sequence').use(gulp).");
		}
		if(skipArrays && isTask) {
			if(foundTasks[t]) {
				throw new Error("Task "+t+" is listed more than once. This is probably a typo.");
			}
			foundTasks[t] = true;
		}
		if(isArray) {
			if(t.length === 0) {
				throw new Error("An empty array was provided as a task set");
			}
			verifyTaskSets(gulp, t, true, foundTasks);
		}
	});
}

function runSequence(gulp) {
	// load gulp directly when no external was passed
	if(gulp === undefined) {
		gulp = require('gulp');
	}

	// Slice and dice the input to prevent modification of parallel arrays.
	var taskSets = Array.prototype.slice.call(arguments, 1).map(function(task) {
			return Array.isArray(task) ? task.slice() : task;
		}),
		callBack = typeof taskSets[taskSets.length-1] === 'function' ? taskSets.pop() : false,
		currentTaskSet,

		finish = function(err) {
			gulp.removeListener('task_stop', onTaskEnd);
			gulp.removeListener('task_err', onError);
			if(callBack) {
				callBack(err);
			} else if(err) {
				console.log(colors.red('Error running task sequence:'), err);
			}
		},

		onError = function(err) {
			finish(err);
		},
		onTaskEnd = function(event) {
			var idx = currentTaskSet.indexOf(event.task);
			if(idx > -1) {
				currentTaskSet.splice(idx,1);
			}
			if(currentTaskSet.length === 0) {
				runNextSet();
			}
		},

		runNextSet = function() {
			if(taskSets.length) {
				var command = taskSets.shift();
				if(!Array.isArray(command)) {
					command = [command];
				}
				currentTaskSet = command;
				gulp.start.apply(gulp, command);
			} else {
				finish();
			}
		};

	verifyTaskSets(gulp, taskSets);

	gulp.on('task_stop', onTaskEnd);
	gulp.on('task_err', onError);

	runNextSet();
}

module.exports = runSequence.bind(null, undefined);
module.exports.use = function(gulp) {
	return runSequence.bind(null, gulp);
};


text:
'use strict';

var crypto = require('crypto');
var fs     = require('fs');
var path   = require('path');

var Mincer    = require('mincer');
var stopwatch = require('../utils/stopwatch');

function md5(str) {
  return crypto.createHash('md5').update(str).digest('hex');
}

////////////////////////////////////////////////////////////////////////////////

module.exports = function (sandbox) {
  var tmpdir = sandbox.tmpdir
    , timer   = stopwatch()
    , N = sandbox.N
    , environment;

  //
  // set custom logger for the Mincer
  //

  Mincer.logger.use(N.logger);

  environment = new Mincer.Environment(tmpdir);

  //
  // set mincer cache dir
  //
  environment.cache = new Mincer.FileStore(N.config.options.cache_dir);

  //
  // rebuild assets on config change:
  //
  // - track `bundle.yml` in all apps (via sandbox.config.packages)
  // - track `package.json` in all apps
  //
  var unique = JSON.stringify(sandbox.config.packages);

  N.runtime.apps.forEach(function (app) {
    unique += fs.readFileSync(path.join(app.root, 'package.json'), 'utf-8');
  });

  environment.version = md5(unique);

  //
  // Enable autoprefixer
  //
  Mincer.Autoprefixer.configure([
    'android >= 2.2',
    'bb >= 7',
    'chrome >= 26',
    'ff >= 24',
    'ie >= 9',
    'ios >= 5',
    'opera >= 12',
    'safari >= 5'
  ]);
  environment.enable('autoprefixer');

  //
  // Enable source maps support. Need future work.
  //
  //environment.enable('source_maps');

  //
  // Provide some helpers to EJS and Stylus
  //

  environment.ContextClass.defineAssetPath(function (pathname, options) {
    // this throws exception with details, if asset not exists
    var resolvedPath = this.resolve(pathname);

    sandbox.assets.used.push(resolvedPath);
    //  console.log(pathname)

    var asset = environment.findAsset(resolvedPath, options);
    return !asset ? null : ('/assets/' + asset.digestPath);
  });

  //
  // Add jetson serializer helper
  //

  environment.registerHelper('jetson', require('../../jetson').serialize);

  //
  // Expose N helper
  //

  environment.registerHelper('N', N);

  sandbox.assets = {
    environment:  environment,
    // holds list of assets to be bundled by mincer
    files:        [],
    // track assets, requested via helpers on compile,
    // used to check integrity in manifest
    //
    // (!!!) Note, that does not track helpers for cached
    // assets (from previous builds) and for runtime calls
    // from .jade templates.
    used:         []
  };

  N.logger.info('Initialized assets manager %s', timer.elapsed);
};


text:
package eu.impact_project.resultsrepository;

import static org.junit.Assert.*;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;

import org.apache.commons.io.IOUtils;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class ServiceImplTest {

	String demonstratorId = "ugoe";
	String workflowId = "testWorkflow";
	long time = 0;

	@BeforeClass
	public static void setUpClass() throws Exception {
		ServerStarter.startWebServer(9001);
		ServerStarter.startDavServer(9002);
	}

	@AfterClass
	public static void tearDown() throws Exception {
		ServerStarter.stopAll();
	}

	@Before
	public void setUp() {
		time = new Date().getTime();
	}

	@Test
	public void testStoreData() {
		ArrayList<String> resultsList = new ArrayList<String>();
		resultsList.add("http://localhost:9001/IMPACTTesseractV3Service/1234/outputFile/outputUrl_tmpfile1.tif.out.txt");
		resultsList.add("http://localhost:9001/IMPACTTesseractV3Service/1234/outputFile/outputUrl_tmpfile2.tif.out.txt");
		String message = executeWithList(resultsList);

		assertTrue(message.indexOf("Stored results at") >= 0);
		assertTrue(message.indexOf(demonstratorId + "/" + workflowId + "/") >= 0);
		assertFalse(message.indexOf("warnings or errors") >= 0);
	}

	@Test
	public void testStoreDataWordEval() {
		ArrayList<String> resultsList = new ArrayList<String>();
		resultsList.add("http://localhost:9001/IMPACTWordEvaluationService/1234/outputFile/outputFile_6922033601589215833.xml");
		String message = executeWithList(resultsList);

		assertTrue(message.indexOf("Stored results at") >= 0);
		assertTrue(message.indexOf(demonstratorId + "/" + workflowId + "/") >= 0);
		assertFalse(message.indexOf("warnings or errors") >= 0);
	}

	@Test
	public void testStoreDataLogs() throws MalformedURLException, IOException {
		String message = executeWithString(getText("http://localhost:9001/log_eval.txt"));
		assertFalse(message.indexOf("warnings or errors") >= 0);

		message = executeWithString(getText("http://localhost:9001/log_tesseract.txt"));
		assertFalse(message.indexOf("warnings or errors") >= 0);

	}

	@Test
	public void testStoreDataBadArguments() throws MalformedURLException, IOException {
		String demonstratorIdCopy = demonstratorId;
		String workflowIdCopy = workflowId;

		String expectedError = "Invalid workflow ID or demonstrator ID.";

		demonstratorId = null;
		String message = executeWithString(getText("http://localhost:9001/log_eval.txt"));
		assertTrue(message.contains(expectedError));

		demonstratorId = "";
		message = executeWithString(getText("http://localhost:9001/log_eval.txt"));
		assertTrue(message.contains(expectedError));

		demonstratorId = "?";
		message = executeWithString(getText("http://localhost:9001/log_eval.txt"));
		assertTrue(message.contains(expectedError));

		demonstratorId = demonstratorIdCopy;

		workflowId = null;
		message = executeWithString(getText("http://localhost:9001/log_eval.txt"));
		assertTrue(message.contains(expectedError));

		workflowId = "";
		message = executeWithString(getText("http://localhost:9001/log_eval.txt"));
		assertTrue(message.contains(expectedError));

		workflowId = ".,";
		message = executeWithString(getText("http://localhost:9001/log_eval.txt"));
		assertTrue(message.contains(expectedError));

		workflowId = workflowIdCopy;
	}

	@Test
	public void testStoreDataSpecialArguments() throws MalformedURLException, IOException {
		String demonstratorIdCopy = demonstratorId;
		String workflowIdCopy = workflowId;

		demonstratorId = "with-dash";
		String message = executeWithString(getText("http://localhost:9001/log_eval.txt"));
		assertTrue(message.indexOf("Stored results at") >= 0);

		demonstratorId = demonstratorIdCopy;

		workflowId = "with-dash";
		message = executeWithString(getText("http://localhost:9001/log_eval.txt"));
		assertTrue(message.indexOf("Stored results at") >= 0);

		workflowId = workflowIdCopy;
	}

	@Test
	public void testStoreDataEmptyResults() throws MalformedURLException, IOException {
		String expectedError = "There were no results to be stored.";

		Results results = new Results();
		Service ws = new ServiceImpl();
		String message =  ws.storeData(results, workflowId, time, demonstratorId);
		assertTrue(message.contains(expectedError));

		message =  ws.storeData(results, null, time, demonstratorId);
		assertTrue(message.contains(expectedError));
	}

	@Test
	public void testStoreDataNoOcrAccuracy() throws MalformedURLException, IOException {

		String noAccuracy = "http://localhost:9001/IMPACTOcrEvalService/1234/outputFile/xmlReportOutputUrl_IMPACT_tmpfilefromurl821755019209514659.tmp.report.xml";
		String message = executeWithString(noAccuracy);

		assertTrue(message.indexOf("Stored results at") >= 0);
		assertTrue(message.indexOf(demonstratorId + "/" + workflowId + "/") >= 0);
		assertFalse(message.indexOf("warnings or errors") >= 0);
	}

	private Results constructFromList(ArrayList<String> res) {
		ToolResults tr = new ToolResults();
		tr.setFields(res);
		Results results = new Results();
		results.addToolResults(tr);
		return results;
	}

	private String getText(String url) throws MalformedURLException, IOException {
		InputStream is = new URL(url).openStream();
		return IOUtils.toString(is);
	}

	private String executeWithString(String result) {
		ArrayList<String> resultsList = new ArrayList<String>();
		resultsList.add(result);
		Results results = constructFromList(resultsList);
		Service ws = new ServiceImpl();
		return ws.storeData(results, workflowId, time, demonstratorId);
	}

	private String executeWithList(ArrayList<String> l) {
		Results results = constructFromList(l);
		Service ws = new ServiceImpl();
		return ws.storeData(results, workflowId, time, demonstratorId);
	}

}


text:
package com.intellij.dvcs.branch;

import com.intellij.dvcs.repo.Repository;
import com.intellij.dvcs.ui.DvcsBundle;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.List;

public final class DvcsBranchUtil {
  @Nullable
  public static <T extends DvcsBranchInfo> T find(@Nullable final Collection<T> branches,
                                                  @Nullable Repository repository,
                                                  @NotNull String sourceBranch) {
    if (branches == null) return null;
    return ContainerUtil.find(branches, targetInfo -> repoAndSourceAreEqual(repository, sourceBranch, targetInfo));
  }

  private static boolean repoAndSourceAreEqual(@Nullable Repository repository,
                                               @NotNull String sourceBranch,
                                               @NotNull DvcsBranchInfo targetInfo) {
    return getPathFor(repository).equals(targetInfo.repoPath) && StringUtil.equals(targetInfo.sourceName, sourceBranch);
  }

  @NotNull
  public static String getPathFor(@Nullable Repository repository) {
    return repository == null ? "" : repository.getRoot().getPath();
  }

  @NotNull
  public static List<Change> swapRevisions(@NotNull List<? extends Change> changes) {
    return ContainerUtil.map(changes, change -> {
      ContentRevision beforeRevision = change.getBeforeRevision();
      ContentRevision afterRevision = change.getAfterRevision();
      if (beforeRevision == null || afterRevision == null) return new Change(afterRevision, beforeRevision);
      return new Change(afterRevision, beforeRevision, change.getFileStatus());
    });
  }

  public static @Nls @NotNull String shortenBranchName(@Nls @NotNull String fullBranchName) {
    // -1, because there are arrows indicating that it is a popup
    int maxLength = DvcsBundle.message("branch.popup.maximum.branch.length.sample").length() - 1;
    return StringUtil.shortenTextWithEllipsis(fullBranchName, maxLength, 5);
  }
}


text:
module MarkdownRubyDocumentation
  class MarkdownPresenter

    attr_reader :items, :title_key, :summary

    def initialize(items: nil, summary:, title_key:, skip_blanks: true)
      @items         = items
      @summary       = summary
      @title_key     = title_key
      @skip_blanks   = skip_blanks
      @present_items = []
    end

    def call(items=nil)
      @items ||= items
      return "" if nothing_to_display?
      md = ["# #{summary.title}", "#{summary.summary}\n".gsub(/\n\n\n/, "\n\n"), class_level_comment, instances_methods, class_methods, "#{null_methods}\n".gsub(/\n\n\n/, "\n\n")]
             .reject(&:empty?)
             .join("\n")
             .gsub(/[\n]{3,}/, "\n\n")
             .gsub(/[\n]+\Z/, "\n\n")
      other_types!
      md
    end

    private

    def item_types
      @item_types ||= items.group_by { |_, hash| hash[:method_object].class.name }
    end

    def class_level_comment
      @class_level_comment ||= (items.delete(:class_level_comment) || {})

      if @class_level_comment[:text]
        "#{@class_level_comment[:text]}\n"
      else
        ""
      end
    end

    def instances_methods
      @instance_methods ||= method_presenters("MarkdownRubyDocumentation::InstanceMethod")
    end

    def class_methods
      @class_methods ||= method_presenters("MarkdownRubyDocumentation::ClassMethod")
    end

    def null_methods
      @null_methods ||= begin
        md = method_presenters("MarkdownRubyDocumentation::NullMethod", "###")
        if md.blank?
          ""
        else
          "\n## Reference Values\n" << md
        end
      end
    end

    def method_presenters(type, heading="##")
      type_methods = item_types.delete(type) || []
      order_by_location(type_methods).map do |(name, hash)|
        %[#{heading} #{name.to_s.titleize}\n#{hash[:text]}] unless hash[:text].blank?
      end.join("\n\n")
    end

    def order_by_location(items)
      items.sort_by do |(name, hash)|
        hash[:method_object].source_location rescue name # NullMethod has no source_location
      end
    end

    def other_types!
      raise "Unhandled methods types: #{item_types}" unless item_types.empty?
    end

    def nothing_to_display?
      [class_level_comment, instances_methods, class_methods, null_methods].all?(&:empty?)
    end
  end
end


text:
Index = {

    init: function(data){
        if(typeof data != 'undefined'){
            var attributes = [

            ];

            $.each(attributes, function(index, element){
                if(typeof data[element] != 'undefined')
                    Index[element] = data[element];
            });
        }

        Index.setHandlers();
    },

    setHandlers: function(){

    }

    // Handlers

    // AND Handlers

    // Functions

    // END Functions

};


text:
module ValidatesRequired
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    def validates_required( name )
      include InstanceMethods

      validates_presence_of name, :if => "#{name}_required".to_sym

      define_method( "#{name}_required" ) do
        require_attributes.include? name.to_sym
      end

      define_method( "#{name}_required=" ) do |v|
        @require_attributes ||= []
        if v == true
          @require_attributes << name.to_sym
        else
          @require_attributes.delete name.to_sym
        end
      end
    end
  end

  module InstanceMethods
    attr_accessor :require_attributes
    def require_attributes
      @require_attributes ||= []
      @require_attributes.flatten!
      @require_attributes.uniq!
      @require_attributes
    end
  end
end


text:
package cn.com.newcapec.citycard.common.po.base;

import java.lang.Comparable;
import java.io.Serializable;

/**
 * This is an object that contains data related to the LOAD_DETAIL_RECORD table.
 * Do not modify this class because it will be overwritten if the configuration file
 * related to this class is modified.
 *
 * @hibernate.class
 *  table="LOAD_DETAIL_RECORD"
 */

public abstract class BaseLoadDetailRecord  implements Comparable, Serializable {

	public static String REF = "LoadDetailRecord";
	public static String PROP_SUCCED = "succed";
	public static String PROP_TRADESTATUS = "tradestatus";
	public static String PROP_BANKDZ = "bankdz";
	public static String PROP_PLAN_ID = "planId";
	public static String PROP_BANKRET = "bankret";
	public static String PROP_BANKTRADENO = "banktradeno";
	public static String PROP_ST_DATE = "stDate";
	public static String PROP_FUNDS_WAY = "fundsWay";
	public static String PROP_OPFARE = "opfare";
	public static String PROP_FOOTDT = "footdt";
	public static String PROP_ASN = "asn";
	public static String PROP_CUSTOMERID = "customerid";
	public static String PROP_NOTES = "notes";
	public static String PROP_FIXFOOTDT = "fixfootdt";
	public static String PROP_TERMTRADENO = "termtradeno";
	public static String PROP_BANKCARDNO = "bankcardno";
	public static String PROP_EDIT_DATE = "editDate";
	public static String PROP_SIGN_WAY = "signWay";
	public static String PROP_BANKRECNO = "bankrecno";
	public static String PROP_BANKRETDESC = "bankretdesc";
	public static String PROP_ACCCODE = "acccode";
	public static String PROP_ID = "id";
	public static String PROP_TERMID = "termid";

	// constructors
	public BaseLoadDetailRecord () {
		initialize();
	}

	/**
	 * Constructor for primary key
	 */
	public BaseLoadDetailRecord (java.lang.String id) {
		this.setId(id);
		initialize();
	}

	/**
	 * Constructor for required fields
	 */
	public BaseLoadDetailRecord (
		java.lang.String id,
		java.lang.Integer bankrecno,
		java.lang.String customerid,
		java.lang.Integer asn,
		java.math.BigDecimal opfare,
		java.lang.String fundsWay,
		java.lang.String bankcardno,
		java.lang.String acccode,
		java.lang.Integer termid,
		java.lang.Integer termtradeno,
		java.lang.String signWay,
		java.util.Date editDate) {

		this.setId(id);
		this.setBankrecno(bankrecno);
		this.setCustomerid(customerid);
		this.setAsn(asn);
		this.setOpfare(opfare);
		this.setFundsWay(fundsWay);
		this.setBankcardno(bankcardno);
		this.setAcccode(acccode);
		this.setTermid(termid);
		this.setTermtradeno(termtradeno);
		this.setSignWay(signWay);
		this.setEditDate(editDate);
		initialize();
	}

	protected void initialize () {}

	private int hashCode = Integer.MIN_VALUE;

	// primary key
	private java.lang.String id;

	// fields
	private java.lang.Integer bankrecno;
	private java.lang.String customerid;
	private java.lang.Integer asn;
	private java.math.BigDecimal opfare;
	private java.lang.Integer footdt;
	private java.lang.Integer fixfootdt;
	private java.lang.String fundsWay;
	private java.lang.String bankcardno;
	private java.lang.String banktradeno;
	private java.lang.String bankret;
	private java.lang.String bankretdesc;
	private java.lang.String bankdz;
	private java.lang.String acccode;
	private java.lang.Integer termid;
	private java.lang.Integer termtradeno;
	private java.lang.String tradestatus;
	private java.lang.String succed;
	private java.lang.String planId;
	private java.lang.String signWay;
	private java.lang.String notes;
	private java.util.Date stDate;
	private java.util.Date editDate;

	/**
	 * Return the unique identifier of this class
     * @hibernate.id
     *  generator-class="uuid.hex"
     *  column="ID"
     */
	public java.lang.String getId () {
		return id;
	}

	/**
	 * Set the unique identifier of this class
	 * @param id the new ID
	 */
	public void setId (java.lang.String id) {
		this.id = id;
		this.hashCode = Integer.MIN_VALUE;
	}

	/**
	 * Return the value associated with the column: BANKRECNO
	 */
	public java.lang.Integer getBankrecno () {
		return bankrecno;
	}

	/**
	 * Set the value related to the column: BANKRECNO
	 * @param bankrecno the BANKRECNO value
	 */
	public void setBankrecno (java.lang.Integer bankrecno) {
		this.bankrecno = bankrecno;
	}

	/**
	 * Return the value associated with the column: CUSTOMERID
	 */
	public java.lang.String getCustomerid () {
		return customerid;
	}

	/**
	 * Set the value related to the column: CUSTOMERID
	 * @param customerid the CUSTOMERID value
	 */
	public void setCustomerid (java.lang.String customerid) {
		this.customerid = customerid;
	}

	/**
	 * Return the value associated with the column: ASN
	 */
	public java.lang.Integer getAsn () {
		return asn;
	}

	/**
	 * Set the value related to the column: ASN
	 * @param asn the ASN value
	 */
	public void setAsn (java.lang.Integer asn) {
		this.asn = asn;
	}

	/**
	 * Return the value associated with the column: OPFARE
	 */
	public java.math.BigDecimal getOpfare () {
		return opfare;
	}

	/**
	 * Set the value related to the column: OPFARE
	 * @param opfare the OPFARE value
	 */
	public void setOpfare (java.math.BigDecimal opfare) {
		this.opfare = opfare;
	}

	/**
	 * Return the value associated with the column: FOOTDT
	 */
	public java.lang.Integer getFootdt () {
		return footdt;
	}

	/**
	 * Set the value related to the column: FOOTDT
	 * @param footdt the FOOTDT value
	 */
	public void setFootdt (java.lang.Integer footdt) {
		this.footdt = footdt;
	}

	/**
	 * Return the value associated with the column: FIXFOOTDT
	 */
	public java.lang.Integer getFixfootdt () {
		return fixfootdt;
	}

	/**
	 * Set the value related to the column: FIXFOOTDT
	 * @param fixfootdt the FIXFOOTDT value
	 */
	public void setFixfootdt (java.lang.Integer fixfootdt) {
		this.fixfootdt = fixfootdt;
	}

	/**
	 * Return the value associated with the column: FUNDS_WAY
	 */
	public java.lang.String getFundsWay () {
		return fundsWay;
	}

	/**
	 * Set the value related to the column: FUNDS_WAY
	 * @param fundsWay the FUNDS_WAY value
	 */
	public void setFundsWay (java.lang.String fundsWay) {
		this.fundsWay = fundsWay;
	}

	/**
	 * Return the value associated with the column: BANKCARDNO
	 */
	public java.lang.String getBankcardno () {
		return bankcardno;
	}

	/**
	 * Set the value related to the column: BANKCARDNO
	 * @param bankcardno the BANKCARDNO value
	 */
	public void setBankcardno (java.lang.String bankcardno) {
		this.bankcardno = bankcardno;
	}

	/**
	 * Return the value associated with the column: BANKTRADENO
	 */
	public java.lang.String getBanktradeno () {
		return banktradeno;
	}

	/**
	 * Set the value related to the column: BANKTRADENO
	 * @param banktradeno the BANKTRADENO value
	 */
	public void setBanktradeno (java.lang.String banktradeno) {
		this.banktradeno = banktradeno;
	}

	/**
	 * Return the value associated with the column: BANKRET
	 */
	public java.lang.String getBankret () {
		return bankret;
	}

	/**
	 * Set the value related to the column: BANKRET
	 * @param bankret the BANKRET value
	 */
	public void setBankret (java.lang.String bankret) {
		this.bankret = bankret;
	}

	/**
	 * Return the value associated with the column: BANKRETDESC
	 */
	public java.lang.String getBankretdesc () {
		return bankretdesc;
	}

	/**
	 * Set the value related to the column: BANKRETDESC
	 * @param bankretdesc the BANKRETDESC value
	 */
	public void setBankretdesc (java.lang.String bankretdesc) {
		this.bankretdesc = bankretdesc;
	}

	/**
	 * Return the value associated with the column: BANKDZ
	 */
	public java.lang.String getBankdz () {
		return bankdz;
	}

	/**
	 * Set the value related to the column: BANKDZ
	 * @param bankdz the BANKDZ value
	 */
	public void setBankdz (java.lang.String bankdz) {
		this.bankdz = bankdz;
	}

	/**
	 * Return the value associated with the column: ACCCODE
	 */
	public java.lang.String getAcccode () {
		return acccode;
	}

	/**
	 * Set the value related to the column: ACCCODE
	 * @param acccode the ACCCODE value
	 */
	public void setAcccode (java.lang.String acccode) {
		this.acccode = acccode;
	}

	/**
	 * Return the value associated with the column: TERMID
	 */
	public java.lang.Integer getTermid () {
		return termid;
	}

	/**
	 * Set the value related to the column: TERMID
	 * @param termid the TERMID value
	 */
	public void setTermid (java.lang.Integer termid) {
		this.termid = termid;
	}

	/**
	 * Return the value associated with the column: TERMTRADENO
	 */
	public java.lang.Integer getTermtradeno () {
		return termtradeno;
	}

	/**
	 * Set the value related to the column: TERMTRADENO
	 * @param termtradeno the TERMTRADENO value
	 */
	public void setTermtradeno (java.lang.Integer termtradeno) {
		this.termtradeno = termtradeno;
	}

	/**
	 * Return the value associated with the column: TRADESTATUS
	 */
	public java.lang.String getTradestatus () {
		return tradestatus;
	}

	/**
	 * Set the value related to the column: TRADESTATUS
	 * @param tradestatus the TRADESTATUS value
	 */
	public void setTradestatus (java.lang.String tradestatus) {
		this.tradestatus = tradestatus;
	}

	/**
	 * Return the value associated with the column: SUCCED
	 */
	public java.lang.String getSucced () {
		return succed;
	}

	/**
	 * Set the value related to the column: SUCCED
	 * @param succed the SUCCED value
	 */
	public void setSucced (java.lang.String succed) {
		this.succed = succed;
	}

	/**
	 * Return the value associated with the column: PLAN_ID
	 */
	public java.lang.String getPlanId () {
		return planId;
	}

	/**
	 * Set the value related to the column: PLAN_ID
	 * @param planId the PLAN_ID value
	 */
	public void setPlanId (java.lang.String planId) {
		this.planId = planId;
	}

	/**
	 * Return the value associated with the column: SIGN_WAY
	 */
	public java.lang.String getSignWay () {
		return signWay;
	}

	/**
	 * Set the value related to the column: SIGN_WAY
	 * @param signWay the SIGN_WAY value
	 */
	public void setSignWay (java.lang.String signWay) {
		this.signWay = signWay;
	}

	/**
	 * Return the value associated with the column: NOTES
	 */
	public java.lang.String getNotes () {
		return notes;
	}

	/**
	 * Set the value related to the column: NOTES
	 * @param notes the NOTES value
	 */
	public void setNotes (java.lang.String notes) {
		this.notes = notes;
	}

	/**
	 * Return the value associated with the column: ST_DATE
	 */
	public java.util.Date getStDate () {
		return stDate;
	}

	/**
	 * Set the value related to the column: ST_DATE
	 * @param stDate the ST_DATE value
	 */
	public void setStDate (java.util.Date stDate) {
		this.stDate = stDate;
	}

	/**
	 * Return the value associated with the column: EDIT_DATE
	 */
	public java.util.Date getEditDate () {
		return editDate;
	}

	/**
	 * Set the value related to the column: EDIT_DATE
	 * @param editDate the EDIT_DATE value
	 */
	public void setEditDate (java.util.Date editDate) {
		this.editDate = editDate;
	}

	public boolean equals (Object obj) {
		if (null == obj) return false;
		if (!(obj instanceof cn.com.newcapec.citycard.common.po.LoadDetailRecord)) return false;
		else {
			cn.com.newcapec.citycard.common.po.LoadDetailRecord loadDetailRecord = (cn.com.newcapec.citycard.common.po.LoadDetailRecord) obj;
			if (null == this.getId() || null == loadDetailRecord.getId()) return false;
			else return (this.getId().equals(loadDetailRecord.getId()));
		}
	}

	public int hashCode () {
		if (Integer.MIN_VALUE == this.hashCode) {
			if (null == this.getId()) return super.hashCode();
			else {
				String hashStr = this.getClass().getName() + ":" + this.getId().hashCode();
				this.hashCode = hashStr.hashCode();
			}
		}
		return this.hashCode;
	}

	public int compareTo (Object obj) {
		if (obj.hashCode() > hashCode()) return 1;
		else if (obj.hashCode() < hashCode()) return -1;
		else return 0;
	}

	public String toString () {
		return super.toString();
	}

}