<?php
define ( 'DIRECTORY_SEPARATOR_WIN', "\\" );
define ( 'DIRECTORY_SEPARATOR_UNIX', "/" );

define ( 'SIZE_KB', 1024 );
define ( 'SIZE_MB', 1024 * SIZE_KB );
define ( 'SIZE_GB', 1024 * SIZE_MB );

define ( 'TIME_SECOND', 1 );
define ( 'TIME_MINUTE', 60 * TIME_SECOND );
define ( 'TIME_HOUR', 60 * TIME_MINUTE );
define ( 'TIME_DAY', 24 * TIME_HOUR );
define ( 'TIME_WEEK', 7 * TIME_DAY );
define ( 'TIME_MONTH', 30 * TIME_DAY );

define ( 'USLEEP_SECOND', 1000000.0 );

function date_interval_to_parsable_string(DateInterval $diff)
{
  $status = "";
  
  if ($diff->y != 0)
    $status .= ' ' . $diff->format ( '%y years' );
  
  if ($diff->m != 0)
    $status .= ' ' . $diff->format ( '%m months' );
  
  if ($diff->d != 0)
    $status .= ' ' . $diff->format ( '%d days' );
  
  if ($diff->h != 0)
    $status .= ' ' . $diff->format ( '%h hours' );
  
  if ($diff->i != 0)
    $status .= ' ' . $diff->format ( '%i minutes' );
  
  if ($diff->s != 0)
    $status .= ' ' . $diff->format ( '%s seconds' );
  
  return trim ( $status );
}

function get_time_limit()
{
  return intval ( ini_get ( 'max_execution_time' ) );
}

function set_time_limit_max($seconds)
{
  $new = intval ( $seconds );
  $current = get_time_limit ();
  
  if ($current == 0)
    return false;
  
  if ($current < $new || $new == 0)
  {
    set_time_limit ( $new );
    return true;
  }
  else
  {
    return false;
  }
}

function date_interval_compare(DateInterval $a, DateInterval $b)
{
  foreach ( $a as $key => $value )
  {
    // after seconds 's' comes 'invert' and other crap we do not care about
    // and it means that the date intervals are the same
    if ($key == 'invert')
    {
      return 0;
    }
    
    // when the values are the same we can move on
    if ($a->$key == $b->$key)
    {
      continue;
    }
    
    // finally a level where we see a difference, return accordingly
    if ($a->$key < $b->$key)
    {
      return - 1;
    }
    else
    {
      return 1;
    }
  }
}

/**
 * check if we can connect to a remote server
 *
 * @param string $host
 *          default=hq.kria.biz
 * @param number $port
 *          default=443
 * @param number $timeout
 *          default=2 The connection timeout, in seconds.
 * @return boolean
 *
 */
function check_internet_connection($host = "hq.kria.biz", $port = 443, $timeout = 2)
{
  if ($host == null)
    $host = "hq.kria.biz";
  if ($port == null)
    $port = 443;
  if ($timeout == null)
    $timeout = 2;
  
  $connected = @fsockopen ( $host, $port, $errno, $errstr, $timeout );
  // website, port (try 80 or 443)
  if ($connected)
  {
    $is_conn = true;
    fclose ( $connected );
  }
  else
    $is_conn = false;
  return $is_conn;
}

function array_trim_and_nonEmptyEntries(array $array)
{
  array_trim ( $array );
  return array_nonEmptyEntries ( $array );
}

function array_trim(array &$array)
{
  foreach ( $array as $key => $value )
    $array [$key] = trim ( $value );
}

function array_nonEmptyEntries(array $array)
{
  $filled = array ();
  foreach ( $array as $key => $value )
    if (! isEmpty ( $value ))
      $filled [$key] = $value;
  return $filled;
}

function strIsPunct($str)
{
  foreach ( str_split ( $str ) as $char )
    if (! ctype_punct ( $char ))
      return false;
  return true;
}

function can_be_string($item)
{
  return ((! is_array ( $item )) && ((! is_object ( $item ) && settype ( $item, 'string' ) !== false) || (is_object ( $item ) && method_exists ( $item, '__toString' ))));
}

function isEmptyOrWhitespace($var)
{
  if (isEmpty ( $var ))
    return true;
  $var = trim ( "$var" );
  if (isEmpty ( $var ))
    return true;
  return false;
}

/**
 *
 * @param array $items          
 * @return array $rows
 */
function query_export_by_pk(array $items)
{
  $data = array ();
  foreach ( $items as $table => $pks )
  {
    foreach ( $pks as $pk )
    {
      $whereConditions = array ();
      $whereParams = array ();
      foreach ( $pk as $column => $value )
      {
        $cid = ":cond_" . uniqid ();
        $whereConditions [$cid] = "$column=$cid";
        $whereParams [$cid] = $value;
      }
      $where = "";
      if (count ( $whereConditions ) > 0)
      {
        $where = "WHERE " . implode ( " AND ", $whereConditions );
      }
      $rows = query ( "SELECT * FROM $table $where", $whereParams, false, false );
      $tableRows = array_get ( $data, $table, array () );
      foreach ( $rows as $row )
        $tableRows [] = $row;
      $data [$table] = $tableRows;
    }
  }
  return $data;
}

/**
 * executes a function in a separate output buffer environment
 *
 * @param function $func
 *          function([$args])
 * @param mixed $args
 *          default=null
 * @return string
 */
function ob_do($func, $args = null)
{
  ob_start ();
  $func ( $args );
  return ob_get_clean ();
}

/**
 *
 * @param mixed $a          
 * @param mixed $b          
 * @param boolean $strict          
 * @return boolean
 */
function equals($a, $b, $strict)
{
  if ($strict)
  {
    if ($a === $b)
      return true;
  }
  else
  {
    if ($a == $b)
      return true;
  }
  return false;
}

function var_dump_ret($var)
{
  return ob_do ( function ($var)
  {
    var_dump ( $var );
  }, $var );
}

function var_dump_html($var, $export = true)
{
  echo ("<pre>");
  if ($export)
    var_export ( $var );
  else
    var_dump ( $var );
  echo ("</pre>");
}

/**
 *
 * @param array $values          
 * @return int[]
 */
function to_int_array(array $values)
{
  $ints = array ();
  if (is_array_ex ( $values ))
    foreach ( $values as $value )
      $ints [] = intval ( $value );
  return $ints;
}

function basename_wo_ext($filename)
{
  $filename = basename ( $filename );
  $index = strrpos ( $filename, "." );
  if ($index !== false)
    $filename = substr ( $filename, 0, $index );
  return $filename;
}

/**
 *
 * @return Controller
 */
function ctrl()
{
  return app ()->controller;
}

/**
 *
 * @return KriaWebApplication
 */
function app()
{
  return Yii::app ();
}

/**
 *
 * @return AuthWebUser
 */
function user()
{
  if (method_exists ( app (), 'getUser' ))
    return app ()->getUser ();
  
  return null;
}

/**
 *
 * @return CClientScript
 */
function script()
{
  return app ()->clientScript;
}

/**
 *
 * @return CAssetManager
 */
function assetmgr()
{
  return app ()->assetManager;
}

/**
 *
 * @return HttpRequest
 */
function request()
{
  return app ()->getRequest ();
}

/**
 *
 * @return CDbHttpSession
 */
function session()
{
  return app ()->getSession ();
}

/**
 * get the config array root or subpath
 *
 * @param
 *          ...
 * @return mixed
 */
function config()
{
  $queue = new CQueue ( func_get_args () );
  $env = new Environment ();
  $obj = $env->getConfig ();
  while ( $queue->count () > 0 )
    $obj = $obj [$queue->dequeue ()];
  return $obj;
}

/**
 *
 * @param
 *          ...
 * @return mixed
 */
function configWeb()
{
  $queue = new CQueue ( func_get_args () );
  $env = new Environment ();
  $obj = $env->getConfig ();
  $obj = $obj ['configWeb'];
  while ( $queue->count () > 0 )
    $obj = $obj [$queue->dequeue ()];
  return $obj;
}

function isLink($string)
{
  return containsStr ( $string, "://", false );
}

function filesize_http($filename)
{
  $remoteFile = $filename;
  $ch = curl_init ( $remoteFile );
  curl_setopt ( $ch, CURLOPT_NOBODY, true );
  curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
  curl_setopt ( $ch, CURLOPT_HEADER, true );
  curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, true ); // not necessary unless the file redirects (like the PHP example we're using here)
  $data = curl_exec ( $ch );
  curl_close ( $ch );
  if ($data === false)
    return false;
  
  $contentLength = null;
  /*
   * $status = 'unknown';
   * if (preg_match('/^HTTP\/1\.[01] (\d\d\d)/', $data, $matches))
   * {
   * $status = (int)$matches[1];
   * }
   */
  if (preg_match ( '/Content-Length: (\d+)/', $data, $matches ))
  {
    $contentLength = ( int ) $matches [1];
  }
  
  if ($contentLength === null)
    return false;
  
  return intval ( $contentLength );
}

/**
 * write a file (full or partial) to the output steam, also using HTTP_RANGEs
 *
 * @param string $file          
 * @param string $mime
 *          could be any valid mime type... 'video/mp4' ... (default='application/octet-stream')
 * @param boolean $useRanges
 *          tells if the ranges (default=true)
 * @param boolean $exit
 *          tells if the exit function must be called at the end (default=true)
 */
function get_file_stream($file, $mime = 'application/octet-stream', $useRanges = true, $exit = true)
{
  if ($useRanges)
    $range = isset ( $_SERVER ['HTTP_RANGE'] ) ? $_SERVER ['HTTP_RANGE'] : null;
  else
    $range = null;
  
  $fp = @fopen ( $file, 'rb' );
  
  $size = startsWithAny ( $file, array (
      "http://",
      "https://" 
  ), false ) ? filesize_http ( $file ) : filesize ( $file ); // File size
  $length = $size; // Content length
  $start = 0; // Start byte
  $end = $size - 1; // End byte
  
  $filename = basename ( $file );
  
  header ( 'Content-Disposition: attachment; filename="' . $filename . '"' );
  header ( "Content-type: $mime" );
  if ($useRanges)
    header ( "Accept-Ranges: 0-$length" );
  
  if (! empty ( $range ))
  {
    
    $c_start = $start;
    $c_end = $end;
    
    list ( , $range ) = explode ( '=', $range, 2 );
    if (strpos ( $range, ',' ) !== false)
    {
      header ( 'HTTP/1.1 416 Requested Range Not Satisfiable' );
      header ( "Content-Range: bytes $start-$end/$size" );
      if ($exit)
        exit ();
    }
    if ($range == '-')
    {
      $c_start = $size - substr ( $range, 1 );
    }
    else
    {
      $range = explode ( '-', $range );
      $c_start = $range [0];
      $c_end = (isset ( $range [1] ) && is_numeric ( $range [1] )) ? $range [1] : $size;
    }
    $c_end = ($c_end > $end) ? $end : $c_end;
    if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size)
    {
      header ( 'HTTP/1.1 416 Requested Range Not Satisfiable' );
      header ( "Content-Range: bytes $start-$end/$size" );
      if ($exit)
        exit ();
    }
    $start = $c_start;
    $end = $c_end;
    $length = $end - $start + 1;
    fseek ( $fp, $start );
    header ( 'HTTP/1.1 206 Partial Content' );
  }
  
  if ($useRanges)
    header ( "Content-Range: bytes $start-$end/$size" );
  
  header ( "Content-Length: " . $length );
  
  $buffer = 1024 * 8;
  while ( ! feof ( $fp ) && ($p = ftell ( $fp )) <= $end )
  {
    
    if ($p + $buffer > $end)
    {
      $buffer = $end - $p + 1;
    }
    set_time_limit ( 0 );
    echo fread ( $fp, $buffer );
    flush ();
  }
  
  fclose ( $fp );
  if ($exit)
    exit ();
}

/**
 *
 * @param string $haystack
 *          the string to search in
 * @param array $needles
 *          the array to search
 * @param boolean $caseSensitive
 *          default=true
 * @return boolean
 */
function startsWithAny($haystack, $needles, $caseSensitive = true)
{
  if (! is_array ( $needles ))
    $needles = array (
        $needles 
    );
  foreach ( $needles as $needle )
  {
    if (startsWith ( $haystack, $needle, $caseSensitive ))
    {
      return true;
    }
  }
  return false;
}

/**
 * converts an array of objects to a matrix
 *
 * @param array $array
 *          of objects
 * @param func|string|array $converter
 *          function(obj) => array row - or - array of fields to take - or - string of function to call that gives an array back
 * @return arrayOfArray
 */
function array_to_matrix($array, $converter)
{
  $matrix = array ();
  foreach ( $array as $item )
  {
    $row = null;
    if (is_string ( $converter ))
    {
      $row = $item->$converter ();
    }
    elseif (is_array ( $converter ))
    {
      $row = array ();
      foreach ( $converter as $field )
        $row [] = $item->$field;
    }
    elseif (is_callable ( $converter ))
    {
      $row = $converter ( $item );
    }
    if ($row != null)
      $matrix [] = $row;
  }
  return $matrix;
}

function get_first_not_empty()
{
  foreach ( func_get_args () as $var )
    if (! isEmpty ( $var ))
      return $var;
  return null;
}

/**
 *
 * @param string $filter          
 * @param bool $recursive          
 * @param bool $findFiles          
 * @param bool $findDirs          
 * @return string[]
 */
