| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707 | 
							- <?php
 -                                                                   
 - # ============================================================================ #
 - 
 - /**
 -  *  L I M O N A D E
 -  * 
 -  *  a PHP micro framework.
 -  * 
 -  *  For more informations: {@link https://github.com/sofadesign/limonade}
 -  *  
 -  *  @author Fabrice Luraine
 -  *  @copyright Copyright (c) 2009 Fabrice Luraine
 -  *  @license http://opensource.org/licenses/mit-license.php The MIT License
 -  *  @package limonade
 -  */
 - 
 - #   -----------------------------------------------------------------------    #
 - #    Copyright (c) 2009 Fabrice Luraine                                        #
 - #                                                                              #
 - #    Permission is hereby granted, free of charge, to any person               #
 - #    obtaining a copy of this software and associated documentation            #
 - #    files (the "Software"), to deal in the Software without                   #
 - #    restriction, including without limitation the rights to use,              #
 - #    copy, modify, merge, publish, distribute, sublicense, and/or sell         #
 - #    copies of the Software, and to permit persons to whom the                 #
 - #    Software is furnished to do so, subject to the following                  #
 - #    conditions:                                                               #
 - #                                                                              #
 - #    The above copyright notice and this permission notice shall be            #
 - #    included in all copies or substantial portions of the Software.           #
 - #                                                                              #
 - #    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,           #
 - #    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES           #
 - #    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                  #
 - #    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT               #
 - #    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,              #
 - #    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING              #
 - #    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR             #
 - #    OTHER DEALINGS IN THE SOFTWARE.                                           #
 - # ============================================================================ # 
 - 
 - 
 - 
 - 
 - 
 - 
 - 
 - 
 - # ============================================================================ #
 - #    0. PREPARE                                                                #
 - # ============================================================================ #
 - 
 - ## CONSTANTS __________________________________________________________________
 - /**
 -  * Limonade version
 -  */
 - define('LIMONADE',              '0.5.0');
 - define('LIM_NAME',              'Un grand cru qui sait se faire attendre');
 - define('LIM_START_MICROTIME',   microtime(true));
 - define('LIM_SESSION_NAME',      'LIMONADE'.str_replace('.','x',LIMONADE));
 - define('LIM_SESSION_FLASH_KEY', '_lim_flash_messages');
 - if(function_exists('memory_get_usage'))
 - 	define('LIM_START_MEMORY',      memory_get_usage());
 - define('E_LIM_HTTP',            32768);
 - define('E_LIM_PHP',             65536);
 - define('E_LIM_DEPRECATED',      35000);
 - define('NOT_FOUND',             404);
 - define('SERVER_ERROR',          500);
 - define('ENV_PRODUCTION',        10);
 - define('ENV_DEVELOPMENT',       100);
 - define('X-SENDFILE',            10);
 - define('X-LIGHTTPD-SEND-FILE',  20);
 - 
 - # for PHP 5.3.0 <
 - if(!defined('E_DEPRECATED'))         define('E_DEPRECATED',        8192);
 - if(!defined('E_USER_DEPRECATED'))    define('E_USER_DEPRECATED',   16384);
 - # for PHP 5.2.0 <
 - if (!defined('E_RECOVERABLE_ERROR')) define('E_RECOVERABLE_ERROR', 4096);
 - 
 - 
 - ## SETTING BASIC SECURITY _____________________________________________________
 - 
 - # A. Unsets all global variables set from a superglobal array
 - 
 - /**
 -  * @access private
 -  * @return void
 -  */
 - function unregister_globals()
 - {
 -   $args = func_get_args();
 -   foreach($args as $k => $v)
 -     if(array_key_exists($k, $GLOBALS)) unset($GLOBALS[$k]);
 - }
 - 
 - if(ini_get('register_globals'))
 - {
 -   unregister_globals( '_POST', '_GET', '_COOKIE', '_REQUEST', '_SERVER', 
 -                       '_ENV', '_FILES');
 -   ini_set('register_globals', 0);
 - }
 - 
 - # B. removing magic quotes
 - 
 - /**
 -  * @access private
 -  * @param string $array 
 -  * @return array
 -  */
 - function remove_magic_quotes($array)
 - {
 -   foreach ($array as $k => $v)
 -     $array[$k] = is_array($v) ? remove_magic_quotes($v) : stripslashes($v);
 -   return $array;
 - }
 - 
 - if (get_magic_quotes_gpc())
 - {
 -   $_GET    = remove_magic_quotes($_GET);
 -   $_POST   = remove_magic_quotes($_POST);
 -   $_COOKIE = remove_magic_quotes($_COOKIE);
 -   ini_set('magic_quotes_gpc', 0);
 - }
 - 
 - if(function_exists('set_magic_quotes_runtime') && get_magic_quotes_runtime()) set_magic_quotes_runtime(false);
 - 
 - # C. Disable error display
 - #    by default, no error reporting; it will be switched on later in run().
 - #    ini_set('display_errors', 1); must be called explicitly in app file
 - #    if you want to show errors before running app
 - ini_set('display_errors', 0);
 - 
 - ## SETTING INTERNAL ROUTES _____________________________________________________
 - 
 - dispatch(array("/_lim_css/*.css", array('_lim_css_filename')), 'render_limonade_css');
 -   /**
 -    * Internal controller that responds to route /_lim_css/*.css
 -    *
 -    * @access private
 -    * @return string
 -    */
 -   function render_limonade_css()
 -   {
 -     option('views_dir', file_path(option('limonade_public_dir'), 'css'));
 -     $fpath = file_path(params('_lim_css_filename').".css");
 -     return css($fpath, null); // with no layout
 -   }
 - 
 - dispatch(array("/_lim_public/**", array('_lim_public_file')), 'render_limonade_file');
 -   /**
 -    * Internal controller that responds to route /_lim_public/**
 -    *
 -    * @access private
 -    * @return void
 -    */
 -   function render_limonade_file()
 -   {
 -     $fpath = file_path(option('limonade_public_dir'), params('_lim_public_file'));
 -     return render_file($fpath, true);
 -   }
 - 
 - 
 - 
 - 
 -                                      # # #
 - 
 - 
 - 
 - 
 - # ============================================================================ #
 - #    1. BASE                                                                   #
 - # ============================================================================ #
 -  
 - ## ABSTRACTS ___________________________________________________________________
 - 
 - # Abstract methods that might be redefined by user:
 - #
 - # - function configure(){}
 - # - function initialize(){}
 - # - function autoload_controller($callback){}
 - # - function before($route){}
 - # - function after($output, $route){}
 - # - function not_found($errno, $errstr, $errfile=null, $errline=null){}
 - # - function server_error($errno, $errstr, $errfile=null, $errline=null){}
 - # - function route_missing($request_method, $request_uri){}
 - # - function before_exit(){}
 - # - function before_render($content_or_func, $layout, $locals, $view_path){}
 - # - function autorender($route){}
 - # - function before_sending_header($header){}
 - #
 - # See abstract.php for more details.
 - 
 - 
 - ## MAIN PUBLIC FUNCTIONS _______________________________________________________
 - 
 - /**
 -  * Set and returns options values
 -  * 
 -  * If multiple values are provided, set $name option with an array of those values.
 -  * If there is only one value, set $name option with the provided $values
 -  *
 -  * @param string $name 
 -  * @param mixed  $values,... 
 -  * @return mixed option value for $name if $name argument is provided, else return all options
 -  */
 - function option($name = null, $values = null)
 - {
 -   static $options = array();
 -   $args = func_get_args();
 -   $name = array_shift($args);
 -   if(is_null($name)) return $options;
 -   if(!empty($args))
 -   {
 -     $options[$name] = count($args) > 1 ? $args : $args[0];
 -   }
 -   if(array_key_exists($name, $options)) return $options[$name];
 -   return;
 - }
 - 
 - /**
 -  * Set and returns params
 -  * 
 -  * Depending on provided arguments:
 -  * 
 -  *  * Reset params if first argument is null
 -  * 
 -  *  * If first argument is an array, merge it with current params
 -  * 
 -  *  * If there is a second argument $value, set param $name (first argument) with $value
 -  * <code>
 -  *  params('name', 'Doe') // set 'name' => 'Doe'
 -  * </code>
 -  *  * If there is more than 2 arguments, set param $name (first argument) value with
 -  *    an array of next arguments
 -  * <code>
 -  *  params('months', 'jan', 'feb', 'mar') // set 'month' => array('months', 'jan', 'feb', 'mar')
 -  * </code>
 -  * 
 -  * @param mixed $name_or_array_or_null could be null || array of params || name of a param (optional)
 -  * @param mixed $value,... for the $name param (optional)
 -  * @return mixed all params, or one if a first argument $name is provided
 -  */
 - function params($name_or_array_or_null = null, $value = null)
 - {
 -   static $params = array();
 -   $args = func_get_args();
 - 
 -   if(func_num_args() > 0)
 -   {
 -     $name = array_shift($args);
 -     if(is_null($name))
 -     {
 -       # Reset params
 -       $params = array();
 -       return $params;
 -     }
 -     if(is_array($name))
 -     {
 -       $params = array_merge($params, $name);
 -       return $params;
 -     }
 -     $nargs = count($args);
 -     if($nargs > 0)
 -     {
 -       $value = $nargs > 1 ? $args : $args[0];
 -       $params[$name] = $value;
 -     }
 -     return array_key_exists($name,$params) ? $params[$name] : null;
 -   }
 - 
 -   return $params;
 - }
 - 
 - /**
 -  * Set and returns template variables
 -  * 
 -  * If multiple values are provided, set $name variable with an array of those values.
 -  * If there is only one value, set $name variable with the provided $values
 -  *
 -  * @param string $name 
 -  * @param mixed  $values,... 
 -  * @return mixed variable value for $name if $name argument is provided, else return all variables
 -  */
 - function set($name = null, $values = null)
 - {
 -   static $vars = array();
 -   $args = func_get_args();
 -   $name = array_shift($args);
 -   if(is_null($name)) return $vars;
 -   if(!empty($args))
 -   {
 -     $vars[$name] = count($args) > 1 ? $args : $args[0];
 -   }
 -   if(array_key_exists($name, $vars)) return $vars[$name];
 -   return $vars;
 - }
 - 
 - /**
 -  * Sets a template variable with a value or a default value if value is empty
 -  *
 -  * @param string $name 
 -  * @param string $value 
 -  * @param string $default 
 -  * @return mixed setted value
 -  */
 - function set_or_default($name, $value, $default)
 - {
 -   return set($name, value_or_default($value, $default));
 - }
 - 
 - /**
 -  * Running application
 -  *
 -  * @param string $env 
 -  * @return void
 -  */
 - function run($env = null)
 - {
 -   if(is_null($env)) $env = env();
 -    
 -   # 0. Set default configuration
 -   $root_dir  = dirname(app_file());
 -   $lim_dir   = dirname(__FILE__);
 -   $base_path = dirname(file_path($env['SERVER']['SCRIPT_NAME']));
 -   $base_file = basename($env['SERVER']['SCRIPT_NAME']);
 -   $base_uri  = file_path($base_path, (($base_file == 'index.php') ? '?' : $base_file.'?'));
 -   
 -   option('root_dir',           $root_dir);
 -   option('limonade_dir',       file_path($lim_dir));
 -   option('limonade_views_dir', file_path($lim_dir, 'limonade', 'views'));
 -   option('limonade_public_dir',file_path($lim_dir, 'limonade', 'public'));
 -   option('public_dir',         file_path($root_dir, 'public'));
 -   option('views_dir',          file_path($root_dir, 'views'));
 -   option('controllers_dir',    file_path($root_dir, 'controllers'));
 -   option('lib_dir',            file_path($root_dir, 'lib'));
 -   option('error_views_dir',    option('limonade_views_dir'));
 -   option('base_path',          $base_path);
 -   option('base_uri',           $base_uri); // set it manually if you use url_rewriting
 -   option('env',                ENV_PRODUCTION);
 -   option('debug',              true);
 -   option('session',            LIM_SESSION_NAME); // true, false or the name of your session
 -   option('encoding',           'utf-8');
 -   option('signature',          LIM_NAME); // X-Limonade header value or false to hide it
 -   option('gzip',               false);
 -   option('x-sendfile',         0); // 0: disabled, 
 -                                    // X-SENDFILE: for Apache and Lighttpd v. >= 1.5,
 -                                    // X-LIGHTTPD-SEND-FILE: for Apache and Lighttpd v. < 1.5
 - 
 - 
 -   # 1. Set handlers
 -   # 1.1 Set error handling
 -   ini_set('display_errors', 1);
 -   set_error_handler('error_handler_dispatcher', E_ALL ^ E_NOTICE);
 -   
 -   # 1.2 Register shutdown function
 -   register_shutdown_function('stop_and_exit');
 - 
 -   # 2. Set user configuration
 -   call_if_exists('configure');
 -   
 -   # 2.1 Set gzip compression if defined
 -   if(is_bool(option('gzip')) && option('gzip'))
 -   {
 -     ini_set('zlib.output_compression', '1');
 -   }
 -   
 -   # 2.2 Set X-Limonade header
 -   if($signature = option('signature')) send_header("X-Limonade: $signature");
 - 
 -   # 3. Loading libs
 -   require_once_dir(option('lib_dir'));
 -   fallbacks_for_not_implemented_functions();
 - 
 -   # 4. Starting session
 -   if(!defined('SID') && option('session'))
 -   {
 -     if(!is_bool(option('session'))) session_name(option('session'));
 -     if(!session_start()) trigger_error("An error occured while trying to start the session", E_USER_WARNING);
 -   }
 - 
 -   # 5. Set some default methods if needed
 -   if(!function_exists('after'))
 -   {
 -     function after($output)
 -     {
 -       return $output;
 -     }
 -   }
 -   if(!function_exists('route_missing'))
 -   {
 -     function route_missing($request_method, $request_uri)
 -     {
 -       halt(NOT_FOUND, "($request_method) $request_uri");
 -     }
 -   }
 - 
 -   call_if_exists('initialize');
 - 
 -   # 6. Check request
 -   if($rm = request_method($env))
 -   {
 -     if(request_is_head($env)) ob_start(); // then no output
 - 
 -     if(!request_method_is_allowed($rm))
 -       halt(HTTP_NOT_IMPLEMENTED, "The requested method <code>'$rm'</code> is not implemented");
 - 
 -     # 6.1 Check matching route
 -     if($route = route_find($rm, request_uri($env)))
 -     {
 -       params($route['params']);
 - 
 -       # 6.2 Load controllers dir
 -       if(!function_exists('autoload_controller'))
 -       {
 -         function autoload_controller($callback)
 -         {
 -           require_once_dir(option('controllers_dir'));
 -         }
 -       }
 -       autoload_controller($route['callback']);
 - 
 -       if(is_callable($route['callback']))
 -       {
 -         # 6.3 Call before function
 -         call_if_exists('before', $route);
 - 
 -         # 6.4 Call matching controller function and output result
 -         $output = call_user_func_array($route['callback'], array_values($route['params']));
 -         if(is_null($output)) $output = call_if_exists('autorender', $route);
 -         echo after(error_notices_render() . $output, $route);
 -       }
 -       else halt(SERVER_ERROR, "Routing error: undefined function '{$route['callback']}'", $route);      
 -     }
 -     else route_missing($rm, request_uri($env));
 - 
 -   }
 -   else halt(HTTP_NOT_IMPLEMENTED, "The requested method <code>'$rm'</code> is not implemented");
 - }
 - 
 - /**
 -  * Stop and exit limonade application
 -  *
 -  * @access private 
 -  * @param boolean exit or not
 -  * @return void
 -  */
 - function stop_and_exit($exit = true)
 - {
 -   call_if_exists('before_exit', $exit);
 -   $headers = headers_list();
 -   if(request_is_head())
 -   { 
 -      ob_end_clean();
 -   } else {
 -     $flash_sweep = true;
 -     foreach($headers as $header)
 -     {
 -       // If a Content-Type header exists, flash_sweep only if is text/html
 -       // Else if there's no Content-Type header, flash_sweep by default
 -       if(stripos($header, 'Content-Type:') === 0)
 -       {
 -         $flash_sweep = stripos($header, 'Content-Type: text/html') === 0;
 -         break;
 -       }
 -     }
 -     if($flash_sweep) flash_sweep();
 -   }
 -   if(defined('SID')) session_write_close();
 -   if($exit) exit;
 - }
 - 
 - /**
 -  * Returns limonade environment variables:
 -  *
 -  * 'SERVER', 'FILES', 'REQUEST', 'SESSION', 'ENV', 'COOKIE', 
 -  * 'GET', 'POST', 'PUT', 'DELETE', 'PATCH'
 -  * 
 -  * If a null argument is passed, reset and rebuild environment
 -  *
 -  * @param null @reset reset and rebuild environment
 -  * @return array
 -  */
 - function env($reset = null)
 - {
 -   static $env = array();
 -   if(func_num_args() > 0)
 -   {
 -     $args = func_get_args();
 -     if(is_null($args[0])) $env = array();
 -   }
 - 
 -   if(empty($env))
 -   {
 -     if(empty($GLOBALS['_SERVER']))
 -     {
 -       // Fixing empty $GLOBALS['_SERVER'] bug 
 -       // http://sofadesign.lighthouseapp.com/projects/29612-limonade/tickets/29-env-is-empty
 -       $GLOBALS['_SERVER']  =& $_SERVER;
 -       $GLOBALS['_FILES']   =& $_FILES;
 -       $GLOBALS['_REQUEST'] =& $_REQUEST;
 -       $GLOBALS['_SESSION'] =& $_SESSION;
 -       $GLOBALS['_ENV']     =& $_ENV;
 -       $GLOBALS['_COOKIE']  =& $_COOKIE;
 -     }
 - 
 -     $glo_names = array('SERVER', 'FILES', 'REQUEST', 'SESSION', 'ENV', 'COOKIE');
 - 
 -     $vars = array_merge($glo_names, request_methods());
 -     foreach($vars as $var)
 -     {
 -       $varname = "_$var";
 -       if(!array_key_exists($varname, $GLOBALS)) $GLOBALS[$varname] = array();
 -       $env[$var] =& $GLOBALS[$varname];
 -     }
 - 
 -     $method = request_method($env);
 - 
 -     $varname = "_$method";
 -     if ((isset($_SERVER['CONTENT_TYPE'])) && (strpos($_SERVER['CONTENT_TYPE'], 'application/json') === 0))
 -     {
 -       // handle PUT/POST requests which have JSON in request body
 -       $GLOBALS[$varname] = json_decode(file_get_contents('php://input'), true);
 -     }
 -     elseif($method == 'PUT' || $method == 'DELETE')
 -     {
 -       if(array_key_exists('_method', $_POST) && $_POST['_method'] == $method)
 -       {
 -         foreach($_POST as $k => $v)
 -         {
 -           if($k == "_method") continue;
 -           $GLOBALS[$varname][$k] = $v;
 -         }
 -       }
 -       else
 -       {
 -         parse_str(file_get_contents('php://input'), $GLOBALS[$varname]);
 -       }
 -     }
 -   }
 -   return $env;
 - }
 - 
 - /**
 -  * Returns application root file path
 -  *
 -  * @return string
 -  */
 - function app_file()
 - {
 -   static $file;
 -   if(empty($file))
 -   {
 -     $debug_backtrace = debug_backtrace();
 -     $stacktrace = array_pop($debug_backtrace);
 -     $file = $stacktrace['file'];
 -   }
 -   return file_path($file);
 - }
 - 
 - 
 - 
 - 
 -                                      # # #
 - 
 - 
 - 
 - 
 - # ============================================================================ #
 - #    2. ERROR                                                                  #
 - # ============================================================================ #
 -  
 - /**
 -  * Associate a function with error code(s) and return all associations
 -  *
 -  * @param string $errno 
 -  * @param string $function 
 -  * @return array
 -  */
 - function error($errno = null, $function = null)
 - {
 -   static $errors = array();
 -   if(func_num_args() > 0)
 -   {
 -     $errors[] = array('errno'=>$errno, 'function'=> $function);
 -   }
 -   return $errors;
 - }
 - 
 - /**
 -  * Raise an error, passing a given error number and an optional message,
 -  * then exit.
 -  * Error number should be a HTTP status code or a php user error (E_USER...)
 -  * $errno and $msg arguments can be passsed in any order
 -  * If no arguments are passed, default $errno is SERVER_ERROR (500)
 -  *
 -  * @param int,string $errno Error number or message string
 -  * @param string,string $msg Message string or error number
 -  * @param mixed $debug_args extra data provided for debugging
 -  * @return void
 -  */
 - function halt($errno = SERVER_ERROR, $msg = '', $debug_args = null)
 - {
 -   $args = func_get_args();
 -   $error = array_shift($args);
 - 
 -   # switch $errno and $msg args
 -   # TODO cleanup / refactoring
 -   if(is_string($errno))
 -   {
 -    $msg = $errno;
 -    $oldmsg = array_shift($args);
 -    $errno = empty($oldmsg) ? SERVER_ERROR : $oldmsg;
 -   }
 -   else if(!empty($args)) $msg = array_shift($args);
 - 
 -   if(empty($msg) && $errno == NOT_FOUND) $msg = request_uri();
 -   if(empty($msg)) $msg = "";
 -   if(!empty($args)) $debug_args = $args;
 -   set('_lim_err_debug_args', $debug_args);
 - 
 -   error_handler_dispatcher($errno, $msg, null, null);
 - 
 - }
 - 
 - /**
 -  * Internal error handler dispatcher
 -  * Find and call matching error handler and exit
 -  * If no match found, call default error handler
 -  *
 -  * @access private
 -  * @param int $errno 
 -  * @param string $errstr 
 -  * @param string $errfile 
 -  * @param string $errline 
 -  * @return void
 -  */
 - function error_handler_dispatcher($errno, $errstr, $errfile, $errline)
 - {
 -   $back_trace = debug_backtrace();
 -   while($trace = array_shift($back_trace))
 -   {
 -     if($trace['function'] == 'halt')
 -     {
 -       $errfile = $trace['file'];
 -       $errline = $trace['line'];
 -       break;
 -     }
 -   }  
 - 
 -   # Notices and warning won't halt execution
 -   if(error_wont_halt_app($errno))
 -   {
 -     error_notice($errno, $errstr, $errfile, $errline);
 -   	return;
 -   }
 -   else
 -   {
 -     # Other errors will stop application
 -     static $handlers = array();
 -     if(empty($handlers))
 -     {
 -       error(E_LIM_PHP, 'error_default_handler');
 -       $handlers = error();
 -     }
 -     
 -     $is_http_err = http_response_status_is_valid($errno);
 -     while($handler = array_shift($handlers))
 -     {
 -       $e = is_array($handler['errno']) ? $handler['errno'] : array($handler['errno']);
 -       while($ee = array_shift($e))
 -       {
 -         if($ee == $errno || $ee == E_LIM_PHP || ($ee == E_LIM_HTTP && $is_http_err))
 -         {
 -           echo call_if_exists($handler['function'], $errno, $errstr, $errfile, $errline);
 -           exit;
 -         }
 -       }
 -     }
 -   }
 - }
 - 
 - 
 - /**
 -  * Default error handler
 -  *
 -  * @param string $errno 
 -  * @param string $errstr 
 -  * @param string $errfile 
 -  * @param string $errline 
 -  * @return string error output
 -  */
 - function error_default_handler($errno, $errstr, $errfile, $errline)
 - {
 -   $is_http_err = http_response_status_is_valid($errno);
 -   $http_error_code = $is_http_err ? $errno : SERVER_ERROR;
 - 
 -   status($http_error_code);
 - 
 -   return $http_error_code == NOT_FOUND ?
 -             error_not_found_output($errno, $errstr, $errfile, $errline) :
 -             error_server_error_output($errno, $errstr, $errfile, $errline);                    
 - }
 - 
 - /**
 -  * Returns not found error output
 -  *
 -  * @access private
 -  * @param string $msg 
 -  * @return string
 -  */
 - function error_not_found_output($errno, $errstr, $errfile, $errline)
 - {
 -   if(!function_exists('not_found'))
 -   {
 -     /**
 -      * Default not found error output
 -      *
 -      * @param string $errno 
 -      * @param string $errstr 
 -      * @param string $errfile 
 -      * @param string $errline 
 -      * @return string
 -      */
 -     function not_found($errno, $errstr, $errfile=null, $errline=null)
 -     {
 -       option('views_dir', option('error_views_dir'));
 -       $msg = h(rawurldecode($errstr));
 -       return html("<h1>Page not found:</h1><p><code>{$msg}</code></p>", error_layout());
 -     }
 -   }
 -   return not_found($errno, $errstr, $errfile, $errline);
 - }
 - 
 - /**
 -  * Returns server error output
 -  *
 -  * @access private
 -  * @param int $errno 
 -  * @param string $errstr 
 -  * @param string $errfile 
 -  * @param string $errline 
 -  * @return string
 -  */
 - function error_server_error_output($errno, $errstr, $errfile, $errline)
 - {
 -   if(!function_exists('server_error'))
 -   {
 -     /**
 -      * Default server error output
 -      *
 -      * @param string $errno 
 -      * @param string $errstr 
 -      * @param string $errfile 
 -      * @param string $errline 
 -      * @return string
 -      */
 -     function server_error($errno, $errstr, $errfile=null, $errline=null)
 -     {
 -       $is_http_error = http_response_status_is_valid($errno);
 -       $args = compact('errno', 'errstr', 'errfile', 'errline', 'is_http_error');
 -       option('views_dir', option('limonade_views_dir'));
 -       $html = render('error.html.php', null, $args);	
 -       option('views_dir', option('error_views_dir'));
 -       return html($html, error_layout(), $args);
 -     }
 -   }
 -   return server_error($errno, $errstr, $errfile, $errline);
 - }
 - 
 - /**
 -  * Set and returns error output layout
 -  *
 -  * @param string $layout 
 -  * @return string
 -  */
 - function error_layout($layout = false)
 - {
 -   static $o_layout = 'default_layout.php';
 -   if($layout !== false)
 -   {
 -     option('error_views_dir', option('views_dir'));
 -     $o_layout = $layout;
 -   }
 -   return $o_layout;
 - }
 - 
 - 
 - /**
 -  * Set a notice if arguments are provided
 -  * Returns all stored notices.
 -  * If $errno argument is null, reset the notices array
 -  *
 -  * @access private
 -  * @param string, null $str 
 -  * @return array
 -  */
 - function error_notice($errno = false, $errstr = null, $errfile = null, $errline = null)
 - {
 -   static $notices = array();
 -   if($errno) $notices[] = compact('errno', 'errstr', 'errfile', 'errline');
 -   else if(is_null($errno)) $notices = array();
 -   return $notices;
 - }
 - 
 - /**
 -  * Returns notices output rendering and reset notices
 -  *
 -  * @return string
 -  */
 - function error_notices_render()
 - {
 -   if(option('debug') && option('env') > ENV_PRODUCTION)
 -   {
 -     $notices = error_notice();
 -     error_notice(null); // reset notices
 -     $c_view_dir = option('views_dir'); // keep for restore after render
 -     option('views_dir', option('limonade_views_dir'));
 -     $o = render('_notices.html.php', null, array('notices' => $notices));
 -     option('views_dir', $c_view_dir); // restore current views dir
 - 
 -     return $o;
 -   }
 - }
 - 
 - /**
 -  * Checks if an error is will halt application execution. 
 -  * Notices and warnings will not.
 -  *
 -  * @access private
 -  * @param string $num error code number
 -  * @return boolean
 -  */
 - function error_wont_halt_app($num)
 - {
 -   return $num == E_NOTICE ||
 -          $num == E_WARNING ||
 -          $num == E_CORE_WARNING ||
 -          $num == E_COMPILE_WARNING ||
 -          $num == E_USER_WARNING ||
 -          $num == E_USER_NOTICE ||
 -          $num == E_DEPRECATED ||
 -          $num == E_USER_DEPRECATED ||
 -          $num == E_LIM_DEPRECATED;
 - }
 - 
 - 
 - 
 - /**
 -  * return error code name for a given code num, or return all errors names
 -  *
 -  * @param string $num 
 -  * @return mixed
 -  */
 - function error_type($num = null)
 - {
 -   $types = array (
 -               E_ERROR              => 'ERROR',
 -               E_WARNING            => 'WARNING',
 -               E_PARSE              => 'PARSING ERROR',
 -               E_NOTICE             => 'NOTICE',
 -               E_CORE_ERROR         => 'CORE ERROR',
 -               E_CORE_WARNING       => 'CORE WARNING',
 -               E_COMPILE_ERROR      => 'COMPILE ERROR',
 -               E_COMPILE_WARNING    => 'COMPILE WARNING',
 -               E_USER_ERROR         => 'USER ERROR',
 -               E_USER_WARNING       => 'USER WARNING',
 -               E_USER_NOTICE        => 'USER NOTICE',
 -               E_STRICT             => 'STRICT NOTICE',
 -               E_RECOVERABLE_ERROR  => 'RECOVERABLE ERROR',
 -               E_DEPRECATED         => 'DEPRECATED WARNING',
 -               E_USER_DEPRECATED    => 'USER DEPRECATED WARNING',
 -               E_LIM_DEPRECATED     => 'LIMONADE DEPRECATED WARNING'
 -               );
 -   return is_null($num) ? $types : $types[$num];
 - }
 - 
 - /**
 -  * Returns http response status for a given error number
 -  *
 -  * @param string $errno 
 -  * @return int
 -  */
 - function error_http_status($errno)
 - {
 -   $code = http_response_status_is_valid($errno) ? $errno : SERVER_ERROR;
 -   return http_response_status($code);
 - }
 - 
 -                                      # # #
 - 
 - 
 - 
 - 
 - # ============================================================================ #
 - #    3. REQUEST                                                                #
 - # ============================================================================ #
 -  
 - /**
 -  * Returns current request method for a given environment or current one
 -  *
 -  * @param string $env 
 -  * @return string
 -  */
 - function request_method($env = null)
 - {
 -   if(is_null($env)) $env = env();
 -   $m = array_key_exists('REQUEST_METHOD', $env['SERVER']) ? $env['SERVER']['REQUEST_METHOD'] : null;
 -   if($m == "POST" && array_key_exists('_method', $env['POST'])) 
 -     $m = strtoupper($env['POST']['_method']);
 -   if(!in_array(strtoupper($m), request_methods()))
 -   {
 -     trigger_error("'$m' request method is unknown or unavailable.", E_USER_WARNING);
 -     $m = false;
 -   }
 -   return $m;
 - }
 - 
 - /**
 -  * Checks if a request method or current one is allowed
 -  *
 -  * @param string $m 
 -  * @return bool
 -  */
 - function request_method_is_allowed($m = null)
 - {
 -   if(is_null($m)) $m = request_method();
 -   return in_array(strtoupper($m), request_methods());
 - }
 - 
 - /**
 -  * Checks if request method is GET
 -  *
 -  * @param string $env 
 -  * @return bool
 -  */
 - function request_is_get($env = null)
 - {
 -   return request_method($env) == "GET";
 - }
 - 
 - /**
 -  * Checks if request method is POST
 -  *
 -  * @param string $env 
 -  * @return bool
 -  */
 - function request_is_post($env = null)
 - {
 -   return request_method($env) == "POST";
 - }
 - 
 - /**
 -  * Checks if request method is PUT
 -  *
 -  * @param string $env 
 -  * @return bool
 -  */
 - function request_is_put($env = null)
 - {
 -   return request_method($env) == "PUT";
 - }
 - 
 - /**
 -  * Checks if request method is DELETE
 -  *
 -  * @param string $env 
 -  * @return bool
 -  */
 - function request_is_delete($env = null)
 - {
 -   return request_method($env) == "DELETE";
 - }
 - 
 - /**
 -  * Checks if request method is HEAD
 -  *
 -  * @param string $env 
 -  * @return bool
 -  */
 - function request_is_head($env = null)
 - {
 -   return request_method($env) == "HEAD";
 - }
 - 
 - /**
 -  * Checks if request method is PATCH
 -  *
 -  * @param string $env
 -  * @return bool
 -  */
 - function request_is_patch($env = null)
 - {
 -   return request_method($env) == "PATCH";
 - }
 - 
 - /**
 -  * Returns allowed request methods
 -  *
 -  * @return array
 -  */
 - function request_methods()
 - {
 -   return array("GET","POST","PUT","DELETE","HEAD","PATCH");
 - }
 - 
 - /**
 -  * Returns current request uri (the path that will be compared with routes)
 -  * 
 -  * (Inspired from codeigniter URI::_fetch_uri_string method)
 -  *
 -  * @return string
 -  */
 - function request_uri($env = null)
 - {
 -   static $uri = null;
 -   if(is_null($env))
 -   {
 -     if(!is_null($uri)) return $uri;
 -     $env = env();
 -   }
 - 
 -   if(array_key_exists('uri', $env['GET']))
 -   {
 -     $uri = $env['GET']['uri'];
 -   }
 -   else if(array_key_exists('u', $env['GET']))
 -   {
 -     $uri = $env['GET']['u'];
 -   }
 -   // bug: dot are converted to _... so we can't use it...
 -   // else if (count($env['GET']) == 1 && trim(key($env['GET']), '/') != '')
 -   // {
 -   //  $uri = key($env['GET']);
 -   // }
 -   else
 -   {
 -     $app_file = app_file();
 -     $path_info = isset($env['SERVER']['PATH_INFO']) ? $env['SERVER']['PATH_INFO'] : @getenv('PATH_INFO');
 -     $query_string =  isset($env['SERVER']['QUERY_STRING']) ? $env['SERVER']['QUERY_STRING'] : @getenv('QUERY_STRING');
 - 
 -     // Is there a PATH_INFO variable?
 -     // Note: some servers seem to have trouble with getenv() so we'll test it two ways
 -     if (trim($path_info, '/') != '' && $path_info != "/".$app_file)
 -     {
 -       if(strpos($path_info, '&') !== 0)
 -       {
 -         # exclude GET params
 -         $params = explode('&', $path_info);
 -         $path_info = array_shift($params);
 -         # populate $_GET
 -         foreach($params as $param)
 -         {
 -           if(strpos($param, '=') > 0)
 -           {
 -             list($k, $v) = explode('=', $param);
 -             $env['GET'][$k] = $v;
 -           }
 -         }
 -       }
 -       $uri = $path_info;
 -     }
 -     // No PATH_INFO?... What about QUERY_STRING?
 -     elseif (trim($query_string, '/') != '' && $query_string[0] == '/')
 -     {
 -       $uri = $query_string;
 -       $get = $env['GET'];
 -       if(count($get) > 0)
 -       {
 -         # exclude GET params
 -         $keys  = array_keys($get);
 -         $first = array_shift($keys);
 -         if(strpos($query_string, $first) === 0) $uri = $first;
 -       }
 -     }
 -     elseif(array_key_exists('REQUEST_URI', $env['SERVER']) && !empty($env['SERVER']['REQUEST_URI']))
 -     {
 -       $request_uri = rtrim($env['SERVER']['REQUEST_URI'], '?/').'/';
 -       $base_path = $env['SERVER']['SCRIPT_NAME'];
 - 
 -       if($request_uri."index.php" == $base_path) $request_uri .= "index.php";
 -       $uri = str_replace($base_path, '', $request_uri);
 -       if(option('base_uri') && strpos($uri, option('base_uri')) === 0) {
 -        $uri = substr($uri, strlen(option('base_uri')));
 -       }
 -       if(strpos($uri, '?') !== false) {
 -       	$uri = substr($uri, 0, strpos($uri, '?')) . '/';
 -       }
 -     }
 -     elseif($env['SERVER']['argc'] > 1 && trim($env['SERVER']['argv'][1], '/') != '')
 -     {
 -       $uri = $env['SERVER']['argv'][1];
 -     }
 -   }
 - 
 -   $uri = rtrim($uri, "/"); # removes ending /
 -   if(empty($uri))
 -   {
 -     $uri = '/';
 -   }
 -   else if($uri[0] != '/')
 -   {
 -     $uri = '/' . $uri; # add a leading slash
 -   }
 -   return rawurldecode($uri);
 - }
 - 
 - 
 - 
 - 
 -                                      # # #
 - 
 - 
 - 
 - 
 - # ============================================================================ #
 - #    4. ROUTER                                                                 #
 - # ============================================================================ #
 -  
 - /**
 -  * An alias of {@link dispatch_get()}
 -  *
 -  * @return void
 -  */
 - function dispatch($path_or_array, $callback, $options = array())
 - {
 -   dispatch_get($path_or_array, $callback, $options);
 - }
 - 
 - /**
 -  * Add a GET route. Also automatically defines a HEAD route.
 -  *
 -  * @param string $path_or_array 
 -  * @param string $callback
 -  * @param array $options (optional). See {@link route()} for available options.
 -  * @return void
 -  */
 - function dispatch_get($path_or_array, $callback, $options = array())
 - {
 -   route("GET", $path_or_array, $callback, $options);
 -   route("HEAD", $path_or_array, $callback, $options);
 - }
 - 
 - /**
 -  * Add a POST route
 -  *
 -  * @param string $path_or_array 
 -  * @param string $callback
 -  * @param array $options (optional). See {@link route()} for available options.
 -  * @return void
 -  */
 - function dispatch_post($path_or_array, $callback, $options = array())
 - {
 -   route("POST", $path_or_array, $callback, $options);
 - }
 - 
 - /**
 -  * Add a PUT route
 -  *
 -  * @param string $path_or_array 
 -  * @param string $callback
 -  * @param array $options (optional). See {@link route()} for available options.
 -  * @return void
 -  */
 - function dispatch_put($path_or_array, $callback, $options = array())
 - {
 -   route("PUT", $path_or_array, $callback, $options);
 - }
 - 
 - /**
 -  * Add a DELETE route
 -  *
 -  * @param string $path_or_array 
 -  * @param string $callback
 -  * @param array $options (optional). See {@link route()} for available options.
 -  * @return void
 -  */
 - function dispatch_delete($path_or_array, $callback, $options = array())
 - {
 -   route("DELETE", $path_or_array, $callback, $options);
 - }
 - 
 - /**
 -  * Add a PATCH route
 -  *
 -  * @param string $path_or_array
 -  * @param string $callback
 -  * @param array $options (optional). See {@link route()} for available options.
 -  * @return void
 -  */
 - function dispatch_patch($path_or_array, $callback, $options = array())
 - {
 -   route("PATCH", $path_or_array, $callback, $options);
 - }
 - 
 - 
 - /**
 -  * Add route if required params are provided.
 -  * Delete all routes if null is passed as a unique argument
 -  * Return all routes
 -  * 
 -  * @see route_build()
 -  * @access private
 -  * @param string $method 
 -  * @param string|array $path_or_array 
 -  * @param callback $func
 -  * @param array $options (optional). Available options: 
 -  *   - 'params' key with an array of parameters: for parametrized routes.
 -  *     those parameters will be merged with routes parameters.
 -  * @return array
 -  */
 - function route()
 - {
 -   static $routes = array();
 -   $nargs = func_num_args();
 -   if( $nargs > 0)
 -   {
 -     $args = func_get_args();
 -     if($nargs === 1 && is_null($args[0])) $routes = array();
 -     else if($nargs < 3) trigger_error("Missing arguments for route()", E_USER_ERROR);
 -     else
 -     {
 -       $method        = $args[0];
 -       $path_or_array = $args[1];
 -       $func          = $args[2];
 -       $options       = $nargs > 3 ? $args[3] : array();
 - 
 -       $routes[] = route_build($method, $path_or_array, $func, $options);
 -     }
 -   }
 -   return $routes;
 - }
 - 
 - /**
 -  * An alias of route(null): reset all routes
 -  * 
 -  * @access private
 -  * @return void
 -  */
 - function route_reset()
 - {
 -   route(null);
 - }
 - 
 - /**
 -  * Build a route and return it
 -  *
 -  * @access private
 -  * @param string $method allowed http method (one of those returned by {@link request_methods()})
 -  * @param string|array $path_or_array 
 -  * @param callback $callback callback called when route is found. It can be
 -  *   a function, an object method, a static method or a closure.
 -  *   See {@link http://php.net/manual/en/language.pseudo-types.php#language.types.callback php documentation}
 -  *   to learn more about callbacks.
 -  * @param array $options (optional). Available options: 
 -  *   - 'params' key with an array of parameters: for parametrized routes.
 -  *     those parameters will be merged with routes parameters.
 -  * @return array array with keys "method", "pattern", "names", "callback", "options"
 -  */
 - function route_build($method, $path_or_array, $callback, $options = array())
 - {
 -   $method = strtoupper($method);
 -   if(!in_array($method, request_methods())) 
 -     trigger_error("'$method' request method is unkown or unavailable.", E_USER_WARNING);
 - 
 -   if(is_array($path_or_array))
 -   {
 -     $path  = array_shift($path_or_array);
 -     $names = $path_or_array[0];
 -   }
 -   else
 -   {
 -     $path  = $path_or_array;
 -     $names = array();
 -   }
 - 
 -   $single_asterisk_subpattern   = "(?:/([^\/]*))?";
 -   $double_asterisk_subpattern   = "(?:/(.*))?";
 -   $optionnal_slash_subpattern   = "(?:/*?)";
 -   $no_slash_asterisk_subpattern = "(?:([^\/]*))?";
 - 
 -   if($path[0] == "^")
 -   {
 -     if($path{strlen($path) - 1} != "$") $path .= "$";
 -      $pattern = "#".$path."#i";
 -   }
 -   else if(empty($path) || $path == "/")
 -   {
 -     $pattern = "#^".$optionnal_slash_subpattern."$#";
 -   }
 -   else
 -   {
 -     $parsed = array();
 -     $elts = explode('/', $path);
 - 
 -     $parameters_count = 0;
 - 
 -     foreach($elts as $elt)
 -     {
 -       if(empty($elt)) continue;
 - 
 -       $name = null; 
 - 
 -       # extracting double asterisk **
 -       if($elt == "**"):
 -         $parsed[] = $double_asterisk_subpattern;
 -         $name = $parameters_count;
 - 
 -       # extracting single asterisk *
 -       elseif($elt == "*"):
 -         $parsed[] = $single_asterisk_subpattern;
 -         $name = $parameters_count;
 - 
 -       # extracting named parameters :my_param 
 -       elseif($elt[0] == ":"):
 -         if(preg_match('/^:([^\:]+)$/', $elt, $matches))
 -         {
 -           $parsed[] = $single_asterisk_subpattern;
 -           $name = $matches[1];
 -         };
 - 
 -       elseif(strpos($elt, '*') !== false):
 -         $sub_elts = explode('*', $elt);
 -         $parsed_sub = array();
 -         foreach($sub_elts as $sub_elt)
 -         {
 -           $parsed_sub[] = preg_quote($sub_elt, "#");
 -           $name = $parameters_count;
 -         }
 -         // 
 -         $parsed[] = "/".implode($no_slash_asterisk_subpattern, $parsed_sub);
 - 
 -       else:
 -         $parsed[] = "/".preg_quote($elt, "#");
 - 
 -       endif;
 - 
 -       /* set parameters names */ 
 -       if(is_null($name)) continue;
 -       if(!array_key_exists($parameters_count, $names) || is_null($names[$parameters_count]))
 -         $names[$parameters_count] = $name;
 -       $parameters_count++;
 -     }
 - 
 -     $pattern = "#^".implode('', $parsed).$optionnal_slash_subpattern."?$#i";
 -   }
 - 
 -   return array( "method"       => $method,
 -                 "pattern"      => $pattern,
 -                 "names"        => $names,
 -                 "callback"     => $callback,
 -                 "options"      => $options  );
 - }
 - 
 - /**
 -  * Find a route and returns it.
 -  * Parameters values extracted from the path are added and merged 
 -  * with the default 'params' option of the route
 -  * If not found, returns false.
 -  * Routes are checked from first added to last added.
 -  *
 -  * @access private
 -  * @param string $method 
 -  * @param string $path
 -  * @return array,false route array has same keys as route returned by 
 -  *  {@link route_build()} ("method", "pattern", "names", "callback", "options")
 -  *  + the processed "params" key
 -  */
 - function route_find($method, $path)
 - {
 -   $routes = route();
 -   $method = strtoupper($method);
 -   foreach($routes as $route)
 -   {
 -     if($method == $route["method"] && preg_match($route["pattern"], $path, $matches))
 -     {
 -       $options = $route["options"];
 -       $params = array_key_exists('params', $options) ? $options["params"] : array();
 -       if(count($matches) > 1)
 -       {
 -         array_shift($matches);
 -         $n_matches = count($matches);
 -         $names     = array_values($route["names"]);
 -         $n_names   = count($names);
 -         if( $n_matches < $n_names )
 -         {
 -           $a = array_fill(0, $n_names - $n_matches, null);
 -           $matches = array_merge($matches, $a);
 -         }
 -         else if( $n_matches > $n_names )
 -         {
 -           $names = range($n_names, $n_matches - 1);
 -         }
 -         $arr_comb = array_combine($names, $matches);
 -         $params = array_replace($params, $arr_comb);
 -       }
 -       $route["params"] = $params;
 -       return $route;
 -     }
 -   }
 -   return false;
 - }
 - 
 - 
 - 
 - 
 - 
 - # ============================================================================ #
 - #    5. OUTPUT AND RENDERING                                                   #
 - # ============================================================================ #
 - 
 - /**
 -  * Returns a string to output
 -  * 
 -  * It might use a template file, a function, or a formatted string (like {@link sprintf()}).
 -  * It could be embraced by a layout or not.
 -  * Local vars can be passed in addition to variables made available with the {@link set()}
 -  * function.
 -  *
 -  * @param string $content_or_func 
 -  * @param string $layout 
 -  * @param string $locals 
 -  * @return string
 -  */
 - function render($content_or_func, $layout = '', $locals = array())
 - {
 -   $args = func_get_args();
 -   $content_or_func = array_shift($args);
 -   $layout = count($args) > 0 ? array_shift($args) : layout();
 -   $view_path = file_path(option('views_dir'),$content_or_func);
 -   
 -   if(function_exists('before_render'))
 -     list($content_or_func, $layout, $locals, $view_path) = before_render($content_or_func, $layout, $locals, $view_path);    
 -   
 -   $vars = array_merge(set(), $locals);
 - 
 -   $flash = flash_now();
 -   if(array_key_exists('flash', $vars)) trigger_error('A $flash variable is already passed to view. Flash messages will only be accessible through flash_now()', E_USER_NOTICE);  
 -   else if(!empty($flash)) $vars['flash'] = $flash;
 - 
 -   $infinite_loop = false;
 - 
 -   # Avoid infinite loop: this function is in the backtrace ?
 -   if(function_exists($content_or_func))
 -   {
 -     $back_trace = debug_backtrace();
 -     while($trace = array_shift($back_trace))
 -     {
 -       if($trace['function'] == strtolower($content_or_func))
 -       {
 -         $infinite_loop = true;
 -         break;
 -       }
 -     }
 -   }
 - 
 -   if(function_exists($content_or_func) && !$infinite_loop)
 -   {
 -     ob_start();
 -     call_user_func($content_or_func, $vars);
 -     $content = ob_get_clean();
 -   }
 -   elseif(file_exists($view_path))
 -   {
 -     ob_start();
 -     extract($vars);
 -     include $view_path;
 -     $content = ob_get_clean();
 -   }
 -   else
 -   {
 -     if(substr_count($content_or_func, '%') !== count($vars)) $content = $content_or_func;
 -     else $content = vsprintf($content_or_func, $vars);
 -   }
 - 
 -   if(empty($layout)) return $content;
 - 
 -   return render($layout, null, array('content' => $content));
 - }
 - 
 - /**
 -  * Returns a string to output
 -  * 
 -  * Shortcut to render with no layout.
 -  *
 -  * @param string $content_or_func 
 -  * @param string $locals 
 -  * @return string
 -  */
 - function partial($content_or_func, $locals = array())
 - {
 -   return render($content_or_func, null, $locals);
 - }
 - 
 - /**
 -  * Returns html output with proper http headers
 -  *
 -  * @param string $content_or_func 
 -  * @param string $layout 
 -  * @param string $locals 
 -  * @return string
 -  */ 
 - function html($content_or_func, $layout = '', $locals = array())
 - {
 -   send_header('Content-Type: text/html; charset='.strtolower(option('encoding')));
 -   $args = func_get_args();
 -   return call_user_func_array('render', $args);
 - }
 - 
 - /**
 -  * Set and return current layout
 -  *
 -  * @param string $function_or_file 
 -  * @return string
 -  */
 - function layout($function_or_file = null)
 - {
 -   static $layout = null;
 -   if(func_num_args() > 0) $layout = $function_or_file;
 -   return $layout;
 - }
 - 
 - /**
 -  * Returns xml output with proper http headers
 -  *
 -  * @param string $content_or_func 
 -  * @param string $layout 
 -  * @param string $locals 
 -  * @return string
 -  */
 - function xml($data)
 - {
 -   send_header('Content-Type: text/xml; charset='.strtolower(option('encoding')));
 -   $args = func_get_args();
 -   return call_user_func_array('render', $args);
 - }
 - 
 - /**
 -  * Returns css output with proper http headers
 -  *
 -  * @param string $content_or_func 
 -  * @param string $layout 
 -  * @param string $locals 
 -  * @return string
 -  */
 - function css($content_or_func, $layout = '', $locals = array())
 - {
 -   send_header('Content-Type: text/css; charset='.strtolower(option('encoding')));
 -   $args = func_get_args();
 -   return call_user_func_array('render', $args);
 - }
 - 
 - /**
 -  * Returns javacript output with proper http headers
 -  *
 -  * @param string $content_or_func 
 -  * @param string $layout 
 -  * @param string $locals 
 -  * @return string
 -  */
 - function js($content_or_func, $layout = '', $locals = array())
 - {
 -   send_header('Content-Type: application/javascript; charset='.strtolower(option('encoding')));
 -   $args = func_get_args();
 -   return call_user_func_array('render', $args);
 - }
 - 
 - /**
 -  * Returns txt output with proper http headers
 -  *
 -  * @param string $content_or_func 
 -  * @param string $layout 
 -  * @param string $locals 
 -  * @return string
 -  */
 - function txt($content_or_func, $layout = '', $locals = array())
 - {
 -   send_header('Content-Type: text/plain; charset='.strtolower(option('encoding')));
 -   $args = func_get_args();
 -   return call_user_func_array('render', $args);
 - }
 - 
 - /**
 -  * Returns json representation of data with proper http headers.
 -  * On PHP 5 < PHP 5.2.0, you must provide your own implementation of the
 -  * <code>json_encode()</code> function beore using <code>json()</code>.
 -  *
 -  * @param string $data 
 -  * @param int $json_option
 -  * @return string
 -  */
 - function json($data, $json_option = 0)
 - {
 -   send_header('Content-Type: application/json; charset='.strtolower(option('encoding')));
 -   return version_compare(PHP_VERSION, '5.3.0', '>=') ? json_encode($data, $json_option) : json_encode($data);
 - }
 - 
 - /**
 -  * undocumented function
 -  *
 -  * @param string $filename 
 -  * @param string $return 
 -  * @return mixed number of bytes delivered or file output if $return = true
 -  */
 - function render_file($filename, $return = false)
 - {
 -   # TODO implements X-SENDFILE headers
 -   // if($x-sendfile = option('x-sendfile'))
 -   // {
 -   //    // add a X-Sendfile header for apache and Lighttpd >= 1.5
 -   //    if($x-sendfile > X-SENDFILE) // add a X-LIGHTTPD-send-file header 
 -   //   
 -   // }
 -   // else
 -   // {
 -   //   
 -   // }
 -   $filename = str_replace('../', '', $filename);
 -   if(file_exists($filename))
 -   {
 -     $content_type = mime_type(file_extension($filename));
 -     $header = 'Content-type: '.$content_type;
 -     if(file_is_text($filename)) $header .= '; charset='.strtolower(option('encoding'));
 -     send_header($header);
 -     return file_read($filename, $return);
 -   }
 -   else halt(NOT_FOUND, "unknown filename $filename");
 - }
 - 
 - /**
 -  * Call before_sending_header() if it exists, then send headers
 -  * 
 -  * @param string $header
 -  * @return void
 -  */
 - function send_header($header = null, $replace = true, $code = false)
 - {
 -     if(!headers_sent()) 
 -     {
 -         call_if_exists('before_sending_header', $header);
 -         header($header, $replace, $code);
 -     }
 - }
 - 
 - 
 - 
 - 
 - 
 -                                      # # #
 - 
 - 
 - 
 - 
 - # ============================================================================ #
 - #    6. HELPERS                                                                #
 - # ============================================================================ #
 - 
 - /**
 -  * Returns an url composed of params joined with /
 -  * A param can be a string or an array.
 -  * If param is an array, its members will be added at the end of the return url
 -  * as GET parameters "&key=value".
 -  *
 -  * @param string or array $param1, $param2 ... 
 -  * @return string
 -  */ 
 - function url_for($params = null)
 - {
 -   $paths  = array();
 -   $params = func_get_args();
 -   $GET_params = array();
 -   foreach($params as $param)
 -   {
 -     if(is_array($param))
 -     {
 -       $GET_params = array_merge($GET_params, $param);
 -       continue;
 -     }
 -     if(filter_var_url($param))
 -     {
 -       $paths[] = $param;
 -       continue;
 -     }
 -     $p = explode('/',$param);
 -     foreach($p as $v)
 -     {
 -       if($v != "") $paths[] = str_replace('%23', '#', rawurlencode($v));
 -     }
 -   }
 - 
 -   $path = rtrim(implode('/', $paths), '/');
 -   
 -   if(!filter_var_url($path)) 
 -   {
 -     # it's a relative URL or an URL without a schema
 -     $base_uri = option('base_uri');
 -     $path = file_path($base_uri, $path);
 -   }
 -   
 -   if(!empty($GET_params))
 -   {
 -     $is_first_qs_param = true;
 -     $path_as_no_question_mark = strpos($path, '?') === false;
 -       
 -     foreach($GET_params as $k => $v)
 -     {
 -       $qs_separator = $is_first_qs_param && $path_as_no_question_mark ? 
 -                         '?' : '&'; 
 -       $path .= $qs_separator . rawurlencode($k) . '=' . rawurlencode($v);
 -       $is_first_qs_param = false;
 -     }
 -   }
 -   
 -   if(DIRECTORY_SEPARATOR != '/') $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
 - 
 -   return $path;
 - }
 - 
 - /**
 -  * An alias of {@link htmlspecialchars()}.
 -  * If no $charset is provided, uses option('encoding') value
 -  *
 -  * @param string $str 
 -  * @param string $quote_style 
 -  * @param string $charset 
 -  * @return void
 -  */
 - function h($str, $quote_style = ENT_NOQUOTES, $charset = null)
 - {
 -   if(is_null($charset)) $charset = strtoupper(option('encoding'));
 -   return htmlspecialchars($str, $quote_style, $charset); 
 - }
 - 
 - /**
 -  * Set and returns flash messages that will be available in the next action
 -  * via the {@link flash_now()} function or the view variable <code>$flash</code>.
 -  * 
 -  * If multiple values are provided, set <code>$name</code> variable with an array of those values.
 -  * If there is only one value, set <code>$name</code> variable with the provided $values
 -  * or if it's <code>$name</code> is an array, merge it with current messages.
 -  *
 -  * @param string, array $name 
 -  * @param mixed  $values,... 
 -  * @return mixed variable value for $name if $name argument is provided, else return all variables
 -  */
 - function flash($name = null, $value = null)
 - {
 -   if(!defined('SID')) trigger_error("Flash messages can't be used because session isn't enabled", E_USER_WARNING);
 -   static $messages = array();
 -   $args = func_get_args();
 -   $name = array_shift($args);
 -   if(is_null($name)) return $messages;
 -   if(is_array($name)) return $messages = array_merge($messages, $name);
 -   if(!empty($args))
 -   {
 -     $messages[$name] = count($args) > 1 ? $args : $args[0];
 -   }
 -   if(!array_key_exists($name, $messages)) return null;
 -   else return $messages[$name];
 -   return $messages;
 - }
 - 
 - /**
 -  * Set and returns flash messages available for the current action, included those
 -  * defined in the previous action with {@link flash()}
 -  * Those messages will also be passed to the views and made available in the 
 -  * <code>$flash</code> variable.
 -  * 
 -  * If multiple values are provided, set <code>$name</code> variable with an array of those values.
 -  * If there is only one value, set <code>$name</code> variable with the provided $values
 -  * or if it's <code>$name</code> is an array, merge it with current messages.
 -  *
 -  * @param string, array $name 
 -  * @param mixed  $values,... 
 -  * @return mixed variable value for $name if $name argument is provided, else return all variables
 -  */
 - function flash_now($name = null, $value = null)
 - {
 -   static $messages = null;
 -   if(is_null($messages))
 -   {
 -     $fkey = LIM_SESSION_FLASH_KEY;
 -     $messages = array();
 -     if(defined('SID') && array_key_exists($fkey, $_SESSION)) $messages = $_SESSION[$fkey];
 -   }
 -   $args = func_get_args();
 -   $name = array_shift($args);
 -   if(is_null($name)) return $messages;
 -   if(is_array($name)) return $messages = array_merge($messages, $name);
 -   if(!empty($args))
 -   {
 -     $messages[$name] = count($args) > 1 ? $args : $args[0];
 -   }
 -   if(!array_key_exists($name, $messages)) return null;
 -   else return $messages[$name];
 -   return $messages;
 - }
 - 
 - /**
 -  * Delete current flash messages in session, and set new ones stored with 
 -  * flash function.
 -  * Called before application exit.
 -  *
 -  * @access private
 -  * @return void
 -  */
 - function flash_sweep()
 - {
 -   if(defined('SID'))
 -   {
 -     $fkey = LIM_SESSION_FLASH_KEY;
 -     $_SESSION[$fkey] = flash();
 -   }
 - }
 - 
 - /**
 -  * Starts capturing block of text
 -  *
 -  * Calling without params stops capturing (same as end_content_for()).
 -  * After capturing the captured block is put into a variable
 -  * named $name for later use in layouts. If second parameter
 -  * is supplied, its content will be used instead of capturing
 -  * a block of text.
 -  *
 -  * @param string $name
 -  * @param string $content
 -  * @return void
 -  */
 - function content_for($name = null, $content = null)
 - {
 -   static $_name = null;
 -   if(is_null($name) && !is_null($_name))
 -   {
 -     set($_name, ob_get_clean());
 -     $_name = null;	
 -   }
 -   elseif(!is_null($name) && !isset($content))
 -   {
 -     $_name = $name;	
 -     ob_start();
 -   }
 -   elseif(isset($name, $content))
 -   {
 -     set($name, $content);
 -   }
 - }
 - 
 - /**
 -  * Stops capturing block of text
 -  *
 -  * @return void
 -  */
 - function end_content_for()
 - {
 -   content_for();
 - }
 - 
 - /**
 -  * Shows current memory and execution time of the application.
 -  * Returns only execution time if <code>memory_get_usage()</code> 
 -  * isn't available.
 -  * ( That's the case before PHP5.2.1 if PHP isn't compiled with option 
 -  *   <code>--enable-memory-limit</code>. )
 -  * 
 -  * @access public
 -  * @return array
 -  */
 - function benchmark()
 - {
 - 	$res = array( 'execution_time' => (microtime(true) - LIM_START_MICROTIME) );
 - 	if(defined('LIM_START_MEMORY'))
 - 	{
 - 		$current_mem_usage     = memory_get_usage();
 - 		$res['current_memory'] = $current_mem_usage;
 - 		$res['start_memory']   = LIM_START_MEMORY;
 - 		$res['average_memory'] = (LIM_START_MEMORY + $current_mem_usage) / 2;
 - 	}
 - 	
 - 	return $res;
 - }
 - 
 - 
 - 
 - 
 -                                      # # #
 - 
 - 
 - 
 - 
 - # ============================================================================ #
 - #    7. UTILS                                                                  #
 - # ============================================================================ #
 -  
 - /**
 -  * Calls a function if exists
 -  *
 -  * @param callback $callback a function stored in a string variable, 
 -  *   or an object and the name of a method within the object
 -  *   See {@link http://php.net/manual/en/language.pseudo-types.php#language.types.callback php documentation}
 -  *   to learn more about callbacks.
 -  * @param mixed $arg,.. (optional)
 -  * @return mixed
 -  */
 - function call_if_exists($callback)
 - {
 -   $args = func_get_args();
 -   $callback = array_shift($args);
 -   if(is_callable($callback)) return call_user_func_array($callback, $args);
 -   return;
 - }
 - 
 - /**
 -  * Define a constant unless it already exists
 -  *
 -  * @param string $name 
 -  * @param string $value 
 -  * @return void
 -  */
 - function define_unless_exists($name, $value)
 - {
 -   if(!defined($name)) define($name, $value);
 - }
 - 
 - /**
 -  * Return a default value if provided value is empty
 -  *
 -  * @param mixed $value 
 -  * @param mixed $default default value returned if $value is empty
 -  * @return mixed
 -  */
 - function value_or_default($value, $default)
 - {
 -   return empty($value) ? $default : $value;
 - }
 - 
 - /**
 -  * An alias of {@link value_or_default()}
 -  *
 -  * 
 -  * @param mixed $value 
 -  * @param mixed $default 
 -  * @return mixed
 -  */
 - function v($value, $default)
 - {
 -   return value_or_default($value, $default);
 - }
 - 
 - /**
 -  * Load php files with require_once in a given dir
 -  *
 -  * @param string $path Path in which are the file to load
 -  * @param string $pattern a regexp pattern that filter files to load
 -  * @param bool $prevents_output security option that prevents output
 -  * @return array paths of loaded files
 -  */
 - function require_once_dir($path, $pattern = "*.php", $prevents_output = true)
 - {
 -   if($path[strlen($path) - 1] != "/") $path .= "/";
 -   $filenames = glob($path.$pattern);
 -   if(!is_array($filenames)) $filenames = array();
 -   if($prevents_output) ob_start();
 -   foreach($filenames as $filename) require_once $filename;
 -   if($prevents_output) ob_end_clean();
 -   return $filenames;
 - }
 - 
 - /**
 -  * Dumps a variable into inspectable format
 -  *
 -  * @param anything $var the variable to debug
 -  * @param bool $output_as_html sets whether to wrap output in <pre> tags. default: true
 -  * @return string the variable with output
 -  */
 - function debug($var, $output_as_html = true)
 - { 
 -   if ( is_null($var) ) { return '<span class="null-value">[NULL]</span>'; };
 -   $out = '';
 -   switch ($var) 
 -   { 
 -     case empty($var):
 -       $out = '[empty value]';
 -       break;
 -     
 -     case is_array($var):
 -       $out = var_export($var, true);
 -       break;
 -     
 -     case is_object($var):
 -       $out = var_export($var, true);
 -       break;
 -       
 -     case is_string($var):
 -       $out = $var;
 -       break;
 -     
 -     default:
 -       $out = var_export($var, true);
 -       break;
 -   }
 -   if ($output_as_html) { $out = "<pre>\n" . h($out) ."</pre>"; }
 -   return $out;
 - }
 - 
 - 
 - ## HTTP utils  _________________________________________________________________
 - 
 - 
 - ### Constants: HTTP status codes
 - 
 - define( 'HTTP_CONTINUE',                      100 );
 - define( 'HTTP_SWITCHING_PROTOCOLS',           101 );
 - define( 'HTTP_PROCESSING',                    102 );
 - define( 'HTTP_OK',                            200 );
 - define( 'HTTP_CREATED',                       201 );
 - define( 'HTTP_ACCEPTED',                      202 );
 - define( 'HTTP_NON_AUTHORITATIVE',             203 );
 - define( 'HTTP_NO_CONTENT',                    204 );
 - define( 'HTTP_RESET_CONTENT',                 205 );
 - define( 'HTTP_PARTIAL_CONTENT',               206 );
 - define( 'HTTP_MULTI_STATUS',                  207 );
 -                                               
 - define( 'HTTP_MULTIPLE_CHOICES',              300 );
 - define( 'HTTP_MOVED_PERMANENTLY',             301 );
 - define( 'HTTP_MOVED_TEMPORARILY',             302 );
 - define( 'HTTP_SEE_OTHER',                     303 );
 - define( 'HTTP_NOT_MODIFIED',                  304 );
 - define( 'HTTP_USE_PROXY',                     305 );
 - define( 'HTTP_TEMPORARY_REDIRECT',            307 );
 - 
 - define( 'HTTP_BAD_REQUEST',                   400 );
 - define( 'HTTP_UNAUTHORIZED',                  401 );
 - define( 'HTTP_PAYMENT_REQUIRED',              402 );
 - define( 'HTTP_FORBIDDEN',                     403 );
 - define( 'HTTP_NOT_FOUND',                     404 );
 - define( 'HTTP_METHOD_NOT_ALLOWED',            405 );
 - define( 'HTTP_NOT_ACCEPTABLE',                406 );
 - define( 'HTTP_PROXY_AUTHENTICATION_REQUIRED', 407 );
 - define( 'HTTP_REQUEST_TIME_OUT',              408 );
 - define( 'HTTP_CONFLICT',                      409 );
 - define( 'HTTP_GONE',                          410 );
 - define( 'HTTP_LENGTH_REQUIRED',               411 );
 - define( 'HTTP_PRECONDITION_FAILED',           412 );
 - define( 'HTTP_REQUEST_ENTITY_TOO_LARGE',      413 );
 - define( 'HTTP_REQUEST_URI_TOO_LARGE',         414 );
 - define( 'HTTP_UNSUPPORTED_MEDIA_TYPE',        415 );
 - define( 'HTTP_RANGE_NOT_SATISFIABLE',         416 );
 - define( 'HTTP_EXPECTATION_FAILED',            417 );
 - define( 'HTTP_UNPROCESSABLE_ENTITY',          422 );
 - define( 'HTTP_LOCKED',                        423 );
 - define( 'HTTP_FAILED_DEPENDENCY',             424 );
 - define( 'HTTP_UPGRADE_REQUIRED',              426 );
 - 
 - define( 'HTTP_INTERNAL_SERVER_ERROR',         500 );
 - define( 'HTTP_NOT_IMPLEMENTED',               501 );
 - define( 'HTTP_BAD_GATEWAY',                   502 );
 - define( 'HTTP_SERVICE_UNAVAILABLE',           503 );
 - define( 'HTTP_GATEWAY_TIME_OUT',              504 );
 - define( 'HTTP_VERSION_NOT_SUPPORTED',         505 );
 - define( 'HTTP_VARIANT_ALSO_VARIES',           506 );
 - define( 'HTTP_INSUFFICIENT_STORAGE',          507 );
 - define( 'HTTP_NOT_EXTENDED',                  510 );
 - 
 - /**
 -  * Output proper HTTP header for a given HTTP code
 -  *
 -  * @param string $code 
 -  * @return void
 -  */
 - function status($code = 500)
 - {
 -   if(!headers_sent())
 -   {
 -     $str = http_response_status_code($code);
 -     send_header($str);
 -   }
 - }
 - 
 - /**
 -  * Http redirection
 -  * 
 -  * Same use as {@link url_for()}
 -  * By default HTTP status code is 302, but a different code can be specified
 -  * with a status key in array parameter.
 -  * 
 -  * <code>
 -  * redirecto('new','url'); # 302 HTTP_MOVED_TEMPORARILY by default
 -  * redirecto('new','url', array('status' => HTTP_MOVED_PERMANENTLY));
 -  * </code>
 -  * 
 -  * @param string or array $param1, $param2... 
 -  * @return void
 -  */
 - function redirect_to($params)
 - {
 -   # [NOTE]: (from php.net) HTTP/1.1 requires an absolute URI as argument to » Location:
 -   # including the scheme, hostname and absolute path, but some clients accept
 -   # relative URIs. You can usually use $_SERVER['HTTP_HOST'],
 -   # $_SERVER['PHP_SELF'] and dirname() to make an absolute URI from a relative
 -   # one yourself.
 - 
 -   # TODO make absolute uri
 -   if(!headers_sent())
 -   {
 -     $status = HTTP_MOVED_TEMPORARILY; # default for a redirection in PHP
 -     $params = func_get_args();
 -     $n_params = array();
 -     # extract status param if exists
 -     foreach($params as $param)
 -     {
 -       if(is_array($param))
 -       {
 -         if(array_key_exists('status', $param))
 -         {
 -           $status = $param['status'];
 -           unset($param['status']);
 -         }
 -       }
 -       $n_params[] = $param;
 -     }
 -     $uri = call_user_func_array('url_for', $n_params);
 -     $uri = htmlspecialchars_decode($uri, ENT_NOQUOTES);
 -     stop_and_exit(false);
 -     send_header('Location: '.$uri, true, $status);
 -     exit;
 -   }
 - }
 - 
 - /**
 -  * Http redirection
 -  *
 -  * @deprecated deprecated since version 0.4. Please use {@link redirect_to()} instead.
 -  * @param string $url 
 -  * @return void
 -  */
 - function redirect($uri)
 - {
 -   # halt('redirect() is deprecated. Please use redirect_to() instead.', E_LIM_DEPRECATED);
 -   # halt not necesary... it won't be visible because of http redirection...
 -   redirect_to($uri);
 - }
 - 
 - /**
 -  * Returns HTTP response status for a given code.
 -  * If no code provided, return an array of all status
 -  *
 -  * @param string $num 
 -  * @return string,array
 -  */
 - function http_response_status($num = null)
 - {
 -   $status =  array(
 -       100 => 'Continue',
 -       101 => 'Switching Protocols',
 -       102 => 'Processing',
 - 
 -       200 => 'OK',
 -       201 => 'Created',
 -       202 => 'Accepted',
 -       203 => 'Non-Authoritative Information',
 -       204 => 'No Content',
 -       205 => 'Reset Content',
 -       206 => 'Partial Content',
 -       207 => 'Multi-Status',
 -       226 => 'IM Used',
 - 
 -       300 => 'Multiple Choices',
 -       301 => 'Moved Permanently',
 -       302 => 'Found',
 -       303 => 'See Other',
 -       304 => 'Not Modified',
 -       305 => 'Use Proxy',
 -       306 => 'Reserved',
 -       307 => 'Temporary Redirect',
 - 
 -       400 => 'Bad Request',
 -       401 => 'Unauthorized',
 -       402 => 'Payment Required',
 -       403 => 'Forbidden',
 -       404 => 'Not Found',
 -       405 => 'Method Not Allowed',
 -       406 => 'Not Acceptable',
 -       407 => 'Proxy Authentication Required',
 -       408 => 'Request Timeout',
 -       409 => 'Conflict',
 -       410 => 'Gone',
 -       411 => 'Length Required',
 -       412 => 'Precondition Failed',
 -       413 => 'Request Entity Too Large',
 -       414 => 'Request-URI Too Long',
 -       415 => 'Unsupported Media Type',
 -       416 => 'Requested Range Not Satisfiable',
 -       417 => 'Expectation Failed',
 -       422 => 'Unprocessable Entity',
 -       423 => 'Locked',
 -       424 => 'Failed Dependency',
 -       426 => 'Upgrade Required',
 - 
 -       500 => 'Internal Server Error',
 -       501 => 'Not Implemented',
 -       502 => 'Bad Gateway',
 -       503 => 'Service Unavailable',
 -       504 => 'Gateway Timeout',
 -       505 => 'HTTP Version Not Supported',
 -       506 => 'Variant Also Negotiates',
 -       507 => 'Insufficient Storage',
 -       510 => 'Not Extended'
 -   );
 -   if(is_null($num)) return $status;
 -   return array_key_exists($num, $status) ? $status[$num] : '';
 - }
 - 
 - /**
 -  * Checks if an HTTP response code is valid
 -  *
 -  * @param string $num 
 -  * @return bool
 -  */
 - function http_response_status_is_valid($num)
 - {
 -   $r = http_response_status($num);
 -   return !empty($r);
 - }
 - 
 - /**
 -  * Returns an HTTP response status string for a given code
 -  *
 -  * @param string $num 
 -  * @return string
 -  */
 - function http_response_status_code($num)
 - {
 -   $protocole = empty($_SERVER["SERVER_PROTOCOL"]) ? "HTTP/1.1" : $_SERVER["SERVER_PROTOCOL"];
 -   if($str = http_response_status($num)) return "$protocole $num $str";
 - }
 - 
 - /**
 -  * Check if the _Accept_ header is present, and includes the given `type`.
 -  *
 -  * When the _Accept_ header is not present `true` is returned. Otherwise
 -  * the given `type` is matched by an exact match, and then subtypes. You
 -  * may pass the subtype such as "html" which is then converted internally
 -  * to "text/html" using the mime lookup table.
 -  *
 -  * @param string $type
 -  * @param string $env 
 -  * @return bool
 -  */
 - function http_ua_accepts($type, $env = null)
 - {
 -   if(is_null($env)) $env = env();
 -   $accept = array_key_exists('HTTP_ACCEPT', $env['SERVER']) ? $env['SERVER']['HTTP_ACCEPT'] : null;
 -   
 -   if(!$accept || $accept === '*/*') return true;
 -   
 -   if($type)
 -   {
 -     // Allow "html" vs "text/html" etc
 -     if(!strpos($type, '/')) $type = mime_type($type);
 -     
 -     // Check if we have a direct match
 -     if(strpos($accept, $type) > -1) return true;
 -     
 -     // Check if we have type/*  
 -     $type_parts = explode('/', $type); 
 -     $type = $type_parts[0].'/*';
 -     return (strpos($accept, $type) > -1);
 -   }
 -   
 -   return false; 
 - }
 - 
 - ## FILE utils  _________________________________________________________________
 - 
 - /**
 -  * Returns mime type for a given extension or if no extension is provided,
 -  * all mime types in an associative array, with extensions as keys. 
 -  * If extension is unknown, returns null.
 -  * (extracted from Orbit source http://orbit.luaforge.net/).
 -  *
 -  *
 -  * @param string $ext
 -  * @return string, array, null
 -  */
 - function mime_type($ext = null)
 - {
 -   $types = array(
 -     'ai'      => 'application/postscript',
 -     'aif'     => 'audio/x-aiff',
 -     'aifc'    => 'audio/x-aiff',
 -     'aiff'    => 'audio/x-aiff',
 -     'asc'     => 'text/plain',
 -     'atom'    => 'application/atom+xml',
 -     'atom'    => 'application/atom+xml',
 -     'au'      => 'audio/basic',
 -     'avi'     => 'video/x-msvideo',
 -     'bcpio'   => 'application/x-bcpio',
 -     'bin'     => 'application/octet-stream',
 -     'bmp'     => 'image/bmp',
 -     'cdf'     => 'application/x-netcdf',
 -     'cgm'     => 'image/cgm',
 -     'class'   => 'application/octet-stream',
 -     'cpio'    => 'application/x-cpio',
 -     'cpt'     => 'application/mac-compactpro',
 -     'csh'     => 'application/x-csh',
 -     'css'     => 'text/css',
 -     'csv'     => 'text/csv',
 -     'dcr'     => 'application/x-director',
 -     'dir'     => 'application/x-director',
 -     'djv'     => 'image/vnd.djvu',
 -     'djvu'    => 'image/vnd.djvu',
 -     'dll'     => 'application/octet-stream',
 -     'dmg'     => 'application/octet-stream',
 -     'dms'     => 'application/octet-stream',
 -     'doc'     => 'application/msword',
 -     'dtd'     => 'application/xml-dtd',
 -     'dvi'     => 'application/x-dvi',
 -     'dxr'     => 'application/x-director',
 -     'eps'     => 'application/postscript',
 -     'etx'     => 'text/x-setext',
 -     'exe'     => 'application/octet-stream',
 -     'ez'      => 'application/andrew-inset',
 -     'gif'     => 'image/gif',
 -     'gram'    => 'application/srgs',
 -     'grxml'   => 'application/srgs+xml',
 -     'gtar'    => 'application/x-gtar',
 -     'hdf'     => 'application/x-hdf',
 -     'hqx'     => 'application/mac-binhex40',
 -     'htm'     => 'text/html',
 -     'html'    => 'text/html',
 -     'ice'     => 'x-conference/x-cooltalk',
 -     'ico'     => 'image/x-icon',
 -     'ics'     => 'text/calendar',
 -     'ief'     => 'image/ief',
 -     'ifb'     => 'text/calendar',
 -     'iges'    => 'model/iges',
 -     'igs'     => 'model/iges',
 -     'jpe'     => 'image/jpeg',
 -     'jpeg'    => 'image/jpeg',
 -     'jpg'     => 'image/jpeg',
 -     'js'      => 'application/x-javascript',
 -     'json'    => 'application/json',
 -     'kar'     => 'audio/midi',
 -     'latex'   => 'application/x-latex',
 -     'lha'     => 'application/octet-stream',
 -     'lzh'     => 'application/octet-stream',
 -     'm3u'     => 'audio/x-mpegurl',
 -     'man'     => 'application/x-troff-man',
 -     'mathml'  => 'application/mathml+xml',
 -     'me'      => 'application/x-troff-me',
 -     'mesh'    => 'model/mesh',
 -     'mid'     => 'audio/midi',
 -     'midi'    => 'audio/midi',
 -     'mif'     => 'application/vnd.mif',
 -     'mov'     => 'video/quicktime',
 -     'movie'   => 'video/x-sgi-movie',
 -     'mp2'     => 'audio/mpeg',
 -     'mp3'     => 'audio/mpeg',
 -     'mpe'     => 'video/mpeg',
 -     'mpeg'    => 'video/mpeg',
 -     'mpg'     => 'video/mpeg',
 -     'mpga'    => 'audio/mpeg',
 -     'ms'      => 'application/x-troff-ms',
 -     'msh'     => 'model/mesh',
 -     'mxu'     => 'video/vnd.mpegurl',
 -     'nc'      => 'application/x-netcdf',
 -     'oda'     => 'application/oda',
 -     'ogg'     => 'application/ogg',
 -     'pbm'     => 'image/x-portable-bitmap',
 -     'pdb'     => 'chemical/x-pdb',
 -     'pdf'     => 'application/pdf',
 -     'pgm'     => 'image/x-portable-graymap',
 -     'pgn'     => 'application/x-chess-pgn',
 -     'png'     => 'image/png',
 -     'pnm'     => 'image/x-portable-anymap',
 -     'ppm'     => 'image/x-portable-pixmap',
 -     'ppt'     => 'application/vnd.ms-powerpoint',
 -     'ps'      => 'application/postscript',
 -     'qt'      => 'video/quicktime',
 -     'ra'      => 'audio/x-pn-realaudio',
 -     'ram'     => 'audio/x-pn-realaudio',
 -     'ras'     => 'image/x-cmu-raster',
 -     'rdf'     => 'application/rdf+xml',
 -     'rgb'     => 'image/x-rgb',
 -     'rm'      => 'application/vnd.rn-realmedia',
 -     'roff'    => 'application/x-troff',
 -     'rss'     => 'application/rss+xml',
 -     'rtf'     => 'text/rtf',
 -     'rtx'     => 'text/richtext',
 -     'sgm'     => 'text/sgml',
 -     'sgml'    => 'text/sgml',
 -     'sh'      => 'application/x-sh',
 -     'shar'    => 'application/x-shar',
 -     'silo'    => 'model/mesh',
 -     'sit'     => 'application/x-stuffit',
 -     'skd'     => 'application/x-koan',
 -     'skm'     => 'application/x-koan',
 -     'skp'     => 'application/x-koan',
 -     'skt'     => 'application/x-koan',
 -     'smi'     => 'application/smil',
 -     'smil'    => 'application/smil',
 -     'snd'     => 'audio/basic',
 -     'so'      => 'application/octet-stream',
 -     'spl'     => 'application/x-futuresplash',
 -     'src'     => 'application/x-wais-source',
 -     'sv4cpio' => 'application/x-sv4cpio',
 -     'sv4crc'  => 'application/x-sv4crc',
 -     'svg'     => 'image/svg+xml',
 -     'svgz'    => 'image/svg+xml',
 -     'swf'     => 'application/x-shockwave-flash',
 -     't'       => 'application/x-troff',
 -     'tar'     => 'application/x-tar',
 -     'tcl'     => 'application/x-tcl',
 -     'tex'     => 'application/x-tex',
 -     'texi'    => 'application/x-texinfo',
 -     'texinfo' => 'application/x-texinfo',
 -     'tif'     => 'image/tiff',
 -     'tiff'    => 'image/tiff',
 -     'tr'      => 'application/x-troff',
 -     'tsv'     => 'text/tab-separated-values',
 -     'txt'     => 'text/plain',
 -     'ustar'   => 'application/x-ustar',
 -     'vcd'     => 'application/x-cdlink',
 -     'vrml'    => 'model/vrml',
 -     'vxml'    => 'application/voicexml+xml',
 -     'wav'     => 'audio/x-wav',
 -     'wbmp'    => 'image/vnd.wap.wbmp',
 -     'wbxml'   => 'application/vnd.wap.wbxml',
 -     'wml'     => 'text/vnd.wap.wml',
 -     'wmlc'    => 'application/vnd.wap.wmlc',
 -     'wmls'    => 'text/vnd.wap.wmlscript',
 -     'wmlsc'   => 'application/vnd.wap.wmlscriptc',
 -     'wrl'     => 'model/vrml',
 -     'xbm'     => 'image/x-xbitmap',
 -     'xht'     => 'application/xhtml+xml',
 -     'xhtml'   => 'application/xhtml+xml',
 -     'xls'     => 'application/vnd.ms-excel',
 -     'xml'     => 'application/xml',
 -     'xpm'     => 'image/x-xpixmap',
 -     'xsl'     => 'application/xml',
 -     'xslt'    => 'application/xslt+xml',
 -     'xul'     => 'application/vnd.mozilla.xul+xml',
 -     'xwd'     => 'image/x-xwindowdump',
 -     'xyz'     => 'chemical/x-xyz',
 -     'zip'     => 'application/zip'
 -   );
 - 
 -   if (is_null($ext)) return $types;
 - 
 -   $lower_ext = strtolower($ext);
 - 
 -   return isset($types[$lower_ext]) ? $types[$lower_ext] : null;
 - }
 - 
 - /**
 -  * Detect MIME Content-type for a file
 -  *
 -  * @param string $filename Path to the tested file.
 -  * @return string
 -  */
 - function file_mime_content_type($filename)
 - {
 -   $ext = file_extension($filename); /* strtolower isn't necessary */
 -   if($mime = mime_type($ext)) return $mime;
 -   elseif (function_exists('finfo_open'))
 -   {
 -     if($finfo = finfo_open(FILEINFO_MIME))
 -     {
 -       if($mime = finfo_file($finfo, $filename))
 -       {
 -         finfo_close($finfo);
 -         return $mime;        
 -       }
 -     }
 -   }
 -   return 'application/octet-stream';
 - }
 - 
 - 
 - /**
 -  * Read and output file content and return filesize in bytes or status after 
 -  * closing file.
 -  * This function is very efficient for outputing large files without timeout
 -  * nor too expensive memory use
 -  *
 -  * @param string $filename 
 -  * @param string $retbytes 
 -  * @return bool, int
 -  */
 - function file_read_chunked($filename, $retbytes = true)
 - {
 -   $chunksize = 1*(1024*1024); // how many bytes per chunk
 -   $buffer    = '';
 -   $cnt       = 0;
 -   $handle    = fopen($filename, 'rb');
 -   if ($handle === false) return false;
 - 
 -   ob_start();
 -   while (!feof($handle)) {
 -     $buffer = fread($handle, $chunksize);
 -     echo $buffer;
 -     ob_flush();
 -     flush();
 -     if ($retbytes) $cnt += strlen($buffer);
 -     set_time_limit(0);
 -   }
 -   ob_end_flush();
 - 
 -   $status = fclose($handle);
 -   if ($retbytes && $status) return $cnt; // return num. bytes delivered like readfile() does.
 -   return $status;
 - }
 - 
 - /**
 -  * Create a file path by concatenation of given arguments.
 -  * Windows paths with backslash directory separators are normalized in *nix paths.
 -  *
 -  * @param string $path, ... 
 -  * @return string normalized path
 -  */
 - function file_path($path)
 - {
 -   $args = func_get_args();
 -   $ds = '/'; 
 -   $win_ds = '\\';
 -   $n_path = count($args) > 1 ? implode($ds, $args) : $path;
 -   if(strpos($n_path, $win_ds) !== false) $n_path = str_replace( $win_ds, $ds, $n_path );
 -   $n_path = preg_replace( "#$ds+#", $ds, $n_path);
 -   
 -   return $n_path;
 - }
 - 
 - /**
 -  * Returns file extension or false if none
 -  *
 -  * @param string $filename 
 -  * @return string, false
 -  */
 - function file_extension($filename)
 - {
 -   $pos = strrpos($filename, '.');
 -   if($pos !== false) return substr($filename, $pos + 1);
 -   return false;
 - }
 - 
 - /**
 -  * Checks if $filename is a text file
 -  *
 -  * @param string $filename 
 -  * @return bool
 -  */
 - function file_is_text($filename)
 - {
 -   if($mime = file_mime_content_type($filename)) return substr($mime,0,5) == "text/";
 -   return null;
 - }
 - 
 - /**
 -  * Checks if $filename is a binary file
 -  *
 -  * @param string $filename 
 -  * @return void
 -  */
 - function file_is_binary($filename)
 - {
 -   $is_text = file_is_text($filename);
 -   return is_null($is_text) ? null : !$is_text;
 - }
 - 
 - /**
 -  * Return or output file content
 -  *
 -  * @return 	string, int
 -  *				
 -  **/
 - 
 - function file_read($filename, $return = false)
 - {
 -   if(!file_exists($filename)) trigger_error("$filename doesn't exists", E_USER_ERROR);
 -   if($return) return file_get_contents($filename);
 -   return file_read_chunked($filename);
 - }
 - 
 - /**
 -  * Returns an array of files contained in a directory
 -  *
 -  * @param string $dir 
 -  * @return array
 -  */
 - function file_list_dir($dir)
 - {
 -   $files = array();
 -   if ($handle = opendir($dir))
 -   {
 -     while (false !== ($file = readdir($handle)))
 -     {
 -       if ($file[0] != "." && $file != "..") $files[] = $file;
 -     }
 -     closedir($handle);
 -   }
 -   return $files;
 - }
 - 
 - ## Extra utils  ________________________________________________________________
 - 
 - if(!function_exists('array_replace'))
 - {
 -   /**
 -    * For PHP 5 < 5.3.0 (backward compatibility)
 -    * (from {@link http://www.php.net/manual/fr/function.array-replace.php#92549 this php doc. note})
 -    * 
 -    * @see array_replace()
 -    * @param string $array 
 -    * @param string $array1 
 -    * @return $array
 -    */
 -   function array_replace( array &$array, array &$array1 )
 -   {
 -     $args  = func_get_args();
 -     $count = func_num_args();
 - 
 -     for ($i = 0; $i < $count; ++$i)
 -     {
 -       if(is_array($args[$i]))
 -       {
 -         foreach ($args[$i] as $key => $val) $array[$key] = $val;
 -       }
 -       else
 -       {
 -         trigger_error(
 -           __FUNCTION__ . '(): Argument #' . ($i+1) . ' is not an array',
 -           E_USER_WARNING
 -         );
 -         return null;
 -       }
 -     }
 -     return $array;
 -   }
 - }
 - 
 - /**
 -  * Check if a string is an url
 -  *
 -  * This implementation no longer requires 
 -  * {@link http://www.php.net/manual/en/book.filter.php the filter extenstion}, 
 -  * so it will improve compatibility with older PHP versions.
 -  *
 -  * @param string $str 
 -  * @return false, str   the string if true, false instead
 -  */
 - function filter_var_url($str)
 - {
 -   $regexp = '@^https?://([-[:alnum:]]+\.)+[a-zA-Z]{2,6}(:[0-9]+)?(.*)?$@';
 -   $options = array( "options" => array("regexp" => $regexp ));
 -   return preg_match($regexp, $str) ? $str : false;
 - }
 - 
 - 
 - /**
 -  * For PHP 5 < 5.1.0 (backward compatibility)
 -  * (from {@link http://www.php.net/manual/en/function.htmlspecialchars-decode.php#82133})
 -  * 
 -  * @param string $string 
 -  * @param string $quote_style, one of: ENT_COMPAT, ENT_QUOTES, ENT_NOQUOTES 
 -  * @return the decoded string
 -  */
 - function limonade_htmlspecialchars_decode($string, $quote_style = ENT_COMPAT)
 - {
 - 	$table = array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style));
 - 	if($quote_style === ENT_QUOTES)
 - 		$table['''] = $table['''] = '\'';
 - 	return strtr($string, $table);
 - }
 - 
 - if(!function_exists('htmlspecialchars_decode'))
 - {
 - 	function htmlspecialchars_decode($string, $quote_style = ENT_COMPAT)
 - 	{
 - 		return limonade_htmlspecialchars_decode($string, $quote_style);
 - 	}
 - }
 - 
 - /**
 -  * Called just after loading libs, it provides fallback for some 
 -  * functions if they don't exists.
 -  *
 -  */
 - function fallbacks_for_not_implemented_functions()
 - {
 -   if(!function_exists('json_encode'))
 -   {
 -     /**
 -      * for PHP 5 < PHP 5.2.0
 -      *
 -      */
 -     function json_encode()
 -     {
 -       trigger_error(
 -         __FUNCTION__ . '(): no JSON functions available. Please provide your own implementation of ' . __FUNCTION__ . '() in order to use it.', E_USER_WARNING
 -       );
 -     }
 -   }
 - }
 - 
 - 
 - 
 - #   ================================= END ==================================   #
 
 
  |