ACC SHELL

Path : /srv/www/vhosts/marevva/nadacekrizovatka/
File Upload :
Current File : /srv/www/vhosts/marevva/nadacekrizovatka/ets.php

<?php



/**

 * ETS - Easy Template System - 3.06a

 * Copyright (C) 2002, 2003, 2004  Franck Marcia <phpets@hotmail.com>

 * http://ets.sourceforge.net

 *

 * This library is free software; you can redistribute it and/or

 * modify it under the terms of the GNU Lesser General Public

 * License as published by the Free Software Foundation; either

 * version 2.1 of the License, or (at your option) any later version.

 *

 * This library is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

 * Lesser General Public License for more details.

 *

 * You should have received a copy of the GNU Lesser General Public

 * License along with this library; if not, write to the Free Software

 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 *

 */



/**

 * Size reducing behaviour

 */

define('_ETS_REDUCE_NULL',       0x0);

define('_ETS_REDUCE_OFF',        0x1);

define('_ETS_REDUCE_SPACES',     0x2);

define('_ETS_REDUCE_ALL',        0x4);



/**

 * Parsing modes

 */

define('_ETS_DATA',              0x1);

define('_ETS_NAME',              0x2);

define('_ETS_CLOSING_TAG',       0x4);

define('_ETS_VALUE',             0x8);

define('_ETS_COMMENT',          0x10);

define('_ETS_CDATA',            0x20);



/**

 * Parsing mode groups

 */

define('_ETS_GROUP0',  _ETS_COMMENT + _ETS_CDATA);



/**

 * Element types

 */

define('_ETS_NULL',              0x0);

define('_ETS_ROOT',              0x1);

define('_ETS_TEXT',              0x2);

define('_ETS_TAG',               0x4);

define('_ETS_ALT_TAG',           0x8);

define('_ETS_TEMPLATE',         0x10);

define('_ETS_SET',              0x20);

define('_ETS_SETVAL',           0x40);

define('_ETS_MIS',              0x80);

define('_ETS_MISVAL',          0x100);

define('_ETS_PHP',             0x200);

define('_ETS_CONST',           0x400);

define('_ETS_IF',              0x800);

define('_ETS_CODE',           0x1000);

define('_ETS_CHOOSE',         0x2000);

define('_ETS_WHENTEST',       0x4000);

define('_ETS_ELSE',           0x8000);

define('_ETS_CHOOSEVAR',     0x10000);

define('_ETS_WHENVAL',       0x20000);

define('_ETS_CALL',          0x40000);

define('_ETS_ARG',           0x80000);

define('_ETS_MIS_TEMPLATE', 0x100000);

define('_ETS_REDUCE',       0x200000);

define('_ETS_REPEAT',       0x400000);

define('_ETS_INCLUDE',      0x800000);

define('_ETS_INSERT',      0x1000000);

define('_ETS_EVAL',        0x2000000);

define('_ETS_SAFE',        0x4000000);

define('_ETS_ROOT_EVAL',   0x8000000);



/**

 * Element type groups

 */

define('_ETS_CODEs',   _ETS_CODE    + _ETS_PHP);

define('_ETS_CHOOSEs', _ETS_CHOOSE  + _ETS_CHOOSEVAR);

define('_ETS_SETs',    _ETS_SET     + _ETS_SETVAL);

define('_ETS_MISs',    _ETS_MIS     + _ETS_MISVAL);

// can't contain cdata, call, const, set, mis, choose, insert, eval, safe, if or repeat elements

define('_ETS_GROUP1',  _ETS_CHOOSEs + _ETS_CALL + _ETS_CODEs + _ETS_ROOT);

// can't contain mask or include elements

define('_ETS_GROUP2',  _ETS_CHOOSEs + _ETS_CALL + _ETS_CODEs);

// can't contain text or simple tag element

define('_ETS_GROUP3',  _ETS_CHOOSEs + _ETS_CALL + _ETS_ROOT);

// doesn't store text when finding closing tag

define('_ETS_GROUP4',  _ETS_CHOOSEs + _ETS_CALL);



/**

 * Building directions

 */

define('_ETS_FORWARD',           0x1);

define('_ETS_BACKWARD',          0x2);



/**

 * Building data types

 */

define('_ETS_MISSING',           0x1);

define('_ETS_SCALAR',            0x2);

define('_ETS_COMPLEX',           0x4);



/**

 * Handler names

 */

define('_ETS_SOURCE_READ', 'ets_source_read_handler');

define('_ETS_CACHE_READ',  'ets_cache_read_handler');

define('_ETS_CACHE_WRITE', 'ets_cache_write_handler');

define('_ETS_STRING_READ', '_printts');



define('_ETS_ENTRY', 'main');





/**

 * Template management class

 * This class is intended to be used by printt functions only

 */

class _ets

{

	/**

	 * Data tree

	 */

	var $datatree;



	/**

	 * Mask tree

	 */

	var $masktree = array();



	/**

	 * Indicate if handler functions are available

	 */

	var $external_source_read = FALSE;

	var $external_cache_read  = FALSE;

	var $external_cache_write = FALSE;



	/**

	 * Names of parsed containers

	 */

	var $containers = NULL;



	/**

	 * Current container name to be parsed

	 */

	var $container = NULL;



	/**

	 * Templates included at the root of other templates

	 */

	var $includes = NULL;



	/**

	 * Flag which indicates if parse must be skipped for the current container

	 */

	var $skip = FALSE;





	/*****   E R R O R   *****/



    /**

     * Check PHP error level

     */

	function check_level($error_level, $errno, $message)

	{

		if (error_reporting() & $error_level) {

			switch ($error_level) {

				case E_NOTICE:  $type = 'notice';  break;

				case E_WARNING: $type = 'warning'; break;

				case E_ERROR:   $type = 'error';   break;

			}

			echo "<b>ETS $type:</b> $message";

		}

		if ($error_level == E_ERROR) {

			exit;

		}

	}



    /**

     * Print out an error message

     */

	function error($error_type, $errno, $message = '', $line = 0, $elt_type = _ETS_NULL)

	{

		switch ($error_type) {

			case 0: // WARNING - wrong element in another or at root

				if ($elt_type == _ETS_ROOT) {

					$this->check_level(E_WARNING, $errno, "$message can't be defined outside a template on line $line of <b>{$this->container}</b><br>");

				} else {

					$this->check_level(E_WARNING, $errno, $this->elt_label($elt_type) . " can't contain $message on line $line of <b>{$this->container}</b><br>");

				}

				break;

			case 1: // WARNING - unexpected closing tag

				$this->check_level(E_WARNING, $errno, 'unexpected closing tag {/' . $message . "} on line $line of <b>{$this->container}</b><br>");

				break;

			case 2: // WARNING - unexpected character or space in tag

				$this->check_level(E_WARNING, $errno, "$message on line $line of <b>{$this->container}</b><br>");

				break;

			case 3: // WARNING - end of comment or cdata not found

				$this->check_level(E_WARNING, $errno, "end of " . $this->mode_label($elt_type) . " starting on line $line not found in <b>{$this->container}</b><br>");

				break;

			case 4: // WARNING - closing tag not found

				$this->check_level(E_WARNING, $errno, "closing tag not found for " . $this->elt_label($elt_type) . " starting on line $line in <b>{$this->container}</b><br>");

				break;

			case 5: // NOTICE - container not found (include element with line number available)

				$this->check_level(E_NOTICE, $errno, "unable to get the content of $message in include element on line $line of <b>{$this->container}</b><br>");

				break;

			case 6: // NOTICE - duplicated use of reduce element (without line number available, with several containers)

				$this->check_level(E_NOTICE, $errno, "$message<br>");

				break;

			case 7: // NOTICE - duplicated use of reduce element, invalid value for reduce element

				$this->check_level(E_NOTICE, $errno, "$message on line $line of <b>{$this->container}</b><br>");

				break;

			case 8: // ERROR - entry mask not found

				$this->check_level(E_ERROR, $errno, "unable to find entry mask $message<br>");

				break;

			case 9: // NOTICE - invalid datatree

				$this->check_level(E_NOTICE, $errno, "datatree is not an array, an object or null<br>");

				break;

			case 10: // ERROR - invalid containers

				$this->check_level(E_ERROR, $errno, "containers are not an array or a string<br>");

				break;

			case 11: // NOTICE - container not found (argument)

				$this->check_level(E_NOTICE, $errno, "unable to get the content of $message given as argument<br>");

				break;

			case 12: // NOTICE - container not found (insert element)

				$this->check_level(E_NOTICE, $errno, "unable to get the content of $message in insert element<br>");

				break;

			case 13: // NOTICE - container not found (include element without line number available)

				$this->check_level(E_NOTICE, $errno, "unable to get the content of $message in include element<br>");

				break;

			case 14: // NOTICE - container not found (eval element)

				$this->check_level(E_NOTICE, $errno, "unable to get the content of $message in eval element<br>");

				break;

			case 15: // NOTICE - wrong element in safe mode

				$this->check_level(E_NOTICE, $errno, $this->elt_label($elt_type) . " disabled for security reasons<br>");

				break;

			case 16: // WARNING - template already defined (without line number available, with several containers) / container already used

				$this->check_level(E_WARNING, $errno, "$message<br>");

				break;

		}

	}