function findInPath($filter, $recursive, $findFiles, $findDirs)
{
  $paths = explode ( ";", getenv ( "PATH" ) );
  return getFilesOrDirs ( $paths, $filter, $recursive, $findFiles, $findDirs );
}

/**
 *
 * @param string $string          
 * @param number $length          
 * @param string $dots          
 * @return string
 */
function truncate($string, $length, $dots = "...")
{
  return (strlen ( $string ) > $length) ? substr ( $string, 0, $length - strlen ( $dots ) ) . $dots : $string;
}

/**
 *
 * @param array $sections          
 * @param string $filename          
 * @return boolean
 */
function ini_file_from_array(array $sections, $filename)
{
  $data = ini_string_from_array ( $sections );
  return file_rewrite_safe ( $filename, $data );
}

/**
 *
 * @param array $sections          
 * @return string
 */
function ini_string_from_array(array $sections)
{
  $lines = array ();
  foreach ( $sections as $section => $values )
  {
    $lines [] = "[$section]";
    foreach ( $values as $key => $value )
    {
      if (is_array ( $value ))
        foreach ( $value as $v )
          $lines [] = "$key=$v";
      else
        $lines [] = "$key=$value";
    }
  }
  return implode ( PHP_EOL, $lines );
}

/**
 *
 * @param string $filename          
 * @return array
 */
function ini_file_to_array($filename)
{
  if (fileExists ( $filename ))
    return ini_string_to_array ( file_get_contents ( $filename ) );
  return array ();
}

/**
 *
 * @param string $data          
 * @return array
 */
function ini_string_to_array($data)
{
  $lines = explode ( PHP_EOL, $data );
  $ini = array ();
  $currentSection = null;
  foreach ( $lines as $line )
  {
    $line = trim ( $line );
    if (! isEmpty ( $line ) && ! startsWith ( $line, ";" ))
    {
      if (startsWith ( $line, "[" ) && endsWith ( $line, "]" ))
      {
        $currentSection = startsWithGet ( $line, "[" );
        $currentSection = endsWithGet ( $currentSection, "]" );
      }
      else
      {
        if (! isEmpty ( $currentSection ))
        {
          if (! isset ( $ini [$currentSection] ))
            $ini [$currentSection] = array ();
          $section = $ini [$currentSection];
          
          $eqPos = strpos ( $line, "=" );
          
          $key = null;
          $value = null;
          
          if ($eqPos !== false)
          {
            $key = trim ( substr ( $line, 0, $eqPos ) );
            $value = trim ( substr ( $line, $eqPos + 1 ) );
          }
          else
          {
            $key = $line;
          }
          
          if (! isset ( $section [$key] ))
            $section [$key] = $value;
          else
          {
            $values = $section [$key];
            if (! is_array ( $values ))
              $values = array (
                  $values 
              );
            $values [] = $value;
            $section [$key] = $values;
          }
          
          $ini [$currentSection] = $section;
        }
      }
    }
  }
  return $ini;
}

/**
 * safely write a file
 *
 * @param string $fileName          
 * @param string $dataToSave          
 * @param number $delay
 *          default 1000
 * @param boolean $append
 *          default = false
 * @return boolean
 */
function file_rewrite_safe($fileName, $dataToSave, $delay = 1000, $append = false)
{
  $done = false;
  if ($fp = fopen ( $fileName, $append ? 'a' : 'w' ))
  {
    $startTime = microtime ();
    do
    {
      $canWrite = flock ( $fp, LOCK_EX );
      // If lock not obtained sleep for 0 - 100 milliseconds, to avoid collision and CPU load
      if (! $canWrite)
        usleep ( round ( rand ( 0, 100 ) * 1000 ) );
    }
    while ( (! $canWrite) and ((microtime () - $startTime) < $delay) );
    
    // file was locked so now we can store information
    if ($canWrite)
    {
      fwrite ( $fp, $dataToSave );
      $done = true;
      flock ( $fp, LOCK_UN );
    }
    fclose ( $fp );
  }
  return $done;
}

function fn_to_string($fn, $strip_comments = true)
{
  static $contents_cache = array ();
  static $nl = "\r\n"; // change this to how you want
  
  if (! is_callable ( $fn ))
    return ''; // it should be a function
  if (! class_exists ( 'ReflectionFunction' ))
    return ''; // PHP 5.1 I think
                 
  // get function info
  $rfn = new ReflectionFunction ( $fn );
  $file = $rfn->getFileName ();
  $start = $rfn->getStartLine ();
  $end = $rfn->getEndLine ();
  
  if (! is_readable ( $file ))
    return ''; // file should be readable
                 
  // cache file contents for subsequent reads (in case we use multiple fns defined in the same file)
  $md5 = md5 ( $file );
  if (! isset ( $contents_cache [$md5] ))
    $contents_cache [$md5] = file ( $file, FILE_IGNORE_NEW_LINES );
  
  if (empty ( $contents_cache [$md5] ))
    return ''; // there should be stuff in the file
  $file = $contents_cache [$md5];
  
  // get function code and tokens
  $code = "<?php " . implode ( $nl, array_slice ( $file, $start - 1, ($end + 1) - $start ) );
  $tokens = token_get_all ( $code );
  
  // now let's parse the code;
  $code = '';
  $function_count = 0;
  $ignore_input = false; // we use this to get rid of "use" or function name
  $got_header = false;
  $in_function = false;
  $braces_level = 0;
  foreach ( $tokens as $token )
  {
    
    // get the token name or string
    if (is_string ( $token ))
    {
      $token_name = $token;
    }
    elseif (is_array ( $token ) && isset ( $token [0] ))
    {
      $token_name = token_name ( $token [0] );
      $token = isset ( $token [1] ) ? $token [1] : "";
    }
    else
    {
      continue;
    }
    
    // strip comments
    if (1 && $strip_comments && ($token_name == "T_COMMENT" || $token_name == "T_DOC_COMMENT" || $token_name == "T_ML_COMMENT"))
    {
      // but put back the new line
      if (substr ( $token, - 1 ) == "\n")
        $code .= $nl;
      continue;
    }
    
    // let's decide what to do with it now
    if ($in_function)
    {
      
      // nesting level
      if ($token_name == "{")
      {
        $braces_level ++;
        
        // done ignoring `use`
        $ignore_input = false;
      }
      
      // append
      if (1 && $function_count == 1 && (0 || 
      // skip function names
      ($ignore_input && $token_name == "(" && ! $got_header && (! ($ignore_input = false))) || 
      
      // skip function () use (...) in closures functions
      ($braces_level == 0 && ! $got_header && $token_name == ")" && ($ignore_input = true) && ($got_header = true)) || 
      
      // this fall-through is intentional
      ! $ignore_input))
      {
        $code .= $token;
      }
      
      // ending "}"
      if ($token_name == "}")
      {
        $braces_level --;
        
        // done collecting the function
        if ($braces_level == 0)
          $in_function = false;
      }
    }
    elseif ($token_name == "T_FUNCTION")
    {
      $function_count ++;
      $in_function = true;
      $ignore_input = true;
      $braces_level = 0;
      $code .= $token;
      
      // we can't detect this properly so bail out
      if ($function_count > 1)
      {
        $code = '';
        break;
      }
    }
  }
  
  return $code;
}

function call_func($funcName, $params = array(), $default = null)
{
  if (function_exists ( $funcName ))
    return call_user_func_array ( $funcName, $params );
  return $default;
}

function file_append($filename, $data, $reset = false)
{
  return file_put_contents ( $filename, $data, $reset ? 0 : FILE_APPEND ) !== false;
}

function file_append_line($filename, $data, $reset = false)
{
  return file_append ( $filename, $data . PHP_EOL, $reset );
}

/**
 * se $text comincia con $substr restituisce ciò che viene dopo (senza $substr), altrimenti $default
 *
 * @param string $text          
 * @param string $substr          
 * @param boolean $caseSensitive
 *          default=false
 * @param number $offset
 *          default=0
 * @param string $default
 *          default=null
 * @return NULL|string
 */
function startsWithGet($text, $substr, $caseSensitive = false, $offset = 0, $default = null)
{
  $strpos = $caseSensitive ? strpos : stripos;
  $pos = $strpos ( $text, $substr, $offset );
  if ($pos === false)
    return $default;
  return substr ( $text, $pos + strlen ( $substr ) );
}

/**
 * se $text finisce con $substr restituisce ciò che viene prima (senza $substr), altrimenti $default
 *
 * @param string $text          
 * @param string $substr          
 * @param boolean $caseSensitive
 *          default=false
 * @param number $offset
 *          default=0
 * @param string $default
 *          default=null
 * @return NULL|string
 */
function endsWithGet($text, $substr, $caseSensitive = false, $offset = 0, $default = null)
{
  $strpos = $caseSensitive ? strpos : stripos;
  $pos = $strpos ( $text, $substr, $offset );
  if ($pos === false)
    return $default;
  return substr ( $text, 0, $pos );
}

function explode_ex($delimiters, $string)
{
  $ready = str_replace ( $delimiters, $delimiters [0], $string );
  $launch = explode ( $delimiters [0], $ready );
  return $launch;
}

function implode_ex($glue, array $data, $filterFunc = null, $editFunc = null)
{
  if ($filterFunc != null)
    $filterFunc = is_callable ( $filterFunc ) ? $filterFunc : create_function ( '$k,$v', "return ($filterFunc); " );
  if ($editFunc != null)
    $editFunc = is_callable ( $editFunc ) ? $editFunc : create_function ( '$k,$v', "return ($editFunc); " );
  
  if ($filterFunc != null || $editFunc != null)
  {
    $data2 = array ();
    foreach ( $data as $k => $v )
      if ($filterFunc == null || $filterFunc ( $k, $v ))
        $data2 [$k] = $editFunc == null ? $v : $editFunc ( $k, $v );
    $data = $data2;
  }
  
  return implode ( $glue, $data );
}

/**
 * concat recursively N arrays without preserving keys
 *
 * @return array
 */
function array_concat_spalm()
{
  $array = array ();
  foreach ( func_get_args () as $item )
  {
    if (! is_array ( $item ))
      $item = array (
          $item 
      );
    foreach ( $item as $subitem )
      $array = array_concat_spalm ( $array, $subitem );
  }
  return $array;
}

/**
 * concat N arrays without preserving keys
 *
 * @return array
 */
function array_concat()
{
  $array = array ();
  foreach ( func_get_args () as $item )
  {
    if (! is_array ( $item ))
      $item = array (
          $item 
      );
    foreach ( $item as $subitem )
      $array [] = $subitem;
  }
  return $array;
}

/**
 * concat N arrays preserving keys
 *
 * @return array
 */
function array_concat_preserve_keys()
{
  $array = array ();
  foreach ( func_get_args () as $key => $item )
  {
    if (! is_array ( $item ))
      $item = array (
          $key => $item 
      );
    foreach ( $item as $subkey => $subitem )
      $array [$subkey] = $subitem;
  }
  return $array;
}

function tail($filename, $tailSize)
{
  $tailSize = intval ( $tailSize );
  if ($tailSize < 1)
    return false;
  $size = filesize ( $filename );
  if ($tailSize > $size)
    $tailSize = $size;
  $fp = fopen ( $filename, "r" );
  if ($fp === false)
    return false;
  fseek ( $fp, - $tailSize, SEEK_END );
  $data = fread ( $fp, $tailSize );
  fclose ( $fp );
  return $data;
}

/**
 *
 * @param string|array $paths          
 * @param string $filter          
 * @param string $recursive          
 * @return string[]
 */
function getFiles($paths, $filter = "*", $recursive = false)
{
  $files = array ();
  $filter = strtolower ( $filter );
  
  if (! is_array ( $paths ))
    $paths = array (
        $paths 
    );
  
  foreach ( $paths as $path )
  {
    try
    {
      $dir = new DirectoryIterator ( $path );
      foreach ( $dir as $dir )
      {
        if ($dir->isDot ())
          continue;
        if ($dir->isDir ())
        {
          if ($recursive)
          {
            $files = array_merge ( $files, getFiles ( $dir->getRealPath (), $filter, $recursive ) );
          }
        }
        else
        {
          if (fnmatch ( $filter, strtolower ( $dir->getFilename () ) ))
          {
            $files [] = $dir->getRealPath ();
          }
        }
      }
    }
    catch ( Exception $e )
    {
      // logObj($e->getMessage());
    }
  }
  
  return $files;
}

/**
 *
 * @param string|array $paths          
 * @param string $filter
 *          default "*"
 * @param bool $recursive
 *          default false
 * @param bool $findFiles
 *          default true
 * @param bool $findDirs
 *          default true
 * @return string[]
 */
function getFilesOrDirs($paths, $filter = "*", $recursive = false, $findFiles = true, $findDirs = true)
{
  $files = array ();
  $filter = strtolower ( $filter );
  
  if (! is_array ( $paths ))
    $paths = array (
        $paths 
    );
  
  foreach ( $paths as $path )
  {
    if (isEmpty ( $path ))
      continue;
    $dir = new DirectoryIterator ( $path );
    foreach ( $dir as $dir )
    {
      if ($dir->isDot ())
        continue;
      
      if (($findDirs && $dir->isDir ()) || ($findFiles && $dir->isFile ()))
        if (fnmatch ( $filter, strtolower ( $dir->getFilename () ) ))
        {
          $files [] = $dir->getRealPath ();
        }
      
      if ($dir->isDir ())
      {
        if ($recursive)
        {
          $files = array_merge ( $files, getFilesOrDirs ( $dir->getRealPath (), $filter, $recursive, $findFiles, $findDirs ) );
        }
      }
    }
  }
  
  return $files;
}

