/** <code>{% for %}</code> tag. */
  public function handleTFor(TemplateCompilerEx $compiler, TemplateNodeEx $node, &$tag, array &$args)
  {
      if (count($args) == 3) {
          // {% for value in iterable %}
          $valueVariable =& $args[0];
          $keyVariable = null;
          $inConstant =& $args[1];
          $iterableVariable =& $args[2];
      } elseif (count($args) == 4) {
          // {% for value in iterable %}
          $valueVariable =& $args[1];
          $keyVariable =& $args[0];
          $compiler->raiseIf(mb_substr($keyVariable, -1, 1) != ',', $node, 'Key variable definition invalid - it should end with a comma', TemplateError::E_INVALID_ARGUMENT);
          $keyVariable = mb_substr($keyVariable, 0, -1);
          $inConstant =& $args[2];
          $iterableVariable =& $args[3];
      } else {
          $compiler->raise($node, 'Invalid argument count - either 3 or 4 are required', TemplateError::E_INVALID_ARGUMENT);
      }
      $compiler->raiseIf($inConstant != 'in', $node, 'Invalid argument given - expected "in", found "' . $inConstant . '"', TemplateError::E_INVALID_ARGUMENT);
      // to avoid loop's block name collisions, and long function names at the same time
      $loopBlockName = $compiler->generateUniqueBlock($keyVariable . $valueVariable . $iterableVariable, 'loop:');
      list($iterable, $filters) = TemplateUtils::split('|', $iterableVariable);
      list($iterable, $iterCheck) = $compiler->parseVariableExpression($node, $iterable);
      if (!isset($compiler->varInLoop)) {
          $compiler->varInLoop = array();
      }
      $loopCall = sprintf('$b.=$this->_' . TemplateUtils::sanitize($loopBlockName) . '($e%s);', $compiler->varInLoop ? ',$f' : '');
      // body of the loop
      list($loopBodyNodes, $emptyNodes) = $compiler->findAlternativeBranch($node, 'empty');
      $compiler->varInLoop[] = $loopBlockName;
      $loopBody = $compiler->handleChildren($loopBodyNodes);
      array_pop($compiler->varInLoop);
      // and loop itself
      //
      // $k              = value of the key
      // $v              = value of the value
      // $kn             = name of context variable holding key
      // $vn             = name of context variable holding value
      // $ic             = item count in iterable
      // $iv             = iterable
      // $f              = name of the forloop variable
      // $this->ctx[$kn] = reference to $k
      // $this->ctx[$vn] = reference to $v
      // $cf             = reference to $this->ctx[$f]
      // sanity check
      $loopCheckCode = 'if(!is_array($iv)&&!(is_object($iv)&&' . 'TemplateUtils::doesImplement($iv,\'Traversable\')&&' . 'TemplateUtils::doesImplement($iv,\'Countable\'))){' . '$this->invalidVar(\'' . TemplateUtils::escape($iterableVariable) . '\',\'iterable expected\');}';
      $loopCode = $iterCheck . '$iv=' . $compiler->parseFilterChain($node, $filters, '@' . $iterable) . ';' . '$f=\'forloop:' . TemplateUtils::escape($loopBlockName) . '\';' . $loopCheckCode;
      if ($keyVariable) {
          $loopCode .= TemplateUtils::strip('
  $k  = null;
  $kn = \'' . TemplateUtils::escape($keyVariable) . '\';
  $this->ctx[$kn] = &$k;
 ');
      }
      $loopCode .= sprintf(TemplateUtils::strip('
 $v  = null;
 $vn = \'' . TemplateUtils::escape($valueVariable) . '\';
 $this->ctx[$vn] = &$v;
 $ic = count($iv);
 
 $this->ctx[$f] = array(
  \'counter\'     => 1,
  \'counter0\'    => 0,
  \'revcounter\'  => $ic,
  \'revcounter0\' => $ic - 1,
  \'first\'       => true,
  \'last\'        => ($ic - 1) == 0
 );
 
 $cf = &$this->ctx[$f];
 
 if (func_num_args() == 2) {
  $cf[\'parentloop\'] = &$this->ctx[func_get_arg(1)];
 }
 
 %s
 
 %s {
  %s
  ++$cf[\'counter\'];
  ++$cf[\'counter0\'];
  --$cf[\'revcounter\'];
  --$cf[\'revcounter0\'];
  $cf[\'first\'] = false;
  $cf[\'last\']  = ($cf[\'revcounter0\'] == 0);
 }
 '), $emptyNodes ? 'if($ic==0){$b=\'\';' . $compiler->handleChildren($emptyNodes) . 'return $b;}' : '', 'foreach($iv as ' . ($keyVariable ? '$k=>' : '') . '$v)', $loopBody);
      $compiler->blocks[$loopBlockName] = '$b=\'\';' . $loopCode . 'return $b;';
      return $loopCall;
  }
 /**
  Runs handlers associated with given hook-point.
  Every handler might return @c true boolean value,
  to break the chain and finish hook execution.
  
  @param[in] $hookPoint Hook-point to execute
  @param[in] $args Array of hook arguments
  @retval true Some handler has broken the chain
  @retval false All handlers have been executed, and none has broken the chain
 */
 private function runHooks($hookPoint, array $args)
 {
     array_unshift($args, $this);
     $handlers = $this->plugins->get('hook', $hookPoint);
     foreach ($handlers as &$hookInfo) {
         $handler =& $hookInfo['handler'];
         if (!is_callable($handler)) {
             throw new TemplateError('Invalid handler [' . TemplateUtils::strip(var_export($hookInfo['handler'], true)) . '] hooked into "' . $hookPoint . '" point by plugin "' . $hookInfo['plugin'] . '"', TemplateError::E_INVALID_HANDLER);
         }
         if (call_user_func_array($handler, $args) === true) {
             return true;
         }
     }
     return false;
 }
 /**
  Tests the behaviour of @ref TemplateUtils::strip.
 */
 public function testUtilsStrip()
 {
     $this->assertEquals('abcdef', TemplateUtils::strip("abc\ndef"));
 }