	/**

	 * Define the label of a element type from an id

	 */

	function elt_label($eltid)

	{

		switch($eltid) {

			case _ETS_ROOT:         return 'root element';

			case _ETS_TEXT:         return 'text element';

			case _ETS_TAG:          return 'simple tag element';

			case _ETS_ALT_TAG:      return 'alternate tag element';

			case _ETS_TEMPLATE:     return 'template element';

			case _ETS_SET:          return 'set element';

			case _ETS_SETVAL:       return 'set-value element';

			case _ETS_MIS:          return 'missing element';

			case _ETS_MISVAL:       return 'missing-value element';

			case _ETS_PHP:          return 'PHP element';

			case _ETS_CONST:        return 'constant element';

			case _ETS_IF:           return 'if element';

			case _ETS_CODE:         return 'PHP code or test';

			case _ETS_CHOOSE:       return 'choose element';

			case _ETS_WHENTEST:     return 'when-test element';

			case _ETS_ELSE:         return 'else element';

			case _ETS_CHOOSEVAR:    return 'choose-variable element';

			case _ETS_WHENVAL:      return 'when-value element';

			case _ETS_CALL:         return 'call element';

			case _ETS_ARG:          return 'argument element';

			case _ETS_MIS_TEMPLATE: return 'missing template element';

			case _ETS_REDUCE:       return 'reduce element';

			case _ETS_REPEAT:       return 'repeat element';

			case _ETS_INCLUDE:      return 'include element';

			case _ETS_INSERT:       return 'insert element';

			case _ETS_EVAL:         return 'eval element';

			case _ETS_SAFE:         return 'safe eval element';

			case _ETS_ROOT_EVAL:    return 'eval or safe element';

		}

	}



	/**

	 * Define the label of a parsing mode from an id

	 */

	function mode_label($modeid)

	{

		switch($modeid) {

			case _ETS_COMMENT:      return 'comment';

			case _ETS_CDATA:        return 'cdata';

		}

	}





	/*****   P A R S I N G   *****/



    /**

     * Store the size reducing behavior

     */

	function store_reduce(&$elts, $value)

	{

		switch(strtoupper($value)) {

			case 'OFF':

			case 'NOTHING':

				$elts['0reduce'] = _ETS_REDUCE_OFF;

				return TRUE;



			case 'SPACE':

			case 'SPACES':

				$elts['0reduce'] = _ETS_REDUCE_SPACES;

				return TRUE;



			case 'CRLF':

			case 'ON':

			case 'ALL':

				$elts['0reduce'] = _ETS_REDUCE_ALL;

				return TRUE;



			default:

				return FALSE;



		}

	}



    /**

     * Walk through a slash separated path of a node to build a tree

     */

	function node_path_walk($elements, $rank, $ptype, &$i, &$line, $cvalue, $ncontent, $content, $code)

	{

		if (count($elements) == 1) {

			$elt[$ptype . ':' . $i . ':' . $elements[0] . ':' . $cvalue] = $this->parse($code ? _ETS_CODE : $ptype, $i, $line, $ncontent, $content);

		} else {

			$element1 = array_shift($elements);

			$masktype = ($ptype == _ETS_MIS || $ptype == _ETS_MISVAL) ? _ETS_MIS_TEMPLATE : _ETS_TEMPLATE;

			$elt[$masktype . ':' . $i . '.' . $rank . ':' . $element1] = $this->node_path_walk($elements, $rank + 1, $ptype, $i, $line, $cvalue, $ncontent, $content, $code);

		}

		return $elt;

	}



    /**

     * Store a new node in the template tree

     */

	function store_node(&$elts, $ptype, &$i, &$line, $cname, $cvalue, $ncontent, $content, $code = FALSE)

	{

		$isabsolute = FALSE;

		if ($cname{0} == '/' && $cname{1} == '/') {

			$isabsolute = TRUE;

			$cname = substr($cname, 2);

		}

		$elements = explode('/', $cname);

		if (count($elements) == 1 && !$isabsolute) {

			$elts[$ptype . ':' . $i . ':' . $cname . ':' . $cvalue] = $this->parse($code ? _ETS_CODE : $ptype, $i, $line, $ncontent, $content);

		} else {

			if ($isabsolute) {

				$elts[_ETS_TEMPLATE . ':' . $i . '.1://'] = $this->node_path_walk($elements, 2, $ptype, $i, $line, $cvalue, $ncontent, $content, $code);

			} else {

				$element1 = array_shift($elements);

				$masktype = ($ptype == _ETS_MIS || $ptype == _ETS_MISVAL) ? _ETS_MIS_TEMPLATE : _ETS_TEMPLATE;

				$elts[$masktype . ':' . $i . '.1:' . $element1] = $this->node_path_walk($elements, 2, $ptype, $i, $line, $cvalue, $ncontent, $content, $code);

			}

		}

	}



    /**

     * Walk through a slash separated path of a leaf to build a tree

     */

	function leaf_path_walk($elements, $rank, $ptype, &$i, $cvalue)

	{

		if (count($elements) == 1) {

			$elt[$ptype . ':' . $i . ':' . $elements[0] . ':' . $cvalue] = '';

		} else {

			$element1 = array_shift($elements);

			$elt[_ETS_TEMPLATE . ':' . $i . '.' . $rank . ':' . $element1] = $this->leaf_path_walk($elements, $rank + 1, $ptype, $i, $cvalue);

		}

		return $elt;

	}



    /**

     * Store a new leaf in the template tree

     */

	function store_leaf(&$elts, $ptype, &$i, $cname, $cvalue = NULL)

	{

		$isabsolute = FALSE;

		if ($cname{0} == '/' && $cname{1} == '/') {

			$isabsolute = TRUE;

			$cname = substr($cname, 2);

		}



		$elements = explode('/', $cname);

		if (count($elements) == 1 && !$isabsolute) {

			$elts[$ptype . ':' . $i . ':' . $cname . ':' . $cvalue] = '';

		} else {

			if ($isabsolute) {

				$elts[_ETS_TEMPLATE . ':' . $i . '.1://'] = $this->leaf_path_walk($elements, 2, $ptype, $i, $cvalue);

			} else {

				$element1 = array_shift($elements);

				$elts[_ETS_TEMPLATE . ':' . $i . '.1:' . $element1] = $this->leaf_path_walk($elements, 2, $ptype, $i, $cvalue);

			}

		}

	}



    /**

     * Store a new text in the template tree

     */

	function store_text(&$elts, &$i, $ptype, $ntext, $ctext)

	{

		if ($ntext == 1 && $ptype != _ETS_ROOT) {

			$elts[_ETS_TEXT . ':' . $i] = $ctext;

		}

	}



	/**

	 * Define if the parameter is a non printable character

	 */

	function is_space($char)

	{

		$asc = ord($char);

		if ($asc == 32) {

			return TRUE;

		} elseif ($asc > 8 && $asc < 14) {

			return TRUE;

		}

		return FALSE;

	}



    /**

     * Recursively parse template

     */

	function parse($ptype, &$i, &$line, $ncontent, $content)