/**
 *
 * @param string $filename          
 * @return boolean
 */
function fileExists($filename)
{
  return ! isEmpty ( $filename ) && file_exists ( $filename ) && is_file ( $filename );
}

/**
 *
 * @param string $dirname          
 * @return boolean
 */
function dirExists($dirname)
{
  return ! isEmpty ( $dirname ) && file_exists ( $dirname ) && is_dir ( $dirname );
}

/**
 *
 * @param string $dir          
 * @return string
 */
function dirEnsureExists($dir)
{
  if (! dirExists ( $dir ))
    mkdir ( $dir, null, true );
  return realpath ( $dir );
}

/**
 *
 * @param string|array $paths          
 * @param string $filter          
 * @param string $recursive          
 * @return string[]
 */
function getDirectories($paths, $filter = "*", $recursive = false)
{
  $files = array ();
  $filter = strtolower ( $filter );
  
  if (! is_array ( $paths ))
    $paths = array (
        $paths 
    );
  
  foreach ( $paths as $path )
  {
    $dir = new DirectoryIterator ( $path );
    foreach ( $dir as $dir )
    {
      if ($dir->isDot () || ! $dir->isDir ())
        continue;
      
      if ($recursive)
      {
        $files = array_merge ( $files, getDirectories ( $dir->getRealPath (), $filter, $recursive ) );
      }
      if (fnmatch ( $filter, strtolower ( $dir->getFilename () ) ))
      {
        $files [] = $dir->getRealPath ();
      }
    }
  }
  
  return $files;
}

function getDbUser()
{
  return configWeb ( 'components', 'db', 'username' );
}

function getDbHost()
{
  $cs = app ()->db->connectionString; // 'mysql:host=192.168.2.201;dbname=eventserverdb'
  
  $hostPos = strpos ( $cs, "host=" );
  if ($hostPos === false)
    return null;
  $cs = substr ( $cs, $hostPos + 4 );
  
  $commaPos = strpos ( $cs, ";" );
  if ($commaPos === false)
    $commaPos = strlen ( $cs );
  else
    $commaPos -= 1;
  $cs = substr ( $cs, 1, $commaPos );
  
  return $cs;
}

function getDbName()
{
  $cs = app ()->db->connectionString; // 'mysql:host=192.168.2.201;dbname=eventserverdb' (string)
  
  $hostPos = strpos ( $cs, "dbname=" );
  if ($hostPos === false)
    return null;
  $cs = substr ( $cs, $hostPos + 6 );
  
  $commaPos = strpos ( $cs, ";" );
  if ($commaPos === false)
    $commaPos = strlen ( $cs );
  else
    $commaPos -= 1;
  $cs = substr ( $cs, 1, $commaPos );
  
  return $cs;
}

/**
 *
 * @param string $message          
 * @param string $context
 *          app login 401 actions(default=app)
 * @param boolean $logStackIfSet          
 * @param mixed $data          
 * @return boolean
 */
function security_log($message, $context = 'app', $logStackIfSet = true, $data = array())
{
  $ex = new DateTimeEx ();
  $security = new CArray ( paramdeep ( 'security' ) );
  if (! array_value_exists ( $security->logContext, $context ))
    return false;
  $logFile = $security->logFile;
  if (empty ( $logFile ))
    return false;
  
  $ipAddress = user ()->getIpAddress ( "UNKNOWN" );
  $logLine = "[$ex] - $ipAddress - $context - $message" . PHP_EOL;
  
  if ($security->logStack && $logStackIfSet)
  {
    $stack = debug_backtrace ();
    /*
     * foreach($stack as $frame)
     * {
     * $logLine .= " $frame[file] : $frame[line]".PHP_EOL;
     * $logLine .= " $frame[class] $frame[function]".PHP_EOL;
     * }
     */
    if (isset ( $stack [1] ))
    {
      $frame = $stack [1];
      $logLine .= "   FILE=$frame[file] LINE=$frame[line] CLASS=$frame[class] FUNC=$frame[function]" . PHP_EOL;
    }
    if (isset ( $stack [2] ))
    {
      $frame = $stack [2];
      $logLine .= "   FILE=$frame[file] LINE=$frame[line] CLASS=$frame[class] FUNC=$frame[function]" . PHP_EOL;
    }
  }
  if ($data != null && is_array ( $data ) && count ( $data ) > 0)
  {
    $logLine .= "   DATA:" . PHP_EOL;
    foreach ( $data as $dataKey => $dataValue )
      $logLine .= "        [$dataKey] " . _2str ( $dataValue ) . PHP_EOL;
  }
  
  $result = file_put_contents ( $logFile, $logLine, FILE_APPEND );
  return ($result !== false);
}

function ziptest($path)
{
  $zip = new ZipArchive ();
  $res = $zip->open ( $path, ZipArchive::CHECKCONS );
  if ($res === true)
    return "OK";
  
  $consts = getconst_namefromvalue ( "ZipArchive", $res );
  $consts = array_filter ( $consts, function ($x)
  {
    return startsWith ( $x, "ER_" );
  } );
  return implode ( ',', $consts );
}

function getconst_namefromvalue($obj, $value)
{
  $values = getconst_fromobj ( $obj );
  $results = array ();
  foreach ( $values as $k => $v )
    if ($value == $v)
      $results [] = $k;
  return $results;
}

function getconst_valuefromname($obj, $name)
{
  $values = getconst_fromobj ( $obj );
  foreach ( $values as $k => $v )
    if ($name == $k)
      return $v;
  return null;
}

function getconst_fromobj($obj)
{
  $class = new ReflectionClass ( $obj );
  return $class->getConstants ();
}

function zip_files($zipFilename, array $files, $relativePath = null, $getRelativePathFromFirstFile = false)
{
  $zip = new ZipArchive ();
  
  if ($zip->open ( $zipFilename, ZipArchive::CREATE ) !== TRUE)
    return - 1;
  
  if (! isEmpty ( $relativePath ) && dirExists ( $relativePath ))
    $relativePath = realpath ( $relativePath );
  else
    $relativePath = null;
  
  $zipped = 0;
  foreach ( $files as $f )
  {
    if (! isEmpty ( $f ) && fileExists ( $f ))
    {
      $f = realpath ( $f );
      $toBeZipped = $f;
      $fpath = realpath ( dirname ( $f ) );
      if ($relativePath == null && $getRelativePathFromFirstFile)
        $relativePath = $fpath;
      
      if ($relativePath != null && startsWith ( $f, $relativePath ))
        $f = substr ( $f, strlen ( $relativePath ) );
      else
        $f = basename ( $f );
      $zipped += $zip->addFile ( $toBeZipped, $f ) ? 1 : 0;
    }
  }
  
  $zip->close ();
  
  return $zipped;
}

/**
 * Unzip the source_file in the destination dir
 *
 * @param
 *          string The path to the ZIP-file.
 * @param
 *          string The path where the zipfile should be unpacked, if false the directory of the zip-file is used (DEFAULT: false)
 * @param
 *          boolean Indicates if the files will be unpacked in a directory with the name of the zip-file (true) or not (false) (only if the destination directory is set to false!) (DEFAULT: true)
 * @param
 *          boolean Overwrite existing files (true) or not (false) (DEFAULT: true)
 *          
 * @return boolean Succesful or not
 */
function unzip($src_file, $dest_dir = false, $create_zip_name_dir = true, $overwrite = true)
{
  $src_file = pathFixWin ( $src_file );
  // logLine("UNZIP: unzip($src_file)");
  if ($zip = zip_open ( $src_file ))
  {
    if ($zip)
    {
      $splitter = ($create_zip_name_dir === true) ? "." : "\\";
      if ($dest_dir === false)
      {
        // from $src_file "xxx\yyy\zzzz.zip" take "xxx\yyy\zzzz"
        $dest_dir = substr ( $src_file, 0, strrpos ( $src_file, $splitter ) ) . "\\";
      }
      elseif (! endsWith ( $dest_dir, "\\" ))
      {
        $dest_dir .= "\\";
      }
      
      // Create the directories to the destination dir if they don't already exist
      create_dirs ( $dest_dir );
      
      // For every file in the zip-packet
      while ( $zip_entry = zip_read ( $zip ) )
      {
        // Now we're going to create the directories in the destination directories
        
        // If the file is not in the root dir
        $pos_last_slash = strrpos ( zip_entry_name ( $zip_entry ), "/" );
        if ($pos_last_slash !== false)
        {
          // Create the directory where the zip-entry should be saved (with a "/" at the end)
          create_dirs ( $dest_dir . substr ( zip_entry_name ( $zip_entry ), 0, $pos_last_slash + 1 ) );
        }
        
        // Open the entry
        if (zip_entry_open ( $zip, $zip_entry, "r" ))
        {
          
          // The name of the file to save on the disk
          $file_name = pathFixWin ( $dest_dir . zip_entry_name ( $zip_entry ) );
          // logLine("UNZIP: zipentry($file_name)");
          
          // Check if the files should be overwritten or not
          if (($overwrite === true || $overwrite === false && ! is_file ( $file_name )) && ! is_dir ( $file_name ))
          {
            // Get the content of the zip entry
            $fstream = zip_entry_read ( $zip_entry, zip_entry_filesize ( $zip_entry ) );
            
            // logLine("UNZIP: file_put_contents($file_name,$fstream)");
            file_put_contents ( $file_name, $fstream );
            // Set the rights
            chmod ( $file_name, 0777 );
          }
          
          // Close the entry
          zip_entry_close ( $zip_entry );
        }
      }
      // Close the zip-file
      zip_close ( $zip );
    }
  }
  else
  {
    return false;
  }
  
  return true;
}

/**
 * This function creates recursive directories if it doesn't already exist
 *
 * @param
 *          String The path that should be created
 *          
 * @return void
 */
function create_dirs($path)
{
  $path = pathFixWin ( $path );
  // logLine("UNZIP: create_dirs($path)");
  if (! is_dir ( $path ))
  {
    $directory_path = "";
    $directories = explode ( DIRECTORY_SEPARATOR_WIN, $path );
    array_pop ( $directories );
    foreach ( $directories as $directory )
    {
      $directory_path .= $directory . DIRECTORY_SEPARATOR_WIN;
      if (! is_dir ( $directory_path ))
      {
        mkdir ( $directory_path );
        chmod ( $directory_path, 0777 );
      }
    }
  }
}

function pathFixWin($path)
{
  return str_replace ( DIRECTORY_SEPARATOR_UNIX, DIRECTORY_SEPARATOR_WIN, $path );
}

function pathCombine()
{
  $path = '';
  foreach ( func_get_args () as $chunk )
  {
    $chunk = pathFixWin ( $chunk );
    $isRelative = ! startsWith ( $chunk, DIRECTORY_SEPARATOR_WIN ) && ! isDriveRoot ( $chunk );
    if ($isRelative && ! endsWith ( $path, DIRECTORY_SEPARATOR_WIN ))
      $path .= DIRECTORY_SEPARATOR_WIN;
    $path .= $chunk;
  }
  return $path;
}

/**
 *
 * @return string[]
 */
function yii_getModels()
{
  $models = array ();
  foreach ( new DirectoryIterator ( pathCombine ( app ()->basePath, 'models' ) ) as $x )
    if ($x->isFile () && endsWith ( $x->getFilename (), '.php' ))
      $models [] = basename_wo_ext ( $x->getFilename () );
  return $models;
}

function yii_find_all_classes()
{
  set_time_limit ( 0 );
  
  $paths = array ();
  
  $paths [] = yii_get_framework_path ();
  $paths [] = yii_get_app_path ();
  
  $classes = array ();
  foreach ( getFiles ( $paths, "*.php", true ) as $filename )
  {
    $size = filesize ( $filename );
    if ($size >= 1500000)
      continue;
    $classFound = false;
    // logLine ( "$filename : $size bytes (max $max)" );
    $source = file_get_contents ( $filename );
    $tokens = token_get_all ( $source );
    foreach ( $tokens as $token )
    {
      if (is_array ( $token ))
      {
        if (! $classFound)
        {
          if ($token [0] == T_CLASS)
          {
            $classFound = true;
          }
        }
        else
        {
          if ($token [0] == T_STRING)
          {
            $classes [] = $token [1];
            $classFound = false;
          }
        }
      }
    }
  }
  
  return $classes;
}

function yii_get_app_path()
{
  return realpath ( app ()->basePath );
}

function yii_get_framework_path()
{
  $class = new ReflectionClass ( 'Yii' );
  return dirname ( realpath ( $class->getFileName () ) );
}

function url($route, $params = array(), $ampersand = '&')
{
  return app ()->createUrl ( $route, $params, $ampersand );
}

function absoluteUrl($route, $params = array(), $schema = '', $ampersand = '&')
{
  return app ()->createAbsoluteUrl ( $route, $params, $schema, $ampersand );
}

function t($message, $params = array(), $category = 'app', $source = null, $language = null)
{
  return Yii::t ( $category, $message, $params, $source, $language );
}

function param($name)
{
  return Yii::app ()->params [$name];
}

function is_abstract_class($className)
{
  $class = new ReflectionClass ( $className );
  return $class->isAbstract ();
}

function array_add_unique(array &$array, $value, $strict = false)
{
  if (! array_value_exists ( $array, $value, $strict ))
    $array [] = $value;
}

