656 lines
18 KiB
PHP
656 lines
18 KiB
PHP
<?php
|
|
/**
|
|
* Klasa FrontControllera
|
|
*
|
|
*/
|
|
class FrontController {
|
|
|
|
private $loadError = false;
|
|
/**
|
|
* Parametry przekazane przez Router
|
|
*
|
|
* @var array
|
|
*/
|
|
private $route;
|
|
/**
|
|
* Katalog z kontrolerami
|
|
*
|
|
* @var string
|
|
*/
|
|
private $directory = 'controller';
|
|
/**
|
|
* Kontroler do uruchomienia
|
|
*
|
|
* @var string
|
|
*/
|
|
private $controller;
|
|
/**
|
|
* Metoda do wywolania
|
|
*
|
|
* @var string
|
|
*/
|
|
private $method;
|
|
/**
|
|
* Parametry dla metody
|
|
*
|
|
* @var array
|
|
*/
|
|
private $param;
|
|
/**
|
|
* Obiekt kontrolera
|
|
*
|
|
* @var Object
|
|
*/
|
|
private $controllerObj;
|
|
/**
|
|
* Domyslny kontroler
|
|
*
|
|
* @var string
|
|
*/
|
|
private $defaultController = 'IndexController';
|
|
/**
|
|
* Konfiguracja kontrolera
|
|
*
|
|
* @var array
|
|
*/
|
|
private $config;
|
|
/**
|
|
* Delimiter tytulu strony
|
|
*
|
|
* @var string
|
|
*/
|
|
private $titleDelimiter;
|
|
/**
|
|
* Czy tytul ma byc generowany w odwrotnej kolejnosci
|
|
*
|
|
* @var bool
|
|
*/
|
|
private $titleReverse = false;
|
|
|
|
|
|
/**
|
|
* Konstruktor
|
|
*
|
|
*/
|
|
public function __construct() {
|
|
$this->route = Router::GetParam();
|
|
//print_r($this->route);
|
|
if(isset($this->route['controller'])) {
|
|
$this->controller = ucfirst($this->route['controller']);
|
|
}
|
|
if(isset($this->route['param'])) {
|
|
$this->param = $this->route['param'];
|
|
}
|
|
|
|
if(isset($this->route['method'])) {
|
|
$this->method = ucfirst($this->route['method']);
|
|
$this->param['methodToRun'] = $this->method;
|
|
}
|
|
if(isset($this->route['config'])) {
|
|
$this->config = $this->route['config'];
|
|
}
|
|
|
|
}
|
|
|
|
public static function dispatchChecker($smarty, $tplFile, $param, $lifetime) {
|
|
if(!$smarty->CacheControl($tplFile, array('cache_id'=> md5($param), 'lifetime'=>$lifetime)) && !Core::GetAppSafeMode()) {
|
|
$smarty->CacheControl($tplFile, array('cache_id'=> md5($param), 'write'=>true));
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public function dispatchTemplate($smarty, $tplFile, $param, $lifetime) {
|
|
|
|
}
|
|
|
|
/**
|
|
* Zmienia domyslny katalog z kontrolerami
|
|
*
|
|
* @param string $dir
|
|
*/
|
|
public function SetDirectory($dir) {
|
|
$this->directory = $dir;
|
|
}
|
|
|
|
/**
|
|
* Laduje plik z klasa kontrolera
|
|
*
|
|
*/
|
|
private function LoadController() {
|
|
//print_r(Config::Get('PATH_MAIN_APP').$this->directory.'/'.str_replace('_', '/', ucfirst($this->controller)).'.php');
|
|
if(is_file(Config::Get('PATH_MAIN_APP').$this->directory.'/'.str_replace('_', '/', ucfirst($this->controller)).'.php')) {
|
|
Core::RequireOnce(Config::Get('PATH_MAIN_APP').$this->directory.'/'.str_replace('_', '/', ucfirst($this->controller)).'.php');
|
|
Core::RequireOnce(Config::Get('PATH_MAIN_APP').$this->directory.'/SharedController.php');
|
|
MFLog::Debug('Loading controller: '.$this->controller);
|
|
} else {
|
|
//print_r(Config::Get('PATH_MAIN_APP').$this->directory.'/'.ucfirst($this->defaultController).'.php');
|
|
Core::RequireOnce(Config::Get('PATH_MAIN_APP').$this->directory.'/'.ucfirst($this->defaultController).'.php');
|
|
Core::RequireOnce(Config::Get('PATH_MAIN_APP').$this->directory.'/SharedController.php');
|
|
MFLog::Debug('Unable to load controller: '.$this->controller.' Loading controller: '.$this->defaultController);
|
|
$this->controller = $this->defaultController;
|
|
$this->loadError = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Laduje plik z klasa kontrolera
|
|
*
|
|
*/
|
|
private function LoadModule() {
|
|
//print_r(Config::Get('PATH_MAIN_APP').$this->directory.'/'.$this->config['module'].'/'.str_replace($this->config['module'].'_', '', ucfirst($this->controller)).'.php');
|
|
if(is_file(Config::Get('PATH_MAIN_APP').$this->directory.'/'.$this->config['module'].'/'.str_replace($this->config['module'].'_', '', ucfirst($this->controller)).'.php')) {
|
|
Core::RequireOnce(Config::Get('PATH_MAIN_APP').$this->directory.'/'.$this->config['module'].'/'.str_replace($this->config['module'].'_', '', ucfirst($this->controller)).'.php');
|
|
Core::RequireOnce(Config::Get('PATH_MAIN_APP').$this->directory.'/SharedController.php');
|
|
MFLog::Debug('Loading module: '.$this->config['module'].': '.$this->controller);
|
|
} else {
|
|
Core::RequireOnce(Config::Get('PATH_MAIN_APP').$this->directory.'/'.ucfirst($this->defaultController).'.php');
|
|
Core::RequireOnce(Config::Get('PATH_MAIN_APP').$this->directory.'/SharedController.php');
|
|
$this->controller = $this->defaultController;
|
|
MFLog::Debug('Unable to load module, Loading controller: '.$this->controller);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Uruchamia obiekt kontrolera
|
|
*
|
|
*/
|
|
private function RunController() {
|
|
$exp = explode('_', $this->controller);
|
|
|
|
$className = $this->controller;
|
|
|
|
if ($this->ValidControllerClass($className)) {
|
|
$this->controllerObj = new $className();
|
|
$method = $this->method;
|
|
|
|
if((!method_exists($this->controllerObj, $method) && !method_exists($this->controllerObj, $method.'Action'))) {
|
|
$this->method = 'Index';
|
|
}
|
|
$urlParam = isset($this->route['param']['urlParam']) ? $this->route['param']['urlParam'] : '';
|
|
if($this->loadError && ($this->method=='Index' && $urlParam!='')) {
|
|
//Utils::ArrayDisplay($this->route, __FILE__.' Line: '.__LINE__);
|
|
$this->method = 'Error404';
|
|
}
|
|
} else {
|
|
throw new Exception('Brak klasy lub brak dziedziczenia!');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Uruchamia obiekt modulu
|
|
*
|
|
*/
|
|
private function RunModule() {
|
|
$className = $this->controller;
|
|
|
|
if ($this->ValidControllerClass($className, true)) {
|
|
$this->controllerObj = new $className();
|
|
$method = $this->method;
|
|
|
|
if(!method_exists($this->controllerObj, $method) && !method_exists($this->controllerObj, $method.'Action')) {
|
|
$this->method = 'Index';
|
|
}
|
|
} else {
|
|
throw new Exception('Brak klasy lub brak dziedziczenia!');
|
|
}
|
|
}
|
|
/**
|
|
* Przypisuje delimiter tytulu strony
|
|
*
|
|
* @param string $titleDelimiter
|
|
*/
|
|
public function SetTitleDelimiter($titleDelimiter) {
|
|
$this->titleDelimiter = $titleDelimiter;
|
|
}
|
|
|
|
/**
|
|
* Dodaje element tytulu strony
|
|
*
|
|
* @param string $title
|
|
*/
|
|
public function AddTitle($title) {
|
|
//$t = Registry::Get('title');
|
|
//$t[] = $title;
|
|
//Registry::Remove('title');
|
|
//Registry::Set('title', $t);
|
|
|
|
$headers = Registry::Get('headers');
|
|
$headers['title'][] = $title;
|
|
Registry::Remove('headers');
|
|
Registry::Set('headers', $headers);
|
|
}
|
|
|
|
private function GenerateScriptsVar($t) {
|
|
$script = array();
|
|
|
|
if ($t && is_array($t) && sizeof($t)) {
|
|
ksort($t);
|
|
|
|
if (count($t)>0) {
|
|
foreach($t as $prio) {
|
|
if ( $prio && is_array($prio) && sizeof($prio) > 0) {
|
|
foreach ($prio as $item) {
|
|
//Utils::ArrayDisplay($item);
|
|
if(isset($item['file']) && $item['file']!='' && !preg_match("((http)(.*))", $item['file'])) {
|
|
$item['file'] = URL_STATIC_CONTENT.'/script/'.$item['file'];
|
|
}
|
|
$script[] = $item;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
$script = array();
|
|
}
|
|
|
|
return $script;
|
|
}
|
|
|
|
|
|
private function GenerateCSSVar($t) {
|
|
$script = array();
|
|
|
|
if ($t && is_array($t) && sizeof($t)) {
|
|
ksort($t);
|
|
|
|
if (count($t)>0) {
|
|
foreach($t as $prio) {
|
|
if ( $prio && is_array($prio) && sizeof($prio) > 0) {
|
|
foreach ($prio as $item) {
|
|
if($item['file']!='' && !preg_match("((http)(.*))", $item['file'])) {
|
|
$item['file'] = URL_STATIC_CONTENT.'/css/'.$item['file'];
|
|
}
|
|
$script[] = $item;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
$script = array();
|
|
}
|
|
|
|
return $script;
|
|
}
|
|
/**
|
|
* Generuje liste skryptow do wyswietlenia w naglowku
|
|
*
|
|
*/
|
|
public function GenerateScripts() {
|
|
$t = Registry::Get('javascript');
|
|
$script = $this->GenerateScriptsVar($t);
|
|
$smarty = Registry::Get('smarty');
|
|
$smarty->assign('javaScript', $script);
|
|
|
|
$t = Registry::Get('footerJavascript');
|
|
$script = $this->GenerateScriptsVar($t);
|
|
$smarty = Registry::Get('smarty');
|
|
$smarty->assign('footerJavaScript', $script);
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Generuje liste CSS do wyswietlenia w naglowku
|
|
*
|
|
*/
|
|
public function GenerateCSS() {
|
|
|
|
$t = Registry::Get('headerCSS');
|
|
$script = $this->GenerateCSSVar($t);
|
|
$smarty = Registry::Get('smarty');
|
|
$smarty->assign('headerCSS', $script);
|
|
|
|
}
|
|
/**
|
|
* Generuje opis strony
|
|
*
|
|
* @return string
|
|
*/
|
|
private function GenerateDescription() {
|
|
|
|
$headers = Registry::Get('headers');
|
|
|
|
if(isset($headers['description'])) {
|
|
$desc = $headers['description'];
|
|
$headers['description']=null;
|
|
Registry::Remove('headers');
|
|
Registry::Set('headers', $headers);
|
|
if(is_array($desc[0])) {
|
|
return "";
|
|
} else {
|
|
$desc = strtr($desc[0], "'", "`");
|
|
$desc = stripslashes($desc);
|
|
return $desc;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Odwraca kolejnosc generowania tytulu strony
|
|
*
|
|
*/
|
|
private function ReverseTitle() {
|
|
$t = null;
|
|
$headers = Registry::Get('headers');
|
|
if(isset($headers['title'])) {
|
|
$t = $headers['title'];
|
|
}
|
|
//Utils::ArrayDisplay($headers);
|
|
if(is_array($t)) {
|
|
$t = array_reverse($t);
|
|
}
|
|
$headers['title']=$t;
|
|
Registry::Remove('headers');
|
|
Registry::Set('headers', $headers);
|
|
}
|
|
|
|
/**
|
|
* Zmienia parametr generowania tytulu strony
|
|
*
|
|
*/
|
|
public function FlipTitle() {
|
|
$this->titleReverse = true;
|
|
}
|
|
|
|
/**
|
|
* Generuje tytul strony
|
|
*
|
|
* @return string
|
|
*/
|
|
private function GenerateTitle() {
|
|
$headers = Registry::Get('headers');
|
|
//Utils::ArrayDisplay($headers);
|
|
|
|
|
|
$t = $headers['title'];
|
|
if(is_array($t) && count($t)>1) {
|
|
$title = implode($this->titleDelimiter, $t);
|
|
} else if (is_array($t) && count($t) == 1) {
|
|
$title = $t[0];
|
|
} else {
|
|
$title = '';
|
|
}
|
|
$headers['title']=null;
|
|
Registry::Remove('headers');
|
|
Registry::Set('headers', $headers);
|
|
|
|
return $title;
|
|
}
|
|
|
|
/**
|
|
* Generuje strone
|
|
*
|
|
* @return string
|
|
*/
|
|
public function Dispatch() {
|
|
$contentCheckout = true;
|
|
$smarty = Registry::Get('smarty');
|
|
|
|
$this->devMode();
|
|
|
|
$smarty->assign('controller', strtolower(str_replace('Controller', '', $this->controller)));
|
|
$smarty->assign('method', strtolower($this->method));
|
|
//Utils::ArrayDisplay($this->param);
|
|
if(is_array($this->param)) {
|
|
$cacheParam = implode('-', $this->param);
|
|
} else {
|
|
$cacheParam = $this->method;
|
|
}
|
|
|
|
if(isset($_POST)) {
|
|
foreach($_POST as $postParam=>$postValue) {
|
|
//Utils::ArrayDisplay($postParam);
|
|
//Utils::ArrayDisplay($postValue);
|
|
if (!is_array($postValue)) {
|
|
$cacheParam.='-'.$postParam.'-'.$postValue;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
$cacheParam = md5($cacheParam);
|
|
|
|
if(isset($this->config['module']) && $this->config['module'] != '') {
|
|
$this->LoadModule();
|
|
$this->RunModule();
|
|
$partialPath = ucfirst($this->config['module']).'/';
|
|
$executeAdditional = true;
|
|
if(isset($this->config['actionSet']) && is_array($this->config['actionSet'])) {
|
|
$this->controllerObj->SetActionSet($this->config['actionSet']);
|
|
}
|
|
} else {
|
|
$partialPath = null;
|
|
$this->LoadController();
|
|
$this->RunController();
|
|
$executeAdditional = false;
|
|
if(isset($this->config['actionSet']) && is_array($this->config['actionSet'])) {
|
|
$this->controllerObj->SetActionSet($this->config['actionSet']);
|
|
$executeAdditional = true;
|
|
}
|
|
}
|
|
|
|
$method = $this->method;
|
|
|
|
$this->controllerObj->SetSmarty($smarty);
|
|
$this->controllerObj->partialTemplate = $method.'.tpl';
|
|
|
|
$templatePartialPath = null;
|
|
if(isset($this->config['module'])) {
|
|
$templatePartialPath = $this->config['module'].'/'.str_replace($this->config['module'].'_', '', str_replace('Controller', '', $this->controller));
|
|
} else {
|
|
$templatePartialPath = str_replace('Controller', '', $this->controller);
|
|
}
|
|
|
|
$this->controllerObj->templatePath = 'partial/' . str_replace('_', '/', $templatePartialPath) . '/';
|
|
|
|
if(Config::Get('SMARTY_INTERNAL_CACHING') == false) {
|
|
$smarty->caching = Config::Get('SMARTY_CACHING_METHOD');
|
|
}
|
|
|
|
$template = Registry::Get('smartyTemplate');
|
|
|
|
if((Config::Get('SMARTY_INTERNAL_CACHING') == false && !$smarty->CacheControl($template, array('cache_id'=>$this->controller.$this->method.md5($cacheParam), 'lifetime'=>CacheParam::Get('global')))) || Config::Get('SMARTY_INTERNAL_CACHING') != false) {
|
|
//echo"pyk";
|
|
if(Config::Get('SMARTY_INTERNAL_CACHING') == false) {
|
|
$smarty->caching = 0;
|
|
|
|
}
|
|
|
|
$this->controllerObj->preDispatch($this->param);
|
|
|
|
//$smarty->cache_lifetime = CacheParam::Get('global');
|
|
|
|
|
|
|
|
if($this->controllerObj->GetActionRedirect()!=true && $this->controllerObj->GetActionRedirect()!=false) {
|
|
$method = $this->controllerObj->GetActionRedirect();
|
|
}
|
|
|
|
$initMethod = $method . 'Init';
|
|
|
|
if (method_exists($this->controllerObj, $initMethod)) {
|
|
$this->controllerObj->$initMethod($this->param);
|
|
}
|
|
|
|
// -->
|
|
|
|
//--MAKL: odpalam wczesniej
|
|
if($executeAdditional == true) {
|
|
$this->controllerObj->ExecuteAdditionalActions($this->param);
|
|
}
|
|
|
|
if((!$this->controllerObj->Init($method, $cacheParam) || $this->controllerObj->CheckLiveMethod($method, $this->param)) && $this->controllerObj->GetActionRedirect()!=true) {
|
|
|
|
if($this->controllerObj->CheckLiveMethod($method, $this->param)) {
|
|
$smarty->cache_lifetime = 0;
|
|
}
|
|
|
|
$methodAction = $method . 'Action';
|
|
$this->controllerObj->$methodAction($this->param);
|
|
$methodRun = true;
|
|
Registry::Set('methodRun',$methodRun);
|
|
|
|
} else {
|
|
$cachedMethod = $method . 'Cached';
|
|
|
|
if (method_exists($this->controllerObj, $cachedMethod)) {
|
|
$this->controllerObj->$cachedMethod($this->param);
|
|
}
|
|
}
|
|
//Utils::ArrayDisplay($this->controllerObj);
|
|
//Utils::ArrayDisplay($this->controllerObj->GetRedirect());
|
|
$redirectArray = $this->controllerObj->GetRedirect();
|
|
|
|
//--MAKL: Przniosłem do odpalenia wczesniej
|
|
|
|
|
|
|
|
if(!isset($this->controllerObj->content) && ($redirectArray['time']==='' || ($redirectArray['time']!=='' && $redirectArray['time']>0))){
|
|
//$smarty->assign('breadCrumbs', $this->controllerObj->GetBreadCrumbs());
|
|
//$smarty->cache_lifetime = $this->controllerObj->cacheTime;
|
|
//echo $smarty->cache_lifetime;
|
|
$this->controllerObj->content = $smarty->fetch($this->controllerObj->templatePath.$this->controllerObj->partialTemplate, md5($method.$cacheParam));
|
|
//echo $this->controllerObj->templatePath.$this->controllerObj->partialTemplate;
|
|
|
|
}
|
|
$contentCheckout = true;
|
|
|
|
if($this->controllerObj->content=='') {
|
|
$contentCheckout = false;
|
|
}
|
|
|
|
$smarty->assign('content', $this->controllerObj->content);
|
|
|
|
$this->controllerObj->postDispatch($this->param);
|
|
} else {
|
|
//echo"myk";
|
|
if(Config::Get('SMARTY_INTERNAL_CACHING') == false) {
|
|
if($executeAdditional == true) {
|
|
$actionSet = $this->controllerObj->GetActionSet();
|
|
$newActionSet = array();
|
|
foreach($actionSet as $set) {
|
|
if(isset($set['liveMethod']) && $set['liveMethod']==1) {
|
|
$newActionSet[] = $set;
|
|
}
|
|
}
|
|
if(count($newActionSet)>0) {
|
|
$this->controllerObj->SetActionSet($newActionSet);
|
|
$this->controllerObj->ExecuteAdditionalActions($this->param);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// -->
|
|
$redirectArray = $this->controllerObj->GetRedirect();
|
|
|
|
$smarty->assign('headerRedirect', $redirectArray);
|
|
|
|
if(isset($redirectArray['time']) && $redirectArray['time']==0 && isset($redirectArray['url']) && $redirectArray['url']!='') {
|
|
// Header('Location: '.$redirectArray['url']);
|
|
Header('Location: '.$redirectArray['url'], true, $redirectArray['code']);
|
|
die();
|
|
}
|
|
|
|
if($this->titleReverse == true) {
|
|
$this->ReverseTitle();
|
|
}
|
|
$smarty->assign('pageTitle', $this->GenerateTitle());
|
|
$smarty->assign('pageDescription', $this->GenerateDescription());
|
|
|
|
$smarty->assign('pageHeaders', Registry::Get('headers'));
|
|
|
|
|
|
|
|
|
|
|
|
$this->GenerateScripts();
|
|
$this->GenerateCSS();
|
|
//echo $smarty->cache_lifetime;
|
|
$template = Registry::Get('smartyTemplate');
|
|
|
|
if(Config::Get('SMARTY_INTERNAL_CACHING') == false) {
|
|
$smarty->caching = Config::Get('SMARTY_CACHING_METHOD');
|
|
}
|
|
|
|
if($this->controllerObj->disableTemplates == false && ($this->controllerObj->CheckLiveMethod($method, $this->param) || !$smarty->CacheControl($template, array('cache_id'=>$this->controller.$this->method.md5($cacheParam), 'lifetime'=>CacheParam::Get('global'))))) {
|
|
|
|
if(!Core::GetAppSafeMode()) {
|
|
// echo"pyk";
|
|
//if($contentCheckout!=false) {//echo"renegerate";
|
|
//$smarty->CacheControl($template, array('cache_id'=>$this->controller.$this->method.md5($cacheParam), 'write'=>true,'methodRun' => true));
|
|
|
|
//} else {
|
|
// $cacheFile = $smarty->generateFileName($this->controller.$this->method.md5($cacheParam), $template);
|
|
// $smarty->touchCacheFile($cacheFile);
|
|
//}
|
|
//return $smarty->Display($template, $this->controller.$this->method.md5($cacheParam), $this->controller.$this->method.md5($cacheParam));
|
|
//if($this->controllerObj->CheckLiveMethod($method, $this->param)) {
|
|
|
|
//$a = $this->controllerObj->content;
|
|
//} else {
|
|
$a = $smarty->Fetch($template, $this->controller.$this->method.md5($cacheParam));
|
|
//}
|
|
//echo"pyk".$template;
|
|
|
|
if ($this->controllerObj->utf8) {
|
|
$a = iconv('iso-8859-2', 'utf-8', $a);
|
|
}
|
|
|
|
echo $a;
|
|
} else {
|
|
//totalny wylot
|
|
Header('Location: '.Config::Get('FATAL_ERROR_URL'));
|
|
}
|
|
|
|
} else if($this->controllerObj->disableTemplates == false) {
|
|
|
|
$a = $smarty->Fetch($template, $this->controller.$this->method.md5($cacheParam));
|
|
if ($this->controllerObj->utf8) {
|
|
$a = iconv('iso-8859-2', 'utf-8', $a);
|
|
}
|
|
echo $a;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sprawdza czy klasa istnieje i ma poprawne dziedziczenie.
|
|
*
|
|
*/
|
|
private function ValidControllerClass($className, $module = false) {
|
|
if (!class_exists($className)) {
|
|
return false;
|
|
}
|
|
|
|
if (!class_parents($className) == Array('MainController'=>'MainController', 'Controller'=>'Controller')) {
|
|
if ($module !== true || !class_parents($className) == Array('ModuleController' => 'ModuleController', 'MainController'=>'MainController', 'Controller'=>'Controller')) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!class_implements($className) == Array('ControllerInterface'=>'ControllerInterface')) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Generuje flagę devMode
|
|
*
|
|
*/
|
|
public function devMode() {
|
|
$smarty = Registry::Get('smarty');
|
|
if (defined('DEVELOPER_MODE')) {
|
|
$smarty->assign('devMode', DEVELOPER_MODE);
|
|
} else {
|
|
$smarty->assign('devMode', false);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
?>
|