	{

		$elts = array();

		$mode = _ETS_DATA;

		$ntext = $nname = $nvalue = $nspace = 0;

		$ctext = $cname = $cvalue = '';

		$nametype = NULL;

		$nspecial = 0;

		$saveline = $line;



		for ( ; $i < $ncontent; ++$i) {



			// skip parsing when error

			if ($this->skip) {

				return array();

			}



			// current character and following

			$c0 = $content{$i};

			$c1 = $content{$i + 1};

			$is_space0 = $this->is_space($c0);

			$a0 = ord($c0);



			// line count

			if ($a0 == 10 || ($a0 == 13 && ord($c1) != 10)) {

				++$line;

			}



			// data acquisition

			if ($mode == _ETS_DATA) {



				// tag?

				if ($c0 == '{') {



					$c2 = $content{$i + 2};

					$c3 = $content{$i + 3};

					$c4 = $content{$i + 4};

					$c5 = $content{$i + 5};

					$c6 = $content{$i + 6};

					$c7 = $content{$i + 7};



					// {* (comment)

					if ($c1 == '*') {

						if ($ptype & _ETS_CODEs) {

							$this->error(0, 1, 'comment', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_COMMENT;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = NULL;

						++$i;

						++$nspecial;

						$saveline = $line;



					// {# (cdata)

					} elseif ($c1 == '#') {

						if ($ptype & _ETS_GROUP1) {

							$this->error(0, 2, 'cdata', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_CDATA;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = NULL;

						++$i;

						++$nspecial;

						$saveline = $line;



					// {mask:

					} elseif ($c1 == 'm' && $c2 == 'a' && $c3 == 's' && $c4 == 'k' && $c5 == ':') {

						if ($ptype & _ETS_GROUP2) {

							$this->error(0, 3, 'template element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_NAME;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = _ETS_TEMPLATE;

						$i += 5;



					// {call:

					} elseif ($c1 == 'c' && $c2 == 'a' && $c3 == 'l' && $c4 == 'l' && $c5 == ':') {

						if ($ptype & _ETS_GROUP1) {

							$this->error(0, 4, 'call element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_DATA;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = NULL;

						$i += 6;

						$index = _ETS_CALL . ':' . $i;

						$elts[$index]['template'] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);

						$elts[$index]['args'] = $this->parse(_ETS_CALL, $i, $line, $ncontent, $content);



					// {const:

					} elseif ($c1 == 'c' && $c2 == 'o' && $c3 == 'n' && $c4 == 's' && $c5 == 't' && $c6 == ':') {

						if ($ptype & _ETS_GROUP1) {

							$this->error(0, 5, 'constant element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_DATA;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = NULL;

						$i += 7;

						$elts[_ETS_CONST . ':' . $i] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);

						--$i;



					// {set:

					} elseif ($c1 == 's' && $c2 == 'e' && $c3 == 't' && $c4 == ':') {

						if ($ptype & _ETS_GROUP1) {

							$this->error(0, 6, 'set element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_NAME;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = _ETS_SET;

						$i += 4;



					// {mis:

					} elseif ($c1 == 'm' && $c2 == 'i' && $c3 == 's' && $c4 == ':') {

						if ($ptype & _ETS_GROUP1) {

							$this->error(0, 7, 'missing element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_NAME;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = _ETS_MIS;

						$i += 4;



					// {choose:

					} elseif ($c1 == 'c' && $c2 == 'h' && $c3 == 'o' && $c4 == 'o' && $c5 == 's' && $c6 == 'e' && $c7 == ':') {

						if ($ptype & _ETS_GROUP1) {

							$this->error(0, 8, 'choose element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_NAME;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = _ETS_CHOOSEVAR;

						$i += 7;



					// {arg:

					} elseif ($c1 == 'a' && $c2 == 'r' && $c3 == 'g' && $c4 == ':') {

						if ($ptype == _ETS_CALL) {

							$mode = _ETS_NAME;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = _ETS_ARG;

							$i += 4;

						} else {

							$this->error(0, 9, 'argument element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {reduce:

					} elseif ($c1 == 'r' && $c2 == 'e' && $c3 == 'd' && $c4 == 'u' && $c5 == 'c' && $c6 == 'e' && $c7 == ':') {

						if ($ptype == _ETS_ROOT) {

							if (!isset($elts['0reduce']) || $elts['0reduce'] == _ETS_REDUCE_NULL) {

								$mode = _ETS_NAME;

								$ntext = $nname = $nvalue = $nspace = 0;

								$ctext = $cname = $cvalue = '';

								$nametype = _ETS_REDUCE;

								$i += 7;

							} else {

								$this->error(7, 10, 'reduce element already used', $line);

							}

						} else {

							$this->error(0, 11, 'reduce element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {include:

					} elseif ($c1 == 'i' && $c2 == 'n' && $c3 == 'c' && $c4 == 'l' && $c5 == 'u' && $c6 == 'd' && $c7 == 'e' & $content{$i + 8} == ':') {

						if ($ptype & _ETS_GROUP2) {

							$this->error(0, 12, 'include element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_DATA;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = NULL;

						$i += 9;

						$container_name = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);

						--$i;

						if ($ptype == _ETS_ROOT) {

							$return = NULL;

							@eval('$return=(string)(' . implode('', $container_name) . ');');

							if (isset($return)) {

								$container = $this->container;

								$skip = $this->skip;

								$masktree = $this->read_container($return, _ETS_ROOT);

								$this->container = $container;

								$this->skip = $skip;

								if ($masktree === FALSE) {

									$this->error(5, 13, $return, $line);

								} else {

									$this->masktree = $this->masktree_merge($this->masktree, $masktree, $cvalue);

									$elts['0include'][] = $return;

								}

							}

						} else {

							$elts[_ETS_INCLUDE . ':' . $i] = $container_name;

						}



					// {insert:

					} elseif ($c1 == 'i' && $c2 == 'n' && $c3 == 's' && $c4 == 'e' && $c5 == 'r' && $c6 == 't' && $c7 == ':') {

						if ($ptype & _ETS_GROUP1) {

							$this->error(0, 14, 'insert element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_DATA;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = NULL;

						$i += 8;

						$elts[_ETS_INSERT . ':' . $i] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);

						--$i;



					// {eval:

					} elseif ($c1 == 'e' && $c2 == 'v' && $c3 == 'a' && $c4 == 'l' && $c5 == ':') {

						if ($ptype & _ETS_GROUP1) {

							$this->error(0, 15, 'eval element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_DATA;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = NULL;

						$i += 6;

						$elts[_ETS_EVAL . ':' . $i] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);

						--$i;



					// {safe:

					} elseif ($c1 == 's' && $c2 == 'a' && $c3 == 'f' && $c4 == 'e' && $c5 == ':') {

						if ($ptype & _ETS_GROUP1) {

							$this->error(0, 16, 'safe eval element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_DATA;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = NULL;

						$i += 6;

						$elts[_ETS_SAFE . ':' . $i] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);

						--$i;



					// {when:

					} elseif ($c1 == 'w' && $c2 == 'h' && $c3 == 'e' && $c4 == 'n' && $c5 == ':') {



						// of of whentest

						if ($ptype == _ETS_CHOOSE) {

							$mode = _ETS_DATA;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 6;

							$index = _ETS_WHENTEST . ':' . $i;

							$elts['when'][$index]['test'] = $this->parse(_ETS_CODE,     $i, $line, $ncontent, $content);

							$elts['when'][$index]['true'] = $this->parse(_ETS_WHENTEST, $i, $line, $ncontent, $content);

						}



						// of whenval

						elseif ($ptype == _ETS_CHOOSEVAR) {

							$mode = _ETS_VALUE;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = _ETS_WHENVAL;

							switch ($c6) {

								case '\'':	$quotetype = 1; $i += 6; break;

								case '"':	$quotetype = 2; $i += 6; break;

								default:	$quotetype = 0; $i += 5; break;

							}



						} else {

							$this->error(0, 17, 'when element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {if:

					} elseif ($c1 == 'i' && $c2 == 'f' && $c3 == ':') {

						if ($ptype & _ETS_GROUP1) {

							$this->error(0, 18, 'if element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_DATA;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = NULL;

						$i += 4;

						$index = _ETS_IF . ':' . $i;

						$elts[$index]['test'] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);

						$elts[$index]['true'] = $this->parse(_ETS_IF, $i, $line, $ncontent, $content);



					// {repeat:

					} elseif ($c1 == 'r' && $c2 == 'e' && $c3 == 'p' && $c4 == 'e' && $c5 == 'a' && $c6 == 't' && $c7 == ':') {

						if ($ptype & _ETS_GROUP1) {

							$this->error(0, 19, 'repeat element', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_DATA;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cname = $cvalue = '';

						$nametype = NULL;

						$i += 8;

						$index = _ETS_REPEAT . ':' . $i;

						$elts[$index]['loops'] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);

						$elts[$index]['repeated'] = $this->parse(_ETS_REPEAT, $i, $line, $ncontent, $content);



					// simple tag with absolute path

					} elseif ($c1 == '/' && $c2 == '/') {

						if ($ptype & _ETS_GROUP3) {

							$this->error(0, 20, 'simple tag element with absolute path', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}

						$this->store_text($elts, $i, $ptype, $ntext, $ctext);

						$mode = _ETS_NAME;

						$ntext = $nname = $nvalue = $nspace = 0;

						$ctext = $cvalue = '';

						$cname = '//';

						$nametype = _ETS_TAG;

						$i += 2;



					// other simple tag

					} elseif ($c1 != '/' && !$this->is_space($c1)) {



						// {else

						if ($c1 == 'e' && $c2 == 'l' && $c3 == 's' && $c4 == 'e' && ($this->is_space($c5) || $c5 == '}' )) {

							if ($ptype & _ETS_CHOOSEs) {

								$mode = _ETS_NAME;

								$ntext = $nvalue = $nspace = 0;

								$nname = 1;

								$ctext = $cvalue = '';

								$cname = 'else';

								$nametype = _ETS_TAG;

								$i += 4;

							} else {

								$this->error(0, 21, 'else element', $line, $ptype);

								$this->skip = TRUE;

								return array();

							}



						} elseif ($ptype & _ETS_GROUP3) {

							$this->error(0, 22, 'simple tag element', $line, $ptype);

							$this->skip = TRUE;

							return array();



						// other

						} else {

							$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							$mode = _ETS_NAME;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = _ETS_TAG;

						}



					// {/mask

					} elseif ($c1 == '/' && $c2 == 'm' && $c3 == 'a' && $c4 == 's' && $c5 == 'k') {

						if ($ptype == _ETS_TEMPLATE) {

							$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 5;

						} else {

							$this->error(1, 23, 'mask', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {/set

					} elseif ($c1 == '/' && $c2 == 's' && $c3 == 'e' && $c4 == 't') {

						if ($ptype & _ETS_SETs) {

							$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 4;

						} else {

							$this->error(1, 24, 'set', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {/mis

					} elseif ($c1 == '/' && $c2 == 'm' && $c3 == 'i' && $c4 == 's') {

						if ($ptype & _ETS_MISs) {

							$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 4;

						} else {

							$this->error(1, 25, 'mis', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {/php

					} elseif ($c1 == '/' && $c2 == 'p' && $c3 == 'h' && $c4 == 'p') {

						if ($ptype == _ETS_PHP) {

							$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 4;

						} else {

							$this->error(1, 26, 'PHP', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {/if

					} elseif ($c1 == '/' && $c2 == 'i' && $c3 == 'f') {

						if ($ptype == _ETS_IF) {

							$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 3;

						} else {

							$this->error(1, 27, 'if', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {/choose

					} elseif ($c1 == '/' && $c2 == 'c' && $c3 == 'h' && $c4 == 'o' && $c5 == 'o' && $c6 == 's' && $c7 == 'e') {

						if ($ptype & _ETS_CHOOSEs) {

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 7;

						} else {

							$this->error(1, 28, 'choose', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {/call

					} elseif ($c1 == '/' && $c2 == 'c' && $c3 == 'a' && $c4 == 'l' && $c5 == 'l') {

						if ($ptype == _ETS_CALL) {

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 5;

						} else {

							$this->error(1, 29, 'call', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {/arg

					} elseif ($c1 == '/' && $c2 == 'a' && $c3 == 'r' && $c4 == 'g') {

						if ($ptype == _ETS_ARG) {

							$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 4;

						} else {

							$this->error(1, 30, 'arg', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {/when

					} elseif ($c1 == '/' && $c2 == 'w' && $c3 == 'h' && $c4 == 'e' && $c5 == 'n') {



						// of when val

						if ($ptype == _ETS_WHENVAL) {

							$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 5;



						// of when test

						} elseif ($ptype == _ETS_WHENTEST) {

							$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 5;



						} else {

							$this->error(1, 31, 'when', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {/else

					} elseif ($c1 == '/' && $c2 == 'e' && $c3 == 'l' && $c4 == 's' && $c5 == 'e') {

						if ($ptype == _ETS_ELSE) {

							$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 5;

						} else {

							$this->error(1, 32, 'else', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {/repeat

					} elseif ($c1 == '/' && $c2 == 'r' && $c3 == 'e' && $c4 == 'p' && $c5 == 'e' && $c6 == 'a' && $c7 == 't') {

						if ($ptype == _ETS_REPEAT) {

							$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							$i += 7;

						} else {

							$this->error(1, 33, 'repeat', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// {/ (simplified closing tag)

					} elseif ($c1 == '/' && ($c2 == '}' || $this->is_space($c2))) {

						if ($ptype != _ETS_ROOT) {

							if (!($ptype & _ETS_GROUP4)) {

								$this->store_text($elts, $i, $ptype, $ntext, $ctext);

							}

							$mode = _ETS_CLOSING_TAG;

							$ntext = $nname = $nvalue = $nspace = 0;

							$ctext = $cname = $cvalue = '';

							$nametype = NULL;

							++$i;

						} else {

							$this->error(1, 34, '', $line, $ptype);

							$this->skip = TRUE;

							return array();

						}



					// text

					} elseif (!($ptype & _ETS_GROUP3)) {

						$ctext .= $c0;

						$ntext = 1;

					}



				// end of code element

				} elseif ($c0 == '}' && $ptype == _ETS_CODE) {

					$this->store_text($elts, $i, $ptype, $ntext, $ctext);

					++$i;

					return $elts;



				// escape } with \} in code acquisition

				} elseif ($c0 == '\\' && $c1 == '}' && $ptype == _ETS_CODE) {

					$ctext .= '}';

					$ntext = 1;

					++$i;



				// no text in choosevar element

				} elseif ($ptype == _ETS_CHOOSE && !$is_space0) {

					$this->error(2, 35, "unexpected character '$c0' in choose element", $line);

					$this->skip = TRUE;

					return array();



				// no text in choose element

				} elseif ($ptype == _ETS_CHOOSEVAR && !$is_space0) {

					$this->error(2, 36, "unexpected character '$c0' in choose-variable element", $line);

					$this->skip = TRUE;

					return array();



				// no text in call element

				} elseif ($ptype == _ETS_CALL && !$is_space0) {

					$this->error(2, 37, "unexpected character '$c0' in call element", $line);

					$this->skip = TRUE;

					return array();



				// text

				} elseif ($ptype != _ETS_ROOT) {

					$ctext .= $c0;

					$ntext = 1;

				}



			// name acquisition

			} elseif ($mode == _ETS_NAME) {



				// end of name acquisition

				if ($c0 == '}' && $nname == 1) {



					// reduce

					if ($nametype == _ETS_REDUCE) {

						if (!isset($elts['0reduce']) || $elts['0reduce'] == _ETS_REDUCE_NULL) {

							if (!$this->store_reduce($elts, $cname)) {

								$this->error(7, 38, "invalid value $cname for reduce element", $line);

							}

						}



					// template

					} elseif ($nametype == _ETS_TEMPLATE) {

						++$i;

						if ($ptype != _ETS_ROOT) {

							$this->store_node($elts, _ETS_TEMPLATE, $i, $line, $cname, NULL, $ncontent, $content);

						} elseif (isset($elts[$cname])) {

							$this->error(2, 39, "template $cname already defined", $line);

							$this->skip = TRUE;

							return $elts; //array();

						} else {

							$elts[$cname] = $this->parse(_ETS_TEMPLATE, $i, $line, $ncontent, $content);

						}



					// set

					} elseif ($nametype == _ETS_SET) {

						++$i;

						$this->store_node($elts, _ETS_SET, $i, $line, $cname, NULL, $ncontent, $content);



					// mis

					} elseif ($nametype == _ETS_MIS) {

						++$i;

						$this->store_node($elts, _ETS_MIS, $i, $line, $cname, NULL, $ncontent, $content);



					// tag?

					} elseif ($nametype == _ETS_TAG) {



						// php

						if ($cname == 'php') {

							++$i;

							$elts[_ETS_PHP . ':' . $i] = $this->parse(_ETS_PHP, $i, $line, $ncontent, $content);



						// choose

						} elseif ($cname == 'choose') {

							++$i;

							$elts[_ETS_CHOOSE . ':' . $i] = $this->parse(_ETS_CHOOSE, $i, $line, $ncontent, $content);



						// else

						} elseif (($ptype == _ETS_CHOOSE || $ptype == _ETS_CHOOSEVAR) && $cname == 'else') {

							if (isset($elts['else'])) {

								$this->error(2, 40, 'else element already exists in ' . $this->elt_label($ptype), $line);

								$this->skip = TRUE;

								return array();

							} else {

								++$i;

								$elts['else'] = $this->parse(_ETS_ELSE, $i, $line, $ncontent, $content);

							}



						// tag!

						} else {

							$this->store_leaf($elts, _ETS_TAG, $i, $cname);

						}



					// choose var

					} elseif ($nametype == _ETS_CHOOSEVAR) {

						++$i;

						$this->store_node($elts, _ETS_CHOOSEVAR, $i, $line, $cname, NULL, $ncontent, $content);



					// arg

					} elseif ($nametype == _ETS_ARG) {

						++$i;

						$this->store_node($elts, _ETS_ARG, $i, $line, $cname, NULL, $ncontent, $content);

					}



					$mode = _ETS_DATA;



				// space in name acquisition

				} elseif ($is_space0) {

					if ($nname == 1) {

						$nspace = 1;

					} else {

						$this->error(2, 41, "unexpected space before name", $line);

						$this->skip = TRUE;

						return array();

					}



				// start of value acquisition

				} elseif ($c0 == ':' && $nname == 1 && ($nametype == _ETS_SET || $nametype == _ETS_MIS)) {

					$cvalue = '';

					$nvalue = 0;

					$nspace = 0;

					$mode = _ETS_VALUE;

					switch ($c1) {

						case '\'':	$quotetype = 1; ++$i; break;

						case '"':	$quotetype = 2; ++$i; break;

						default:	$quotetype = 0;       break;

					}



				// start of second name acquisition

				} elseif ($c0 == ':' && $nametype == _ETS_TAG && $nname == 1 && $nvalue == 0) {

					++$i;

					$this->store_node($elts, _ETS_ALT_TAG, $i, $line, $cname, $cvalue, $ncontent, $content, TRUE);

					--$i;

					$mode = _ETS_DATA;

					$ntext = $nname = $nvalue = $nspace = 0;

					$ctext = $cname = $cvalue = '';

					$nametype = NULL;



				// data after trailing spaces

				} elseif ($nspace == 1) {

					$this->error(2, 42, "unexpected character '$c0' after spaces in name", $line);

					$this->skip = TRUE;

					return array();



				// name acquisition

				} elseif (($nname == 0 && preg_match('/[a-zA-Z_\.\x7f-\xff]/', $c0)) || ($nname == 1 && preg_match('/[\[\]\'\/a-zA-Z0-9_\.\x7f-\xff]/', $c0))) {

					$cname .= $c0;

					$nname = 1;



				// absolute path at the beginning of name acquisition

				} elseif ($c0 == '/' && $c1 == '/' && $nname == 0) {

					$cname = '//';

					++$i;



				// error in name acquisition

				} else {

					$this->error(2, 43, "unexpected character '$c0' in name", $line);

					$this->skip = TRUE;

					return array();

				}



			// end of closing tag

			} elseif ($mode == _ETS_CLOSING_TAG) {

				if ($c0 == '}') {

					$this->store_text($elts, $i, $ptype, $ntext, $ctext);

					return $elts;

				} elseif (!$is_space0) {

					$this->error(2, 44, "unexpected character '$c0' in closing tag", $line);

					$this->skip = TRUE;

					return array();

				}



			// value acquisition

			} elseif ($mode == _ETS_VALUE) {



				// end of value acquisition

				if ($c0 == '}' && $nvalue == 1 && ($quotetype == 0 || $nspace == 1 || $nspace == 2)) {



					if ($nametype == _ETS_SET) {

						++$i;

						$this->store_node($elts, _ETS_SETVAL, $i, $line, $cname, $cvalue, $ncontent, $content);



					} elseif ($nametype == _ETS_MIS) {

						++$i;

						$this->store_node($elts, _ETS_MISVAL, $i, $line, $cname, $cvalue, $ncontent, $content);



					} elseif ($nametype == _ETS_WHENVAL) {

						++$i;

						$elts['when'][_ETS_WHENVAL . ':' . $i . '::' . $cvalue] = $this->parse(_ETS_WHENVAL, $i, $line, $ncontent, $content);

					}



					$mode = _ETS_DATA;



				// no more character after space for single quoted string

				} elseif ($c0 == '\'' && $quotetype == 1 && $nspace == 0) {

					$nspace = 2;



				// no more character after space for double quoted string

				} elseif ($c0 == '"' && $quotetype == 2 && $nspace == 0) {

					$nspace = 2;



				// space in value acquisition

				} elseif ($is_space0) {

					if ($nvalue == 0 && $quotetype == 0) { // no value without quote

						$this->error(2, 45, "unexpected space at the beginning of a value", $line);

						$this->skip = TRUE;

						return array();

					} else { // value found or with quotes

						if ($quotetype == 0) { // no quote

							$nspace = 1;

						} else { // with quotes

							if ($nspace == 2) { // after quotes

								$nspace = 1;

							} else {			// in quotes

								$cvalue .= $c0;

								$nvalue = 1;

							}

						}

					}



				// escape } with \} in value acquisition without quote

				} elseif ($c0 == '\\' && $c1 == '}' && $nspace == 0) {

					$cvalue .= '}';

					$nvalue = 1;

					++$i;



				// espace ' with \' in value acquisition for single quoted string

				} elseif ($c0 == '\\' && $c1 == '\'' && $quotetype == 1 && $nspace == 0) {

					$cvalue .= '\'';

					$nvalue = 1;

					++$i;



				// espace " with \" in value acquisition for single quoted string

				} elseif ($c0 == '\\' && $c1 == '"' && $quotetype == 2 && $nspace == 0) {

					$cvalue .= '"';

					$nvalue = 1;

					++$i;



				// value acquisition

				} elseif ($nspace == 0) {

					$cvalue .= $c0;

					$nvalue = 1;



				// error in value acquisition

				} else {

					$this->error(2, 46, "unexpected character '$c0' in value", $line);

					$this->skip = TRUE;

					return array();

				}



			// comment

			} elseif ($mode == _ETS_COMMENT) {



				// nested

				if ($c0 == '{' && $c1 == '*') {

					++$i;

					++$nspecial;



				// end

				} elseif ($c0 == '*' && $c1 == '}') {

					++$i;

					--$nspecial;



					// last end

					if ($nspecial == 0) {

						$mode = _ETS_DATA;

					}

				}



			// cdata

			} elseif ($mode == _ETS_CDATA) {



				// nested

				if ($c0 == '{' && $c1 == '#') {

					++$i;

					++$nspecial;



				// end

				} elseif ($c0 == '#' && $c1 == '}') {

					++$i;

					--$nspecial;



					// last end

					if ($nspecial == 0) {

						$mode = _ETS_DATA;

					}



				// text acquisition

				} else {

					switch ($c0) {

						case "\n": $ctext .= "\1n\1"; break;

						case "\r": $ctext .= "\1r\1"; break;

						case "\t": $ctext .= "\1t\1"; break;

						case " " : $ctext .= "\1s\1"; break;

						default  : $ctext .= $c0; break;

					}

					$ntext = 1;

				}

			}



		}



		// end

		if ($mode & _ETS_GROUP0) {

			$this->error(3, 47, '', $saveline, $mode);

			$this->skip = TRUE;

			return array();

		}



		if ($ptype == _ETS_ROOT_EVAL) {

			$this->store_text($elts, $i, $ptype, $ntext, $ctext);



		} elseif ($ptype != _ETS_ROOT) {

			$this->error(4, 48, '', $saveline, $ptype);

			$this->skip = TRUE;

			return array();

		}



		return $elts;

	}



    /**

     * Merge two template trees

     */

	function masktree_merge($masktree1, $masktree2, $maskname)

	{

		$merged = array_merge($masktree1, $masktree2);



		if (count($merged) < count($masktree1) + count($masktree2)) {



			$keys1 = array_keys($masktree1);

			$keys2 = array_keys($masktree2);

			$keysm = array_merge($keys1, $keys2);

			$keysc = array_count_values($keysm);



			foreach ($keysc as $keyn => $keyc) {

				if ($keyc > 1) {

					if ($keyn == '0reduce') {

						$this->error(6, 49, 'reduce element already used');

					} elseif ($keyn != '0include') {

						$this->error(16, 60, "template $keyn already defined in <b>$maskname</b>");

					}

				}

			}

		}



		return $merged;

	}





	/*****   C O N T E N T   *****/



    /**

     * Read a stream and return its content or FALSE if fail

     */

	function read_content()

	{

		if ($this->external_source_read) {

			$fct = $this->source_read_name;

			return $fct($this->container);

		} else {

			$content = FALSE;

			if ($handle = @fopen($this->container, 'rb')) {

				$size = @filesize($this->container);

				$content = @fread($handle, $size);

				fclose($handle);

			}

			return $content;

		}

	}



    /**

     * Return container content or masktree in container content

     */

	function read_container($container, $parse)

	{

		$this->container = $container = trim($container);

		$this->skip = FALSE;



		// content must be parsed...

		if ($parse != _ETS_TEXT) {



			// null containers are avoid

			if ($this->container === '' || strtoupper($this->container) == 'NULL') {

				return array();

			}



			// check if container is already used

			if ($parse == _ETS_ROOT) {

				if (isset($this->containers[$container])) {

					$this->error(16, 50, "container $container already used");

					return array();

				}

			}



			// cache handlers are available...

			if ($this->external_cache_read && $this->external_cache_write) {



				// the cache exists and is not obsolete

				$fct = $this->cache_read_name;

				if ($envelope = $fct($this->container)) {

					// the cache is a valid envelope

					if (isset($envelope) && $envelope{0} == 'E' && $envelope{1} == 'T' && $envelope{2} == 'S' && $envelope{3} == "\1") {

						$masktree = unserialize(substr($envelope, 4));

						// the envelope contains valid templates

						if ($masktree && is_array($masktree)) {

							$this->containers[$container] = TRUE;

							// the container calls other containers

							if (isset($masktree['0include'])) {

								foreach ($masktree['0include'] as $includedname) {

									$included = $this->read_container($includedname, _ETS_ROOT);

									if ($included === FALSE) {

										$this->error(13, 51, $includedname);

									} else {

										$masktree = $this->masktree_merge($masktree, $included, $includedname);

									}

								}

							}

							return $masktree;

						}

					}

				}



				// refresh the cache

				$content = $this->read_content();

				if ($content === FALSE) {

					return FALSE;

				}

				$this->containers[$container] = TRUE;

				$masktree = $this->parse($parse, $i = 0, $line = 1, strlen($content), "$content       ");

				$fct = $this->cache_write_name;

				$fct($this->container, "ETS\1" . serialize($masktree));

				return $masktree;



			// .. or not

			} else {

				$content = $this->read_content();

				if ($content === FALSE) {

					return FALSE;

				}

				$this->containers[$container] = TRUE;
				
				// return $this->parse($parse, $i = 0, $line = 1, strlen($content), "$content       ");
				$i = 0; $line = 1;
				return $this->parse($parse, $i, $line, strlen($content), "$content       ");

			}



		// .. or not

		} else {



			// null containers are avoid

			if ($this->container === '' || strtoupper($this->container) == 'NULL') {

				return '';

			}



			return $this->read_content();

		}

	}



    /**

     * Read containers then parse their content to build a template tree

     */

	function parse_containers($containers)

	{

		// Construct an array of container names

		if (!is_array($containers)) {

			$containers = explode(',', $containers);

		}



		// Parse each container

		foreach ($containers as $container) {

			$masktree = $this->read_container($container, _ETS_ROOT);

			if ($masktree === FALSE) {

				$this->error(11, 52, $this->container);

			} else {

				$this->masktree = $this->masktree_merge($this->masktree, $masktree, $container);

			}

		}

	}



	/*****   M A T C H I N G   *****/



    /**

     * Retrieve the value of a string representation of a variable

     */

	function get_value($parent, $varname)

	{

		if (isset($parent->$varname)) {

			return $parent->$varname;

		} else {

			$elements = explode('[', $varname);

			if (count($elements) == 1) {

				return NULL;

			} else {

				$vartest = $parent;

				foreach ($elements as $elementid => $element) {

					if ($elementid == 0) {

						$vartest = $parent->$element;

						if (!isset($vartest)) {

							return NULL;

						}

					} else {

						$index = substr($element, 0, -1);

						if ($index == '_first') {

							$keys = array_keys($vartest);

							$index = $keys[0];

						} elseif ($index == '_last') {

							$keys = array_keys($vartest);

							$index = $keys[count($keys) - 2];

						}

						if (!isset($vartest[$index])) {

							return NULL;

						} else {

							$vartest = $vartest[$index];

						}

					}

				}

			}

			return $vartest;

		}

	}



    /**

     * Define the type of the current data, the direction and parent property

     */

	function get_datatype($maskname, $carray, $incode, &$cindex, &$ckey, &$clast, &$datatree, &$datatype, &$direction, &$currentdata, $safemode)

	{

		// . from root

		if ($maskname == '//' && !$safemode) {

			$datatype = _ETS_COMPLEX;

			$currentdata = $this->datatree;

			if ($direction == _ETS_FORWARD) {

				if (is_array($currentdata)) {

					$currentdata['_parent'] = &$datatree;

				} elseif (is_object($currentdata)) {

					$currentdata->_parent = &$datatree;

				}

			}



		// . parent

		} elseif (($maskname == '..' || $maskname == '_parent') && !$safemode) {

			if (is_array($datatree)) {

				$datatype = _ETS_COMPLEX;

				$currentdata = $datatree['_parent'];

				$direction = _ETS_BACKWARD;

			} elseif (is_object($datatree)) {

				$datatype = _ETS_COMPLEX;

				$currentdata = $datatree->_parent;

				$direction = _ETS_BACKWARD;

			} else {

				$datatype = _ETS_MISSING;

				$currentdata = NULL;

				$direction = _ETS_FORWARD;

			}



		// . first sibling in an array

		} elseif ($maskname == '_start') {

			$direction = _ETS_FORWARD;

			$keys = array_keys($carray);

			$cindex = 0;

			if (isset($keys[$cindex]) && isset($carray[$keys[$cindex]])) {

				$ckey = $keys[$cindex];

				$clast = ($cindex == count($carray) - 2);

				$currentdata = $carray[$ckey];

				$datatype = _ETS_COMPLEX;

			} else {

				$currentdata = NULL;

				$datatype = _ETS_MISSING;

			}



		// . previous sibling in an array

		} elseif ($maskname == '_previous') {

			$direction = _ETS_FORWARD;

			$keys = array_keys($carray);

			--$cindex;

			if (isset($keys[$cindex]) && isset($carray[$keys[$cindex]])) {

				$ckey = $keys[$cindex];

				$clast = FALSE;

				$currentdata = $carray[$ckey];

				$datatype = _ETS_COMPLEX;

			} else {

				$currentdata = NULL;

				$datatype = _ETS_MISSING;

			}



		// . next sibling in an array

		} elseif ($maskname == '_next') {

			$direction = _ETS_FORWARD;

			$keys = array_keys($carray);

			++$cindex;

			if (isset($keys[$cindex]) && isset($carray[$keys[$cindex]]) && $keys[$cindex] != '_parent') {

				$ckey = $keys[$cindex];

				$clast = ($cindex == count($carray) - 2);

				$currentdata = $carray[$ckey];

				$datatype = _ETS_COMPLEX;

			} else {

				$currentdata = NULL;

				$datatype = _ETS_MISSING;

			}



		// . last sibling in an array

		} elseif ($maskname == '_end') {

			$direction = _ETS_FORWARD;

			$keys = array_keys($carray);

			$cindex = count($keys) - 2;

			if (isset($keys[$cindex]) && isset($carray[$keys[$cindex]])) {

				$ckey = $keys[$cindex];

				$clast = TRUE;

				$currentdata = $carray[$ckey];

				$datatype = _ETS_COMPLEX;

			} else {

				$currentdata = NULL;

				$datatype = _ETS_MISSING;

			}



		// . real data

		} else {



			// retrieve the value

			$currentdata = $this->get_value($datatree, $maskname);

			if (isset($currentdata)) {



				if (is_scalar($currentdata)) {

					$direction = _ETS_FORWARD;

					if ($currentdata === FALSE && !$incode) {

						$datatype = _ETS_MISSING;

					} elseif ($currentdata === '' && !$incode) {

						$datatype = _ETS_MISSING;

					} else {

						$datatype = _ETS_SCALAR;

					}



				} elseif (is_object($currentdata) && count(get_object_vars($currentdata)) > 0) {

					$datatype = _ETS_COMPLEX;

					if ($direction == _ETS_FORWARD && !$safemode) {

						$currentdata->_parent = &$datatree;

					}



				} elseif (is_array($currentdata) && count($currentdata) > 0) {

					$datatype = _ETS_COMPLEX;

					if ($direction == _ETS_FORWARD && !$safemode) {

						$currentdata['_parent'] = &$datatree;

					}



				} else {

					$direction = _ETS_FORWARD;

					$datatype = _ETS_MISSING;

				}



			} else {

				$direction = _ETS_FORWARD;

				$datatype = _ETS_MISSING;

			}

		}

	}



	/**

	 * Add system variables to an object

	 */

	function add_system_var(&$datatree, $index, $last, $key)

	{

		$datatree->_key = $key;

		$datatree->_index = $index;

		$datatree->_rank = $index + 1;

		$datatree->_odd = $datatree->_not_even = (1 == $datatree->_rank % 2);

		$datatree->_even = $datatree->_not_odd = (0 == $datatree->_rank % 2);

		$datatree->_first = (0 == $index);

		$datatree->_middle = !$datatree->_first && !$last;

		$datatree->_last = $last;

		$datatree->_not_first = !$datatree->_first;

		$datatree->_not_last = !$last;

		$datatree->_not_middle = !$datatree->_middle;

	}



    /**

     * Excerpt info defined in the index of each node of the template tree

     */

	function parse_info($info)

	{

		$elements = explode(':', $info);

		$count = count($elements);

		if ($count > 4) {

			for ($i = 4; $i < $count; ++$i) {

				$elements[3] .= ':' . $elements[$i];

			}

		} else {

			$elements = array_pad($elements, 4, '');

		}

		return array($elements[0], $elements[2], $elements[3]);

	}



    /**

     * Protect non printable characters

     */

	function protect_spaces($data)

	{

		$data = str_replace("\n", "\1n\1", $data);

		$data = str_replace("\r", "\1r\1", $data);

		$data = str_replace("\t", "\1t\1", $data);

		return  str_replace(" " , "\1s\1", $data);

	}



    /**

     * Recursively match the template tree with the data tree

     */

	function build_mask($datatree, $masktree, $direction = _ETS_FORWARD, $index = -1, $last = FALSE, $key = '', $incode = FALSE, $carray = array(), $safemode = FALSE)

	{

		$built = array();



		// array

		if (isset($datatree) && is_array($datatree) && count($datatree) > 0) {

			$lindex = 0;

			$count = count($datatree) - 1; // don't count parent element

			foreach ($datatree as $dk => $dv) {

				if (!is_scalar($dv) && $dk !== '_parent') {

					if (is_object($dv)) {

						$dv->_parent = &$datatree['_parent'];

					} elseif (is_array($dv)) {

						$dv['_parent'] = &$datatree['_parent'];

					}

					$built[] = $this->build_mask($dv, $masktree, $direction, $lindex, ($count == $lindex + 1), $dk, $incode, $datatree);

				}

				++$lindex;

			}

			return implode('', $built);

		}



		// define system variables

		if (is_object($datatree) && $index > -1 && !isset($datatree->_key)) {

			$this->add_system_var($datatree, $index, $last, $key);

		}



		// loop through each child element

		foreach ($masktree as $maskinfo => $child) {



			// save array information

			$cindex = $index;

			$clast = $last;

			$ckey = $key;



			// retrieve info from index

			list($masktype, $maskname, $maskvalue) = $this->parse_info($maskinfo);



			// in safe mode, only a subset of elements are available

			if ($safemode) {



				// retrieve datatype and direction and define parent property if necessary

				$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, TRUE);



				switch ($masktype) {

					// content data element

					case _ETS_TEXT:

						$built[] = $child;

						break;



					// simple tag element are only used to place scalar values

					case _ETS_TAG:

						if ($datatype == _ETS_SCALAR) {

							$built[] = $this->protect_spaces($currentdata);

						}

						break;



					// set element

					case _ETS_SET:

						if ($datatype != _ETS_MISSING) {

							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);

						}

						break;



					// mis element

					case _ETS_MIS:

						if ($datatype == _ETS_MISSING) {

							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);

						}

						break;



					// set val element

					case _ETS_SETVAL:

						if ($datatype == _ETS_SCALAR) {

							if ($currentdata == $maskvalue) {

								$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);

							}

						}

						break;



					// mis val element

					case _ETS_MISVAL:

						if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {

							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);

						}

						break;



					// template element

					case _ETS_TEMPLATE:

						if ($datatype == _ETS_SCALAR) {

							$built[] = $this->build_mask($datatree, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);



						} elseif ($datatype == _ETS_COMPLEX) {

							$built[] = $this->build_mask($currentdata, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);

						}

						break;



					// other element: error

					default:

						$this->error(15, 53, '', 0, $masktype);

						break;

				}



			// normal mode

			} else {

				switch ($masktype) {



					// content data element

					case _ETS_TEXT:

						$built[] = $child;

						break;



					// php element

					case _ETS_PHP:

						$return = NULL;

						@eval('$return=(string)(' . $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray) . ');');

						if (isset($return)) {

							$built[] = $return;

						}

						break;



					// const element

					case _ETS_CONST:

						$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);

						$return = NULL;

						@eval('$return=(string)(' . $template . ');');

						if (isset($return) && isset($this->masktree[$return])) {

							$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);

						}

						break;



					// call element

					case _ETS_CALL:

						$template = $this->build_mask($datatree, $child['template'], $direction, $cindex, $clast, $ckey, TRUE, $carray);

						$return = NULL;

						@eval('$return=(string)(' . $template . ');');

						if (isset($return) && isset($this->masktree[$return]) && isset($child['args'])) {

							$argdatatree = $datatree;

							foreach ($child['args'] as $arginfo => $argchild) {

								list($argtype, $argname, $argvalue) = $this->parse_info($arginfo);

								$argdatatree->$argname = $this->build_mask($datatree, $argchild, $direction, $cindex, $clast, $ckey, $incode, $carray);

							}

							$built[] = $this->build_mask($argdatatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);

						}

						break;



					// include element

					case _ETS_INCLUDE:

						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);

						$return = NULL;

						@eval('$return=(string)(' . $container . ');');

						if (isset($return)) {

							$included = $this->read_container($return, _ETS_ROOT);

							if ($included === FALSE) {

								$this->error(13, 54, $return);

							} else {

								$this->masktree = $this->masktree_merge($this->masktree, $included, $maskvalue);

							}

						}

						break;



					// insert element

					case _ETS_INSERT:

						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);

						$return = NULL;

						@eval('$return=(string)(' . $container . ');');

						if (isset($return)) {

							$inserted = $this->read_container($return, _ETS_TEXT);

							if ($inserted === FALSE) {

								$this->error(12, 55, $return);

							} else {

								$built[] = $inserted;

							}

						}

						break;



					// eval and safe elements

					case _ETS_EVAL:

					case _ETS_SAFE:

						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);

						$return = NULL;

						@eval('$return=(string)(' . $container . ');');

						if (isset($return)) {

							$evaluated = $this->read_container($return, _ETS_ROOT_EVAL);

							if ($evaluated === FALSE) {

								$this->error(14, 56, $return);

							} else {

								$built[] = $this->build_mask($datatree, $evaluated, $direction, $cindex, $clast, $ckey, $incode, $carray, $masktype == _ETS_SAFE);

							}

						}

						break;



					// other types of element

					default:



						// retrieve datatype and direction and define parent property if necessary

						$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, $safemode);



						switch ($masktype) {



							// simple tag element

							case _ETS_TAG:

								if ($datatype == _ETS_SCALAR && isset($this->masktree[$maskname])) {

									$built[] = $this->build_mask($datatree, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);



								} elseif ($datatype == _ETS_SCALAR) {

									if ($incode) {

										if ($currentdata === TRUE) {

											$built[] = 'TRUE';

										} elseif ($currentdata === FALSE) {

											$built[] = 'FALSE';

										} elseif (is_string($currentdata)) {

											$built[] = '"' . addcslashes($currentdata, "\0..\31\"") . '"';

										} else {

											$built[] = $currentdata;

										}



									} else {

										$built[] = $this->protect_spaces($currentdata);

									}



								} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$maskname])) {

									$built[] = $this->build_mask($currentdata, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);



								} elseif ($datatype == _ETS_MISSING && $incode) {

									$built[] = 'NULL';

								}

								break;



							// alternate tag element

							case _ETS_ALT_TAG:

								$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);

								$return = NULL;

								@eval('$return=(string)(' . $template . ');');

								if (isset($return)) {

									if ($datatype == _ETS_SCALAR && isset($this->masktree[$return])) {

										$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);



									} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$return])) {

										$built[] = $this->build_mask($currentdata, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);



									} elseif ($datatype == _ETS_SCALAR) {

										$built[] = $currentdata;

									}

								}

								break;



							// template element

							case _ETS_TEMPLATE:

								if ($datatype == _ETS_SCALAR) {

									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);



								} elseif ($datatype == _ETS_COMPLEX) {

									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);



								} elseif ($datatype == _ETS_MISSING && $incode) {

									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);

								}

								break;



							// if element

							case _ETS_IF:

								$test = $this->build_mask($datatree, $child['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);

								$return = NULL;

								@eval('$return=(bool)(' . $test . ');');

								if ($return === TRUE) {

									$built[] = $this->build_mask($datatree, $child['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);

								}

								break;



							// repeat element

							case _ETS_REPEAT:

								$loop = $this->build_mask($datatree, $child['loops'], $direction, $cindex, $clast, $ckey, TRUE, $carray);

								$return = NULL;

								@eval('$return=(int)(' . $loop . ');');

								for ($i = 0; $i < $return; ++$i) {

									if (is_object($datatree)) {

										$datatree->_count = $i + 1;

									}

									$built[] = $this->build_mask($datatree, $child['repeated'], $direction, $cindex, $clast, $ckey, $incode, $carray);

								}

								break;



							// choose element

							case _ETS_CHOOSE:

								$notfound = TRUE;

								if (isset($child['when'])) {

									foreach ($child['when'] as $grandchild)  {

										$test = $this->build_mask($datatree, $grandchild['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);

										$return = NULL;

										@eval('$return=(bool)(' . $test . ');');

										if ($return === TRUE) {

											$notfound = FALSE;

											$built[] = $this->build_mask($datatree, $grandchild['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);

											break;

										}

									}

								}

								if ($notfound && isset($child['else'])) {

									$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);

								}

								break;



							// choose variable element

							case _ETS_CHOOSEVAR:

								if ($datatype == _ETS_SCALAR) {

									$notfound = TRUE;

									if (isset($child['when'])) {

										foreach ($child['when'] as $gcmaskinfo => $grandchild)  {

											list($gcmasktype, $gcmaskname, $gcmaskvalue) = $this->parse_info($gcmaskinfo);

											if ($currentdata == $gcmaskvalue) {

												$built[] = $this->build_mask($datatree, $grandchild, $direction, $cindex, $clast, $ckey, $incode, $carray);

												$notfound = FALSE;

											}

										}

									}

									if ($notfound && isset($child['else'])) {

										$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);

									}

								}

								break;



							// set element

							case _ETS_SET:

								if ($datatype != _ETS_MISSING) {

									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);

								}

								break;



							// mis element

							case _ETS_MIS:

								if ($datatype == _ETS_MISSING) {

									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);

								}

								break;



							// set val element

							case _ETS_SETVAL:

								if ($datatype == _ETS_SCALAR) {

									if ($currentdata == $maskvalue) {

										$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);

									}

								}

								break;



							// mis val element

							case _ETS_MISVAL:

								if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {

									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);

								}

								break;



							// mis mask element

							case _ETS_MIS_TEMPLATE:

								if ($datatype == _ETS_MISSING || $datatype == _ETS_COMPLEX) {

									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);

								}

								break;

						}

						break;

				}

			}

		}



		// done

		return implode('', $built);

	}





	/*****   I N T E R F A C E   *****/



    /**

     * Build the result

     */

	function build_all($datatree, $entry)

	{

		// No entry: stop

		if (!isset($this->masktree[$entry])) {

			$this->error(8, 57, $entry);

		}



		// Data tree



		$this->datatree = $datatree;



		if (is_array($this->datatree)) {

			$this->datatree['_parent'] = NULL;



		} elseif (is_object($this->datatree)) {

			$this->datatree->_parent = NULL;



		} elseif (isset($this->datatree)) {

			$this->error(9, 58);

			$this->datatree = NULL;

		}



		// Build

		$built = $this->build_mask($this->datatree, $this->masktree[$entry]);



		// Reduce and return



		if (!isset($this->masktree['0reduce'])) {

			$this->masktree['0reduce'] = _ETS_REDUCE_OFF;

		}



		switch ($this->masktree['0reduce']) {

			case _ETS_REDUCE_OFF:

				break;

			case _ETS_REDUCE_SPACES:

				$built = preg_replace('/(\r\n|\r|\n)+/sm', "\n", preg_replace('/[ \t]*?(\r\n|\r|\n)+[\t ]*/sm', "\n", $built));

				break;

			case _ETS_REDUCE_ALL:

				$built = preg_replace('/[ \t]*?(\r\n|\r|\n)+[\t ]*/sm', '', $built);

				break;

		}



		$built = str_replace("\1n\1", "\n", $built);

		$built = str_replace("\1r\1", "\r", $built);

		$built = str_replace("\1t\1", "\t", $built);

		$built = str_replace("\1s\1", " ",  $built);



		return $built;

	}



    /**

     * Contructor: create the template tree

     */

	function _ets($containers, $hsr, $hcr, $hcw)

	{

		$this->source_read_name = $hsr;

		$this->cache_read_name  = $hcr;

		$this->cache_write_name = $hcw;



		$this->external_source_read = function_exists($hsr);

		$this->external_cache_read  = function_exists($hcr);

		$this->external_cache_write = function_exists($hcw);



		if (is_array($containers) || is_string($containers)) {

			$this->parse_containers($containers);

		} else {

			$this->error(10, 59);

		}

	}

}



/**

 * Source read handler for template string

 */

function _printts($id)

{

	return $id;

}



/**

 * Return a built template

 */

function sprintt($datatree, $containers, $entry = 'main', $hsr = _ETS_SOURCE_READ, $hcr = _ETS_CACHE_READ, $hcw = _ETS_CACHE_WRITE)

{

	$ets = new _ets($containers, $hsr, $hcr, $hcw);

	return $ets->build_all($datatree, $entry);

}



/**

 * Print out a built template

 */

function printt($datatree, $containers, $entry = 'main', $hsr = _ETS_SOURCE_READ, $hcr = _ETS_CACHE_READ, $hcw = _ETS_CACHE_WRITE)

{

	$ets = new _ets($containers, $hsr, $hcr, $hcw);

	echo $ets->build_all($datatree, $entry);

}



/**

 * Return the same value than missing element in PHP code

 */

function mis($value)

{

	return is_null($value) || $value === '' || $value === FALSE || !is_scalar($value);

}



/**

 * Return the same value than set element in PHP code

 */

function set($value)

{

	return !mis($value);

}



/**

 * Return a built template string

 */

function sprintts($datatree, $containers, $entry = 'main')

{

	return sprintt($datatree, $containers, $entry, _ETS_STRING_READ, '', '');

}



/**

 * Print out a built template string

 */

function printts($datatree, $containers, $entry = 'main')

{

	printt($datatree, $containers, $entry, _ETS_STRING_READ, '', '');

}



?>

ACC SHELL 2018