/**
 *
 * @param array $array
 *          by reference
 * @param unknown $value          
 * @param boolean $condition          
 * @param string $key
 *          default=null -> auto key
 * @param boolean $leaveUntouched
 *          default=true
 * @return boolean
 */
function array_add_if(array &$array, $value, $condition, $key = null, $leaveUntouched = true)
{
  if ($array == null && (! $leaveUntouched || $condition))
  {
    $array = array ();
  }
  
  if ($condition)
  {
    if ($key === null)
      $array [] = $value;
    else
      $array [$key] = $value;
    return true;
  }
  
  return false;
}

function array_from_code_to_array($arrayCode)
{
  return eval ( "return {$arrayCode};" );
}

function array_from_array_to_code(array $array, $formatForFile = false)
{
  $code = _2str ( $array, true );
  if ($formatForFile)
    $code = "<?php return {$code};";
  return $code;
}

function array_build_nested()
{
  $args = func_get_args ();
  $args = array_reverse ( $args );
  $result = null;
  $index = 0;
  foreach ( $args as $arg )
  {
    if ($index == 0)
    {
      $result = $arg;
    }
    else
    {
      $result = array (
          $arg => $result 
      );
    }
    $index ++;
  }
  return $result;
}

function array_build_nested_from_array(array $args)
{
  $args = array_reverse ( $args );
  $result = null;
  $index = 0;
  foreach ( $args as $arg )
  {
    if ($index == 0)
    {
      $result = $arg;
    }
    else
    {
      $result = array (
          $arg => $result 
      );
    }
    $index ++;
  }
  return $result;
}

/**
 * $b overrides $a
 *
 * @param array $a          
 * @param array $b          
 * @return array
 */
function array_merge_ex($a, $b)
{
  foreach ( $b as $k => $v )
  {
    if (is_integer ( $k ))
      $a [] = $v;
    else if (is_array ( $v ) && isset ( $a [$k] ) && is_array ( $a [$k] ))
      $a [$k] = array_merge_ex ( $a [$k], $v );
    else
      $a [$k] = $v;
  }
  return $a;
}

/**
 * BODY: return func_get_args();
 *
 * @return array
 */
function arrayfy()
{
  return func_get_args ();
}

/**
 *
 * @param string $password          
 * @param int $length          
 * @param bool $upper          
 * @param bool $lower          
 * @param bool $digit          
 * @param bool $symbol          
 * @return bool|string true if ok ales string
 */
function validate_password($password, $length, $upper, $lower, $digit, $symbol)
{
  if (empty ( $password ) || strlen ( $password ) < $length)
    return t ( "Password must be at least $length characters" );
  if ($upper && ! strHasChars ( $password, "QAZWSXEDCRFVTGBYHNUJMIKOLP" ))
    return t ( 'Password must contain at least one uppercase letter' );
  if ($lower && ! strHasChars ( $password, "qwertyuiopasdfghjklzxcvbnm" ))
    return t ( 'Password must contain at least one lowercase letter' );
  if ($digit && ! strHasChars ( $password, "0123456789" ))
    return t ( 'Password must contain at least one digit' );
  if ($symbol && ! strHasChars ( $password, "\\|!\"£$%&/()=?^'[]{},.-;:_@+*#§<>" ))
    return t ( 'Password must contain at least one symbol' );
  return true;
}

function strHasChars($str, $charArray)
{
  $str = str_split ( $str );
  if (is_string ( $charArray ))
    $charArray = str_split ( $charArray );
  foreach ( $str as $c1 )
    foreach ( $charArray as $c2 )
      if ($c1 == $c2)
        return true;
  return false;
}

function plate_error_calc($plateCorrect, $plateRead, $calcRange = false)
{
  $plateCorrect = strtoupper ( $plateCorrect );
  $plateRead = strtoupper ( $plateRead );
  
  $error = new CArray ();
  
  $error->exists = false;
  $error->levenshtein = 0;
  $error->btlfsa = 0;
  $error->similar_text = 100.0;
  
  $range = array ();
  if ($plateCorrect != $plateRead)
  {
    $error->exists = true;
    $error->levenshtein = levenshtein ( $plateCorrect, $plateRead );
    $error->btlfsa = btlfsa ( $plateCorrect, $plateRead );
    $percent = 0.0;
    similar_text ( $plateCorrect, $plateRead, $percent );
    $error->similar_text = $percent;
    
    $expr = ExpressionHelper::parse ( $plateRead );
    $range = ExpressionHelper::getValues ( $expr, "1234567890QAZWSXEDCRFVTGBYHNUJMIKOLP" );
  }
  
  $error->range = $range;
  
  return $error;
}

function wordMatch($words, $input, $sensitivity)
{
  $shortest = - 1;
  foreach ( $words as $word )
  {
    $lev = levenshtein ( $input, $word );
    if ($lev == 0)
    {
      $closest = $word;
      $shortest = 0;
      break;
    }
    if ($lev <= $shortest || $shortest < 0)
    {
      $closest = $word;
      $shortest = $lev;
    }
  }
  if ($shortest <= $sensitivity)
  {
    return $closest;
  }
  else
  {
    return 0;
  }
}

function btlfsa($word1, $word2)
{
  $score = 0;
  
  // For each char that is different add 2 to the score
  // as this is a BIG difference
  
  $remainder = preg_replace ( "/[" . preg_replace ( "/[^A-Za-z0-9\']/", ' ', $word1 ) . "]/i", '', $word2 );
  $remainder .= preg_replace ( "/[" . preg_replace ( "/[^A-Za-z0-9\']/", ' ', $word2 ) . "]/i", '', $word1 );
  $score = strlen ( $remainder ) * 2;
  
  // Take the difference in string length and add it to the score
  $w1_len = strlen ( $word1 );
  $w2_len = strlen ( $word2 );
  $score += $w1_len > $w2_len ? $w1_len - $w2_len : $w2_len - $w1_len;
  
  // Calculate how many letters are in different locations
  // And add it to the score i.e.
  //
  // h e a r t
  // 1 2 3 4 5
  //
  // h a e r t a e = 2
  // 1 2 3 4 5 1 2 3 4 5
  //
  
  $w1 = $w1_len > $w2_len ? $word1 : $word2;
  $w2 = $w1_len > $w2_len ? $word2 : $word1;
  
  for($i = 0; $i < strlen ( $w1 ); $i ++)
  {
    if (! isset ( $w2 [$i] ) || $w1 [$i] != $w2 [$i])
    {
      $score ++;
    }
  }
  
  return $score;
}

/**
 *
 * @param string $condition
 *          PHP CODE!!
 * @param string $initCode          
 * @return unknown
 */
function checkAccess($condition, $initCode = "")
{
  $code = $initCode . PHP_EOL;
  foreach ( AuthItem::getAllNames ( 'name' ) as $key )
  {
    $value = user ()->checkAccess ( $key ) ? "true" : "false";
    $code .= '$' . "$key = $value;" . PHP_EOL;
  }
  $code .= "return ($condition);";
  // logLine ( "=======" );
  // logLine ( $code );
  $result = eval ( $code );
  // logObj ( $result );
  return $result;
}

/**
 * Remap an array changing the keys
 *
 * @param array $array          
 * @param function($k,$v) $function
 *          return the key for item($k,$v)
 * @return array An array with same values of $array but different (remapped) keys
 */
function array_remap($array, $function)
{
  $array2 = array ();
  foreach ( $array as $key => $value )
    $array2 [$function ( $key, $value )] = $value;
  return $array2;
}

/**
 *
 * @param array $array          
 * @param function($k,$v) $function
 *          return the value for key $k
 * @return array
 */
function array_map_kv($array, $function)
{
  $array2 = array ();
  foreach ( $array as $key => $value )
    $array2 [$key] = $function ( $key, $value );
  return $array2;
}

function array_remove_dup($array, $strict = false)
{
  $unique = array ();
  if ($array !== null && is_array ( $array ))
  {
    foreach ( $array as $item )
    {
      if (! array_value_exists ( $unique, $item, $strict ))
      {
        $unique [] = $item;
      }
    }
  }
  return $unique;
}

/**
 *
 * @param string $plates          
 * @return string[]
 */
function plate_list_normalization($plates, $separator = PHP_EOL)
{
  $rawInput = strtoupper ( $plates );
  $input = "";
  $charset = "1234567890QAZWSXEDCRFVTGBYHNUJMIKOLP";
  $badCharCount = 0;
  foreach ( str_split ( $rawInput ) as $char )
  {
    if (containsStr ( $charset, $char ))
    {
      $badCharCount = 0;
      $input .= $char;
    }
    else
    {
      $badCharCount ++;
      if ($badCharCount == 1)
        $input .= PHP_EOL;
    }
  }
  $plates = explode ( PHP_EOL, $input );
  $plates = array_remove ( $plates, function ($k, $v)
  {
    return empty ( $v );
  } );
  $uniquePlates = array_remove_dup ( $plates );
  $uniquePlates = array_sort ( $uniquePlates );
  return $uniquePlates;
}

function isEmpty($var)
{
  return empty ( $var );
}

/**
 *
 * @param string $path          
 * @param boolean $recursive          
 * @param string $pattern
 *          default=*
 * @return number|boolean
 */
function dir_count_files($path, $recursive, $pattern = '*')
{
  $cntobj = new stdClass ();
  $cntobj->pattern = $pattern;
  $cntobj->counter = 0;
  if (dir_traverse ( $path, $recursive, function (DirectoryIterator $x, stdClass $cntobj1)
  {
    if ($x->isFile () && fnmatch ( $cntobj1->pattern, $x->getFilename () ))
      $cntobj1->counter ++;
  }, $cntobj ))
    return $cntobj->counter;
  else
    return false;
}

/**
 *
 * @param string $path          
 * @param boolean $recursive          
 * @param function $func
 *          function(DirectoryIterator $item, [$arg]){}
 *          
 * @return boolean
 */
function dir_traverse($path, $recursive, $func, $arg = null)
{
  if (! dirExists ( $path ) || $func == null)
    return false;
  $dir = new DirectoryIterator ( $path );
  foreach ( $dir as $item )
    if (! $item->isDot ())
    {
      $func ( $item, $arg );
      if ($item->isDir () && $recursive)
        dir_traverse ( $item->getRealPath (), $recursive, $func );
    }
  return true;
}

