SlideShare a Scribd company logo
1 of 50
Download to read offline
$return[‘fileLocation’]=$this->cachePath.$keyDir.’/’; $return[‘fileName’]=$return[‘keyHash’].’.cache’; return $return; } /** * Sets a value in the cache for a certain key. * @param String $key * @param Mixed $value * @param String $expireTime * @return Boolean - indicating if the key was correctly saved in the cache */ public function
set($key, $value, $expireTime=0) { // CHECK INPUTS // if key is not set if (!$key) return false; // do not store ‘null’ values if ($value===null) return false; // FILE AND DIRECTORY MANAGEMENT $params=$this->getFileDetails($key); // attempt to create the directory chain if (!Dir::create($params[‘fileLocation’])) return false; //
DETERMINE THE EXPIRE TIMESTAMP if (is_numeric($expireTime) and $expireTime>0) { $expireTimestamp=TIMESTAMP+$expireTime; } else { switch (substr($expireTime, -1)) { case ‘s’: $expireTimestamp=TIMESTAMP+$expireTime;break; case ‘m’: $expireTimestamp=TIMESTAMP+$expireTime*60;break; case ‘h’:
$expireTimestamp=TIMESTAMP+$expireTime*3600;break; case ‘d’: $expireTimestamp=TIMESTAMP+$expireTime*86400;break; default: $expireTimestamp=0; } } if (!$expireTimestamp) $expireTimestamp = TIMESTAMP + $this->defaultExpireTime; // FILE CONTENT $fileContent =$expire Timestamp .serialize($value) ; // WRITE THE
CACHE FILE return File::create($params[‘fileLocation’].$params[‘fileName’], $fileContent); } /** * Gets a value stored in the cache for a certain key. * @param String $key * @return Mixed - the stored value or null if the key was not found */ public function get($key) { // CHECK INPUTS if (!$key) return null; // CHECK THE FILE // get file
params $params=$this->getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’] .$params[‘fileName’]) or !is_readable($params [‘fileLocation’].$params[‘fileName’])) return null; // READ THE FILE$fc=File::getContents($params[‘fileLocation’].$params[‘fileName’]); // get and check expiration time $expirationTimestamp
=substr ($fc, 0, 10); if ($expirationTimestamp<TIMESTAMP) { // delete the expired cache from disk $this->delete($key); return null; } // get contents, unserialize it and return it $valueSer=substr($fc, 10); $value=@unserialize($valueSer); if ($valu e===false) return null; else return $value; } /** * Deletes the value stored in the cache
for a certain key. * @param Mixed $key - if it is an array - deletes all those keys; if it is a string - deleted only that key * @return Boolean - indicating if the key was correctly deleted in the cache */ public function delete($key) { // CHECK INPUTS if (!$key) return true; // CHECK THE FILE $return=1; // A LIST OF KEYS TO BE DELETED if
(is_array($key)) { foreach($key as $k) { // get file params $params=$this->getFileDetails($k); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) continue; // delete the file $return*=File::delete($params[‘fileLocation’].$params[‘fileName’]); } } // ONLY ONE KEY else { // get file params $params=$this-
>getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) return true; // delete the file $return=File::delete($params[‘fileLocation’].$params[‘fileName’]); } return (Bool)$return; } /** * Deletes the whole cache content. * @return Boolean - indicating if the cache was completely destroyed * @see
EngineCacheBaseInterface::flush() */ public function flush() { return Dir::delete($this->cachePath); } /** * Returns an associative array of details for a certain key: the file location, the expire timestamp * @return Array */ public function getInfo($key) { $return=array(); // associate the key $return[‘key’]=$key; // get more details
$params=$this->getFileDetails($key); $fullFileName=$params[‘fileLocation’].$params[‘fileName’]; // CHECK IF THE FILE EXISTS if (!file_exists($fullFileName) or !is_readable($fullFileName)) { $return[‘fileExists’]=false; } else { // associate some more keys $return[‘fileExists’]=true; $return[‘keyHash’]=$params[‘keyHash’];
$return[‘fileLocation’]=$params[‘fileLocation’]; $return[‘fileName’]=$params[‘fileName’]; $return[‘fileSize’]=filesize($fullFileName); // get expire time $fc=File::getContents($fullFileName); $return[‘expireTimestamp’]=substr($fc, 0, 10); $return[‘expireTimestampReadable’]=date(TIMESTAMP_FULL_FORMAT, $return[‘expireTimestamp’]); //
get the value $return [‘cachedValue’] =unserialize (substr($fc, 10)); } return $return; } } <?php namespace EnginePlugins; /** * The class is used for registering a new plugin. It is extended in a class which is automatically * executed. * @author Gabriel */ abstract class RegisterAbstract { /** * The list of observers for a registered plugin.
* @var Array - associative array of [triggerName][index][EnginePluginsObserver object] */ protected $observers=array(); /** * The constructor will register the current plugin. */ public function __construct() { $this->register(); } /** * Stores a new observer for this plugin (the method is called from the defined method register() * in the
concrete classes. * @param String $triggerName - the trigger name * @param EnginePluginsObserver $obs - the observer object * @throws Exception - if the triger name is not correct */ protected function addObserver($triggerName, EnginePluginsObserver $obs) { // check trigger name if (!$triggerName) { throw new Exception(‘The
trigger name was not set in ‘.get_called_class().’::’.__FUNCTION__.”.”); } $this->observers[$triggerName][] = $obs; } /** * The method will add new observers to the current plugin (using the addObserver() method. */ abstract protected function register(); /** * Returns the list of observers for the current * @return multitype: */ public
function getObservers() { return $this->observers; } } <?php namespace AppEntityMatch; /** * The class manages the matching of suppliers * @author Gabriel */ class Supplier extends AppEntityMatchBaseAbstract { /** * The export fields for suppliers. * @var Array */ protected $exportFields = array(‘alias’, ‘company’); /** * Extra
filters - deleted and duplicated suppliers are not allwed. * @var String */ protected $matchingFilteringSQL = ‘AND ent.deleted=0 AND ent.idRealSupplier=0’; /** * The class name which will instantiate the Entity - used for primaryKey search. * @var String */ protected $entityClassName = ‘EntitySupplier’; /** * (non-PHPdoc) * @see
AppEntityMatchBaseAbstract::setTableName() */ protected function setTableName() { global $DBTSuppliers; $this->tableName = $DBTSuppliers; } /** * Sets a search by supplier alias. * @param String $value - the supplier alias. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setAlias($value,
$useWildcard=true) { $this->setSearchCriterion(‘alias’, $value, $useWildcard); } /** * Sets a search by supplier company name. * @param String $value - the supplier company name. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setCompany($value, $useWildcard=true) { $this-
>setSearchCriterion(‘company’, $value, $useWildcard); } /** * Sets a search by supplier fiscal code. * @param String $value - the supplier fiscal code. */ public function setFiscalCode($value) { $this->setSearchCriterion(‘fiscalCode’, $value, false); } /** * Searches a supplier by its code. * @param String $value * @param String $codeName
- indicate the type of code (iata, tktCode, etc) */ public function setCode($value, $codeName) { // check the code name global $CFG; if (!$CFG[‘travel’][‘standardCodes’][$codeName]) { throw new Exception(“The supplier code `{$codeName}` is not valid - you can only use: “.implode(‘, ‘, array_keys($CFG[‘travel’][‘standardCodes’]))); } //
add the search criterion $this->setSearchCriterion(‘code’, $value, false, array(‘codeName’=>$codeName)); } /** * Searches a supplier by the matching manually set in the external reservations system configs. * @param String $name - the supplier name * @param Int $idExternalResSystem - the external system */ public function
setExtResSysName($name, $idExternalResSystem) { $this->setSearchCriterion(‘extResSys’, $name, false, array(‘idExtResSystem’=>$idExternalResSystem)); } /** * This method does a special search for supplier code (for the rest of the criteria, it uses the parent call. * @see AppEntityMatchBaseAbstract::searchRecords() */ protected
function dispatchSearchRecords($field, $value, $useWildcard, Array $options=array()) { switch ($field) { case ‘code’: return $this->searchRecords_code($value, $options); break; case ‘extResSys’: return $this->searchRecords_extResSys($value, $options); break; default: return parent::dispatchSearchRecords($field, $value,
$useWildcard, $options); } } /** * Searches a supplier by its code. * @param String $value - the supplier code * @param Array $options - stores the code name used */ private function searchRecords_code($value, Array $options) { global $DBTSupplierCodes; $db = DB::getInstance(); // RUN SQL $matchSupplierCodeSQL = “ SELECT
“.$this->getSelectingFieldsSQL().” FROM `$DBTSupplierCodes` AS sc, `{$this->tableName}` AS ent WHERE sc.`code`=? AND sc.`value`=? AND `ent`.`id`=`sc`.`idSupplier` {$this->matchingFilteringSQL} “; $matchSupplierCodeEx = $db->Execute($matchSupplierCodeSQL, array($options[‘codeName’], $value)); if (!$matchSupplierCodeEx)
{ writeLog(“Could not match supplier by their code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by their code.’); } // STORE RESULTS $return = array(); foreach($matchSupplierCodeEx as $supp) { $return[$supp[‘id’]] = $supp; } return $return; } /** * Searches a supplier by its matching in the external reservation
systems. * @param unknown $valuem * @param array $options */ private function searchRecords_extResSys($value, Array $options) { global $DBTImportRes_suppliersAssociations; $db = DB::getInstance(); // SEARCH IN THE DB $searchSupplierSQL=”SELECT tinaSupplierId FROM `$DBTImportRes_suppliersAssociations` WHERE
systemSupplierId=? AND systemId=?”; $searchSupplierEx=$db->Execute($searchSupplierSQL, array($value, $options[‘idExtResSystem’])); if (!$searchSupplierEx) { writeLog(“Could not match supplier by the external reservation systems code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by the external reservation systems
code.’); } // RETURN THE RESULT $supp=$searchSupplierEx->FetchRow(); $return = array(); if ($supp[‘tinaSupplierId’]) { $return=$this->searchRecord_primaryKey($supp[‘tinaSupplierId’]); } return $return; } } <?php namespace AppConfig; abstract class XmlBasicAbstract extends BaseAbstract { /** * Stores the configuration file
(relative to the “files/config/” dir). For config files stored * inside subdirectories, the subdirectory is included (Ex: services/servicesList.xml). * @var String */ protected $fileName=null; /** * The filename with its full path. * @var String */ protected $fileNameWithPath=null; /** * (non-PHPdoc) * @see
AppConfigBaseAbstract::constructInit() */ protected function constructInit() { // check if the file name is okay if (!$this->fileName) { throw new Exception(‘You did not set the `fileName` attribute for the class `’.get_called_class().’`.’); } // set the $this->fileNameWithPath=MODULE_REL_PATH . FILEPATH_APPCONFIGS . $this->fileName;
} /** * Sets a reference to the current data in session so it can be stored during session lifetime. * @see AppConfigBaseAbstract::constructAdmin() */ protected function constructAdmin() { global $S; $className =get_called_ class(); // if items list and changed flag are set in session - they are copied into class attributes if
(isset($S[‘admin’][‘configApp’][$className][‘itemsList’])) { $this->itemsList=$S [‘admin’] [‘configApp’] [$className ][‘itemsList’]; } if (isset($S[‘admin’][‘configApp’][$className][‘changedFlag’])) { $this->changedFlag=$S[‘admin’][‘configApp’][$className][‘changedFlag’]; } // these references will keep the data over different page loads
$S[‘admin’] [‘configApp’] [$className] [‘itemsList’] =&$this->itemsList; $S[‘admin’][‘configApp’][$className][‘changedFlag’]=&$this->changedFlag; } /** * (non-PHPdoc) * @see AppConfigBaseAbstract::getAll_rawData() */ protected function getAll_rawData() { // return the output in case the file does not exist if (!file_exists($this-
>fileNameWithPath)) return $this->getAll_rawData_fileNotExists(); // the file exists - load the content as XML (and check it) $xml=@simplexml_load_file($this->fileNameWithPath); if (!($xml instanceof SimpleXMLElement)) throw new Exception(‘The config file is not a well formed XML (class = ‘.get_called_class().’ ; file = ‘.$this-
>fileNameWithPath.’).’); // return the array from the parsed XML content return $this->getAll _rawData _extract DataFromFile($xml); } /** * Sets the default output in case the XML file is missing. * @return Array */ protected function getAll_rawData_fileNotExists() { return array(); } /** * Returns the extracted data after the XML content
is parsed. * @param SimpleXMLElement $xml - the parsed xml * @return Array - the items list or whatever output is needed. */ abstract protected function getAll_ rawData _extractData FromFile ( Simple XMLElement $xml); /** * Sets an element in the internal attribute $this->itemsList. The method can be called multiple * times and they
will overwrite the older values. * @param String $var - or the name of one key (a string); * @param Mixed $value - the value of the key; * @throws Exception - if input is bad */ public function set($var, $value) { // check constructor type if ($this->constructType!=’admin’) throw new Exception(“You can use the method `”.get _called_
class().’::’.__FUNCTION__.”` only if the constructor type is `admin`.”); // check inputs if (!is_string($var)) throw new Exception(“You did not set() a correct name for the key.”); // (re)set one key $this->itemsList[$var]=$value; // update the changed flag $this->changedFlag=true; } /** * Sets all the elements in the internal attribute $this-
>itemsList (rewrites any old data * already stored). The parameter is an associative array and the keys will be * stored one by one. * @param Array $vars - associative array of keys * @throws Exception - if input is bad */ public function setAll($vars) { // check constructor type if ($this->constructType!=’admin’) throw new Exception(“You
can use the method `”.get_c alled_class().’::’.__ FUNCTION__.”` only if the constructor type is `admin`.”); // check inputs if (!is_array($vars)) throw new Exception(“You did not setAll() a correct list of elements - the parameter is not an array.”); // (re)set a list of keys $this->itemsList=$vars; // update the changed flag $this->changed
Flag=true; } /** * (non-PHPdoc) * @see AppConfigBaseAbstract::save_write_do() */ protected function save_write_do() { // GETS THE SIMPLEXML OBJECT TO BE WRITTEN ON DISK gets the simplexml object $xmlObj=$this->save_write_do _getXml(); // checks that the object is correct (it is a valid simplexml object) if (!($xmlObj
instanceof SimpleXMLElement)) throw new Exception(‘The output of the method `’.get_ called_class() .’::save_write_do_getXml` must be a `SimpleXMLElement` object.’); // (RE)WRITE FILE ON DISK // check if the file is writeable $fileChmod=false; if (file_exists($this->fileNameWithPath)) { if (!is_writeable($this->fileNameWithPath)) $this-
>addErrorMessage(‘The config file exists but it is not writeable.’); } else { $fileChmod=true; } // (OVER)WRITE THE FILE CONTENT - if (!file_put_contents($this->fileNameWithPath, $xmlObj->asXml())) { $this->addErrorMessage(‘The config file could not be (over)written.’); } // if the file did not exist - chmod it if ($fileChmod) { if
(!chmod($this->fileNameWithPath, 0777)) { $this->addErrorMessage(‘The config file could not have its acess rights updated.’); } } } /** * Returns the SimpleXML object to be written on disk. * @return SimpleXMLElement */ abstract protected function save_write_do_getXml(); } <?php namespace EngineCache; /** * The class is used to
manage the cache stored on disk. * @author Gabriel Grosu */ class Disk implements EngineCacheBaseInterface { /** * The full location where the cache files are stored. * @var String */ protected $cachePath=’’; /** * The prefix key is used to avoid the reusing of keys if the application was updated. * @var String */ protected
$keyPrefix=’’; /** * The default expiration time limit, if no param is specified when calling set() * @var int */ protected $defaultExpireTime = 2592000; // 2592000 = one month /** * The class constructor. */ public function __construct() { global $CFG; // realpath is used because cwd may change in __destructor(s) - AppEntityCache
caches the entity object in destructors. $this->cachePath=realpath(MODULE_REL_PATH.$CFG[‘paths’][‘files’]).’/’.$CFG[‘cache’][‘disk’][‘location’]; // sets the mem cached key prefix $this->keyPrefix=$CFG[‘global’][‘application’][‘versionBuild’]; return true; } /** * Returns some associative array of data determined from the key * @param Array
$key */ private function getFileDetails($key) { $return=array(); // rewrite the key $key=$this->keyPrefix.’-’.$key; // the key hash $return[‘keyHash’]=md5($key); // the subdir for the current key $keyDir=substr($return[‘keyHash’], 0, 2); // the full file location $return[‘fileLocation’]=$this->cachePath.$keyDir.’/’;
$return[‘fileName’]=$return[‘keyHash’].’.cache’; return $return; } /** * Sets a value in the cache for a certain key. * @param String $key * @param Mixed $value * @param String $expireTime * @return Boolean - indicating if the key was correctly saved in the cache */ public function set($key, $value, $expireTime=0) { // CHECK INPUTS
// if key is not set if (!$key) return false; // do not store ‘null’ values if ($value===null) return false; // FILE AND DIRECTORY MANAGEMENT $params=$this->getFileDetails($key); // attempt to create the directory chain if (!Dir::create($params[‘fileLocation’])) return false; // DETERMINE THE EXPIRE TIMESTAMP if
(is_numeric($expireTime) and $expireTime>0) { $expireTimestamp=TIMESTAMP+$expireTime; } else { switch (substr($expireTime, -1)) { case ‘s’: $expireTimestamp=TIMESTAMP+$expireTime;break; case ‘m’: $expireTimestamp=TIMESTAMP+$expireTime*60;break; case ‘h’: $expireTimestamp=TIMESTAMP+$expireTime*3600;break; case
‘d’: $expireTimestamp=TIMESTAMP+$expireTime*86400;break; default: $expireTimestamp=0; } } if (!$expireTimestamp) $expireTimestamp = TIMESTAMP + $this->defaultExpireTime; // FILE CONTENT $fileContent =$expire Timestamp .serialize($value) ; // WRITE THE CACHE FILE return
File::create($params[‘fileLocation’].$params[‘fileName’], $fileContent); } /** * Gets a value stored in the cache for a certain key. * @param String $key * @return Mixed - the stored value or null if the key was not found */ public function get($key) { // CHECK INPUTS if (!$key) return null; // CHECK THE FILE // get file params
$params=$this->getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’] .$params[‘fileName’]) or !is_readable($params [‘fileLocation’].$params[‘fileName’])) return null; // READ THE FILE$fc=File::getContents($params[‘fileLocation’].$params[‘fileName’]); // get and check expiration time $expirationTimestamp =substr
($fc, 0, 10); if ($expirationTimestamp<TIMESTAMP) { // delete the expired cache from disk $this->delete($key); return null; } // get contents, unserialize it and return it $valueSer=substr($fc, 10); $value=@unserialize($valueSer); if ($valu e===false) return null; else return $value; } /** * Deletes the value stored in the cache for a
certain key. * @param Mixed $key - if it is an array - deletes all those keys; if it is a string - deleted only that key * @return Boolean - indicating if the key was correctly deleted in the cache */ public function delete($key) { // CHECK INPUTS if (!$key) return true; // CHECK THE FILE $return=1; // A LIST OF KEYS TO BE DELETED if
(is_array($key)) { foreach($key as $k) { // get file params $params=$this->getFileDetails($k); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) continue; // delete the file $return*=File::delete($params[‘fileLocation’].$params[‘fileName’]); } } // ONLY ONE KEY else { // get file params $params=$this-
>getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) return true; // delete the file $return=File::delete($params[‘fileLocation’].$params[‘fileName’]); } return (Bool)$return; } /** * Deletes the whole cache content. * @return Boolean - indicating if the cache was completely destroyed * @see
EngineCacheBaseInterface::flush() */ public function flush() { return Dir::delete($this->cachePath); } /** * Returns an associative array of details for a certain key: the file location, the expire timestamp * @return Array */ public function getInfo($key) { $return=array(); // associate the key $return[‘key’]=$key; // get more details
$params=$this->getFileDetails($key); $fullFileName=$params[‘fileLocation’].$params[‘fileName’]; // CHECK IF THE FILE EXISTS if (!file_exists($fullFileName) or !is_readable($fullFileName)) { $return[‘fileExists’]=false; } else { // associate some more keys $return[‘fileExists’]=true; $return[‘keyHash’]=$params[‘keyHash’];
$return[‘fileLocation’]=$params[‘fileLocation’]; $return[‘fileName’]=$params[‘fileName’]; $return[‘fileSize’]=filesize($fullFileName); // get expire time $fc=File::getContents($fullFileName); $return[‘expireTimestamp’]=substr($fc, 0, 10); $return[‘expireTimestampReadable’]=date(TIMESTAMP_FULL_FORMAT, $return[‘expireTimestamp’]); //
get the value $return [‘cachedValue’] =unserialize (substr($fc, 10)); } return $return; } } <?php namespace EnginePlugins; /** * The class is used for registering a new plugin. It is extended in a class which is automatically * executed. * @author Gabriel */ abstract class RegisterAbstract { /** * The list of observers for a registered plugin.
* @var Array - associative array of [triggerName][index][EnginePluginsObserver object] */ protected $observers=array(); /** * The constructor will register the current plugin. */ public function __construct() { $this->register(); } /** * Stores a new observer for this plugin (the method is called from the defined method register() * in the
concrete classes. * @param String $triggerName - the trigger name * @param EnginePluginsObserver $obs - the observer object * @throws Exception - if the triger name is not correct */ protected function addObserver($triggerName, EnginePluginsObserver $obs) { // check trigger name if (!$triggerName) { throw new Exception(‘The
trigger name was not set in ‘.get_called_class().’::’.__FUNCTION__.”.”); } $this->observers[$triggerName][] = $obs; } /** * The method will add new observers to the current plugin (using the addObserver() method. */ abstract protected function register(); /** * Returns the list of observers for the current * @return multitype: */ public
function getObservers() { return $this->observers; } } <?php namespace AppEntityMatch; /** * The class manages the matching of suppliers * @author Gabriel */ class Supplier extends AppEntityMatchBaseAbstract { /** * The export fields for suppliers. * @var Array */ protected $exportFields = array(‘alias’, ‘company’); /** * Extra
filters - deleted and duplicated suppliers are not allwed. * @var String */ protected $matchingFilteringSQL = ‘AND ent.deleted=0 AND ent.idRealSupplier=0’; /** * The class name which will instantiate the Entity - used for primaryKey search. * @var String */ protected $entityClassName = ‘EntitySupplier’; /** * (non-PHPdoc) * @see
AppEntityMatchBaseAbstract::setTableName() */ protected function setTableName() { global $DBTSuppliers; $this->tableName = $DBTSuppliers; } /** * Sets a search by supplier alias. * @param String $value - the supplier alias. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setAlias($value,
$useWildcard=true) { $this->setSearchCriterion(‘alias’, $value, $useWildcard); } /** * Sets a search by supplier company name. * @param String $value - the supplier company name. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setCompany($value, $useWildcard=true) { $this-
>setSearchCriterion(‘company’, $value, $useWildcard); } /** * Sets a search by supplier fiscal code. * @param String $value - the supplier fiscal code. */ public function setFiscalCode($value) { $this->setSearchCriterion(‘fiscalCode’, $value, false); } /** * Searches a supplier by its code. * @param String $value * @param String $codeName
- indicate the type of code (iata, tktCode, etc) */ public function setCode($value, $codeName) { // check the code name global $CFG; if (!$CFG[‘travel’][‘standardCodes’][$codeName]) { throw new Exception(“The supplier code `{$codeName}` is not valid - you can only use: “.implode(‘, ‘, array_keys($CFG[‘travel’][‘standardCodes’]))); } //
add the search criterion $this->setSearchCriterion(‘code’, $value, false, array(‘codeName’=>$codeName)); } /** * Searches a supplier by the matching manually set in the external reservations system configs. * @param String $name - the supplier name * @param Int $idExternalResSystem - the external system */ public function
setExtResSysName($name, $idExternalResSystem) { $this->setSearchCriterion(‘extResSys’, $name, false, array(‘idExtResSystem’=>$idExternalResSystem)); } /** * This method does a special search for supplier code (for the rest of the criteria, it uses the parent call. * @see AppEntityMatchBaseAbstract::searchRecords() */ protected
function dispatchSearchRecords($field, $value, $useWildcard, Array $options=array()) { switch ($field) { case ‘code’: return $this->searchRecords_code($value, $options); break; case ‘extResSys’: return $this->searchRecords_extResSys($value, $options); break; default: return parent::dispatchSearchRecords($field, $value,
$useWildcard, $options); } } /** * Searches a supplier by its code. * @param String $value - the supplier code * @param Array $options - stores the code name used */ private function searchRecords_code($value, Array $options) { global $DBTSupplierCodes; $db = DB::getInstance(); // RUN SQL $matchSupplierCodeSQL = “ SELECT
“.$this->getSelectingFieldsSQL().” FROM `$DBTSupplierCodes` AS sc, `{$this->tableName}` AS ent WHERE sc.`code`=? AND sc.`value`=? AND `ent`.`id`=`sc`.`idSupplier` {$this->matchingFilteringSQL} “; $matchSupplierCodeEx = $db->Execute($matchSupplierCodeSQL, array($options[‘codeName’], $value)); if (!$matchSupplierCodeEx)
{ writeLog(“Could not match supplier by their code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by their code.’); } // STORE RESULTS $return = array(); foreach($matchSupplierCodeEx as $supp) { $return[$supp[‘id’]] = $supp; } return $return; } /** * Searches a supplier by its matching in the external reservation
systems. * @param unknown $valuem * @param array $options */ private function searchRecords_extResSys($value, Array $options) { global $DBTImportRes_suppliersAssociations; $db = DB::getInstance(); // SEARCH IN THE DB $searchSupplierSQL=”SELECT tinaSupplierId FROM `$DBTImportRes_suppliersAssociations` WHERE
systemSupplierId=? AND systemId=?”; $searchSupplierEx=$db->Execute($searchSupplierSQL, array($value, $options[‘idExtResSystem’])); if (!$searchSupplierEx) { writeLog(“Could not match supplier by the external reservation systems code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by the external reservation systems
code.’); } // RETURN THE RESULT $supp=$searchSupplierEx->FetchRow(); $return = array(); if ($supp[‘tinaSupplierId’]) { $return=$this->searchRecord_primaryKey($supp[‘tinaSupplierId’]); } return $return; } } <?php namespace AppConfig; abstract class XmlBasicAbstract extends BaseAbstract { /** * Stores the configuration file
(relative to the “files/config/” dir). For config files stored * inside subdirectories, the subdirectory is included (Ex: services/servicesList.xml). * @var String */ protected $fileName=null; /** * The filename with its full path. * @var String */ protected $fileNameWithPath=null; /** * (non-PHPdoc) * @see
AppConfigBaseAbstract::constructInit() */ protected function constructInit() { // check if the file name is okay if (!$this->fileName) { throw new Exception(‘You did not set the `fileName` attribute for the class `’.get_called_class().’`.’); } // set the $this->fileNameWithPath=MODULE_REL_PATH . FILEPATH_APPCONFIGS . $this->fileName;
} /** * Sets a reference to the current data in session so it can be stored during session lifetime. * @see AppConfigBaseAbstract::constructAdmin() */ protected function constructAdmin() { global $S; $className =get_called_ class(); // if items list and changed flag are set in session - they are copied into class attributes if
$return[‘fileLocation’]=$this->cachePath.$keyDir.’/’; $return[‘fileName’]=$return[‘keyHash’].’.cache’; return $return; } /** * Sets a value in the cache for a certain key. * @param String $key * @param Mixed $value * @param String $expireTime * @return Boolean - indicating if the key was correctly saved in the cache */ public function
set($key, $value, $expireTime=0) { // CHECK INPUTS // if key is not set if (!$key) return false; // do not store ‘null’ values if ($value===null) return false; // FILE AND DIRECTORY MANAGEMENT $params=$this->getFileDetails($key); // attempt to create the directory chain if (!Dir::create($params[‘fileLocation’])) return false; //
DETERMINE THE EXPIRE TIMESTAMP if (is_numeric($expireTime) and $expireTime>0) { $expireTimestamp=TIMESTAMP+$expireTime; } else { switch (substr($expireTime, -1)) { case ‘s’: $expireTimestamp=TIMESTAMP+$expireTime;break; case ‘m’: $expireTimestamp=TIMESTAMP+$expireTime*60;break; case ‘h’:
$expireTimestamp=TIMESTAMP+$expireTime*3600;break; case ‘d’: $expireTimestamp=TIMESTAMP+$expireTime*86400;break; default: $expireTimestamp=0; } } if (!$expireTimestamp) $expireTimestamp = TIMESTAMP + $this->defaultExpireTime; // FILE CONTENT $fileContent =$expire Timestamp .serialize($value) ; // WRITE THE
CACHE FILE return File::create($params[‘fileLocation’].$params[‘fileName’], $fileContent); } /** * Gets a value stored in the cache for a certain key. * @param String $key * @return Mixed - the stored value or null if the key was not found */ public function get($key) { // CHECK INPUTS if (!$key) return null; // CHECK THE FILE // get file
params $params=$this->getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’] .$params[‘fileName’]) or !is_readable($params [‘fileLocation’].$params[‘fileName’])) return null; // READ THE FILE$fc=File::getContents($params[‘fileLocation’].$params[‘fileName’]); // get and check expiration time $expirationTimestamp
=substr ($fc, 0, 10); if ($expirationTimestamp<TIMESTAMP) { // delete the expired cache from disk $this->delete($key); return null; } // get contents, unserialize it and return it $valueSer=substr($fc, 10); $value=@unserialize($valueSer); if ($valu e===false) return null; else return $value; } /** * Deletes the value stored in the cache
for a certain key. * @param Mixed $key - if it is an array - deletes all those keys; if it is a string - deleted only that key * @return Boolean - indicating if the key was correctly deleted in the cache */ public function delete($key) { // CHECK INPUTS if (!$key) return true; // CHECK THE FILE $return=1; // A LIST OF KEYS TO BE DELETED if
(is_array($key)) { foreach($key as $k) { // get file params $params=$this->getFileDetails($k); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) continue; // delete the file $return*=File::delete($params[‘fileLocation’].$params[‘fileName’]); } } // ONLY ONE KEY else { // get file params $params=$this-
>getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) return true; // delete the file $return=File::delete($params[‘fileLocation’].$params[‘fileName’]); } return (Bool)$return; } /** * Deletes the whole cache content. * @return Boolean - indicating if the cache was completely destroyed * @see
EngineCacheBaseInterface::flush() */ public function flush() { return Dir::delete($this->cachePath); } /** * Returns an associative array of details for a certain key: the file location, the expire timestamp * @return Array */ public function getInfo($key) { $return=array(); // associate the key $return[‘key’]=$key; // get more details
$params=$this->getFileDetails($key); $fullFileName=$params[‘fileLocation’].$params[‘fileName’]; // CHECK IF THE FILE EXISTS if (!file_exists($fullFileName) or !is_readable($fullFileName)) { $return[‘fileExists’]=false; } else { // associate some more keys $return[‘fileExists’]=true; $return[‘keyHash’]=$params[‘keyHash’];
$return[‘fileLocation’]=$params[‘fileLocation’]; $return[‘fileName’]=$params[‘fileName’]; $return[‘fileSize’]=filesize($fullFileName); // get expire time $fc=File::getContents($fullFileName); $return[‘expireTimestamp’]=substr($fc, 0, 10); $return[‘expireTimestampReadable’]=date(TIMESTAMP_FULL_FORMAT, $return[‘expireTimestamp’]); //
get the value $return [‘cachedValue’] =unserialize (substr($fc, 10)); } return $return; } } <?php namespace EnginePlugins; /** * The class is used for registering a new plugin. It is extended in a class which is automatically * executed. * @author Gabriel */ abstract class RegisterAbstract { /** * The list of observers for a registered plugin.
* @var Array - associative array of [triggerName][index][EnginePluginsObserver object] */ protected $observers=array(); /** * The constructor will register the current plugin. */ public function __construct() { $this->register(); } /** * Stores a new observer for this plugin (the method is called from the defined method register() * in the
concrete classes. * @param String $triggerName - the trigger name * @param EnginePluginsObserver $obs - the observer object * @throws Exception - if the triger name is not correct */ protected function addObserver($triggerName, EnginePluginsObserver $obs) { // check trigger name if (!$triggerName) { throw new Exception(‘The
trigger name was not set in ‘.get_called_class().’::’.__FUNCTION__.”.”); } $this->observers[$triggerName][] = $obs; } /** * The method will add new observers to the current plugin (using the addObserver() method. */ abstract protected function register(); /** * Returns the list of observers for the current * @return multitype: */ public
function getObservers() { return $this->observers; } } <?php namespace AppEntityMatch; /** * The class manages the matching of suppliers * @author Gabriel */ class Supplier extends AppEntityMatchBaseAbstract { /** * The export fields for suppliers. * @var Array */ protected $exportFields = array(‘alias’, ‘company’); /** * Extra
filters - deleted and duplicated suppliers are not allwed. * @var String */ protected $matchingFilteringSQL = ‘AND ent.deleted=0 AND ent.idRealSupplier=0’; /** * The class name which will instantiate the Entity - used for primaryKey search. * @var String */ protected $entityClassName = ‘EntitySupplier’; /** * (non-PHPdoc) * @see
AppEntityMatchBaseAbstract::setTableName() */ protected function setTableName() { global $DBTSuppliers; $this->tableName = $DBTSuppliers; } /** * Sets a search by supplier alias. * @param String $value - the supplier alias. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setAlias($value,
$useWildcard=true) { $this->setSearchCriterion(‘alias’, $value, $useWildcard); } /** * Sets a search by supplier company name. * @param String $value - the supplier company name. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setCompany($value, $useWildcard=true) { $this-
>setSearchCriterion(‘company’, $value, $useWildcard); } /** * Sets a search by supplier fiscal code. * @param String $value - the supplier fiscal code. */ public function setFiscalCode($value) { $this->setSearchCriterion(‘fiscalCode’, $value, false); } /** * Searches a supplier by its code. * @param String $value * @param String $codeName
- indicate the type of code (iata, tktCode, etc) */ public function setCode($value, $codeName) { // check the code name global $CFG; if (!$CFG[‘travel’][‘standardCodes’][$codeName]) { throw new Exception(“The supplier code `{$codeName}` is not valid - you can only use: “.implode(‘, ‘, array_keys($CFG[‘travel’][‘standardCodes’]))); } //
add the search criterion $this->setSearchCriterion(‘code’, $value, false, array(‘codeName’=>$codeName)); } /** * Searches a supplier by the matching manually set in the external reservations system configs. * @param String $name - the supplier name * @param Int $idExternalResSystem - the external system */ public function
setExtResSysName($name, $idExternalResSystem) { $this->setSearchCriterion(‘extResSys’, $name, false, array(‘idExtResSystem’=>$idExternalResSystem)); } /** * This method does a special search for supplier code (for the rest of the criteria, it uses the parent call. * @see AppEntityMatchBaseAbstract::searchRecords() */ protected
function dispatchSearchRecords($field, $value, $useWildcard, Array $options=array()) { switch ($field) { case ‘code’: return $this->searchRecords_code($value, $options); break; case ‘extResSys’: return $this->searchRecords_extResSys($value, $options); break; default: return parent::dispatchSearchRecords($field, $value,
$useWildcard, $options); } } /** * Searches a supplier by its code. * @param String $value - the supplier code * @param Array $options - stores the code name used */ private function searchRecords_code($value, Array $options) { global $DBTSupplierCodes; $db = DB::getInstance(); // RUN SQL $matchSupplierCodeSQL = “ SELECT
“.$this->getSelectingFieldsSQL().” FROM `$DBTSupplierCodes` AS sc, `{$this->tableName}` AS ent WHERE sc.`code`=? AND sc.`value`=? AND `ent`.`id`=`sc`.`idSupplier` {$this->matchingFilteringSQL} “; $matchSupplierCodeEx = $db->Execute($matchSupplierCodeSQL, array($options[‘codeName’], $value)); if (!$matchSupplierCodeEx)
{ writeLog(“Could not match supplier by their code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by their code.’); } // STORE RESULTS $return = array(); foreach($matchSupplierCodeEx as $supp) { $return[$supp[‘id’]] = $supp; } return $return; } /** * Searches a supplier by its matching in the external reservation
systems. * @param unknown $valuem * @param array $options */ private function searchRecords_extResSys($value, Array $options) { global $DBTImportRes_suppliersAssociations; $db = DB::getInstance(); // SEARCH IN THE DB $searchSupplierSQL=”SELECT tinaSupplierId FROM `$DBTImportRes_suppliersAssociations` WHERE
systemSupplierId=? AND systemId=?”; $searchSupplierEx=$db->Execute($searchSupplierSQL, array($value, $options[‘idExtResSystem’])); if (!$searchSupplierEx) { writeLog(“Could not match supplier by the external reservation systems code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by the external reservation systems
code.’); } // RETURN THE RESULT $supp=$searchSupplierEx->FetchRow(); $return = array(); if ($supp[‘tinaSupplierId’]) { $return=$this->searchRecord_primaryKey($supp[‘tinaSupplierId’]); } return $return; } } <?php namespace AppConfig; abstract class XmlBasicAbstract extends BaseAbstract { /** * Stores the configuration file
(relative to the “files/config/” dir). For config files stored * inside subdirectories, the subdirectory is included (Ex: services/servicesList.xml). * @var String */ protected $fileName=null; /** * The filename with its full path. * @var String */ protected $fileNameWithPath=null; /** * (non-PHPdoc) * @see
AppConfigBaseAbstract::constructInit() */ protected function constructInit() { // check if the file name is okay if (!$this->fileName) { throw new Exception(‘You did not set the `fileName` attribute for the class `’.get_called_class().’`.’); } // set the $this->fileNameWithPath=MODULE_REL_PATH . FILEPATH_APPCONFIGS . $this->fileName;
} /** * Sets a reference to the current data in session so it can be stored during session lifetime. * @see AppConfigBaseAbstract::constructAdmin() */ protected function constructAdmin() { global $S; $className =get_called_ class(); // if items list and changed flag are set in session - they are copied into class attributes if
(isset($S[‘admin’][‘configApp’][$className][‘itemsList’])) { $this->itemsList=$S [‘admin’] [‘configApp’] [$className ][‘itemsList’]; } if (isset($S[‘admin’][‘configApp’][$className][‘changedFlag’])) { $this->changedFlag=$S[‘admin’][‘configApp’][$className][‘changedFlag’]; } // these references will keep the data over different page loads
$S[‘admin’] [‘configApp’] [$className] [‘itemsList’] =&$this->itemsList; $S[‘admin’][‘configApp’][$className][‘changedFlag’]=&$this->changedFlag; } /** * (non-PHPdoc) * @see AppConfigBaseAbstract::getAll_rawData() */ protected function getAll_rawData() { // return the output in case the file does not exist if (!file_exists($this-
>fileNameWithPath)) return $this->getAll_rawData_fileNotExists(); // the file exists - load the content as XML (and check it) $xml=@simplexml_load_file($this->fileNameWithPath); if (!($xml instanceof SimpleXMLElement)) throw new Exception(‘The config file is not a well formed XML (class = ‘.get_called_class().’ ; file = ‘.$this-
>fileNameWithPath.’).’); // return the array from the parsed XML content return $this->getAll _rawData _extract DataFromFile($xml); } /** * Sets the default output in case the XML file is missing. * @return Array */ protected function getAll_rawData_fileNotExists() { return array(); } /** * Returns the extracted data after the XML content
is parsed. * @param SimpleXMLElement $xml - the parsed xml * @return Array - the items list or whatever output is needed. */ abstract protected function getAll_ rawData _extractData FromFile ( Simple XMLElement $xml); /** * Sets an element in the internal attribute $this->itemsList. The method can be called multiple * times and they
will overwrite the older values. * @param String $var - or the name of one key (a string); * @param Mixed $value - the value of the key; * @throws Exception - if input is bad */ public function set($var, $value) { // check constructor type if ($this->constructType!=’admin’) throw new Exception(“You can use the method `”.get _called_
class().’::’.__FUNCTION__.”` only if the constructor type is `admin`.”); // check inputs if (!is_string($var)) throw new Exception(“You did not set() a correct name for the key.”); // (re)set one key $this->itemsList[$var]=$value; // update the changed flag $this->changedFlag=true; } /** * Sets all the elements in the internal attribute $this-
>itemsList (rewrites any old data * already stored). The parameter is an associative array and the keys will be * stored one by one. * @param Array $vars - associative array of keys * @throws Exception - if input is bad */ public function setAll($vars) { // check constructor type if ($this->constructType!=’admin’) throw new Exception(“You
can use the method `”.get_c alled_class().’::’.__ FUNCTION__.”` only if the constructor type is `admin`.”); // check inputs if (!is_array($vars)) throw new Exception(“You did not setAll() a correct list of elements - the parameter is not an array.”); // (re)set a list of keys $this->itemsList=$vars; // update the changed flag $this->changed
Flag=true; } /** * (non-PHPdoc) * @see AppConfigBaseAbstract::save_write_do() */ protected function save_write_do() { // GETS THE SIMPLEXML OBJECT TO BE WRITTEN ON DISK gets the simplexml object $xmlObj=$this->save_write_do _getXml(); // checks that the object is correct (it is a valid simplexml object) if (!($xmlObj
instanceof SimpleXMLElement)) throw new Exception(‘The output of the method `’.get_ called_class() .’::save_write_do_getXml` must be a `SimpleXMLElement` object.’); // (RE)WRITE FILE ON DISK // check if the file is writeable $fileChmod=false; if (file_exists($this->fileNameWithPath)) { if (!is_writeable($this->fileNameWithPath)) $this-
>addErrorMessage(‘The config file exists but it is not writeable.’); } else { $fileChmod=true; } // (OVER)WRITE THE FILE CONTENT - if (!file_put_contents($this->fileNameWithPath, $xmlObj->asXml())) { $this->addErrorMessage(‘The config file could not be (over)written.’); } // if the file did not exist - chmod it if ($fileChmod) { if
(!chmod($this->fileNameWithPath, 0777)) { $this->addErrorMessage(‘The config file could not have its acess rights updated.’); } } } /** * Returns the SimpleXML object to be written on disk. * @return SimpleXMLElement */ abstract protected function save_write_do_getXml(); } <?php namespace EngineCache; /** * The class is used to
manage the cache stored on disk. * @author Gabriel Grosu */ class Disk implements EngineCacheBaseInterface { /** * The full location where the cache files are stored. * @var String */ protected $cachePath=’’; /** * The prefix key is used to avoid the reusing of keys if the application was updated. * @var String */ protected
$keyPrefix=’’; /** * The default expiration time limit, if no param is specified when calling set() * @var int */ protected $defaultExpireTime = 2592000; // 2592000 = one month /** * The class constructor. */ public function __construct() { global $CFG; // realpath is used because cwd may change in __destructor(s) - AppEntityCache
caches the entity object in destructors. $this->cachePath=realpath(MODULE_REL_PATH.$CFG[‘paths’][‘files’]).’/’.$CFG[‘cache’][‘disk’][‘location’]; // sets the mem cached key prefix $this->keyPrefix=$CFG[‘global’][‘application’][‘versionBuild’]; return true; } /** * Returns some associative array of data determined from the key * @param Array
$key */ private function getFileDetails($key) { $return=array(); // rewrite the key $key=$this->keyPrefix.’-’.$key; // the key hash $return[‘keyHash’]=md5($key); // the subdir for the current key $keyDir=substr($return[‘keyHash’], 0, 2); // the full file location $return[‘fileLocation’]=$this->cachePath.$keyDir.’/’;
$return[‘fileName’]=$return[‘keyHash’].’.cache’; return $return; } /** * Sets a value in the cache for a certain key. * @param String $key * @param Mixed $value * @param String $expireTime * @return Boolean - indicating if the key was correctly saved in the cache */ public function set($key, $value, $expireTime=0) { // CHECK INPUTS
// if key is not set if (!$key) return false; // do not store ‘null’ values if ($value===null) return false; // FILE AND DIRECTORY MANAGEMENT $params=$this->getFileDetails($key); // attempt to create the directory chain if (!Dir::create($params[‘fileLocation’])) return false; // DETERMINE THE EXPIRE TIMESTAMP if
(is_numeric($expireTime) and $expireTime>0) { $expireTimestamp=TIMESTAMP+$expireTime; } else { switch (substr($expireTime, -1)) { case ‘s’: $expireTimestamp=TIMESTAMP+$expireTime;break; case ‘m’: $expireTimestamp=TIMESTAMP+$expireTime*60;break; case ‘h’: $expireTimestamp=TIMESTAMP+$expireTime*3600;break; case
‘d’: $expireTimestamp=TIMESTAMP+$expireTime*86400;break; default: $expireTimestamp=0; } } if (!$expireTimestamp) $expireTimestamp = TIMESTAMP + $this->defaultExpireTime; // FILE CONTENT $fileContent =$expire Timestamp .serialize($value) ; // WRITE THE CACHE FILE return
File::create($params[‘fileLocation’].$params[‘fileName’], $fileContent); } /** * Gets a value stored in the cache for a certain key. * @param String $key * @return Mixed - the stored value or null if the key was not found */ public function get($key) { // CHECK INPUTS if (!$key) return null; // CHECK THE FILE // get file params
$params=$this->getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’] .$params[‘fileName’]) or !is_readable($params [‘fileLocation’].$params[‘fileName’])) return null; // READ THE FILE$fc=File::getContents($params[‘fileLocation’].$params[‘fileName’]); // get and check expiration time $expirationTimestamp =substr
($fc, 0, 10); if ($expirationTimestamp<TIMESTAMP) { // delete the expired cache from disk $this->delete($key); return null; } // get contents, unserialize it and return it $valueSer=substr($fc, 10); $value=@unserialize($valueSer); if ($valu e===false) return null; else return $value; } /** * Deletes the value stored in the cache for a
certain key. * @param Mixed $key - if it is an array - deletes all those keys; if it is a string - deleted only that key * @return Boolean - indicating if the key was correctly deleted in the cache */ public function delete($key) { // CHECK INPUTS if (!$key) return true; // CHECK THE FILE $return=1; // A LIST OF KEYS TO BE DELETED if
(is_array($key)) { foreach($key as $k) { // get file params $params=$this->getFileDetails($k); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileN
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@
@
@
@ @
@ @ @
@ @
@
@
@ @ @
@
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@
@
@
@ @
@ @ @
@ @
@
@
@ @ @
@
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@
@
@
@ @
@ @ @
@ @
@
@
@ @ @
@
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@
@
@
@ @
@ @ @
@ @
@
@
@ @ @
@
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@ @
@ @
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@
@
@
@ @
@ @ @
@ @
@
@
@ @ @
@
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@
@
@
@ @
@ @ @
@ @
@
@
@ @ @
@
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@
@
@
@ @
@ @ @
@ @
@
@
@ @ @
@
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@
@
@
@ @
@ @ @
@ @
@
@
@ @ @
@
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@
@
@
@ @
@ @ @
@ @
@
@
@ @ @
@
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@ @
@ @
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
@ @
@ @ @
@ @
@
@ @
@ @
@ @ @
@
@
@
@
@ @
@ @ @
@ @
@
@
@ @ @
@
@
@ @ @ @
@ @
@
@ @
@ @
@
@
@
@ @ @
@
@ @
@ @ @
@ @
Business critical
end-to-end solutions
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015
dcs plus Catalogue 2015

More Related Content

What's hot

The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsSam Hennessy
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201Fabien Potencier
 
Everything About PowerShell
Everything About PowerShellEverything About PowerShell
Everything About PowerShellGaetano Causio
 
購物車程式架構簡介
購物車程式架構簡介購物車程式架構簡介
購物車程式架構簡介Jace Ju
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data ObjectsWez Furlong
 
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Fabien Potencier
 
Extbase and Beyond
Extbase and BeyondExtbase and Beyond
Extbase and BeyondJochen Rau
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Fabien Potencier
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsRoss Tuck
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkG Woo
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretssmueller_sandsmedia
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome TownRoss Tuck
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsBastian Feder
 

What's hot (20)

The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
 
Everything About PowerShell
Everything About PowerShellEverything About PowerShell
Everything About PowerShell
 
購物車程式架構簡介
購物車程式架構簡介購物車程式架構簡介
購物車程式架構簡介
 
zinno
zinnozinno
zinno
 
My shell
My shellMy shell
My shell
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data Objects
 
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
 
Oops in php
Oops in phpOops in php
Oops in php
 
Extbase and Beyond
Extbase and BeyondExtbase and Beyond
Extbase and Beyond
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and Hobgoblins
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secrets
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown Parts
 

Similar to dcs plus Catalogue 2015

DRUPAL 8 STORAGES OVERVIEW
DRUPAL 8 STORAGES OVERVIEWDRUPAL 8 STORAGES OVERVIEW
DRUPAL 8 STORAGES OVERVIEWDrupalCamp Kyiv
 
vfsStream - effective filesystem mocking
vfsStream - effective filesystem mocking vfsStream - effective filesystem mocking
vfsStream - effective filesystem mocking Sebastian Marek
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Developmentjsmith92
 
Aura Project for PHP
Aura Project for PHPAura Project for PHP
Aura Project for PHPHari K T
 
PHP Traits
PHP TraitsPHP Traits
PHP Traitsmattbuzz
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Jeff Carouth
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency InjectionRifat Nabi
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitsmueller_sandsmedia
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutesBarang CK
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 MinutesAzim Kurt
 

Similar to dcs plus Catalogue 2015 (20)

DRUPAL 8 STORAGES OVERVIEW
DRUPAL 8 STORAGES OVERVIEWDRUPAL 8 STORAGES OVERVIEW
DRUPAL 8 STORAGES OVERVIEW
 
vfsStream - effective filesystem mocking
vfsStream - effective filesystem mocking vfsStream - effective filesystem mocking
vfsStream - effective filesystem mocking
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Dando nome aos códigos
Dando nome aos códigosDando nome aos códigos
Dando nome aos códigos
 
Twitter codeigniter library
Twitter codeigniter libraryTwitter codeigniter library
Twitter codeigniter library
 
Aura Project for PHP
Aura Project for PHPAura Project for PHP
Aura Project for PHP
 
PHP Traits
PHP TraitsPHP Traits
PHP Traits
 
Drupal7 dbtng
Drupal7  dbtngDrupal7  dbtng
Drupal7 dbtng
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
BEAR DI
BEAR DIBEAR DI
BEAR DI
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
C99
C99C99
C99
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 

Recently uploaded

"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 

Recently uploaded (20)

"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 

dcs plus Catalogue 2015

  • 1. $return[‘fileLocation’]=$this->cachePath.$keyDir.’/’; $return[‘fileName’]=$return[‘keyHash’].’.cache’; return $return; } /** * Sets a value in the cache for a certain key. * @param String $key * @param Mixed $value * @param String $expireTime * @return Boolean - indicating if the key was correctly saved in the cache */ public function set($key, $value, $expireTime=0) { // CHECK INPUTS // if key is not set if (!$key) return false; // do not store ‘null’ values if ($value===null) return false; // FILE AND DIRECTORY MANAGEMENT $params=$this->getFileDetails($key); // attempt to create the directory chain if (!Dir::create($params[‘fileLocation’])) return false; // DETERMINE THE EXPIRE TIMESTAMP if (is_numeric($expireTime) and $expireTime>0) { $expireTimestamp=TIMESTAMP+$expireTime; } else { switch (substr($expireTime, -1)) { case ‘s’: $expireTimestamp=TIMESTAMP+$expireTime;break; case ‘m’: $expireTimestamp=TIMESTAMP+$expireTime*60;break; case ‘h’: $expireTimestamp=TIMESTAMP+$expireTime*3600;break; case ‘d’: $expireTimestamp=TIMESTAMP+$expireTime*86400;break; default: $expireTimestamp=0; } } if (!$expireTimestamp) $expireTimestamp = TIMESTAMP + $this->defaultExpireTime; // FILE CONTENT $fileContent =$expire Timestamp .serialize($value) ; // WRITE THE CACHE FILE return File::create($params[‘fileLocation’].$params[‘fileName’], $fileContent); } /** * Gets a value stored in the cache for a certain key. * @param String $key * @return Mixed - the stored value or null if the key was not found */ public function get($key) { // CHECK INPUTS if (!$key) return null; // CHECK THE FILE // get file params $params=$this->getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’] .$params[‘fileName’]) or !is_readable($params [‘fileLocation’].$params[‘fileName’])) return null; // READ THE FILE$fc=File::getContents($params[‘fileLocation’].$params[‘fileName’]); // get and check expiration time $expirationTimestamp =substr ($fc, 0, 10); if ($expirationTimestamp<TIMESTAMP) { // delete the expired cache from disk $this->delete($key); return null; } // get contents, unserialize it and return it $valueSer=substr($fc, 10); $value=@unserialize($valueSer); if ($valu e===false) return null; else return $value; } /** * Deletes the value stored in the cache for a certain key. * @param Mixed $key - if it is an array - deletes all those keys; if it is a string - deleted only that key * @return Boolean - indicating if the key was correctly deleted in the cache */ public function delete($key) { // CHECK INPUTS if (!$key) return true; // CHECK THE FILE $return=1; // A LIST OF KEYS TO BE DELETED if (is_array($key)) { foreach($key as $k) { // get file params $params=$this->getFileDetails($k); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) continue; // delete the file $return*=File::delete($params[‘fileLocation’].$params[‘fileName’]); } } // ONLY ONE KEY else { // get file params $params=$this- >getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) return true; // delete the file $return=File::delete($params[‘fileLocation’].$params[‘fileName’]); } return (Bool)$return; } /** * Deletes the whole cache content. * @return Boolean - indicating if the cache was completely destroyed * @see EngineCacheBaseInterface::flush() */ public function flush() { return Dir::delete($this->cachePath); } /** * Returns an associative array of details for a certain key: the file location, the expire timestamp * @return Array */ public function getInfo($key) { $return=array(); // associate the key $return[‘key’]=$key; // get more details $params=$this->getFileDetails($key); $fullFileName=$params[‘fileLocation’].$params[‘fileName’]; // CHECK IF THE FILE EXISTS if (!file_exists($fullFileName) or !is_readable($fullFileName)) { $return[‘fileExists’]=false; } else { // associate some more keys $return[‘fileExists’]=true; $return[‘keyHash’]=$params[‘keyHash’]; $return[‘fileLocation’]=$params[‘fileLocation’]; $return[‘fileName’]=$params[‘fileName’]; $return[‘fileSize’]=filesize($fullFileName); // get expire time $fc=File::getContents($fullFileName); $return[‘expireTimestamp’]=substr($fc, 0, 10); $return[‘expireTimestampReadable’]=date(TIMESTAMP_FULL_FORMAT, $return[‘expireTimestamp’]); // get the value $return [‘cachedValue’] =unserialize (substr($fc, 10)); } return $return; } } <?php namespace EnginePlugins; /** * The class is used for registering a new plugin. It is extended in a class which is automatically * executed. * @author Gabriel */ abstract class RegisterAbstract { /** * The list of observers for a registered plugin. * @var Array - associative array of [triggerName][index][EnginePluginsObserver object] */ protected $observers=array(); /** * The constructor will register the current plugin. */ public function __construct() { $this->register(); } /** * Stores a new observer for this plugin (the method is called from the defined method register() * in the concrete classes. * @param String $triggerName - the trigger name * @param EnginePluginsObserver $obs - the observer object * @throws Exception - if the triger name is not correct */ protected function addObserver($triggerName, EnginePluginsObserver $obs) { // check trigger name if (!$triggerName) { throw new Exception(‘The trigger name was not set in ‘.get_called_class().’::’.__FUNCTION__.”.”); } $this->observers[$triggerName][] = $obs; } /** * The method will add new observers to the current plugin (using the addObserver() method. */ abstract protected function register(); /** * Returns the list of observers for the current * @return multitype: */ public function getObservers() { return $this->observers; } } <?php namespace AppEntityMatch; /** * The class manages the matching of suppliers * @author Gabriel */ class Supplier extends AppEntityMatchBaseAbstract { /** * The export fields for suppliers. * @var Array */ protected $exportFields = array(‘alias’, ‘company’); /** * Extra filters - deleted and duplicated suppliers are not allwed. * @var String */ protected $matchingFilteringSQL = ‘AND ent.deleted=0 AND ent.idRealSupplier=0’; /** * The class name which will instantiate the Entity - used for primaryKey search. * @var String */ protected $entityClassName = ‘EntitySupplier’; /** * (non-PHPdoc) * @see AppEntityMatchBaseAbstract::setTableName() */ protected function setTableName() { global $DBTSuppliers; $this->tableName = $DBTSuppliers; } /** * Sets a search by supplier alias. * @param String $value - the supplier alias. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setAlias($value, $useWildcard=true) { $this->setSearchCriterion(‘alias’, $value, $useWildcard); } /** * Sets a search by supplier company name. * @param String $value - the supplier company name. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setCompany($value, $useWildcard=true) { $this- >setSearchCriterion(‘company’, $value, $useWildcard); } /** * Sets a search by supplier fiscal code. * @param String $value - the supplier fiscal code. */ public function setFiscalCode($value) { $this->setSearchCriterion(‘fiscalCode’, $value, false); } /** * Searches a supplier by its code. * @param String $value * @param String $codeName - indicate the type of code (iata, tktCode, etc) */ public function setCode($value, $codeName) { // check the code name global $CFG; if (!$CFG[‘travel’][‘standardCodes’][$codeName]) { throw new Exception(“The supplier code `{$codeName}` is not valid - you can only use: “.implode(‘, ‘, array_keys($CFG[‘travel’][‘standardCodes’]))); } // add the search criterion $this->setSearchCriterion(‘code’, $value, false, array(‘codeName’=>$codeName)); } /** * Searches a supplier by the matching manually set in the external reservations system configs. * @param String $name - the supplier name * @param Int $idExternalResSystem - the external system */ public function setExtResSysName($name, $idExternalResSystem) { $this->setSearchCriterion(‘extResSys’, $name, false, array(‘idExtResSystem’=>$idExternalResSystem)); } /** * This method does a special search for supplier code (for the rest of the criteria, it uses the parent call. * @see AppEntityMatchBaseAbstract::searchRecords() */ protected function dispatchSearchRecords($field, $value, $useWildcard, Array $options=array()) { switch ($field) { case ‘code’: return $this->searchRecords_code($value, $options); break; case ‘extResSys’: return $this->searchRecords_extResSys($value, $options); break; default: return parent::dispatchSearchRecords($field, $value, $useWildcard, $options); } } /** * Searches a supplier by its code. * @param String $value - the supplier code * @param Array $options - stores the code name used */ private function searchRecords_code($value, Array $options) { global $DBTSupplierCodes; $db = DB::getInstance(); // RUN SQL $matchSupplierCodeSQL = “ SELECT “.$this->getSelectingFieldsSQL().” FROM `$DBTSupplierCodes` AS sc, `{$this->tableName}` AS ent WHERE sc.`code`=? AND sc.`value`=? AND `ent`.`id`=`sc`.`idSupplier` {$this->matchingFilteringSQL} “; $matchSupplierCodeEx = $db->Execute($matchSupplierCodeSQL, array($options[‘codeName’], $value)); if (!$matchSupplierCodeEx) { writeLog(“Could not match supplier by their code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by their code.’); } // STORE RESULTS $return = array(); foreach($matchSupplierCodeEx as $supp) { $return[$supp[‘id’]] = $supp; } return $return; } /** * Searches a supplier by its matching in the external reservation systems. * @param unknown $valuem * @param array $options */ private function searchRecords_extResSys($value, Array $options) { global $DBTImportRes_suppliersAssociations; $db = DB::getInstance(); // SEARCH IN THE DB $searchSupplierSQL=”SELECT tinaSupplierId FROM `$DBTImportRes_suppliersAssociations` WHERE systemSupplierId=? AND systemId=?”; $searchSupplierEx=$db->Execute($searchSupplierSQL, array($value, $options[‘idExtResSystem’])); if (!$searchSupplierEx) { writeLog(“Could not match supplier by the external reservation systems code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by the external reservation systems code.’); } // RETURN THE RESULT $supp=$searchSupplierEx->FetchRow(); $return = array(); if ($supp[‘tinaSupplierId’]) { $return=$this->searchRecord_primaryKey($supp[‘tinaSupplierId’]); } return $return; } } <?php namespace AppConfig; abstract class XmlBasicAbstract extends BaseAbstract { /** * Stores the configuration file (relative to the “files/config/” dir). For config files stored * inside subdirectories, the subdirectory is included (Ex: services/servicesList.xml). * @var String */ protected $fileName=null; /** * The filename with its full path. * @var String */ protected $fileNameWithPath=null; /** * (non-PHPdoc) * @see AppConfigBaseAbstract::constructInit() */ protected function constructInit() { // check if the file name is okay if (!$this->fileName) { throw new Exception(‘You did not set the `fileName` attribute for the class `’.get_called_class().’`.’); } // set the $this->fileNameWithPath=MODULE_REL_PATH . FILEPATH_APPCONFIGS . $this->fileName; } /** * Sets a reference to the current data in session so it can be stored during session lifetime. * @see AppConfigBaseAbstract::constructAdmin() */ protected function constructAdmin() { global $S; $className =get_called_ class(); // if items list and changed flag are set in session - they are copied into class attributes if (isset($S[‘admin’][‘configApp’][$className][‘itemsList’])) { $this->itemsList=$S [‘admin’] [‘configApp’] [$className ][‘itemsList’]; } if (isset($S[‘admin’][‘configApp’][$className][‘changedFlag’])) { $this->changedFlag=$S[‘admin’][‘configApp’][$className][‘changedFlag’]; } // these references will keep the data over different page loads $S[‘admin’] [‘configApp’] [$className] [‘itemsList’] =&$this->itemsList; $S[‘admin’][‘configApp’][$className][‘changedFlag’]=&$this->changedFlag; } /** * (non-PHPdoc) * @see AppConfigBaseAbstract::getAll_rawData() */ protected function getAll_rawData() { // return the output in case the file does not exist if (!file_exists($this- >fileNameWithPath)) return $this->getAll_rawData_fileNotExists(); // the file exists - load the content as XML (and check it) $xml=@simplexml_load_file($this->fileNameWithPath); if (!($xml instanceof SimpleXMLElement)) throw new Exception(‘The config file is not a well formed XML (class = ‘.get_called_class().’ ; file = ‘.$this- >fileNameWithPath.’).’); // return the array from the parsed XML content return $this->getAll _rawData _extract DataFromFile($xml); } /** * Sets the default output in case the XML file is missing. * @return Array */ protected function getAll_rawData_fileNotExists() { return array(); } /** * Returns the extracted data after the XML content is parsed. * @param SimpleXMLElement $xml - the parsed xml * @return Array - the items list or whatever output is needed. */ abstract protected function getAll_ rawData _extractData FromFile ( Simple XMLElement $xml); /** * Sets an element in the internal attribute $this->itemsList. The method can be called multiple * times and they will overwrite the older values. * @param String $var - or the name of one key (a string); * @param Mixed $value - the value of the key; * @throws Exception - if input is bad */ public function set($var, $value) { // check constructor type if ($this->constructType!=’admin’) throw new Exception(“You can use the method `”.get _called_ class().’::’.__FUNCTION__.”` only if the constructor type is `admin`.”); // check inputs if (!is_string($var)) throw new Exception(“You did not set() a correct name for the key.”); // (re)set one key $this->itemsList[$var]=$value; // update the changed flag $this->changedFlag=true; } /** * Sets all the elements in the internal attribute $this- >itemsList (rewrites any old data * already stored). The parameter is an associative array and the keys will be * stored one by one. * @param Array $vars - associative array of keys * @throws Exception - if input is bad */ public function setAll($vars) { // check constructor type if ($this->constructType!=’admin’) throw new Exception(“You can use the method `”.get_c alled_class().’::’.__ FUNCTION__.”` only if the constructor type is `admin`.”); // check inputs if (!is_array($vars)) throw new Exception(“You did not setAll() a correct list of elements - the parameter is not an array.”); // (re)set a list of keys $this->itemsList=$vars; // update the changed flag $this->changed Flag=true; } /** * (non-PHPdoc) * @see AppConfigBaseAbstract::save_write_do() */ protected function save_write_do() { // GETS THE SIMPLEXML OBJECT TO BE WRITTEN ON DISK gets the simplexml object $xmlObj=$this->save_write_do _getXml(); // checks that the object is correct (it is a valid simplexml object) if (!($xmlObj instanceof SimpleXMLElement)) throw new Exception(‘The output of the method `’.get_ called_class() .’::save_write_do_getXml` must be a `SimpleXMLElement` object.’); // (RE)WRITE FILE ON DISK // check if the file is writeable $fileChmod=false; if (file_exists($this->fileNameWithPath)) { if (!is_writeable($this->fileNameWithPath)) $this- >addErrorMessage(‘The config file exists but it is not writeable.’); } else { $fileChmod=true; } // (OVER)WRITE THE FILE CONTENT - if (!file_put_contents($this->fileNameWithPath, $xmlObj->asXml())) { $this->addErrorMessage(‘The config file could not be (over)written.’); } // if the file did not exist - chmod it if ($fileChmod) { if (!chmod($this->fileNameWithPath, 0777)) { $this->addErrorMessage(‘The config file could not have its acess rights updated.’); } } } /** * Returns the SimpleXML object to be written on disk. * @return SimpleXMLElement */ abstract protected function save_write_do_getXml(); } <?php namespace EngineCache; /** * The class is used to manage the cache stored on disk. * @author Gabriel Grosu */ class Disk implements EngineCacheBaseInterface { /** * The full location where the cache files are stored. * @var String */ protected $cachePath=’’; /** * The prefix key is used to avoid the reusing of keys if the application was updated. * @var String */ protected $keyPrefix=’’; /** * The default expiration time limit, if no param is specified when calling set() * @var int */ protected $defaultExpireTime = 2592000; // 2592000 = one month /** * The class constructor. */ public function __construct() { global $CFG; // realpath is used because cwd may change in __destructor(s) - AppEntityCache caches the entity object in destructors. $this->cachePath=realpath(MODULE_REL_PATH.$CFG[‘paths’][‘files’]).’/’.$CFG[‘cache’][‘disk’][‘location’]; // sets the mem cached key prefix $this->keyPrefix=$CFG[‘global’][‘application’][‘versionBuild’]; return true; } /** * Returns some associative array of data determined from the key * @param Array $key */ private function getFileDetails($key) { $return=array(); // rewrite the key $key=$this->keyPrefix.’-’.$key; // the key hash $return[‘keyHash’]=md5($key); // the subdir for the current key $keyDir=substr($return[‘keyHash’], 0, 2); // the full file location $return[‘fileLocation’]=$this->cachePath.$keyDir.’/’; $return[‘fileName’]=$return[‘keyHash’].’.cache’; return $return; } /** * Sets a value in the cache for a certain key. * @param String $key * @param Mixed $value * @param String $expireTime * @return Boolean - indicating if the key was correctly saved in the cache */ public function set($key, $value, $expireTime=0) { // CHECK INPUTS // if key is not set if (!$key) return false; // do not store ‘null’ values if ($value===null) return false; // FILE AND DIRECTORY MANAGEMENT $params=$this->getFileDetails($key); // attempt to create the directory chain if (!Dir::create($params[‘fileLocation’])) return false; // DETERMINE THE EXPIRE TIMESTAMP if (is_numeric($expireTime) and $expireTime>0) { $expireTimestamp=TIMESTAMP+$expireTime; } else { switch (substr($expireTime, -1)) { case ‘s’: $expireTimestamp=TIMESTAMP+$expireTime;break; case ‘m’: $expireTimestamp=TIMESTAMP+$expireTime*60;break; case ‘h’: $expireTimestamp=TIMESTAMP+$expireTime*3600;break; case ‘d’: $expireTimestamp=TIMESTAMP+$expireTime*86400;break; default: $expireTimestamp=0; } } if (!$expireTimestamp) $expireTimestamp = TIMESTAMP + $this->defaultExpireTime; // FILE CONTENT $fileContent =$expire Timestamp .serialize($value) ; // WRITE THE CACHE FILE return File::create($params[‘fileLocation’].$params[‘fileName’], $fileContent); } /** * Gets a value stored in the cache for a certain key. * @param String $key * @return Mixed - the stored value or null if the key was not found */ public function get($key) { // CHECK INPUTS if (!$key) return null; // CHECK THE FILE // get file params $params=$this->getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’] .$params[‘fileName’]) or !is_readable($params [‘fileLocation’].$params[‘fileName’])) return null; // READ THE FILE$fc=File::getContents($params[‘fileLocation’].$params[‘fileName’]); // get and check expiration time $expirationTimestamp =substr ($fc, 0, 10); if ($expirationTimestamp<TIMESTAMP) { // delete the expired cache from disk $this->delete($key); return null; } // get contents, unserialize it and return it $valueSer=substr($fc, 10); $value=@unserialize($valueSer); if ($valu e===false) return null; else return $value; } /** * Deletes the value stored in the cache for a certain key. * @param Mixed $key - if it is an array - deletes all those keys; if it is a string - deleted only that key * @return Boolean - indicating if the key was correctly deleted in the cache */ public function delete($key) { // CHECK INPUTS if (!$key) return true; // CHECK THE FILE $return=1; // A LIST OF KEYS TO BE DELETED if (is_array($key)) { foreach($key as $k) { // get file params $params=$this->getFileDetails($k); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) continue; // delete the file $return*=File::delete($params[‘fileLocation’].$params[‘fileName’]); } } // ONLY ONE KEY else { // get file params $params=$this- >getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) return true; // delete the file $return=File::delete($params[‘fileLocation’].$params[‘fileName’]); } return (Bool)$return; } /** * Deletes the whole cache content. * @return Boolean - indicating if the cache was completely destroyed * @see EngineCacheBaseInterface::flush() */ public function flush() { return Dir::delete($this->cachePath); } /** * Returns an associative array of details for a certain key: the file location, the expire timestamp * @return Array */ public function getInfo($key) { $return=array(); // associate the key $return[‘key’]=$key; // get more details $params=$this->getFileDetails($key); $fullFileName=$params[‘fileLocation’].$params[‘fileName’]; // CHECK IF THE FILE EXISTS if (!file_exists($fullFileName) or !is_readable($fullFileName)) { $return[‘fileExists’]=false; } else { // associate some more keys $return[‘fileExists’]=true; $return[‘keyHash’]=$params[‘keyHash’]; $return[‘fileLocation’]=$params[‘fileLocation’]; $return[‘fileName’]=$params[‘fileName’]; $return[‘fileSize’]=filesize($fullFileName); // get expire time $fc=File::getContents($fullFileName); $return[‘expireTimestamp’]=substr($fc, 0, 10); $return[‘expireTimestampReadable’]=date(TIMESTAMP_FULL_FORMAT, $return[‘expireTimestamp’]); // get the value $return [‘cachedValue’] =unserialize (substr($fc, 10)); } return $return; } } <?php namespace EnginePlugins; /** * The class is used for registering a new plugin. It is extended in a class which is automatically * executed. * @author Gabriel */ abstract class RegisterAbstract { /** * The list of observers for a registered plugin. * @var Array - associative array of [triggerName][index][EnginePluginsObserver object] */ protected $observers=array(); /** * The constructor will register the current plugin. */ public function __construct() { $this->register(); } /** * Stores a new observer for this plugin (the method is called from the defined method register() * in the concrete classes. * @param String $triggerName - the trigger name * @param EnginePluginsObserver $obs - the observer object * @throws Exception - if the triger name is not correct */ protected function addObserver($triggerName, EnginePluginsObserver $obs) { // check trigger name if (!$triggerName) { throw new Exception(‘The trigger name was not set in ‘.get_called_class().’::’.__FUNCTION__.”.”); } $this->observers[$triggerName][] = $obs; } /** * The method will add new observers to the current plugin (using the addObserver() method. */ abstract protected function register(); /** * Returns the list of observers for the current * @return multitype: */ public function getObservers() { return $this->observers; } } <?php namespace AppEntityMatch; /** * The class manages the matching of suppliers * @author Gabriel */ class Supplier extends AppEntityMatchBaseAbstract { /** * The export fields for suppliers. * @var Array */ protected $exportFields = array(‘alias’, ‘company’); /** * Extra filters - deleted and duplicated suppliers are not allwed. * @var String */ protected $matchingFilteringSQL = ‘AND ent.deleted=0 AND ent.idRealSupplier=0’; /** * The class name which will instantiate the Entity - used for primaryKey search. * @var String */ protected $entityClassName = ‘EntitySupplier’; /** * (non-PHPdoc) * @see AppEntityMatchBaseAbstract::setTableName() */ protected function setTableName() { global $DBTSuppliers; $this->tableName = $DBTSuppliers; } /** * Sets a search by supplier alias. * @param String $value - the supplier alias. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setAlias($value, $useWildcard=true) { $this->setSearchCriterion(‘alias’, $value, $useWildcard); } /** * Sets a search by supplier company name. * @param String $value - the supplier company name. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setCompany($value, $useWildcard=true) { $this- >setSearchCriterion(‘company’, $value, $useWildcard); } /** * Sets a search by supplier fiscal code. * @param String $value - the supplier fiscal code. */ public function setFiscalCode($value) { $this->setSearchCriterion(‘fiscalCode’, $value, false); } /** * Searches a supplier by its code. * @param String $value * @param String $codeName - indicate the type of code (iata, tktCode, etc) */ public function setCode($value, $codeName) { // check the code name global $CFG; if (!$CFG[‘travel’][‘standardCodes’][$codeName]) { throw new Exception(“The supplier code `{$codeName}` is not valid - you can only use: “.implode(‘, ‘, array_keys($CFG[‘travel’][‘standardCodes’]))); } // add the search criterion $this->setSearchCriterion(‘code’, $value, false, array(‘codeName’=>$codeName)); } /** * Searches a supplier by the matching manually set in the external reservations system configs. * @param String $name - the supplier name * @param Int $idExternalResSystem - the external system */ public function setExtResSysName($name, $idExternalResSystem) { $this->setSearchCriterion(‘extResSys’, $name, false, array(‘idExtResSystem’=>$idExternalResSystem)); } /** * This method does a special search for supplier code (for the rest of the criteria, it uses the parent call. * @see AppEntityMatchBaseAbstract::searchRecords() */ protected function dispatchSearchRecords($field, $value, $useWildcard, Array $options=array()) { switch ($field) { case ‘code’: return $this->searchRecords_code($value, $options); break; case ‘extResSys’: return $this->searchRecords_extResSys($value, $options); break; default: return parent::dispatchSearchRecords($field, $value, $useWildcard, $options); } } /** * Searches a supplier by its code. * @param String $value - the supplier code * @param Array $options - stores the code name used */ private function searchRecords_code($value, Array $options) { global $DBTSupplierCodes; $db = DB::getInstance(); // RUN SQL $matchSupplierCodeSQL = “ SELECT “.$this->getSelectingFieldsSQL().” FROM `$DBTSupplierCodes` AS sc, `{$this->tableName}` AS ent WHERE sc.`code`=? AND sc.`value`=? AND `ent`.`id`=`sc`.`idSupplier` {$this->matchingFilteringSQL} “; $matchSupplierCodeEx = $db->Execute($matchSupplierCodeSQL, array($options[‘codeName’], $value)); if (!$matchSupplierCodeEx) { writeLog(“Could not match supplier by their code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by their code.’); } // STORE RESULTS $return = array(); foreach($matchSupplierCodeEx as $supp) { $return[$supp[‘id’]] = $supp; } return $return; } /** * Searches a supplier by its matching in the external reservation systems. * @param unknown $valuem * @param array $options */ private function searchRecords_extResSys($value, Array $options) { global $DBTImportRes_suppliersAssociations; $db = DB::getInstance(); // SEARCH IN THE DB $searchSupplierSQL=”SELECT tinaSupplierId FROM `$DBTImportRes_suppliersAssociations` WHERE systemSupplierId=? AND systemId=?”; $searchSupplierEx=$db->Execute($searchSupplierSQL, array($value, $options[‘idExtResSystem’])); if (!$searchSupplierEx) { writeLog(“Could not match supplier by the external reservation systems code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by the external reservation systems code.’); } // RETURN THE RESULT $supp=$searchSupplierEx->FetchRow(); $return = array(); if ($supp[‘tinaSupplierId’]) { $return=$this->searchRecord_primaryKey($supp[‘tinaSupplierId’]); } return $return; } } <?php namespace AppConfig; abstract class XmlBasicAbstract extends BaseAbstract { /** * Stores the configuration file (relative to the “files/config/” dir). For config files stored * inside subdirectories, the subdirectory is included (Ex: services/servicesList.xml). * @var String */ protected $fileName=null; /** * The filename with its full path. * @var String */ protected $fileNameWithPath=null; /** * (non-PHPdoc) * @see AppConfigBaseAbstract::constructInit() */ protected function constructInit() { // check if the file name is okay if (!$this->fileName) { throw new Exception(‘You did not set the `fileName` attribute for the class `’.get_called_class().’`.’); } // set the $this->fileNameWithPath=MODULE_REL_PATH . FILEPATH_APPCONFIGS . $this->fileName; } /** * Sets a reference to the current data in session so it can be stored during session lifetime. * @see AppConfigBaseAbstract::constructAdmin() */ protected function constructAdmin() { global $S; $className =get_called_ class(); // if items list and changed flag are set in session - they are copied into class attributes if $return[‘fileLocation’]=$this->cachePath.$keyDir.’/’; $return[‘fileName’]=$return[‘keyHash’].’.cache’; return $return; } /** * Sets a value in the cache for a certain key. * @param String $key * @param Mixed $value * @param String $expireTime * @return Boolean - indicating if the key was correctly saved in the cache */ public function set($key, $value, $expireTime=0) { // CHECK INPUTS // if key is not set if (!$key) return false; // do not store ‘null’ values if ($value===null) return false; // FILE AND DIRECTORY MANAGEMENT $params=$this->getFileDetails($key); // attempt to create the directory chain if (!Dir::create($params[‘fileLocation’])) return false; // DETERMINE THE EXPIRE TIMESTAMP if (is_numeric($expireTime) and $expireTime>0) { $expireTimestamp=TIMESTAMP+$expireTime; } else { switch (substr($expireTime, -1)) { case ‘s’: $expireTimestamp=TIMESTAMP+$expireTime;break; case ‘m’: $expireTimestamp=TIMESTAMP+$expireTime*60;break; case ‘h’: $expireTimestamp=TIMESTAMP+$expireTime*3600;break; case ‘d’: $expireTimestamp=TIMESTAMP+$expireTime*86400;break; default: $expireTimestamp=0; } } if (!$expireTimestamp) $expireTimestamp = TIMESTAMP + $this->defaultExpireTime; // FILE CONTENT $fileContent =$expire Timestamp .serialize($value) ; // WRITE THE CACHE FILE return File::create($params[‘fileLocation’].$params[‘fileName’], $fileContent); } /** * Gets a value stored in the cache for a certain key. * @param String $key * @return Mixed - the stored value or null if the key was not found */ public function get($key) { // CHECK INPUTS if (!$key) return null; // CHECK THE FILE // get file params $params=$this->getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’] .$params[‘fileName’]) or !is_readable($params [‘fileLocation’].$params[‘fileName’])) return null; // READ THE FILE$fc=File::getContents($params[‘fileLocation’].$params[‘fileName’]); // get and check expiration time $expirationTimestamp =substr ($fc, 0, 10); if ($expirationTimestamp<TIMESTAMP) { // delete the expired cache from disk $this->delete($key); return null; } // get contents, unserialize it and return it $valueSer=substr($fc, 10); $value=@unserialize($valueSer); if ($valu e===false) return null; else return $value; } /** * Deletes the value stored in the cache for a certain key. * @param Mixed $key - if it is an array - deletes all those keys; if it is a string - deleted only that key * @return Boolean - indicating if the key was correctly deleted in the cache */ public function delete($key) { // CHECK INPUTS if (!$key) return true; // CHECK THE FILE $return=1; // A LIST OF KEYS TO BE DELETED if (is_array($key)) { foreach($key as $k) { // get file params $params=$this->getFileDetails($k); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) continue; // delete the file $return*=File::delete($params[‘fileLocation’].$params[‘fileName’]); } } // ONLY ONE KEY else { // get file params $params=$this- >getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileName’])) return true; // delete the file $return=File::delete($params[‘fileLocation’].$params[‘fileName’]); } return (Bool)$return; } /** * Deletes the whole cache content. * @return Boolean - indicating if the cache was completely destroyed * @see EngineCacheBaseInterface::flush() */ public function flush() { return Dir::delete($this->cachePath); } /** * Returns an associative array of details for a certain key: the file location, the expire timestamp * @return Array */ public function getInfo($key) { $return=array(); // associate the key $return[‘key’]=$key; // get more details $params=$this->getFileDetails($key); $fullFileName=$params[‘fileLocation’].$params[‘fileName’]; // CHECK IF THE FILE EXISTS if (!file_exists($fullFileName) or !is_readable($fullFileName)) { $return[‘fileExists’]=false; } else { // associate some more keys $return[‘fileExists’]=true; $return[‘keyHash’]=$params[‘keyHash’]; $return[‘fileLocation’]=$params[‘fileLocation’]; $return[‘fileName’]=$params[‘fileName’]; $return[‘fileSize’]=filesize($fullFileName); // get expire time $fc=File::getContents($fullFileName); $return[‘expireTimestamp’]=substr($fc, 0, 10); $return[‘expireTimestampReadable’]=date(TIMESTAMP_FULL_FORMAT, $return[‘expireTimestamp’]); // get the value $return [‘cachedValue’] =unserialize (substr($fc, 10)); } return $return; } } <?php namespace EnginePlugins; /** * The class is used for registering a new plugin. It is extended in a class which is automatically * executed. * @author Gabriel */ abstract class RegisterAbstract { /** * The list of observers for a registered plugin. * @var Array - associative array of [triggerName][index][EnginePluginsObserver object] */ protected $observers=array(); /** * The constructor will register the current plugin. */ public function __construct() { $this->register(); } /** * Stores a new observer for this plugin (the method is called from the defined method register() * in the concrete classes. * @param String $triggerName - the trigger name * @param EnginePluginsObserver $obs - the observer object * @throws Exception - if the triger name is not correct */ protected function addObserver($triggerName, EnginePluginsObserver $obs) { // check trigger name if (!$triggerName) { throw new Exception(‘The trigger name was not set in ‘.get_called_class().’::’.__FUNCTION__.”.”); } $this->observers[$triggerName][] = $obs; } /** * The method will add new observers to the current plugin (using the addObserver() method. */ abstract protected function register(); /** * Returns the list of observers for the current * @return multitype: */ public function getObservers() { return $this->observers; } } <?php namespace AppEntityMatch; /** * The class manages the matching of suppliers * @author Gabriel */ class Supplier extends AppEntityMatchBaseAbstract { /** * The export fields for suppliers. * @var Array */ protected $exportFields = array(‘alias’, ‘company’); /** * Extra filters - deleted and duplicated suppliers are not allwed. * @var String */ protected $matchingFilteringSQL = ‘AND ent.deleted=0 AND ent.idRealSupplier=0’; /** * The class name which will instantiate the Entity - used for primaryKey search. * @var String */ protected $entityClassName = ‘EntitySupplier’; /** * (non-PHPdoc) * @see AppEntityMatchBaseAbstract::setTableName() */ protected function setTableName() { global $DBTSuppliers; $this->tableName = $DBTSuppliers; } /** * Sets a search by supplier alias. * @param String $value - the supplier alias. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setAlias($value, $useWildcard=true) { $this->setSearchCriterion(‘alias’, $value, $useWildcard); } /** * Sets a search by supplier company name. * @param String $value - the supplier company name. * @param Boolean $useWildcard - uses wildcard for this search or not. */ public function setCompany($value, $useWildcard=true) { $this- >setSearchCriterion(‘company’, $value, $useWildcard); } /** * Sets a search by supplier fiscal code. * @param String $value - the supplier fiscal code. */ public function setFiscalCode($value) { $this->setSearchCriterion(‘fiscalCode’, $value, false); } /** * Searches a supplier by its code. * @param String $value * @param String $codeName - indicate the type of code (iata, tktCode, etc) */ public function setCode($value, $codeName) { // check the code name global $CFG; if (!$CFG[‘travel’][‘standardCodes’][$codeName]) { throw new Exception(“The supplier code `{$codeName}` is not valid - you can only use: “.implode(‘, ‘, array_keys($CFG[‘travel’][‘standardCodes’]))); } // add the search criterion $this->setSearchCriterion(‘code’, $value, false, array(‘codeName’=>$codeName)); } /** * Searches a supplier by the matching manually set in the external reservations system configs. * @param String $name - the supplier name * @param Int $idExternalResSystem - the external system */ public function setExtResSysName($name, $idExternalResSystem) { $this->setSearchCriterion(‘extResSys’, $name, false, array(‘idExtResSystem’=>$idExternalResSystem)); } /** * This method does a special search for supplier code (for the rest of the criteria, it uses the parent call. * @see AppEntityMatchBaseAbstract::searchRecords() */ protected function dispatchSearchRecords($field, $value, $useWildcard, Array $options=array()) { switch ($field) { case ‘code’: return $this->searchRecords_code($value, $options); break; case ‘extResSys’: return $this->searchRecords_extResSys($value, $options); break; default: return parent::dispatchSearchRecords($field, $value, $useWildcard, $options); } } /** * Searches a supplier by its code. * @param String $value - the supplier code * @param Array $options - stores the code name used */ private function searchRecords_code($value, Array $options) { global $DBTSupplierCodes; $db = DB::getInstance(); // RUN SQL $matchSupplierCodeSQL = “ SELECT “.$this->getSelectingFieldsSQL().” FROM `$DBTSupplierCodes` AS sc, `{$this->tableName}` AS ent WHERE sc.`code`=? AND sc.`value`=? AND `ent`.`id`=`sc`.`idSupplier` {$this->matchingFilteringSQL} “; $matchSupplierCodeEx = $db->Execute($matchSupplierCodeSQL, array($options[‘codeName’], $value)); if (!$matchSupplierCodeEx) { writeLog(“Could not match supplier by their code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by their code.’); } // STORE RESULTS $return = array(); foreach($matchSupplierCodeEx as $supp) { $return[$supp[‘id’]] = $supp; } return $return; } /** * Searches a supplier by its matching in the external reservation systems. * @param unknown $valuem * @param array $options */ private function searchRecords_extResSys($value, Array $options) { global $DBTImportRes_suppliersAssociations; $db = DB::getInstance(); // SEARCH IN THE DB $searchSupplierSQL=”SELECT tinaSupplierId FROM `$DBTImportRes_suppliersAssociations` WHERE systemSupplierId=? AND systemId=?”; $searchSupplierEx=$db->Execute($searchSupplierSQL, array($value, $options[‘idExtResSystem’])); if (!$searchSupplierEx) { writeLog(“Could not match supplier by the external reservation systems code.”, ‘events’, 9); throw new Exception(‘Could not match supplier by the external reservation systems code.’); } // RETURN THE RESULT $supp=$searchSupplierEx->FetchRow(); $return = array(); if ($supp[‘tinaSupplierId’]) { $return=$this->searchRecord_primaryKey($supp[‘tinaSupplierId’]); } return $return; } } <?php namespace AppConfig; abstract class XmlBasicAbstract extends BaseAbstract { /** * Stores the configuration file (relative to the “files/config/” dir). For config files stored * inside subdirectories, the subdirectory is included (Ex: services/servicesList.xml). * @var String */ protected $fileName=null; /** * The filename with its full path. * @var String */ protected $fileNameWithPath=null; /** * (non-PHPdoc) * @see AppConfigBaseAbstract::constructInit() */ protected function constructInit() { // check if the file name is okay if (!$this->fileName) { throw new Exception(‘You did not set the `fileName` attribute for the class `’.get_called_class().’`.’); } // set the $this->fileNameWithPath=MODULE_REL_PATH . FILEPATH_APPCONFIGS . $this->fileName; } /** * Sets a reference to the current data in session so it can be stored during session lifetime. * @see AppConfigBaseAbstract::constructAdmin() */ protected function constructAdmin() { global $S; $className =get_called_ class(); // if items list and changed flag are set in session - they are copied into class attributes if (isset($S[‘admin’][‘configApp’][$className][‘itemsList’])) { $this->itemsList=$S [‘admin’] [‘configApp’] [$className ][‘itemsList’]; } if (isset($S[‘admin’][‘configApp’][$className][‘changedFlag’])) { $this->changedFlag=$S[‘admin’][‘configApp’][$className][‘changedFlag’]; } // these references will keep the data over different page loads $S[‘admin’] [‘configApp’] [$className] [‘itemsList’] =&$this->itemsList; $S[‘admin’][‘configApp’][$className][‘changedFlag’]=&$this->changedFlag; } /** * (non-PHPdoc) * @see AppConfigBaseAbstract::getAll_rawData() */ protected function getAll_rawData() { // return the output in case the file does not exist if (!file_exists($this- >fileNameWithPath)) return $this->getAll_rawData_fileNotExists(); // the file exists - load the content as XML (and check it) $xml=@simplexml_load_file($this->fileNameWithPath); if (!($xml instanceof SimpleXMLElement)) throw new Exception(‘The config file is not a well formed XML (class = ‘.get_called_class().’ ; file = ‘.$this- >fileNameWithPath.’).’); // return the array from the parsed XML content return $this->getAll _rawData _extract DataFromFile($xml); } /** * Sets the default output in case the XML file is missing. * @return Array */ protected function getAll_rawData_fileNotExists() { return array(); } /** * Returns the extracted data after the XML content is parsed. * @param SimpleXMLElement $xml - the parsed xml * @return Array - the items list or whatever output is needed. */ abstract protected function getAll_ rawData _extractData FromFile ( Simple XMLElement $xml); /** * Sets an element in the internal attribute $this->itemsList. The method can be called multiple * times and they will overwrite the older values. * @param String $var - or the name of one key (a string); * @param Mixed $value - the value of the key; * @throws Exception - if input is bad */ public function set($var, $value) { // check constructor type if ($this->constructType!=’admin’) throw new Exception(“You can use the method `”.get _called_ class().’::’.__FUNCTION__.”` only if the constructor type is `admin`.”); // check inputs if (!is_string($var)) throw new Exception(“You did not set() a correct name for the key.”); // (re)set one key $this->itemsList[$var]=$value; // update the changed flag $this->changedFlag=true; } /** * Sets all the elements in the internal attribute $this- >itemsList (rewrites any old data * already stored). The parameter is an associative array and the keys will be * stored one by one. * @param Array $vars - associative array of keys * @throws Exception - if input is bad */ public function setAll($vars) { // check constructor type if ($this->constructType!=’admin’) throw new Exception(“You can use the method `”.get_c alled_class().’::’.__ FUNCTION__.”` only if the constructor type is `admin`.”); // check inputs if (!is_array($vars)) throw new Exception(“You did not setAll() a correct list of elements - the parameter is not an array.”); // (re)set a list of keys $this->itemsList=$vars; // update the changed flag $this->changed Flag=true; } /** * (non-PHPdoc) * @see AppConfigBaseAbstract::save_write_do() */ protected function save_write_do() { // GETS THE SIMPLEXML OBJECT TO BE WRITTEN ON DISK gets the simplexml object $xmlObj=$this->save_write_do _getXml(); // checks that the object is correct (it is a valid simplexml object) if (!($xmlObj instanceof SimpleXMLElement)) throw new Exception(‘The output of the method `’.get_ called_class() .’::save_write_do_getXml` must be a `SimpleXMLElement` object.’); // (RE)WRITE FILE ON DISK // check if the file is writeable $fileChmod=false; if (file_exists($this->fileNameWithPath)) { if (!is_writeable($this->fileNameWithPath)) $this- >addErrorMessage(‘The config file exists but it is not writeable.’); } else { $fileChmod=true; } // (OVER)WRITE THE FILE CONTENT - if (!file_put_contents($this->fileNameWithPath, $xmlObj->asXml())) { $this->addErrorMessage(‘The config file could not be (over)written.’); } // if the file did not exist - chmod it if ($fileChmod) { if (!chmod($this->fileNameWithPath, 0777)) { $this->addErrorMessage(‘The config file could not have its acess rights updated.’); } } } /** * Returns the SimpleXML object to be written on disk. * @return SimpleXMLElement */ abstract protected function save_write_do_getXml(); } <?php namespace EngineCache; /** * The class is used to manage the cache stored on disk. * @author Gabriel Grosu */ class Disk implements EngineCacheBaseInterface { /** * The full location where the cache files are stored. * @var String */ protected $cachePath=’’; /** * The prefix key is used to avoid the reusing of keys if the application was updated. * @var String */ protected $keyPrefix=’’; /** * The default expiration time limit, if no param is specified when calling set() * @var int */ protected $defaultExpireTime = 2592000; // 2592000 = one month /** * The class constructor. */ public function __construct() { global $CFG; // realpath is used because cwd may change in __destructor(s) - AppEntityCache caches the entity object in destructors. $this->cachePath=realpath(MODULE_REL_PATH.$CFG[‘paths’][‘files’]).’/’.$CFG[‘cache’][‘disk’][‘location’]; // sets the mem cached key prefix $this->keyPrefix=$CFG[‘global’][‘application’][‘versionBuild’]; return true; } /** * Returns some associative array of data determined from the key * @param Array $key */ private function getFileDetails($key) { $return=array(); // rewrite the key $key=$this->keyPrefix.’-’.$key; // the key hash $return[‘keyHash’]=md5($key); // the subdir for the current key $keyDir=substr($return[‘keyHash’], 0, 2); // the full file location $return[‘fileLocation’]=$this->cachePath.$keyDir.’/’; $return[‘fileName’]=$return[‘keyHash’].’.cache’; return $return; } /** * Sets a value in the cache for a certain key. * @param String $key * @param Mixed $value * @param String $expireTime * @return Boolean - indicating if the key was correctly saved in the cache */ public function set($key, $value, $expireTime=0) { // CHECK INPUTS // if key is not set if (!$key) return false; // do not store ‘null’ values if ($value===null) return false; // FILE AND DIRECTORY MANAGEMENT $params=$this->getFileDetails($key); // attempt to create the directory chain if (!Dir::create($params[‘fileLocation’])) return false; // DETERMINE THE EXPIRE TIMESTAMP if (is_numeric($expireTime) and $expireTime>0) { $expireTimestamp=TIMESTAMP+$expireTime; } else { switch (substr($expireTime, -1)) { case ‘s’: $expireTimestamp=TIMESTAMP+$expireTime;break; case ‘m’: $expireTimestamp=TIMESTAMP+$expireTime*60;break; case ‘h’: $expireTimestamp=TIMESTAMP+$expireTime*3600;break; case ‘d’: $expireTimestamp=TIMESTAMP+$expireTime*86400;break; default: $expireTimestamp=0; } } if (!$expireTimestamp) $expireTimestamp = TIMESTAMP + $this->defaultExpireTime; // FILE CONTENT $fileContent =$expire Timestamp .serialize($value) ; // WRITE THE CACHE FILE return File::create($params[‘fileLocation’].$params[‘fileName’], $fileContent); } /** * Gets a value stored in the cache for a certain key. * @param String $key * @return Mixed - the stored value or null if the key was not found */ public function get($key) { // CHECK INPUTS if (!$key) return null; // CHECK THE FILE // get file params $params=$this->getFileDetails($key); // check the file if (!file_exists($params[‘fileLocation’] .$params[‘fileName’]) or !is_readable($params [‘fileLocation’].$params[‘fileName’])) return null; // READ THE FILE$fc=File::getContents($params[‘fileLocation’].$params[‘fileName’]); // get and check expiration time $expirationTimestamp =substr ($fc, 0, 10); if ($expirationTimestamp<TIMESTAMP) { // delete the expired cache from disk $this->delete($key); return null; } // get contents, unserialize it and return it $valueSer=substr($fc, 10); $value=@unserialize($valueSer); if ($valu e===false) return null; else return $value; } /** * Deletes the value stored in the cache for a certain key. * @param Mixed $key - if it is an array - deletes all those keys; if it is a string - deleted only that key * @return Boolean - indicating if the key was correctly deleted in the cache */ public function delete($key) { // CHECK INPUTS if (!$key) return true; // CHECK THE FILE $return=1; // A LIST OF KEYS TO BE DELETED if (is_array($key)) { foreach($key as $k) { // get file params $params=$this->getFileDetails($k); // check the file if (!file_exists($params[‘fileLocation’].$params[‘fileN @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ Business critical end-to-end solutions