function dirSize($path)
{
  $total_size = 0;
  $files = scandir ( $path );
  $cleanPath = rtrim ( $path, DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR;
  
  foreach ( $files as $t )
  {
    if ($t != "." && $t != "..")
    {
      $currentFile = $cleanPath . $t;
      if (is_dir ( $currentFile ))
      {
        $size = dirSize ( $currentFile );
        $total_size += $size;
      }
      else
      {
        $size = filesize ( $currentFile );
        $total_size += $size;
      }
    }
  }
  
  return $total_size;
}

function formatBytes($bytes, $precision = 2)
{
  $units = array (
      'B',
      'KB',
      'MB',
      'GB',
      'TB' 
  );
  
  $bytes = max ( $bytes, 0 );
  $pow = floor ( ($bytes ? log ( $bytes ) : 0) / log ( 1024 ) );
  $pow = min ( $pow, count ( $units ) - 1 );
  
  // Uncomment one of the following alternatives
  $bytes /= pow ( 1024, $pow );
  // $bytes /= (1 << (10 * $pow));
  
  return round ( $bytes, $precision ) . ' ' . $units [$pow];
}

function dirEmpty($str, $deleteDir = false, $deleteSubDir = true)
{
  if (is_file ( $str ))
  {
    return @unlink ( $str );
  }
  elseif (is_dir ( $str ))
  {
    $scan = glob ( rtrim ( $str, '/' ) . '/*' );
    foreach ( $scan as $index => $path )
    {
      dirEmpty ( $path, $deleteSubDir, $deleteSubDir );
    }
    if ($deleteDir)
      return @rmdir ( $str );
    else
      return true;
  }
  else
    return false;
}

/**
 *
 * @param array $parameters          
 * @return array
 */
function escape_params(array $parameters)
{
  foreach ( $parameters as $k => $v )
  {
    $parameters [$k] = self::escape_param ( $v );
  }
  return $parameters;
}

/**
 *
 * @param mixed $parameters          
 * @return string
 */
function escape_param($param)
{
  return ((is_int ( $param ) || is_float ( $param )) ? $param : (NULL === $param ? 'NULL' : "'" . mysql_real_escape_string ( $param ) . "'"));
}

/**
 * Run a SQL statement
 *
 * @param string $sql          
 * @param array $params          
 * @param boolean $returnSingleOnSingleRow
 *          default true
 * @param boolean $returnCArrayObjects
 *          default true
 * @return CArray[]
 */
function query($sql, array $params = array(), $returnSingleOnSingleRow = true, $returnCArrayObjects = true)
{
  $command = app ()->db->createCommand ( $sql );
  if ($params != null && is_array ( $params ))
    $command->params = $params;
  $rows = array ();
  foreach ( $command->queryAll () as $row )
  {
    if ($returnCArrayObjects)
      $rows [] = new CArray ( $row );
    else
      $rows [] = $row;
  }
  if (count ( $rows ) == 1 && $returnSingleOnSingleRow)
    return array_pop ( $rows );
  else
    return $rows;
}

/**
 *
 * @param string $sql          
 * @param array $params          
 * @return CDbDataReader
 */
function queryReader($sql, array $params = array())
{
  $command = app ()->db->createCommand ( $sql );
  if ($params != null && is_array ( $params ))
    $command->params = $params;
  return $command->query ();
}

/**
 *
 * @deprecated incompleta
 * @todo da finire
 * @param unknown $filename          
 * @param unknown $sql          
 * @param array $params          
 */
function queryIntoOutfile($filename, $sql, array $params = array())
{
  $finalSql = "SELECT * INTO OUTFILE '$filename'";
  $finalSql .= " FIELDS TERMINATED BY ','";
  $finalSql .= " OPTIONALLY";
  $finalSql .= " ENCLOSED BY '\"'";
  $finalSql .= " LINES TERMINATED BY '\n'";
  $finalSql .= " FROM test_table;";
}

/**
 *
 * @param string $sql          
 * @param array $params          
 */
function queryToCsv($filename, $sql, array $params = array(), $filter = null)
{
  $reader = queryReader ( $sql, $params );
  outputCsvFromReader ( $filename, $reader, $filter );
}

/**
 *
 * @param string|CDbTableSchema $table          
 * @param CDbCriteria $criteria          
 * @return CDbDataReader
 */
function queryFromCriteria($table, CDbCriteria $criteria)
{
  return queryFromCriteriaCommand ( $table, $criteria )->query ();
}

/**
 *
 * @param string|CDbTableSchema $table          
 * @param CDbCriteria $criteria          
 * @return CDbCommand
 */
function queryFromCriteriaCommand($table, CDbCriteria $criteria)
{
  return app ()->db->getCommandBuilder ()
    ->createFindCommand ( $table, $criteria );
}

/**
 *
 * @param string $filename          
 * @param Iterator $reader          
 * @param function $filter
 *          func(array[,$args]):array
 *          takes a input object/array and returns an array default null
 */
function outputCsvFromReader($filename, Iterator $reader, $filter = null, $args = null)
{
  prepare_download ( $filename, "text/csv;charset=utf-8" );
  $index = 0;
  foreach ( $reader as $row )
  {
    if ($index == 0)
    {
      $data = array_keys ( $row );
      if ($filter != null && is_callable ( $filter ))
        $data = $filter ( $data, $args );
      echo (ECSVExport::arrayToCsvRow ( $data ));
    }
    
    $data = $row;
    if ($filter != null && is_callable ( $filter ))
      $data = $filter ( $data, $args );
    echo (ECSVExport::arrayToCsvRow ( $data ));
    $index ++;
  }
  exit ();
}

/**
 *
 * @param string $filename          
 * @param Iterator $reader          
 * @param function $filter
 *          func(array[,$args]):array
 *          takes a input object/array and returns an array default null
 */
function saveCsvFromReader($filename, Iterator $reader, $filter = null, $args = null)
{
  $index = 0;
  foreach ( $reader as $row )
  {
    if ($index == 0)
    {
      $data = array_keys ( $row );
      if ($filter != null && is_callable ( $filter ))
        $data = $filter ( $data, $args );
      file_put_contents ( $filename, ECSVExport::arrayToCsvRow ( $data ), FILE_APPEND );
    }
    
    $data = $row;
    if ($filter != null && is_callable ( $filter ))
      $data = $filter ( $data, $args );
    file_put_contents ( $filename, ECSVExport::arrayToCsvRow ( $data ), FILE_APPEND );
    $index ++;
  }
}

function outputXlsx($filename, $dataset, $filter = null, $title = null, $description = null)
{
  $objPHPExcel = new PHPExcel ();
  
  // PHPExcel_DocumentProperties
  $props = $objPHPExcel->getProperties ();
  $props->setCreator ( "Event Server" );
  $props->setLastModifiedBy ( "Event Server" );
  if (! isEmptyOrWhitespace ( $title ))
    $props->setTitle ( $title );
  if (! isEmptyOrWhitespace ( $title ))
    $props->setSubject ( $title );
  if (! isEmptyOrWhitespace ( $description ))
    $props->setDescription ( $description );
    
    // PHPExcel_Worksheet
  $sheet = $objPHPExcel->setActiveSheetIndex ( 0 );
  $rowIndex = 1; // row index
  foreach ( $dataset as $row )
  {
    if ($rowIndex == 1)
    {
      $data = array_keys ( $row );
      if ($filter != null && is_callable ( $filter ))
        $data = $filter ( $data );
      $columnIndex = 0;
      foreach ( $data as $column )
      {
        $cell = $sheet->setCellValueByColumnAndRow ( $columnIndex ++, $rowIndex, $column, true );
        if ($cell instanceof PHPExcel_Cell)
          $cell->getStyle ()
            ->getFont ()
            ->setBold ( true );
      }
      $rowIndex ++;
    }
    
    $data = $row;
    if ($filter != null && is_callable ( $filter ))
      $data = $filter ( $data );
    $columnIndex = 0;
    foreach ( $data as $column )
      $sheet->setCellValueByColumnAndRow ( $columnIndex ++, $rowIndex, $column );
    $rowIndex ++;
  }
  
  // Rename worksheet
  if (! isEmptyOrWhitespace ( $title ))
    $sheet->setTitle ( $title );
  
  outputXlsx2007From ( $objPHPExcel, $filename );
  exit ();
}

function outputXlsx2007From(PHPExcel $objPHPExcel, $filename)
{
  // Redirect output to a client’s web browser (Excel2007)
  header ( 'Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' );
  header ( 'Content-Disposition: attachment;filename="' . $filename . '"' );
  header ( 'Cache-Control: max-age=0' );
  // If you're serving to IE 9, then the following may be needed
  header ( 'Cache-Control: max-age=1' );
  // If you're serving to IE over SSL, then the following may be needed
  header ( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' ); // Date in the past
  header ( 'Last-Modified: ' . gmdate ( 'D, d M Y H:i:s' ) . ' GMT' ); // always modified
  header ( 'Cache-Control: cache, must-revalidate' ); // HTTP/1.1
  header ( 'Pragma: public' ); // HTTP/1.0
  $objWriter = PHPExcel_IOFactory::createWriter ( $objPHPExcel, 'Excel2007' );
  $objWriter->save ( 'php://output' );
  exit ();
}

/**
 *
 * @return string
 */
function paramdeep()
{
  $queue = new CQueue ( func_get_args () );
  $obj = Yii::app ()->params;
  while ( $queue->count () > 0 )
  {
    $key = $queue->dequeue ();
    if (isset ( $obj [$key] ))
      $obj = $obj [$key];
    else
      return null;
  }
  return $obj;
}

/**
 *
 * @param mixed $value          
 * @param mixed $default
 *          (default=null)
 * @param boolean $strict
 *          (default=false)
 * @return mixed
 */
function onNull($value, $default = null, $strict = false)
{
  if ($strict)
    if ($value === null)
      return $default;
    else
      return $value;
  else if ($value == null)
    return $default;
  else
    return $value;
}

/**
 *
 * @param integer $uid          
 * @return UserSettingsManager
 */
function settings($uid = null)
{
  return new UserSettingsManager ( $uid );
}

/**
 *
 * @return string
 */
function kria_get_esgui_folder()
{
  $mi = new MachineInfo ();
  if (isEmptyOrWhitespace ( $mi->ApplicationDataFolder ))
    $mi->ApplicationDataFolder = 'C:\\KRIA\\DATA\\';
  dirEnsureExists ( $mi->ApplicationDataFolder );
  $folder = pathCombine ( $mi->ApplicationDataFolder, "EventServerGui" );
  dirEnsureExists ( $folder );
  return $folder;
}

/**
 *
 * @param string $operation
 *          The operation/task/riole to be checked for the current user
 * @param bool $fail
 *          The check always fails (default: false)
 * @param string $message
 *          Message to display (default: null)
 * @param string $logMessage
 *          Message to log using the Yii::trace() function (default: null)
 * @throws CHttpException HTTP ERROR 401
 */
function access_denied_check($operation, $fail = false, $message = null, $logMessage = null)
{
  if ($fail || (! isEmpty ( $operation ) && ! user ()->checkAccess ( $operation )))
  {
    if (! empty ( $logMessage ))
      Yii::trace ( $logMessage );
    
    if (empty ( $message ))
      $message = Yii::t ( 'yii', 'You are not authorized to perform this action.' );
    
    $user = user ()->model;
    security_log ( "USER $user->username (ID=$user->id) FAILED CHECK '$operation' (FORCED=$fail) (MESSAGE=$message) (TRACE=$logMessage)", "401" );
    
    throw new CHttpException ( 401, $message );
  }
}

function access_basic_check($username = null, $password = null)
{
  if (($username === null) || ($password === null))
  {
    if (isset ( $_SERVER ['PHP_AUTH_USER'] ) && isset ( $_SERVER ['PHP_AUTH_PW'] ))
    {
      $username = $_SERVER ['PHP_AUTH_USER'];
      $password = $_SERVER ['PHP_AUTH_PW'];
    }
  }
  
  $auth = new UserIdentity ( $username, $password );
  if (! $auth->authenticate ())
  {
    header ( "WWW-Authenticate: Basic realm=\"Event Server\"" );
    access_denied_check ( null, true );
    return;
  }
}

function access_denied_png_url($useEnglish = false)
{
  if ($useEnglish)
    return Yii::app ()->createAbsoluteUrl ( '/images/access_denied_en.png' );
  else
    return Yii::app ()->createAbsoluteUrl ( '/images/access_denied_' . Yii::app ()->language . '.png' );
}

function is_array_ex($array, $notEmpty = false)
{
  if ($array != null)
  {
    if (is_array ( $array ))
    {
      if ($notEmpty)
        return count ( $array ) > 0;
      else
        return true;
    }
  }
  return false;
}

/**
 * create an array where key=value and value=$array.value
 *
 * @param array $array          
 * @param boolean $forceStringKey
 *          default false
 * @return array
 */
function array_values_to_keys(array $array, $forceStringKey = false)
{
  $result = array ();
  foreach ( $array as $value )
    if ($forceStringKey)
      $result [( string ) $value] = $value;
    else
      $result [$value] = $value;
  return $result;
}

function array_values_exist($array, $values, $any = true, $strict = false)
{
  if ($values != null && is_array ( $values ))
  {
    foreach ( $values as $value )
    {
      $exists = array_value_exists ( $array, $value, $strict );
      if ($exists && $any)
        return true;
      if (! $exists && ! $any)
        return false;
    }
    return ! $any;
  }
  return false;
}

function array_value_exists($array, $value, $strict = false)
{
  if ($array != null && is_array ( $array ))
  {
    foreach ( $array as $itemValue )
    {
      if ($strict)
      {
        if ($value === $itemValue)
        {
          return true;
        }
      }
      else
      {
        if ($value == $itemValue)
        {
          return true;
        }
      }
    }
  }
  return false;
}

function reflection_write_method_signature(ReflectionMethod $method)
{
  $writer = new StringWriter ();
  $params = array ();
  foreach ( $method->getParameters () as $param )
  {
    $paramDecl = "";
    $paramType = reflection_getParamType ( $param );
    if (! isEmptyOrWhitespace ( $paramType ))
    {
      $paramDecl .= " $paramType ";
    }
    $paramDecl .= "$" . $param->getName ();
    // $param = new ReflectionParameter($function, $parameter);
    if ($param->isDefaultValueAvailable ())
    {
      $paramDecl .= " = " . _2str ( $param->getDefaultValue () );
    }
    $params [] = $paramDecl;
  }
  $params = implode ( ',', $params );
  $writer->writeline ( $method->getDocComment () );
  
  if ($method->isPublic ())
    $writer->write ( " public" );
  
  if ($method->isProtected ())
    $writer->write ( " protected" );
  
  if ($method->isPrivate ())
    $writer->write ( " private" );
  
  if ($method->isStatic ())
    $writer->write ( " static" );
  
  $writer->write ( " function {$method->getName()}({$params})" );
  
  return $writer->__toString ();
}

/**
 *
 * @return string
 */
function reflection_getParamType(ReflectionParameter $refParam)
{
  $export = ReflectionParameter::export ( array (
      $refParam->getDeclaringClass ()->name,
      $refParam->getDeclaringFunction ()->name 
  ), $refParam->name, true );
  
  // $type = preg_replace('/.*?(\w+)\s+\$'.$refParam->name.'.*/', '\\1', $export);
  // echo("$export\n");
  
  $closePos = strpos ( $export, "> " );
  if ($closePos === false)
    return null;
  
  $type = substr ( $export, $closePos + 2 );
  if (startsWith ( $type, '$' ))
    return null;
  
  $endPos = strpos ( $type, " " );
  if ($endPos === false)
    return null;
  
  $type = substr ( $type, 0, $endPos );
  
  // echo("[$type]\n");
  
  return $type;
}

function create_interface_from_two_types($interfaceName, $className1, $className2)
{
  $c1 = new ReflectionClass ( $className1 );
  $c2 = new ReflectionClass ( $className2 );
  
  // check methods
  $c1_methods = array_remove ( $c1->getMethods (), function ($k, ReflectionMethod $v, $className1)
  {
    return $v->getDeclaringClass ()
      ->getName () != $className1;
  }, $className1 );
  $c2_methods = array_remove ( $c2->getMethods (), function ($k, ReflectionMethod $v, $className2)
  {
    return $v->getDeclaringClass ()
      ->getName () != $className2;
  }, $className2 );
  $c1_methods = array_remap ( $c1_methods, function ($k, ReflectionMethod $v)
  {
    return $v->getName ();
  } );
  $c2_methods = array_remap ( $c2_methods, function ($k, ReflectionMethod $v)
  {
    return $v->getName ();
  } );
  $common_methods = array_intersect ( array_keys ( $c1_methods ), array_keys ( $c2_methods ) );
  
  // check properties
  $c1_props = array_remove ( $c1->getProperties (), function ($k, ReflectionProperty $v, $className1)
  {
    return $v->getDeclaringClass ()
      ->getName () != $className1;
  }, $className1 );
  $c2_props = array_remove ( $c2->getProperties (), function ($k, ReflectionProperty $v, $className2)
  {
    return $v->getDeclaringClass ()
      ->getName () != $className2;
  }, $className2 );
  $c1_props = array_remap ( $c1_props, function ($k, ReflectionProperty $v)
  {
    return $v->getName ();
  } );
  $c2_props = array_remap ( $c2_props, function ($k, ReflectionProperty $v)
  {
    return $v->getName ();
  } );
  $common_props = array_intersect ( array_keys ( $c1_props ), array_keys ( $c2_props ) );
  
  if (count ( $common_methods ) > 0 || count ( $common_props ) > 0)
  {
    $buffer = new StringWriter ();
    
    $buffer->writeline ( "/**" );
    foreach ( $common_props as $propName )
    {
      $propValue = $c1_props [$propName];
      $buffer->writeline ( " * @property string $propName" );
    }
    $buffer->writeline ( "*/" );
    
    $buffer->writeline ( "interface $interfaceName" );
    $buffer->writeline ( "{" );
    foreach ( $common_methods as $methName )
      $buffer->writeline ( reflection_write_method_signature ( $c1_methods [$methName] ) . ";" );
    $buffer->writeline ( "}" );
    $buffer->writeline ();
    return $buffer->__toString ();
  }
  
  return null;
}

/**
 * select the first item in the array that returns true in the filter function
 *
 * @param array $array          
 * @param function $func
 *          function($value, [$args], [$key]):boolean
 * @param mixed $args
 *          default=null
 * @param boolean $getKey
 *          default=false
 * @return mixed the VALUE or the KEY
 */
function array_find_first(array $array, $func, $args = null, $getKey = false)
{
  foreach ( $array as $key => $value )
    if ($func ( $value, $key ))
      return $value;
  return null;
}

function array_first_not_null(array $array)
{
  foreach ( $array as $value )
    if (! isEmpty ( $value ))
      return $value;
  return null;
}

function array_first($array, $default = null)
{
  if (is_array ( $array ))
    foreach ( $array as $item )
      return $item;
  return $default;
}

function array_last($array, $default = null)
{
  $last = $default;
  if (is_array ( $array ))
    foreach ( $array as $item )
      $last = $item;
  return $last;
}

/**
 *
 * @param array $array          
 * @param mixed $value          
 * @param mixed $default
 *          default=null
 * @param boolean $strict
 *          default=false
 * @return mixed the key or the $default value
 */
function array_index_of(array $array, $value, $default = null, $strict = false)
{
  foreach ( $array as $k => $v )
    if (equals ( $v, $value, $strict ))
      return $k;
  return $default;
}

/**
 *
 * @param array $items          
 * @param f(x)=y $func          
 * @return array
 */
function array_convert(array $items, $func)
{
  $output = array ();
  foreach ( $items as $key => $item )
    $output [$key] = $func ( $item );
  return $output;
}

/**
 *
 * @param array $array          
 * @param array $keys          
 * @return array
 */
function array_filter_keys_keep(array $array, array $keys)
{
  foreach ( array_keys ( $array ) as $key )
    if (! array_value_exists ( $keys, $key ))
      unset ( $array [$key] );
  return $array;
}

/**
 *
 * @param array $array          
 * @param array $keys          
 * @return array
 */
function array_filter_keys_remove(array $array, array $keys)
{
  foreach ( array_keys ( $array ) as $key )
    if (array_value_exists ( $keys, $key ))
      unset ( $array [$key] );
  return $array;
}

/**
 *
 * @param array $input          
 * @param function($k,$v) $keyFunc
 *          function that returns the new key
 * @param function($k,$v) $valFunc
 *          function that returns the new value
 * @return array
 */
function array_convert_ex($input, $keyFunc = null, $valFunc = null)
{
  $output = array ();
  
  foreach ( $input as $key => $val )
  {
    $newKey = $keyFunc != null ? $keyFunc ( $key, $val ) : $key;
    $newVal = $valFunc != null ? $valFunc ( $key, $val ) : $val;
    $output [$newKey] = $newVal;
  }
  
  return $output;
}

function array_set_by_path(array &$config, array $path, $value = null)
{
  $cnfg = &$config;
  $index = 1;
  $count = count ( $path );
  foreach ( $path as $key )
  {
    if ($index < $count)
    {
      if (! isset ( $cnfg [$key] ))
        $cnfg [$key] = array ();
      $cnfg = &$cnfg [$key];
    }
    else
    {
      $cnfg [$key] = $value;
    }
    $index ++;
  }
}

function bu($url = null)
{
  static $baseUrl;
  if ($baseUrl === null)
    $baseUrl = Yii::app ()->getRequest ()
      ->getBaseUrl ();
  return $url === null ? $baseUrl : $baseUrl . '/' . ltrim ( $url, '/' );
}

function t_by_num($count, $text_sing, $text_plur, array $params = array(), $category = 'app', $source = null, $language = null)
{
  return $count == 1 ? t ( $text_sing, $params, $category, $source, $language ) : t ( $text_plur, $params, $category, $source, $language );
}

function not_empty_string($str)
{
  return (is_string ( $str ) && $str != '');
}

/**
 *
 * @return CLogger
 */
function logger()
{
  return Yii::getLogger ();
}

/**
 *
 * @return CLogRoute[]
 */
function logger_routes()
{
  $handlers = logger ()->getEventHandlers ( 'onFlush' );
  $routers = array ();
  foreach ( $handlers as $item )
  {
    if (is_array ( $item ))
    {
      foreach ( $item as $item2 )
        if ($item2 instanceof CLogRouter)
          $routers [] = $item2;
    }
    else
    {
      if ($item instanceof CLogRouter)
        $routers [] = $item;
    }
  }
  
  /** @var CLogRouter[] $routers */
  $routes = array ();
  /** @var CLogRoute[] $routes */
  foreach ( $routers as $routerKey => $router )
    foreach ( $router->routes as $routeKey => $route )
      $routes [$routeKey] = $route;
  
  return $routes;
}

function log_routes_classes($search = false)
{
  if ($search)
  {
    $classes = yii_find_all_classes ();
    
    $routesClasses = array ();
    foreach ( $classes as $className )
    {
      if (class_extends ( $className, "CLogRoute" ))
        if (! is_abstract_class ( $className ))
          $routesClasses [] = $className;
    }
    return $routesClasses;
  }
  else
  {
    return array (
        'CDbLogRoute',
        'CEmailLogRoute',
        'CFileLogRoute',
        'CProfileLogRoute',
        'CWebLogRoute',
        'YiiDebugToolbarRoute',
        'CSocketLogRoute' 
    );
  }
}

function class_extends($class, $parent, $autoload = true)
{
  if ($class == $parent)
    return true;
  $friends = @class_parents ( $class, $autoload );
  if ($friends === false)
    return false;
  foreach ( $friends as $f )
    if ($f == $parent)
      return true;
  return false;
}

/**
 * any var to string
 *
 * @param mixed $obj          
 * @param boolean $export
 *          (default true) true=php parsable, false=not parsable
 * @param boolean $singleLine
 *          (default false)
 * @return string
 */
function _2str($obj, $export = true, $singleLine = false)
{
  if ($export)
    $text = var_export ( $obj, true );
  else
    $text = print_r ( $obj, true );
  if ($singleLine)
  {
    foreach ( array (
        "\r",
        "\n",
        PHP_EOL 
    ) as $needle )
      while ( strpos ( $text, $needle ) !== false )
        $text = str_replace ( $needle, "", $text );
  }
  return $text;
}

function echoObj($obj)
{
  echo (_2str ( $obj ));
}

/**
 *
 * @return string
 */
function getBWListsLabels($wll = null, $bll = null, $bothl = null)
{
  $cbl = 0;
  $cwl = 0;
  $canSeeBlack = user ()->checkAccess ( 'blacklist_visibility' );
  $canSeeWhite = user ()->checkAccess ( 'whitelist_visibility' );
  
  foreach ( PlateList::getCurrentUserLists () as $pl )
    if ($pl->mode == PlateList::MODE_BLACK_LIST)
    {
      if ($canSeeBlack)
        $cbl ++;
    }
    else if ($pl->mode == PlateList::MODE_WHITE_LIST)
    {
      if ($canSeeWhite)
        $cwl ++;
    }
  
  if ($cbl > 0 && $cwl <= 0)
    return empty ( $bll ) ? Yii::t ( 'app', 'Black lists' ) : $bll;
  
  if ($cbl <= 0 && $cwl > 0)
    return empty ( $wll ) ? Yii::t ( 'app', 'White lists' ) : $wll;
  
  return empty ( $bothl ) ? Yii::t ( 'app', 'Lists' ) : $bothl;
}

/* draws a calendar */
function draw_calendar($month, $year)
{
  
  /* draw table */
  $calendar = '<table cellpadding="0" cellspacing="0" class="calendar">';
  
  /* table headings */
  $headings = array (
      'Sunday',
      'Monday',
      'Tuesday',
      'Wednesday',
      'Thursday',
      'Friday',
      'Saturday' 
  );
  $calendar .= '<tr class="calendar-row"><td class="calendar-day-head">' . implode ( '</td><td class="calendar-day-head">', $headings ) . '</td></tr>';
  
  /* days and weeks vars now ... */
  $running_day = date ( 'w', mktime ( 0, 0, 0, $month, 1, $year ) );
  $days_in_month = date ( 't', mktime ( 0, 0, 0, $month, 1, $year ) );
  $days_in_this_week = 1;
  $day_counter = 0;
  $dates_array = array ();
  
  /* row for week one */
  $calendar .= '<tr class="calendar-row">';
  
  /* print "blank" days until the first of the current week */
  for($x = 0; $x < $running_day; $x ++)
  {
    $calendar .= '<td class="calendar-day-np"> </td>';
    $days_in_this_week ++;
  }
  
  /* keep going with days.... */
  for($list_day = 1; $list_day <= $days_in_month; $list_day ++)
  {
    $calendar .= '<td class="calendar-day">';
    /* add in the day number */
    $calendar .= '<div class="day-number">' . $list_day . '</div>';
    
    /**
     * QUERY THE DATABASE FOR AN ENTRY FOR THIS DAY !! IF MATCHES FOUND, PRINT THEM !! *
     */
    $calendar .= str_repeat ( '<p> </p>', 2 );
    
    $calendar .= '</td>';
    if ($running_day == 6)
    {
      $calendar .= '</tr>';
      if (($day_counter + 1) != $days_in_month)
      {
        $calendar .= '<tr class="calendar-row">';
      }
      $running_day = - 1;
      $days_in_this_week = 0;
    }
    $days_in_this_week ++;
    $running_day ++;
    $day_counter ++;
  }
  
  /* finish the rest of the days in the week */
  if ($days_in_this_week < 8)
  {
    for($x = 1; $x <= (8 - $days_in_this_week); $x ++)
    {
      $calendar .= '<td class="calendar-day-np"> </td>';
    }
  }
  
  /* final row */
  $calendar .= '</tr>';
  
  /* end the table */
  $calendar .= '</table>';
  
  /* all done, return result */
  return $calendar;
}

function toHtml($tag, $childs)
{
  if ($childs == null)
    return "<$tag/>";
  
  $content = "";
  if (is_array ( $childs ))
    foreach ( $childs as $c )
      $content .= "$c";
  else
    $content = "$childs";
  
  return "<$tag>$content<$tag/>";
}

function date_in_range($from, $to, $target)
{
  $from = DateHelper::ensureObject ( $from );
  $to = DateHelper::ensureObject ( $to );
  $target = DateHelper::ensureObject ( $target );
  $result = ($from <= $target && $target <= $to);
  return $result;
}

function convertEnumerableToArray($enumerable)
{
  $arr = array ();
  foreach ( $enumerable as $obj )
    $arr [] = $obj;
  return $arr;
}

function uniqidex($prefix = "", $useMicrotime = false, $hashIt = true)
{
  $id = 'error';
  if ($useMicrotime)
    $id = $prefix . microtime ( true );
  else
    $id = uniqid ( $prefix, true );
  if ($hashIt)
    $id = $prefix . md5 ( $id );
  return $id;
}

/**
 *
 * @param mixed $line          
 * @param boolean $resetLog
 *          default false
 * @return string
 */
function logLine($line, $resetLog = false)
{
  $line = "[" . date ( "Y-m-d H:i:s" ) . "] " . $line;
  /*
   * if($resetLog)
   * file_put_contents ("D:\\_yii.log", $line."\n");
   * else
   * file_put_contents ("D:\\_yii.log", $line."\n", FILE_APPEND);
   */
  TcpClient::writeTo ( "127.0.0.1", 9999, $line );
  return $line;
}

function logDump($var, $resetLog = false)
{
  return logLine ( var_dump_ret ( $var ), $resetLog );
}

function logDumps()
{
  return logDump ( func_get_args () );
}

function logObj($obj, $resetLog = false)
{
  return logLine ( _2str ( $obj ), $resetLog );
}

function logObjs()
{
  return logObj ( func_get_args () );
}

function logStack($full = false, $trace = null, $reetLog = false)
{
  logLine ( "CALL STACK", $resetLog );
  if ($trace === null)
    $trace = debug_backtrace ();
  if ($full)
  {
    logObj ( $trace );
  }
  else
  {
    foreach ( $trace as $id => $obj )
    {
      logLine ( "LEVEL [$id]" );
      logLine ( "         FILE:     $obj[file]:$obj[line]" );
      logLine ( "         FUNCTION: $obj[class]::$obj[function]" );
    }
  }
}

function check_page_online($url)
{
  $agent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";
  $ch = curl_init ();
  curl_setopt ( $ch, CURLOPT_URL, $url );
  curl_setopt ( $ch, CURLOPT_USERAGENT, $agent );
  curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
  curl_setopt ( $ch, CURLOPT_VERBOSE, false );
  curl_setopt ( $ch, CURLOPT_TIMEOUT, 5 );
  curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
  curl_setopt ( $ch, CURLOPT_SSLVERSION, 3 );
  curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
  $page = curl_exec ( $ch );
  // echo curl_error($ch);
  $httpcode = curl_getinfo ( $ch, CURLINFO_HTTP_CODE );
  curl_close ( $ch );
  if ($httpcode >= 200 && $httpcode < 300)
    return true;
  else
    return false;
}

function resolve_redirect($url)
{
  $headers = get_headers ( $url );
  $headers = array_reverse ( $headers );
  foreach ( $headers as $header )
  {
    if (strpos ( $header, 'Location: ' ) === 0)
    {
      $url = str_replace ( 'Location: ', '', $header );
      $url = resolve_redirect ( $url );
    }
  }
  
  return $url;
}

/**
 * check if your variable is an int or a string containing a int without others digit than 0 to 9
 *
 * @param mixed $var          
 * @return boolean
 */
function is_int_ex($var)
{
  return (! is_int ( $value ) ? (ctype_digit ( $value )) : true);
}

function array_swap($array, $i, $j)
{
  $tmp = $array [$i];
  $array [$i] = $array [$j];
  $array [$j] = $tmp;
  return $array;
}

/**
 *
 * @param ISortable[] $array          
 * @return ISortable[]
 */
function sort_sortable($array)
{
  for($i = 0; $i < count ( $array ); $i ++)
    for($j = $i; $j < count ( $array ); $j ++)
      if ($array [$i]->compare ( $array [$j] ) > 0)
        $array = array_swap ( $array, $i, $j );
  return $array;
}

function compare($a, $b, $strict = false, $reverse = false)
{
  if (($a == $b && ! $strict) || ($a === $b && $strict))
    return 0;
  elseif ($a < $b)
    return $reverse ? 1 : - 1;
  else
    return $reverse ? - 1 : 1;
}

/**
 *
 * @param array $array          
 * @param function(x,y) $comparer
 *          - default: function($x,$y){ return $x<$y };
 * @param boolean $strict
 *          (default: false)
 * @param boolean $invert
 *          (default: false)
 * @return array
 */
function array_sort($array, $comparer = null, $strict = false, $invert = false)
{
  if ($comparer == null)
  {
    if ($strict)
    {
      $comparer = function ($x, $y)
      {
        if ($x === $y)
          return 0;
        return $x > $y ? 1 : - 1;
      };
    }
    else
    {
      $comparer = function ($x, $y)
      {
        if ($x == $y)
          return 0;
        return $x > $y ? 1 : - 1;
      };
    }
  }
  else
  {
    if (is_callable ( $comparer ))
    {
      // ok
    }
    else
    {
      if (is_string ( $comparer ))
      {
        // codice da eseguire
        $comparer = eval ( 'return function ($x,$y) { return (' . $comparer . '); };' );
      }
      else
      {
        // nessuna opzione disponibile
      }
    }
  }
  for($i = 0; $i < count ( $array ); $i ++)
    for($j = $i; $j < count ( $array ); $j ++)
    {
      if ((! $invert && call_user_func_array ( $comparer, array (
          $array [$i],
          $array [$j] 
      ) ) > 0) || ($invert && call_user_func_array ( $comparer, array (
          $array [$i],
          $array [$j] 
      ) ) < 0))
        $array = array_swap ( $array, $i, $j );
    }
  return $array;
}

/**
 * remove any element that return false
 *
 * @param array $array          
 * @param unknown $func($key,$value,$args)          
 * @param string $args
 *          = null
 * @return multitype:unknown
 */
function array_remove(array $array, $func, $args = null)
{
  $array2 = array ();
  foreach ( $array as $key => $value )
    if (! $func ( $key, $value, $args ))
      $array2 [$key] = $value;
  return $array2;
}

/**
 *
 * @param mixed $value          
 * @param mixed $min
 *          inclusive
 * @param mixed $max
 *          inclusive
 * @return boolean
 */
function in_range($value, $min, $max)
{
  return ($value >= $min && $value <= $max);
}

function keep_in_range($min, $value, $max)
{
  return max ( $min, min ( $value, $max ) );
}

/**
 * keep_in_range alias
 *
 * @param unknown $min          
 * @param unknown $value          
 * @param unknown $max          
 */
function minmax($min, $value, $max)
{
  return keep_in_range ( $min, $value, $max );
}

function echoln($var)
{
  echo ($var);
  echo (PHP_EOL);
}

function echolnln($var)
{
  echoln ( $var );
  echo (PHP_EOL);
}

/**
 * converts any recognized value to a DateTime object and then to string (format ISO9075)
 *
 * @param mixed $dt          
 * @return string
 */
function dt2s($dt)
{
  return DateHelper::formatISO9075DateTime ( $dt );
}

function isZtlSystem()
{
  foreach ( Gate::getAllGates () as $gate )
  {
    foreach ( $gate->gateBehavior as $gb )
    {
      if ($gb->behavior->tag == WHITELIST_VIOLATION)
      {
        return true;
      }
    }
  }
  return false;
}

/**
 *
 * @param string $haystack
 *          the string to search in
 * @param string $needle
 *          the string to search
 * @param boolean $caseSensitive
 *          default=true
 * @return boolean
 */
function startsWith($haystack, $needle, $caseSensitive = true)
{
  $strpos = $caseSensitive ? strpos : stripos;
  return $needle === "" || $strpos ( $haystack, $needle ) === 0;
}

/**
 * check if a string starts with [letter]:\ example 'c:\\'
 *
 * @param string $drive          
 * @return boolean
 */
function isDriveRoot($drive)
{
  $drive = strtoupper ( "{$drive}" );
  if (strlen ( $drive ) < 3)
    return false;
  return ctype_upper ( $drive [0] ) && $drive [1] == ':' && $drive [2] == '\\';
}

/**
 *
 * @param string $haystack
 *          the string
 * @param string $needle
 *          the string to search
 * @return boolean
 */
function endsWith($haystack, $needle)
{
  return $needle === "" || substr ( $haystack, - strlen ( $needle ) ) === $needle;
}

/**
 *
 * @param string $text          
 * @param string $pattern          
 * @param boolean $ignoreCase
 *          (default=true)
 * @return boolean
 */
function containsStr($text, $pattern, $ignoreCase = true)
{
  $func = $ignoreCase ? stripos : strpos;
  return $func ( $text, $pattern ) !== false;
}

/**
 *
 * @param string $password          
 * @param boolean $weak          
 * @return boolean
 */
function passwordStrengthOk($password, $weak)
{
  if ($weak)
    $pattern = '/^(?=.*[a-zA-Z0-9]).{5,}$/';
  else
    $pattern = '/^(?=.*\d(?=.*\d))(?=.*[a-zA-Z](?=.*[a-zA-Z])).{5,}$/';
  
  return ! preg_match ( $pattern, $password );
}

/**
 *
 * @param string $root          
 * @return SimpleXMLElement
 */
function simplexml_create_doc($root)
{
  return simplexml_load_string ( "<?xml version='1.0' encoding='utf-8'?><$root />" );
}

/**
 *
 * @param SimpleXMLElement $xmlElement          
 * @param array $array          
 * @return SimpleXMLElement
 */
function simplexml_add_array($xmlElement, array $array)
{
  foreach ( $array as $k => $v )
  {
    if (is_numeric ( $k ))
      $k = $xmlElement->getName () . '_' . $k;
    
    $child = null;
    $type = gettype ( $v );
    $couldBeNumer = is_numeric ( $v );
    
    if (is_object ( $v ))
    {
      $type = get_class ( $v );
      $v = ( array ) $v;
    }
    
    if (is_array ( $v ))
      $child = simplexml_add_array ( $xmlElement->addChild ( $k ), $v );
    else
      $child = $xmlElement->addChild ( $k, ( string ) $v );
    
    /*
     * if($child !== null)
     * {
     * $child->addAttribute('type', $type);
     * $child->addAttribute('number', $couldBeNumer?'1':'0');
     * }
     */
  }
  return $xmlElement;
}

/**
 *
 * @param array $array          
 * @param string $root          
 * @return SimpleXMLElement
 */
function xmlSerializeSimple(array $array, $root)
{
  $doc = simplexml_create_doc ( $root );
  return simplexml_add_array ( $doc, $array );
}

/**
 *
 * @return ZtlParameters
 */
function params_ztl()
{
  Yii::import ( 'protected.params.ZtlParameters' );
  return new ZtlParameters ( param ( 'ztl' ) );
}

function getFormat_Date($type = null, $lang = null)
{
  if (empty ( $type ))
    $type = 'php';
  if (empty ( $lang ))
    $lang = Yii::app ()->language;
  return Yii::app ()->params ['dateselect_format'] [$lang] [$type];
}

function getFormat_DayOfTheYear($type = null, $lang = null)
{
  if (empty ( $type ))
    $type = 'php';
  if (empty ( $lang ))
    $lang = Yii::app ()->language;
  return Yii::app ()->params ['dayoftheyearselect_format'] [$lang] [$type];
}

function getFormat_Time($type = null, $lang = null)
{
  if (empty ( $type ))
    $type = 'php';
  if (empty ( $lang ))
    $lang = Yii::app ()->language;
  return Yii::app ()->params ['timeselect_format'] [$lang] [$type];
}

function getFormat_DateTime($type = null, $lang = null)
{
  if (empty ( $type ))
    $type = 'php';
  if (empty ( $lang ))
    $lang = Yii::app ()->language;
  return Yii::app ()->params ['datetimeselect_format'] [$lang] [$type];
}

/**
 * time to string
 *
 * @param mixed $datetime          
 * @return DateTimeEx
 */
function tts($datetime)
{
  return DateHelper::ensureObjectEx ( $datetime );
}

/**
 *
 * @param string $id          
 * @return boolean
 */
function controllerExists($id) // $id is controllerID (eg post,user)
{
  $i = ucfirst ( $id );
  $controllerPath = Yii::app ()->getControllerPath ();
  return file_exists ( $controllerPath . DIRECTORY_SEPARATOR . $i . "Controller.php" ); // returns boolean
}

function array_set_if($array, $true, $key, $value)
{
  if ($true)
    $array [$key] = $value;
  return $array;
}

function createBeautifulString($text)
{
  return ucwords ( str_replace ( "_", " ", $text ) );
}

function createVarName($name)
{
  $varName = "";
  
  foreach ( str_split ( $name ) as $char )
    if (ctype_alpha ( $char ) || ctype_digit ( $char ))
      $varName .= $char;
    elseif ($char == ' ')
      $varName .= '_';
  
  $varName = trim ( $varName );
  while ( containsStr ( $varName, "__" ) )
    $varName = str_replace ( "__", "_", $varName );
  
  return $varName;
}

function createVarNameEx($name)
{
  $name = createVarName ( $name );
  $varName = "";
  foreach ( str_split ( $name ) as $char )
  {
    if (ctype_upper ( $char ) && strlen ( $varName ) > 0)
      $varName .= "_";
    $varName .= $char;
  }
  
  $varName = trim ( $varName );
  while ( containsStr ( $varName, "__" ) )
    $varName = str_replace ( "__", "_", $varName );
  
  return strtolower ( $varName );
}

function createNiceName($name)
{
  $varName = "";
  foreach ( str_split ( $name ) as $char )
  {
    if (ctype_upper ( $char ) && strlen ( $varName ) > 0)
      $varName .= " ";
    $varName .= $char;
  }
  
  $varName = trim ( $varName );
  while ( containsStr ( $varName, "  " ) )
    $varName = str_replace ( "  ", " ", $varName );
  
  return $varName;
}

function switcha($key, $defaultValue, array $switchValues)
{
  if (isset ( $switchValues [$key] ))
    return $switchValues [$key];
  else
    return $defaultValue;
}

function array_translate($array, $category = 'app', $transValues = true, $transKeys = false)
{
  if ($array !== null && is_array ( $array ))
  {
    $transArray = array ();
    foreach ( $array as $key => $value )
    {
      if ($transKeys)
        $key = t ( $key, array (), $category );
      if ($transValues)
        $value = t ( $value, array (), $category );
      $transArray [$key] = $value;
    }
    return $transArray;
  }
  return $array;
}

function prepare_download($filename, $mime = 'application/octet-stream')
{
  header ( 'Content-Description: File Transfer' );
  header ( 'Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1' );
  header ( 'Pragma: public' );
  header ( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' );
  header ( 'Last-Modified: ' . gmdate ( 'D, d M Y H:i:s' ) . ' GMT' );
  if (strpos ( php_sapi_name (), 'cgi' ) === false)
  {
    header ( 'Content-Type: application/force-download' );
    header ( 'Content-Type: application/octet-stream', false );
    header ( 'Content-Type: application/download', false );
    header ( "Content-Type: $mime", false );
  }
  else
  {
    header ( "Content-Type: $mime" );
  }
  header ( 'Content-Disposition: attachment; filename="' . basename ( $filename ) . '"' );
  header ( 'Content-Transfer-Encoding: binary' );
}

/**
 * md5 of md5 of password
 *
 * @param string $password          
 * @return string
 */
function kria_password($password)
{
  return md5 ( md5 ( $password ) );
}

function kv($key, $value = null, array $attrbibutes = array())
{
  $item = array ();
  $item ['key'] = $key;
  $item ['value'] = $value;
  $attrkvs = array ();
  foreach ( $attrbibutes as $k => $v )
    $attrkvs [] = kv ( $k, $v );
  $item ['attributes'] = $attrkvs;
  return array (
      'item' => $item 
  );
}

/**
 * ensure that a value exists at the specified key
 *
 * @param array& $array          
 * @param mixed $key          
 * @param mixed $default          
 */
function array_ensure_value(array &$array, $key, $default)
{
  if (! isset ( $array [$key] ))
    $array [$key] = $value;
}

/**
 *
 * @param unknown $obj          
 * @return array
 */
function array_ensure($obj)
{
  if (! is_array_ex ( $obj ))
    $obj = array ();
  return $obj;
}

/**
 *
 * @param unknown $var          
 * @return string
 */
function getTypeEx($var, $recursiveMax = 1)
{
  if ($var === null)
    return "NULL";
  $type = gettype ( $var );
  if ($type == "object")
    return get_class ( $var );
  else
  {
    if ($type == 'array')
    {
      if ($recursiveMax <= 0)
        return 'array';
      
      $arrtypes = array ();
      foreach ( $var as $varitem )
      {
        $itemtype = getTypeEx ( $varitem, $recursiveMax - 1 );
        $arrtypes [$itemtype] = 0;
      }
      $arrtypes = array_keys ( $arrtypes );
      if (count ( $arrtypes ) == 1)
        return array_first ( $arrtypes ) . "[]";
      else
        return 'array';
    }
    else
    {
      return $type;
    }
  }
}

function obj()
{
  return objex ( func_get_args () );
}

function objex(array $fields = array(), $class = 'stdClass')
{
  $obj = new $class ();
  foreach ( $fields as $key => $value )
    $obj->$key = $value;
  return $obj;
}

/**
 * crea array [$low,$high] del tipo $array[$value]=$value
 *
 * @param unknown $low          
 * @param unknown $high          
 * @param number $step          
 * @return unknown[]
 */
function rangek($low, $high, $step = 1)
{
  $data = array ();
  foreach ( range ( $low, $high, $step ) as $item )
    $data [$item] = $item;
  return $data;
}

/**
 *
 * @param array $from
 *          rgb
 * @param array $to
 *          rgb
 * @param double $rate
 *          from 0.0 to 1.0
 * @return array
 */
function color_gradient(array $from, array $to, $rate)
{
  $from = new CArray ( $from );
  $to = new CArray ( $to );
  
  $interval_r = abs ( $to->r - $from->r );
  $interval_g = abs ( $to->g - $from->g );
  $interval_b = abs ( $to->b - $from->b );
  
  return array (
      'r' => $from->r + $interval_r * $rate,
      'g' => $from->g + $interval_g * $rate,
      'b' => $from->b + $interval_b * $rate 
  );
}

function color_gradient_2($hexstart, $hexend, $steps, $stepIndex = null)
{
  $hexstart = str_replace ( "#", "", $hexstart );
  $hexend = str_replace ( "#", "", $hexend );
  
  $start ['r'] = hexdec ( substr ( $hexstart, 0, 2 ) );
  $start ['g'] = hexdec ( substr ( $hexstart, 2, 2 ) );
  $start ['b'] = hexdec ( substr ( $hexstart, 4, 2 ) );
  
  $end ['r'] = hexdec ( substr ( $hexend, 0, 2 ) );
  $end ['g'] = hexdec ( substr ( $hexend, 2, 2 ) );
  $end ['b'] = hexdec ( substr ( $hexend, 4, 2 ) );
  
  $step ['r'] = ($start ['r'] - $end ['r']) / ($steps - 1);
  $step ['g'] = ($start ['g'] - $end ['g']) / ($steps - 1);
  $step ['b'] = ($start ['b'] - $end ['b']) / ($steps - 1);
  
  $gradient = array ();
  
  if ($stepIndex === null)
    for($i = 0; $i <= $steps; $i ++)
    {
      $rgb = array ();
      $rgb ['r'] = floor ( $start ['r'] - ($step ['r'] * $i) );
      $rgb ['g'] = floor ( $start ['g'] - ($step ['g'] * $i) );
      $rgb ['b'] = floor ( $start ['b'] - ($step ['b'] * $i) );
      
      // $hex ['r'] = sprintf ( '%02x', ($rgb ['r']) );
      // $hex ['g'] = sprintf ( '%02x', ($rgb ['g']) );
      // $hex ['b'] = sprintf ( '%02x', ($rgb ['b']) );
      // $hex = implode ( NULL, $hex );
      
      $hex = rgb2hex ( $rgb );
      
      $gradient [$i] = $hex;
    }
  else
  {
    $rgb = array ();
    $rgb ['r'] = floor ( $start ['r'] - ($step ['r'] * $stepIndex) );
    $rgb ['g'] = floor ( $start ['g'] - ($step ['g'] * $stepIndex) );
    $rgb ['b'] = floor ( $start ['b'] - ($step ['b'] * $stepIndex) );
    
    // $hex ['r'] = sprintf ( '%02x', ($rgb ['r']) );
    // $hex ['g'] = sprintf ( '%02x', ($rgb ['g']) );
    // $hex ['b'] = sprintf ( '%02x', ($rgb ['b']) );
    // $hex = implode ( NULL, $hex );
    
    $hex = rgb2hex ( $rgb );
    
    return $hex;
  }
  
  return $gradient;
}

/**
 *
 * @param string $from
 *          rgb
 * @param string $to
 *          rgb
 * @param double $rate
 *          from 0.0 to 1.0
 * @return string
 */
function color_gradient_html($from, $to, $rate)
{
  return rgb2hex ( color_gradient ( hex2rgb ( $from ), hex2rgb ( $to ), $rate ) );
}

function color_gradient_from_red_to_green_get_all($returnHtml = false)
{
  $red = 255; // i.e. FF
  $green = 0;
  $stepSize = 1; // how many colors do you want?
  $counter = 0;
  $colors = array ();
  while ( $green < 255 )
  {
    $green += $stepSize;
    if ($green > 255)
    {
      $green = 255;
    }
    $colors [] = array (
        'r' => $red,
        'g' => $green,
        'b' => 0 
    );
    // output($red, $green); //assume output is function that takes RGB
  }
  while ( $red > 0 )
  {
    $red -= $stepSize;
    if ($red < 0)
    {
      $red = 0;
    }
    $colors [] = array (
        'r' => $red,
        'g' => $green,
        'b' => 0 
    );
    // $output($red, $green); //assume output is function that takes RGB
  }
  if ($returnHtml)
    $colors = array_map ( function ($rgb)
    {
      return rgb2hex ( $rgb );
    }, $colors );
  return $colors;
}

function color_gradient_from_red_to_green($n, $returnHtml = false)
{
  $n /= 100.0;
  $n = 1.0 - $n;
  $colors = color_gradient_from_red_to_green_get_all ( $returnHtml );
  $colorsCount = count ( $colors );
  $colorIndex = intval ( $colorsCount * $n );
  $colorIndex = keep_in_range ( 0, $colorIndex, $colorsCount - 1 );
  return $colors [$colorIndex];
}

function color_gradient_from_red_to_green_old($n, $returnHtml = false)
{
  $R = (255.0 * $n) / 100.0;
  $G = (255.0 * (100.0 - $n)) / 100.0;
  $B = 0.0;
  $rgb = array (
      'r' => $R,
      'g' => $G,
      'b' => $B 
  );
  if ($returnHtml)
    $rgb = rgb2hex ( $rgb );
  return $rgb;
}

function hex2rgb($hex)
{
  $hex = str_replace ( "#", "", $hex );
  
  if (strlen ( $hex ) == 3)
  {
    $r = hexdec ( substr ( $hex, 0, 1 ) . substr ( $hex, 0, 1 ) );
    $g = hexdec ( substr ( $hex, 1, 1 ) . substr ( $hex, 1, 1 ) );
    $b = hexdec ( substr ( $hex, 2, 1 ) . substr ( $hex, 2, 1 ) );
  }
  else
  {
    $r = hexdec ( substr ( $hex, 0, 2 ) );
    $g = hexdec ( substr ( $hex, 2, 2 ) );
    $b = hexdec ( substr ( $hex, 4, 2 ) );
  }
  $rgb = array (
      'r' => $r,
      'g' => $g,
      'b' => $b 
  );
  // return implode(",", $rgb); // returns the rgb values separated by commas
  return $rgb; // returns an array with the rgb values
}

function rgb2hex(array $rgb)
{
  $hex = "#";
  $hex .= str_pad ( dechex ( intval ( array_get ( $rgb, 'r', 0 ) ) ), 2, "0", STR_PAD_LEFT );
  $hex .= str_pad ( dechex ( intval ( array_get ( $rgb, 'g', 0 ) ) ), 2, "0", STR_PAD_LEFT );
  $hex .= str_pad ( dechex ( intval ( array_get ( $rgb, 'b', 0 ) ) ), 2, "0", STR_PAD_LEFT );
  return $hex; // returns the hex value including the number sign (#)
}

function toString($var)
{
  return "{$var}";
}

function array_get(array $array, $index, $default = null)
{
  if (is_array_ex ( $array, true ))
    if (isset ( $array [$index] ))
      return $array [$index];
  return $default;
}

function array_get_at($array, $pos, $getPair = false, $base0 = true)
{
  $index = $base0 ? 0 : 1;
  foreach ( $array as $key => $value )
  {
    if ($index == $pos)
      return $getPair ? array (
          'key' => $key,
          'value' => $value 
      ) : $value;
    $index ++;
  }
  return null;
}

/**
 *
 * @param array $array          
 * @param func $func
 *          function(v,k,params)
 * @param unknown $params          
 * @return boolean
 */
function true_for_all(array $array, $func, $params = null)
{
  foreach ( $array as $k => $v )
    if (! $func ( $v, $k, $params ))
      return false;
  return true;
}

/**
 *
 * @param class $obj          
 * @param string $public
 *          default=true
 * @param string $private
 *          default=false
 * @param string $resolveGet
 *          default=true
 * @return string[]
 */
function get_object_readable($obj, $public = true, $private = false, $resolveGet = true)
{
  $class = new ReflectionClass ( $obj );
  $readables = array ();
  foreach ( $class->getProperties () as $prop )
  {
    /** @var ReflectionProperty $prop */
    if (($prop->isPublic () && $public) || (! $prop->isPublic () && $private))
      $readables [] = $prop->getName ();
  }
  foreach ( $class->getMethods () as $meth )
  {
    /** @var ReflectionMethod $meth */
    if (($meth->isPublic () && $public) || (! $meth->isPublic () && $private))
      if (count ( $meth->getParameters () ) == 0 || true_for_all ( $meth->getParameters (), function (ReflectionParameter $v)
      {
        return $v->isDefaultValueAvailable ();
      } ))
        if ($resolveGet)
          $readables [] = startsWithGet ( $meth->getName (), 'get', false, 0, $meth->getName () );
        else
          $readables [] = $meth->getName ();
  }
  return $readables;
}

function get_object_var_doc($object, $var)
{
  $class = new ReflectionClass ( $object );
  $descriptions = array ();
  if ($class->hasProperty ( $var ))
    $descriptions [] = $class->getProperty ( $var )
      ->getDocComment ();
  if ($class->hasMethod ( "get{$var}" ))
    $descriptions [] = $class->getMethod ( "get{$var}" )
      ->getDocComment ();
  if ($class->hasMethod ( "set{$var}" ))
    $descriptions [] = $class->getMethod ( "set{$var}" )
      ->getDocComment ();
  return implode ( PHP_EOL, $descriptions );
}

function array_remove_values(array $array, $value)
{
  return array_remove ( $array, function ($key, $value, $args)
  {
    if (is_array ( $args ))
      return array_value_exists ( $args, $value );
    else
      return $value == $args;
  }, $value );
}

function array_remove_at($array, $index, $base0 = true)
{
  $item = array_get_at ( $array, $index, true, $base0 );
  if ($item === null)
    return $array;
  unset ( $array [$item ['key']] );
  return $array;
}

function array_to_list($var, $prefix = '', $separator = "\\")
{
  $list = array ();
  
  if ($var !== null)
  {
    if (is_array ( $var ))
    {
      if (! empty ( $prefix ))
        $prefix = $prefix . $separator;
      foreach ( $var as $k => $v )
      {
        $result = array_to_list ( $v, $prefix . $k );
        foreach ( $result as $rk => $rv )
          $list [$rk] = $rv;
      }
    }
    else
    {
      $list [$prefix] = var_export ( $var, true );
    }
  }
  
  return $list;
}
