From e2d6ab6e8f119fb526d6ed217dd196219504d594 Mon Sep 17 00:00:00 2001 From: vl Date: Fri, 4 May 2012 12:04:49 +0200 Subject: [PATCH] Added: new webig system --- code/web/api/client/auth.php | 49 +++ code/web/api/client/config.php.default | 20 + code/web/api/client/user.php | 23 ++ code/web/api/client/utils.php | 3 + code/web/api/common/auth.php | 57 +++ code/web/api/common/config.php.default | 28 ++ code/web/api/common/db_lib.php | 422 +++++++++++++++++++++ code/web/api/common/logger.php | 43 +++ code/web/api/common/render.php | 218 +++++++++++ code/web/api/common/user.php | 3 + code/web/api/common/utils.php | 182 +++++++++ code/web/api/data/css/ryzom_iphone.css | 248 ++++++++++++ code/web/api/data/css/ryzom_ui.css | 227 +++++++++++ code/web/api/data/css/skin_b.gif | Bin 0 -> 748 bytes code/web/api/data/css/skin_bl.gif | Bin 0 -> 129 bytes code/web/api/data/css/skin_blank.png | Bin 0 -> 11070 bytes code/web/api/data/css/skin_blank_inner.png | Bin 0 -> 8986 bytes code/web/api/data/css/skin_br.gif | Bin 0 -> 130 bytes code/web/api/data/css/skin_header_l.gif | Bin 0 -> 434 bytes code/web/api/data/css/skin_header_m.gif | Bin 0 -> 6290 bytes code/web/api/data/css/skin_header_r.gif | Bin 0 -> 977 bytes code/web/api/data/css/skin_l.gif | Bin 0 -> 477 bytes code/web/api/data/css/skin_r.gif | Bin 0 -> 488 bytes code/web/api/data/css/skin_t.gif | Bin 0 -> 315 bytes code/web/api/data/css/skin_tl.gif | Bin 0 -> 99 bytes code/web/api/data/css/skin_tr.gif | Bin 0 -> 127 bytes code/web/api/data/img/bg.jpg | Bin 0 -> 50750 bytes code/web/api/data/img/lang/de.png | Bin 0 -> 229 bytes code/web/api/data/img/lang/en.png | Bin 0 -> 396 bytes code/web/api/data/img/lang/fr.png | Bin 0 -> 2889 bytes code/web/api/data/img/lang/ru.png | Bin 0 -> 2886 bytes code/web/api/data/img/lang/sp.png | Bin 0 -> 62 bytes code/web/api/data/img/logo.gif | Bin 0 -> 6763 bytes code/web/api/index.php | 1 + code/web/api/player_auth.php | 44 +++ code/web/api/ryzom_api.php | 49 +++ code/web/api/server/auth.php | 111 ++++++ code/web/api/server/config.php.default | 31 ++ code/web/api/server/user.php | 111 ++++++ code/web/api/server/utils.php | 49 +++ code/web/app/app_test/favicon.png | Bin 0 -> 2596 bytes code/web/app/app_test/index.php | 34 ++ code/web/app/app_test/lang.php | 15 + code/web/app/config.php.default | 26 ++ code/web/app/index.php | 35 ++ code/web/app/lang.php | 371 ++++++++++++++++++ 46 files changed, 2400 insertions(+) create mode 100644 code/web/api/client/auth.php create mode 100644 code/web/api/client/config.php.default create mode 100644 code/web/api/client/user.php create mode 100644 code/web/api/client/utils.php create mode 100644 code/web/api/common/auth.php create mode 100644 code/web/api/common/config.php.default create mode 100644 code/web/api/common/db_lib.php create mode 100644 code/web/api/common/logger.php create mode 100644 code/web/api/common/render.php create mode 100644 code/web/api/common/user.php create mode 100644 code/web/api/common/utils.php create mode 100644 code/web/api/data/css/ryzom_iphone.css create mode 100644 code/web/api/data/css/ryzom_ui.css create mode 100644 code/web/api/data/css/skin_b.gif create mode 100644 code/web/api/data/css/skin_bl.gif create mode 100644 code/web/api/data/css/skin_blank.png create mode 100644 code/web/api/data/css/skin_blank_inner.png create mode 100644 code/web/api/data/css/skin_br.gif create mode 100644 code/web/api/data/css/skin_header_l.gif create mode 100644 code/web/api/data/css/skin_header_m.gif create mode 100644 code/web/api/data/css/skin_header_r.gif create mode 100644 code/web/api/data/css/skin_l.gif create mode 100644 code/web/api/data/css/skin_r.gif create mode 100644 code/web/api/data/css/skin_t.gif create mode 100644 code/web/api/data/css/skin_tl.gif create mode 100644 code/web/api/data/css/skin_tr.gif create mode 100644 code/web/api/data/img/bg.jpg create mode 100644 code/web/api/data/img/lang/de.png create mode 100644 code/web/api/data/img/lang/en.png create mode 100644 code/web/api/data/img/lang/fr.png create mode 100644 code/web/api/data/img/lang/ru.png create mode 100644 code/web/api/data/img/lang/sp.png create mode 100644 code/web/api/data/img/logo.gif create mode 100644 code/web/api/index.php create mode 100644 code/web/api/player_auth.php create mode 100644 code/web/api/ryzom_api.php create mode 100644 code/web/api/server/auth.php create mode 100644 code/web/api/server/config.php.default create mode 100644 code/web/api/server/user.php create mode 100644 code/web/api/server/utils.php create mode 100644 code/web/app/app_test/favicon.png create mode 100644 code/web/app/app_test/index.php create mode 100644 code/web/app/app_test/lang.php create mode 100644 code/web/app/config.php.default create mode 100644 code/web/app/index.php create mode 100644 code/web/app/lang.php diff --git a/code/web/api/client/auth.php b/code/web/api/client/auth.php new file mode 100644 index 000000000..cab8a5886 --- /dev/null +++ b/code/web/api/client/auth.php @@ -0,0 +1,49 @@ +. + */ + +require_once(RYAPI_PATH.'client/config.php'); + +// Og (non-ryzom.com) method +function ryzom_authenticate_with_serverkey($cid, $name, $authserver, $authkey) { + global $_RYZOM_API_CONFIG; + $fn = $_RYZOM_API_CONFIG['auth_script'].'?name='.$name.'&cid='.$cid.'&authkey='.$authkey.'&authserver='.$authserver; + + $res = file_get_contents($fn); + return $res == '1'; +} + +// Ig method +function ryzom_authenticate_ingame($cid, $name, $authkey) { + global $_RYZOM_API_CONFIG; + $fn = $_RYZOM_API_CONFIG['auth_script'].'?name='.$name.'&cid='.$cid.'&authkey='.$authkey.'&ig=1'; + + $res = file_get_contents($fn); + echo $res; + return $res == '1'; +} + +// Session method +function ryzom_authenticate_with_session($name, $redirect) { + global $_RYZOM_API_CONFIG; + $fn = $_RYZOM_API_CONFIG['auth_script'].'?name='.$name; + + $res = file_get_contents($fn); + return $res == '1'; +} + +?> diff --git a/code/web/api/client/config.php.default b/code/web/api/client/config.php.default new file mode 100644 index 000000000..3c8ca869d --- /dev/null +++ b/code/web/api/client/config.php.default @@ -0,0 +1,20 @@ +. + */ + +// Url where player_auth.php is located +define('RYAPI_AUTH_SCRIPT', ''); diff --git a/code/web/api/client/user.php b/code/web/api/client/user.php new file mode 100644 index 000000000..de526dcca --- /dev/null +++ b/code/web/api/client/user.php @@ -0,0 +1,23 @@ +. + */ + +function ryzom_user_get_info($cid) { + return Array(); +} + +?> diff --git a/code/web/api/client/utils.php b/code/web/api/client/utils.php new file mode 100644 index 000000000..62a2de0c8 --- /dev/null +++ b/code/web/api/client/utils.php @@ -0,0 +1,3 @@ + diff --git a/code/web/api/common/auth.php b/code/web/api/common/auth.php new file mode 100644 index 000000000..b6bcdd799 --- /dev/null +++ b/code/web/api/common/auth.php @@ -0,0 +1,57 @@ +The application '._t(APP_NAME).' require authentication. Please enter your credentials'; + + $c .= '
'.$welcome_message.'

'; + + if ($user['message']) + $c .= '
'._t($user['message']).'

'; + $c .= ryzom_render_login_form($name, false); + echo ryzom_app_render(_t('app_'.APP_NAME), $c); + exit; + } + return false; + } + } + + if ($lang) + $_SESSION['lang'] = $lang; + + // get user informations + $user = ryzom_user_get_info($cid); + $user['lang'] = $_SESSION['lang']; + + $user['id'] = ryzom_get_user_id($cid, $user['char_name'], $user['creation_date']); + unset($user['last_played_date']); + unset($user['creation_date']); + return true; +} + +?> diff --git a/code/web/api/common/config.php.default b/code/web/api/common/config.php.default new file mode 100644 index 000000000..3a00bb04e --- /dev/null +++ b/code/web/api/common/config.php.default @@ -0,0 +1,28 @@ +. + */ + +// Url where the api is +define('RYAPI_URL', 'http://'); +if (!defined('RYAPI_PATH')) + define('RYAPI_PATH', dirname(__FILE__).'/'); +// used by "home" link +if (!defined('RYAPP_URL')) + define('RYAPP_URL', 'http://'); + +?> diff --git a/code/web/api/common/db_lib.php b/code/web/api/common/db_lib.php new file mode 100644 index 000000000..c3c7e8677 --- /dev/null +++ b/code/web/api/common/db_lib.php @@ -0,0 +1,422 @@ +. + */ + +define('SQL_DEF_TEXT', 0); +define('SQL_DEF_BOOLEAN', 1); +define('SQL_DEF_INT', 2); +define('SQL_DEF_DATE', 3); + + +// Wrapper for SQL database interactions +class ServerDatabase +{ + var $hostname = ''; + var $username = ''; + var $password = ''; + var $database = ''; + + var $_connection = Null; + + function ServerDatabase($host='', $user='', $passwd='', $dbname='') + { + if (($host != '') && ($user != '') && ($dbname != '')) + { + $this->hostname = $host; + $this->username = $user; + $this->password = $passwd; + $this->database = $dbname; + } + + if (($this->hostname != '') && ($this->username != '') && ($this->database != '')) + { + $this->_connection = mysql_connect($this->hostname, $this->username, $this->password) + or die("ERR1"); // ace . $this->get_error()); + $this->select_db($this->database); + } + } + + function close() + { + @mysql_close($this->_connection); + } + + function query($sql_statement) + { + $result = mysql_query($sql_statement, $this->_connection); + return $result; + } + + function select_db($dbname) { + $this->database = $dbname; + mysql_select_db($this->database, $this->_connection) or die("Database selection error : " . $this->get_error()); + } + + function num_rows($result) + { + return @mysql_num_rows($result); + } + + function fetch_row($result, $result_type=MYSQL_BOTH) + { + return @mysql_fetch_array($result, $result_type); + } + + function fetch_assoc($result) + { + return @mysql_fetch_array($result, MYSQL_ASSOC); + } + + + function query_single_row($sql_statement) + { + $result = $this->query($sql_statement); + return @mysql_fetch_array($result); + } + + function free_result($result) + { + @mysql_free_result($result); + } + + function get_error() + { + return mysql_errno($this->_connection) .": ". mysql_error($this->_connection); + } + + function last_insert_id() + { + return @mysql_insert_id(); + } + + function change_to($host,$user,$pass,$dbname) + { + $this->close(); + $this->hostname = $host; + $this->username = $user; + $this->password = $pass; + $this->database = $dbname; + $this->ServerDatabase(); + } +} + + + + +class ryDB { + + private static $_instances = array(); + private $db; + private $defs = array(); + private $errors = ''; + + + private function __construct($db_name) { + global $_RYZOM_API_CONFIG; + + $this->db = new ServerDatabase(RYAPI_WEBDB_HOST, RYAPI_WEBDB_LOGIN, RYAPI_WEBDB_PASS, $db_name); + $this->db->query("SET NAMES utf8"); + } + + public static function getInstance($db_name) { + if (!array_key_exists($db_name, self::$_instances)) + self::$_instances[$db_name] = new ryDB($db_name); + + self::$_instances[$db_name]->db->select_db($db_name); + return self::$_instances[$db_name]; + } + + function setDbDefs($table, $defs) { + $this->defs[$table] = $defs; + } + + function getDefs($table) { + if (!array_key_exists($table, $this->defs)) + die("Please add tables defs using setDbDefs('$table', \$defs)"); + return $this->defs[$table]; + } + + function getErrors() { + return $this->db->get_error(); + } + + function now() { + return date('Y-m-d H:i:s', time()); + } + + function toDate($timestamp) { + return date('Y-m-d H:i:s', $timestamp); + } + + function fromDate($string_date) { + return strtotime($string_date); + } + + function addDbTableProp($table, $props) { + $this->props[$table] = $props; + } + + /// DIRECT QUERY + function sqlQuery($sql) { + $result = $this->db->query($sql); + $ret = array(); + while ($row = $this->db->fetch_row($result)) { + $ret[] = $row; + } + return $ret; + } + + + /// QUERY /// + function sqlSelect($table, $props, $values=array(), $extra='') { + if ($table) { + $sql = "SELECT\n\t"; + $params = array(); + $test = array(); + if (!$props) + die("Bad Select on [$table] : missing props"); + + foreach($props as $name => $type) + $params[] = '`'.addslashes($name).'`'; + + foreach($values as $name => $value) { + if ($name[0] == '=') + $test[] = '('.addslashes(substr($name, 1)).' LIKE '.var_export($value, true).')'; + else + $test[] = '('.addslashes($name).' = '.var_export($value, true).')'; + } + $sql .= implode(",\n\t", $params)."\nFROM\n\t".$table."\n"; + if ($test) + $sql .= "WHERE\n\t".implode("\nAND\n\t", $test); + } + + if ($extra) + $sql .= "\n".$extra; + return $sql.';'; + + } + + function querySingle($table, $values=array(), $extra='') { + $sql = $this->sqlSelect($table, $this->getDefs($table), $values, $extra); + $result = $this->db->query($sql); + return $this->db->fetch_row($result); + } + + function querySingleAssoc($table, $values=array(), $extra='') { + $sql = $this->sqlSelect($table, $this->getDefs($table), $values, $extra); + $result = $this->db->query($sql); + return $this->db->fetch_row($result, MYSQL_ASSOC); + } + + function query($table, $values=array(), $extra='') { + $sql = $this->sqlSelect($table, $this->getDefs($table), $values, $extra); + $result = $this->db->query($sql); + $ret = array(); + while ($row = $this->db->fetch_row($result)) { + $ret[] = $row; + } + return $ret; + } + + function queryAssoc($table, $values=array(), $extra='') { + $sql = $this->sqlSelect($table, $this->getDefs($table), $values, $extra); + $result = $this->db->query($sql); + $ret = array(); + while ($row = $this->db->fetch_row($result, MYSQL_ASSOC)) { + $ret[] = $row; + } + return $ret; + } + + /// INSERT /// + function sqlInsert($table, $props, $vals) { + $sql = 'INSERT INTO '.$table.' '; + $params = array(); + $values = array(); + foreach($props as $name => $type) { + if (!isset($vals[$name])) + continue; + $params[] = $name; + switch ($type) { + case SQL_DEF_BOOLEAN: + $values[] = $vals[$name]?1:0; + break; + case SQL_DEF_INT: + $values[] = $vals[$name]; + break; + case SQL_DEF_DATE: // date + if (is_string($vals[$name])) + $values[] = "'".addslashes($vals[$name])."'"; + else + $values[] = "'".$this->toDate($vals[$name])."'"; + break; + default: + $values[] = "'".addslashes($vals[$name])."'"; + break; + } + } + $sql .= "(\n\t".implode(",\n\t", $params)."\n) VALUES (\n\t".implode(",\n\t", $values)."\n);"; + return $sql; + } + + function insert($table, $values) { + $sql = $this->sqlInsert($table, $this->getDefs($table), $values); + $this->db->query($sql); + return $this->db->last_insert_id(); + } + + /// DELETE /// + function sqlDelete($table, $values=array(), $where='') { + $sql = "DELETE FROM\n\t".$table."\n"; + $test = array(); + foreach($values as $name => $value) + $test[] = '('.addslashes($name).' = '.var_export($value, true).')'; + + if ($test or $where) + $sql .= "WHERE\n\t"; + if ($test) + $sql .= implode("\nAND\n\t", $test); + if ($where) + $sql .= "\n".$where; + return $sql.';'; + } + + function delete($table, $values=array(), $where='') { + $sql = $this->sqlDelete($table, $values, $where); + $result = $this->db->query($sql); + return $result; + } + + /// UPDATE /// + function sqlUpdate($table, $props, $vals, $tests, $extra) { + $sql = 'UPDATE '.$table.' SET '; + $params = array(); + $test = array(); + $values = array(); + foreach($props as $name => $type) { + if (!array_key_exists($name, $vals)) + continue; + switch ($type) { + case SQL_DEF_BOOLEAN: + $values[] = '`'.$name.'` = '.($vals[$name]?'1':'0'); + break; + case SQL_DEF_DATE: + if (is_string($vals[$name])) + $values[] = '`'.$name.'` = \''.addslashes($vals[$name]).'\''; + else + $values[] = '`'.$name.'` = \''.$this->toDate($vals[$name]).'\''; + break; + default: + $values[] = '`'.$name.'` = \''.addslashes($vals[$name]).'\''; + break; + } + } + $sql .= "\n\t".implode(",\n\t", $values)."\n"; + + foreach($tests as $name => $value) { + $test[] = '('.addslashes($name).' = '.var_export($value, true).')'; + } + if ($test) + $sql .= "WHERE\n\t".implode("\nAND\n\t", $test); + + $sql .= "\n".$extra; + + return $sql; + } + + + function update($table, $values=array(), $test=array(), $extra='') { + $sql = $this->sqlUpdate($table, $this->getDefs($table), $values, $test, $extra); + $result = $this->db->query($sql); + return $result; + } + + function sqlInsertOrUpdate($table, $props, $vals) { + $sql = $this->sqlInsert($table, $props, $vals); + $sql = substr($sql, 0, strlen($sql)-1); + $params = array(); + $test = array(); + $values = array(); + foreach($props as $prop) { + if (!array_key_exists($prop[2], $vals)) + continue; + $type = $prop[0]; + $check = $prop[1]; + $name = $prop[2]; + if ($type{0} == '#') + $type = substr($type, 1); + if (($type{0} == '>') or ($type == 'id')) + continue; + switch ($type) { + case 'trad': + $values[] = '`'.$name."` = '".addslashes($vals[$name])."'"; + break; + case 'textarea': + case 'string': + case 'option': + $values[] = '`'.$name."` = '".addslashes($vals[$name])."'"; + break; + case 'id': + case 'int': + case 'float': + $values[] = '`'.$name.'` = '.addslashes($vals[$name]); + break; + case 'bool': + $values[] = '`'.$name.'` = '.($vals[$name]?'1':'0'); + break; + } + } + $sql .= "\nON DUPLICATE KEY UPDATE\n\t".implode(",\n\t", $values)."\n"; + return $sql; + } + + function insertOrUpdate($table, $values) { + $sql = $this->sqlInsertOrUpdate($table, $this->getDefs($table), $values); + return $result; + } + + + /// Display + function getTableHtml($name, $params, $values, $order_by='') + { + $ret = ''; + $tr_header = ''; + $ret .= _s('t header', $tr_header); + $i = 0; + if (!$values) + return ''; + $current_section = ''; + foreach ($values as $rows) { + if ($order_by && $rows[$order_by] != $current_section) { + $current_section = $rows[$order_by]; + if ($current_section != '0') + $ret .= _s('t row ', ''.str_repeat('', count($params)-1)); + } + $td = ''; + foreach ($params as $test => $param) + $td .= ''; + $ret .= _s('t row '.strval($i % 2), $td); + $i++; + } + $ret .= '
 '; + $tr_header .= implode(' ', array_keys($params)).''._s('section', $current_section).''._s('section', ' ').' '.$rows[$param].'
'; + return $ret; + } + +} + +?> diff --git a/code/web/api/common/logger.php b/code/web/api/common/logger.php new file mode 100644 index 000000000..f4909e721 --- /dev/null +++ b/code/web/api/common/logger.php @@ -0,0 +1,43 @@ +log_indent += $indent; + if ($log) { + $tabs = str_repeat(" ", $this->log_indent); + $a = $tabs.str_replace("\n", "\n ".$tabs, $log); + $this->logs[] = ''.$a.''; + } + } + + function addPrint($log, $color='#FFFF00') { + $this->logs[] = ''.$log.''; + } + + function addError($log) { + $this->logs[] = ' ERROR: '.$log.''; + } + + function getLogs() { + $ret = ''; + if ($this->logs && $this->enable) + $ret = "Debug\n".implode("\n", $this->logs); + $this->logs = array(); + return $ret; + } +} + + +?> diff --git a/code/web/api/common/render.php b/code/web/api/common/render.php new file mode 100644 index 000000000..a2ec31795 --- /dev/null +++ b/code/web/api/common/render.php @@ -0,0 +1,218 @@ +. + */ + +function ryzom_app_render($title, $content, $bgcolor='', $javascript=array(), $homeLink=false) { + $c = ''; + // Render header + $title_prefix = ''; + if (ON_IPHONE) { + $title_prefix = 'Ryzom - '; + } + + if (!$bgcolor) + $bgcolor = '#000000'.(RYZOM_IG?'00':''); + + $c .= ''."\n"; + $c .= ' + '."\n"; + $c .= ' '.$title_prefix.(translation_exists($title)?_t($title):$title).''."\n"; + $c .= ' '."\n"; + + if (!RYZOM_IG) { + $c .= ryzom_render_header(); + $c .= ryzom_render_header_www(); + } + + $events = ON_IPHONE ? 'onorientationchange="updateOrientation();" ' : ''; + + $c .= ' '."\n"; + + $c .= ' '."\n"; + + // Javascript + $js_code = ''; + foreach ($javascript as $js) + $js_code .= ''; + $c .= $js_code; + + if (RYZOM_IG) + $c .= $content; + else{ + $c .= ryzom_render_www(ryzom_render_window($title, $content, $homeLink)); + } + + $c .= ''; + return $c; +} + +function ryzom_render_header() { + if (ON_IPHONE) { + return ''; + } else { + return ' '; + } +} + +// Call this inside the part if you want to use ryzom_render_www +function ryzom_render_header_www() { + if (ON_IPHONE) { + return ' + + + + + '; + } else { + return ' + +'; + } +} + +// Render a Ryzom style window +function ryzom_render_window($title, $content, $homeLink=false) { + return ryzom_render_window_begin($title, $homeLink) . $content . ryzom_render_window_end(); +} + +function ryzom_render_window_begin($title, $homeLink=false) { + + if ($homeLink === false) + $homeLink = ''._t('home').''; + + return ' +
+
+
'.$title_prefix.(translation_exists($title)?_t($title):$title).$homeLink.'
+
+
+
+
+'; +} + +function ryzom_render_window_end() { + return '
+
'.ryLogger::getInstance()->getLogs().'
+

powered by ryzom-api

+
+ '; +} + +// Render a webpage using www.ryzom.com style +function ryzom_render_www($content) { + return ryzom_render_www_begin() . $content . ryzom_render_www_end(); +} + +function ryzom_render_www_begin($url='') { + $style1 = 'position: relative; padding-top: 20px; padding-right: 30px; margin-bottom: -3px'; + $style2 = 'position: absolute; bottom: 0; right: 0; '; + if (ON_IPHONE) { + $style1 = 'position: relative; padding-top: 30px; padding-right: 30px; '; + $style2 = 'position: fixed; top: 0; right: 0; padding-right: 0px;'; + $marginBottom = ''; + } + if (!$url) { + $url_params = parse_query($_SERVER['REQUEST_URI']); + unset($url_params['lang']); + + $url = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?'.http_build_query($url_params); + } + return ' +
+
+
+ English + French + German + Russian +
+ +
+
+'; +} + +function ryzom_render_www_end() { + return '
'; +} + +function ryzom_render_login_form($char, $aligned=true) { + $c = ''; + if ($aligned) { + $c .= '
'; + $c .= ''; + $c .= ''; + $c .= ''; + $c .= ''; + $c .= ''; + } else { + $c .= '
'._t('enter_char').'
'._t('enter_password').'
'; + $c .= ''; + $c .= ''; + $c .= ''; + $c .= ''; + $c .= ''; + } + $c .= '
'._t('login').'
'._t('password').'
'; + return $c; +} + +?> diff --git a/code/web/api/common/user.php b/code/web/api/common/user.php new file mode 100644 index 000000000..62a2de0c8 --- /dev/null +++ b/code/web/api/common/user.php @@ -0,0 +1,3 @@ + diff --git a/code/web/api/common/utils.php b/code/web/api/common/utils.php new file mode 100644 index 000000000..9f12fdfc1 --- /dev/null +++ b/code/web/api/common/utils.php @@ -0,0 +1,182 @@ + $v) { + if (is_int($k) && $prefix != null) { + $k = urlencode($prefix . $k); + } + if ((!empty($key)) || ($key === 0)) $k = $key.'['.urlencode($k).']'; + if (is_array($v) || is_object($v)) { + array_push($ret, http_build_query($v, '', $sep, $k)); + } else { + array_push($ret, $k.'='.urlencode($v)); + } + } + if (empty($sep)) $sep = ini_get('arg_separator.output'); + return implode($sep, $ret); + } +} + + +/*** + * + * Translation utilities + * + * ***/ + +function translation_exists($id) { + global $user, $ryzom_texts; + return isset($ryzom_texts[$id]) && isset($ryzom_texts[$id][$user['lang']]); +} + +// Translate the $id in the selected language +function get_translation($id, $lang, $args=array()) { + global $ryzom_texts, $user; + if(!isset($ryzom_texts[$id])) return '{'.$id.'}'; + if(!isset($ryzom_texts[$id][$lang])) return '{'.$id.'['.$lang.']}'; + if($ryzom_texts[$id][$lang] == '' && isset($ryzom_texts[$id]['en'])) return @vsprintf($ryzom_texts[$id]['en'], $args); + return @vsprintf($ryzom_texts[$id][$lang], $args); +} + + +// Translate the $id in the user language +function _t($id, $args=array()) { + global $ryzom_texts, $user; + + $a = ''; + if ($args) { + if (is_array($args)) { + $a = array(); + foreach ($args as $arg) + $a[] = strval($arg); + $a = ' '.implode(', ', $a); + } else + $a = ' '.strval($args); + } + if(!isset($ryzom_texts[$id])) return '{'.$id.$a.'}'; + if(!isset($ryzom_texts[$id][$user['lang']])) return '{'.$id.'['.$user['lang'].']'.$a.'}'; + if($ryzom_texts[$id][$user['lang']] == '' && isset($ryzom_texts[$id]['en']) && $ryzom_texts[$id]['en'] != '') return @vsprintf($ryzom_texts[$id]['en'], $args); + if($ryzom_texts[$id][$user['lang']] == '' && isset($ryzom_texts[$id]['fr']) && $ryzom_texts[$id]['fr'] != '') return '{'.$id.$a.'}'; + if($ryzom_texts[$id][$user['lang']] == '' && isset($ryzom_texts[$id]['de']) && $ryzom_texts[$id]['de'] != '') return '{'.$id.$a.'}'; + return @vsprintf($ryzom_texts[$id][$user['lang']], $args); +} + +/*** + * + * Ryzom time + * + * ***/ + + + +// Get a human and translated readable time, for example "3 days ago" +function ryzom_relative_time($timestamp) { + global $ryzom_periods, $user; + $difference = time() - $timestamp; + $lengths = array("60","60","24","7","4.35","12","10"); + + if ($difference >= 0) { // this was in the past + $ending = _t('ago'); + } else { // this was in the future + $difference = -$difference; + $ending = _t('to_go'); + } + for($j = 0,$m=count($lengths); $j<$m && $difference >= $lengths[$j]; $j++) + $difference /= $lengths[$j]; + // round hours as '1.2 hours to go' + $difference = round($difference, ($j == 2) ? 1 : 0); + + $form = ($difference == 1) ? 'singular' : 'plural'; + + // Handle exceptions + // French uses singular form if difference = 0 + if ($user['lang'] == 'fr' && ($difference == 0)) { + $form = 'singular'; + } + // Russian has a different plural form for plurals of 2 through 4 + if ($user['lang'] == 'ru' && ($form == 'plural')) { + if ($difference < 5) { + $form = '2-4'; + } + } + + $final = $ryzom_periods[$user['lang']][$form][$j]; + $text = _t('date_format', array($difference, $final, $ending)); + return $text; +} + +// Get a human and translated absolute date +function ryzom_absolute_time($timestamp) { + global $user, $ryzom_daysofweek, $ryzom_monthnames; + $day_of_month = date("j", $timestamp); + $dow = date("w", $timestamp); + $month = date("n", $timestamp); + $day_of_week = $ryzom_daysofweek[$user['lang']][$dow]; + $month_str = $ryzom_monthnames[$user['lang']][$month-1]; + $text = _t("absolute_date_format", array($day_of_month, $day_of_week, $month_str, $month, date("m", $timestamp), date("d", $timestamp))); + return $text; +} + +/*** + * + * Debug tools + * + * ***/ + +function p($var, $value=NULL) { + ob_start(); + debug_print_backtrace(); + $bt = ob_get_contents(); + ob_end_clean(); + $bt = explode("\n",$bt); + $bt = explode('[', $bt[1]); + ob_start(); + echo ''.substr($bt[count($bt)-1], 0, -1)."\n"; + if ($value !== NULL) { + echo ''.$var.' : '; + $var = $value; + } + //if (is_array($var)) + echo '
';
+	print_r($var);
+	echo '
'; +// else + // var_dump($var); + ryLogger::getInstance()->addPrint(ob_get_contents()); + ob_end_clean(); +} + +?> diff --git a/code/web/api/data/css/ryzom_iphone.css b/code/web/api/data/css/ryzom_iphone.css new file mode 100644 index 000000000..c837ffbf4 --- /dev/null +++ b/code/web/api/data/css/ryzom_iphone.css @@ -0,0 +1,248 @@ +/* Copyright (C) 2009 Winch Gate Property Limited + * + * This file is part of ryzom_api. + * ryzom_api is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ryzom_api is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with ryzom_api. If not, see . + */ + +html, body, form, fieldset, p, div, h1, h2, h3, h4, h5, h6 { + margin:0; + padding:0; + -webkit-text-size-adjust: none; +} + +body { + font-size: 14px; + background: black; + font-family: Helvetica; +} + +ul li { + padding: 0px 4px 10px 2px; + list-style: circle outside; +} +ol li { + padding: 0px 4px 10px 2px; +} +.ryzom-ui p { + padding-bottom:8px; +} + +#main { + clear: both; + padding-top: 0px; + overflow:auto; + margin-left:auto; + margin-right:auto; + text-align:left +} +.error { + padding:.5em; + background:#ff5555; + color:white; + font-weight:bold +} +/*----------------------------- + ORIENTATION +-----------------------------*/ + +.content_wide, +.content_normal { + display:none; +} + +.show_normal { + width: 320px; +} + +.show_wide { + width: 480px; +} + +.show_wide .content_wide, +.show_normal .content_normal { + display: block; +} + +/* ---------------------- */ + + +.ryzom-ui { + color: white; +} +.ryzom-ui input, .ryzom-ui select { + border-top: 1px solid #030403; + border-right: 1px solid #6e7f57; + border-bottom: 1px solid #889e6c; + border-left: 1px solid #272d1f; + background-color: #37402b; + color: #ddd; + font-size: 16px; + margin: 2px 0 5px 0; +} +.ryzom-ui input[type=text] { + width: 96%; +} + +.ryzom-ui textarea { + width: 96%; + background-color: black; + color: white; + font-size: 16px; + font-family: Helvetica; +} +/* input[type=submit] will make IE6 to ignore whole CSS rule, so cant combine this with .ryzom-ui-button below */ +input[type=submit] { + border-bottom: 1px solid #030403; + border-left: 1px solid #6e7f57; + border-top: 1px solid #889e6c; + border-right: 1px solid #272d1f; + background-color: #435120; +} +input.ryzom-ui-button, .ryzom-ui-button { + border-bottom: 1px solid #030403; + border-left: 1px solid #6e7f57; + border-top: 1px solid #889e6c; + border-right: 1px solid #272d1f; + background-color: #435120; +} + +a, a:visited {color:orange} + +a:hover {color:orange} + +a.ryzom-ui-button, a.ryzom-ui-button:visited { + color: white; + padding: 0 .5em; + text-decoration: none; +} +a.ryzom-ui-button:hover { + background: #536130; + color: #ddd; +} +/* window without title - just borders */ +.ryzom-ui-tl { +} +.ryzom-ui-tr { +} +.ryzom-ui-t { + background-image: url(skin_t.gif); + background-repeat: repeat-x; + background-position: left top; + height: 8px; + margin: 0; +} +/* window with proper header */ +.ryzom-ui-header .ryzom-ui-tl { + margin: 0px 0px; + height: 32px; +} +.ryzom-ui-header .ryzom-ui-tr { + height: 32px; +} +.ryzom-ui-header .ryzom-ui-t { + background-image: url(skin_header_m.gif); + background-repeat: repeat-x; + background-position: left top; + padding: 7px 0 0 12px; + height: 32px; + text-transform: uppercase; + color: white; + border-top: 1px solid #030403; +} +/* window body */ +.ryzom-ui-l { +} +.ryzom-ui-r { +} +.ryzom-ui-m { + margin: 0 0px; + padding: 0px; + background-image: url(skin_blank.png); + background-repeat: repeat; +} +.ryzom-ui-body { + background-image: url(skin_blank_inner.png); + background-repeat: repeat; + /* leave 5px room after bottom border */ + margin: 0 8px 5px 2px; + padding: 5px 5px 5px 5px; + border-top: 1px solid #030403; + border-right: 1px solid #6e7f57; + border-bottom: 1px solid #889e6c; + border-left: 1px solid #272d1f; +} +/* window bottom border */ +.ryzom-ui-bl { + height: 8px; +} +.ryzom-ui-br { + height: 8px; +} +.ryzom-ui-b { + height: 8px; + margin: 0 8px; +} +.ryzom-ui-notice { + margin: 0px; + padding: 0px; + color: #999; + text-align: center; +} +a.ryzom-ui-notice, a.ryzom-ui-notice:visited { + margin: 0px; + padding: 0px; + color: #BBB; + padding: 0 .5em; + text-decoration: underline; +} +a.ryzom-ui-notice:hover { + color: gray; +} + +.ryzom-ui-t .ryzom-ui-text-button { + font-size: 85%; +} +a.ryzom-ui-text-button, a:visited.ryzom-ui-text-button { + color:#FFFF11; + text-decoration:none; +} + +.ryzom-ui-text-button { + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; +} +.ryzom-ui-text-button { + padding: 0;margin: 0; + border-color: #ff8 #ff3 #ff3 #ff8; + border-width: 1px; + border-style: solid; + padding: 0px 4px; + color: white; +} + +.ryzom-ui-wrap-ul { + float: left; + text-align: center; + padding: 0; + list-style: none; +} + +.ryzom-ui-wrap-li { + float: left; + margin: 0 0 10px 5px; + width: 6.1em; + list-style: none; + height: 70px; +} diff --git a/code/web/api/data/css/ryzom_ui.css b/code/web/api/data/css/ryzom_ui.css new file mode 100644 index 000000000..8342b77f8 --- /dev/null +++ b/code/web/api/data/css/ryzom_ui.css @@ -0,0 +1,227 @@ +/* Copyright (C) 2009 Winch Gate Property Limited + * + * This file is part of ryzom_api. + * ryzom_api is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ryzom_api is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with ryzom_api. If not, see . + */ + +/* + * Check ryzom_api/functions_render.php for easy php function to render ryzom layout or use this following html: + * +
+
+
+
+
+
+
+
+
+ */ + +.ryzom-ui { + color: white; +} +.ryzom-ui input, .ryzom-ui select { + border-top: 1px solid #030403; + border-right: 1px solid #6e7f57; + border-bottom: 1px solid #889e6c; + border-left: 1px solid #272d1f; + background-color: #37402b; + color: #ddd; + font-size: 12px; + margin: 2px 0 5px 0; +} +.ryzom-ui input[type=text] { + width: 100%; +} + +.ryzom-ui textarea { + width: 98%; +} + +/* input[type=submit] will make IE6 to ignore whole CSS rule, so cant combine this with .ryzom-ui-button below */ +input[type=submit] { + border-bottom: 1px solid #030403; + border-left: 1px solid #6e7f57; + border-top: 1px solid #889e6c; + border-right: 1px solid #272d1f; + background-color: #435120; +} +input.ryzom-ui-button, .ryzom-ui-button { + border-bottom: 1px solid #030403; + border-left: 1px solid #6e7f57; + border-top: 1px solid #889e6c; + border-right: 1px solid #272d1f; + background-color: #435120; +} +a.ryzom-ui-button, a.ryzom-ui-button:visited { + color: white; + padding: 0 .5em; + text-decoration: none; +} +a.ryzom-ui-button:hover { + background: #536130; + color: #ddd; +} +/* window without title - just borders */ +.ryzom-ui-tl { + background-image: url(skin_tl.gif); + background-repeat: no-repeat; + background-position: left top; + width: 100%; height: 8px; +} +.ryzom-ui-tr { + background-image: url(skin_tr.gif); + background-repeat: no-repeat; + background-position: right top; + height: 8px; +} +.ryzom-ui-t { + background-image: url(skin_t.gif); + background-repeat: repeat-x; + background-position: left top; + height: 8px; + margin: 0 8px; +} +/* window with proper header */ +.ryzom-ui-header .ryzom-ui-tl { + margin: 0px 0px; + background-image: url(skin_header_l.gif); + background-repeat: no-repeat; + background-position: left top; + height: 32px; +} +.ryzom-ui-header .ryzom-ui-tr { + background-image: url(skin_header_r.gif); + background-repeat: no-repeat; + background-position: right top; + height: 32px; +} +.ryzom-ui-header .ryzom-ui-t { + background-image: url(skin_header_m.gif); + background-repeat: repeat-x; + background-position: left top; + margin-left: 12px; + margin-right: 26px; + padding-top: 9px; + height: 32px; + text-transform: uppercase; + color: white; +} +/* window body */ +.ryzom-ui-l { + background-image: url(skin_l.gif); + background-position: left top; + background-repeat: repeat-y; + width: 100%; +} +.ryzom-ui-r { + background-image: url(skin_r.gif); + background-position: right top; + background-repeat: repeat-y; + width: 100%; +} +.ryzom-ui-m { + margin: 0 8px; + padding: 8px; + background-image: url(skin_blank.png); + background-repeat: repeat; +} +.ryzom-ui-body { + background-image: url(skin_blank_inner.png); + background-repeat: repeat; + /* leave 5px room after bottom border */ + margin: 0px 0 5px 0; + padding: 10px 10px 5px 10px; + border-top: 1px solid #030403; + border-right: 1px solid #6e7f57; + border-bottom: 1px solid #889e6c; + border-left: 1px solid #272d1f; +} +/* window bottom border */ +.ryzom-ui-bl { + background-image: url(skin_bl.gif); + background-repeat: no-repeat; + background-position: left top; + height: 8px; +} +.ryzom-ui-br { + background-image: url(skin_br.gif); + background-repeat: no-repeat; + background-position: right top; + height: 8px; +} +.ryzom-ui-b { + background-image: url(skin_b.gif); + background-repeat: repeat-x; + background-position: left top; + height: 8px; + margin: 0 8px; +} +.ryzom-ui-notice { + margin: 0px; + padding: 0px; + color: #333; + text-align: center; +} +a.ryzom-ui-notice, a.ryzom-ui-notice:visited { + margin: 0px; + padding: 0px; + color: #555; + padding: 0 .5em; + text-decoration: underline; +} +a.ryzom-ui-notice:hover { + color: gray; +} + +.ryzom-ui-t .ryzom-ui-text-button { + font-size: 85%; +} +a.ryzom-ui-text-button, a:visited.ryzom-ui-text-button { + color:#FFFF11; + text-decoration:none; +} + +.ryzom-ui-text-button { + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; +} +.ryzom-ui-text-button { + padding: 0;margin: 0; + border-color: #ff8 #ff3 #ff3 #ff8; + border-width: 1px; + border-style: solid; + padding: 0px 4px; + color: white; +} + +.ryzom-ui-wrap-ul { + float: left; + text-align: center; + padding: 0; + list-style: none; + margin-top: -5px; + margin-bottom: -20px; +} + +.ryzom-ui-wrap-li { + float: left; + margin: 0 5px 10px 5px; + width: 6.1em; + padding: 0; + list-style: none; + height: 70px; +} diff --git a/code/web/api/data/css/skin_b.gif b/code/web/api/data/css/skin_b.gif new file mode 100644 index 0000000000000000000000000000000000000000..a1a0390bca7bfd19ebec43da73eba1772bafaa62 GIT binary patch literal 748 zcmZ?wbhEHbY+&GEIOfR!1cHKsLP9_U1j52#EDQu9Km-IJLKKKZfk;$L42ZN=iy9D=Vw2s%mR%>+0$n8ynl( z+dDcs)~sIre<%ROe}c|Msfi`2DGKG8B^e6tp1uJLia%KxxftphbU@JqiYNy5e+@=W z%`L5M?H!$6-95d1{T&RGCQq3R(eXZ zVv_O-iZZftqLPa8G7>VPB4RRf;u=P3(jp3SDk|z*blhFt937l=owY^9U98RRZEf6~ zEggh~rG!L<4l4s=SKdfROW)Mk#KKP7XTpgKj!mundI>iwrYAbJ@CusTIA!pdm5oQ( zz~R9J%>zx$%zPbxDiRJdv8uCb6dZVPu#tsNM#dl^;b3#WnzNNbrqGf`Mm`Rch6fIf zC)jw?)O2TFX*|uyJ*iD4^HRe_RzqeUi3JNBPORh>=y|iU)X`&tJa>(ZzyakG%%&cX zPR;e+zV7bsiqEg^p5DIx{_X`#+;ToU3Le;Z2y4fk*|G8Q@d?V_^L%!0dU|?>arV74 JmW2uo)&N9#QHKBk literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_bl.gif b/code/web/api/data/css/skin_bl.gif new file mode 100644 index 0000000000000000000000000000000000000000..459dc00654dbdbfabe3f6ab1032995e26b485ad9 GIT binary patch literal 129 zcmZ?wbhEHbA5G*1U)9LQh>7D)lc0tZHipahS3Qw4Z#1ttn*$h~Z-&6ROy Gum%9i_b>JU literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_blank.png b/code/web/api/data/css/skin_blank.png new file mode 100644 index 0000000000000000000000000000000000000000..0fefeaab0dcd339231a9c5c12729382873e9ebe6 GIT binary patch literal 11070 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 literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_blank_inner.png b/code/web/api/data/css/skin_blank_inner.png new file mode 100644 index 0000000000000000000000000000000000000000..b728324eff2496ec1606a0a633cfe3693af1b9c1 GIT binary patch literal 8986 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 literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_br.gif b/code/web/api/data/css/skin_br.gif new file mode 100644 index 0000000000000000000000000000000000000000..3a01335f8780d044591538ca6f1feddb5da63987 GIT binary patch literal 130 zcmZ?wbhEHbDEgwtm8XB6Knp#>~+S=MWIy$<#x_Wwg`uh3?1_nk(M#jd* zW@cvQ=H@mwHZCqM9v&W^o}OM_Uf$l`K0ZEvetuzLVXIcIT(f%hf69R3KSAfB)Wnk1 z6ovB4k_-iRPu~Cr#h)yUTnzRMIw0?XJj%ef>%ja14;`s~52b{YF?@`xR+wnDteSP^ zm1qlV24hU4(#C)q#zuywi4Jr4SvDQ|)2zqN>Z*LuLirjG4}Ur%8#ljzP&z9cuYiDP zORu2d#L{pECU!nyUa4+&9w7nAbmoO3qVuPFw{nR~$t+{#7Lk-*#>OcuyL1f$3oDO^ z{Jyf8OdLXT5-o=oiG^xow1m9=(cJ Sy#M7xnZ|t;rN@p84AuaFuAIF9 literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_header_m.gif b/code/web/api/data/css/skin_header_m.gif new file mode 100644 index 0000000000000000000000000000000000000000..48d539173dcce5c8188433c200787243f2f03a70 GIT binary patch literal 6290 zcmds$i$BwQ{KxnGem~#u=91_nU6A2JbczcEL8-0C! z1B2iG#?bKp&hR%zzx~bsj`44ee`{=F@>>&AQ&TfDvstrdnVXx>o;`ccoH-U27M7Nl z6bc2$aVnKcqtWPex|NlcwY9a4jg76XErY?Zv$M0ex1T$Au7iUElgV^+baZlZVzF4x z&dx3_F7xKib9Hrfb8~ZdclYq{m_L8Mr>Ccvm)C*?3l=V1=l9K)V_a8WLptQ8KyuAF-p+kocAFisZI(qcz z@#Du&oH!wu%WG?EPoF+rS65eGUw`i0x%0n0fBwRS3sFn(6>gxLY@4tI{d;9wO1_lORzI>@xs|N=MhlYlR zhlfW-M#jg-CnhE)Cnw*(e?K)f_3QsB)MZIu+Js*O zhyTrk0O14zX`1j$YYtB#Z_6hc+Ar@=RNvf1rUxJ8HPzhSYc_9ve@D~FyZdq9J#&JZ zYwztNM4nxKuldx2L#$Qzj|Tm5`cc*V&13!d{-_HMW#?;K1YfLwdXiUWzvBMIGtcVy zCxed#yREwqL9oMomRj_pfoS5uXT^wMqORo}o?6)kA(+X+Zu>vaAx%kF&CS#zHbT-f z+M1?Pr@c}XSkzl6z*{fp4{;;)0InZwsEDPzvZU$qn#eY^NV zapGR{M&kW8#?1Z%yfy;UC~sVAq>VUR zKzNCcuV8a9qfEXSHH;E*^2|eJ5N4W6rV?jw)vP2^Mf^6Rjg-$JS{;>(weVDBn-;BH z$-yjBH5?*sH;YT67b{>bE6d6@U?OBerN*gzF;P360inDswHibPD{6rOzgv9J*kKk2 zHDbg;#Q0!!fO*EPY8d65-&AO}WW<(3#J8%fFmL<%S9=VFN)BnRQh>~ucaiU}=Nd|o z%=Es+lI#j;#!;ZZj{F8tT&sPJ=Xc-*M)pFLpRu(SRjOygXG7RDIZDO>my{@`I%fSdjNbX8OTLI#-=>*XC<0oRge&sD)XO_MMc*lM~^xV|; zoXY5>-iei_qLj9VMlPPcYtFUov=&;XnlnxM?naVepDzWzti|tNTX~$GBxLUTw&Kdl z+%O+A$9Ai`Z;wCTzFlyFXrx&nZna6pB|3JM1Uivea-F(|T`HGoS!+lqPUFRW$I&|h z^>)PfN$fYbJ>I{4h3b<}w3X|}DxiagnP=vsTQ543%+uxSLW>>6A8wZ9-N>ew-tih0 zqnsOLso^pa6*F13LyVH5-YMFiaVkZesafnzZGg-Vv##)pZ8xkG0;(BDE0n?2m#Gjl znVM@PV*eXIyy#rwS?;5JLO~}Te>!XjW)nE1EECBm0nWK&-m^XVqFDFny+xk?D)Zhv zt6pQr+iYA(zQY}<9$2ljY46zuZeP1UBv z8ldL`8r&Q&WKje&btU8ir;%#?lCSx5I?1Tn);5q$hqV?aiwzt&A-@b~>FP27jUglP z$n8djIIzLnNcC2d8NH0Q*kg}4*9Ko6baibeA5<6p`ZjZ{e9N6V)}!%1+bp&_XvD-* zb%jn{<+;maDQhM#6nybC$)hPRtj?-m^eowIY{~{E*VY3XNj$|?h8vXQsJ&3E8>4|u zE)r0iX#uS`IErUFHW7Q}+lvlvVcXI;4UETDo(vZv#%nEPx6r_ z?jU#Mf9#fFUh-GE>%RKV8e`9OXsRo?+^H}9=F6~TLo>?x{>;=@d%_7x5lcnwmt0g2 zF9*p<&Vn_1JG`X0j13DySEA{5k{Nz@Qfw!|s9X)`W{K#}bL<#mPwU{{W4o!!ByEYS z<4kEZ-*&mFjO*H-_&hLn`c?X&)2l-tpRqlIcO1s9WnN7>vo_9iOiAS7@XXq07q)uE z7Kyqf29-GPhXDs`9Dz*_r6*Xj+r-^=utBZ-=$9!aNyg}%A>QEo{ZaIsiq}@RM+G`t z%%u1a#qLF_#F?J;qB&m)yWMKrbWFW(Qq*jseWD0U5FpcLQoiK;ahBA$BUP_PhK2n# zXmVNR&j5)iRms-%TDN~haZySa$VqIKSU*-o35%}35_Fcoq3m_-vRo07O=#CI7fGEG zjYGbleBN-x$mzvB5o*Qac>M})xKXnua55)}hGw3a5vn8nIchR_WvxTv)v-k{O81|4 zwWbXh=$k!gq6#3LD7l1uRNga}4UvLG3d0fRAEYCn zCuEG9#4Np}x24O`Qd5RmEJyzkSxWmx*yZz4ttIWgY2GaZwm-6FZk>-1W$axpJ2<*4 zMkMAcCGwTAKhUuQGJJ>^MLn!BX;9y?n66bLhPQB?sLD1ifij;lpM&|T+sNU zvcLpi^`OS`E^Tf@r=^t;*@YixggaQN!HX!=^& z+=M_Eo*Z@&A`wD3fDHu;!DNB8zUz8(Wh{e$%;h7&I3^+!mn}(RW;*;x5`5USrL&XU zo0RI*=4r(!4m3~0E$N^6yF82G>A7pIDiZmu-u*Gu#Z6wMGm)qOv-$|)STs% zw*`KcRct3npKp+lldVcBXn1Fi=72+c2KQJ6>%o+N%2&yqLCBU2mZ%UXGAUC?%3>9$ zY>5lWE?ZQXGfrI1$JUZbX)1IbzV!N6EBte~Bc2(nMC19`Mgee^!>cNo#zMrK1?VjN zL4Md;I>KT(CQJM_USu)-^31uwfsC*SsFw_3@TVbPA#kkaJep_ybYxZODI`imYGP@p zC=iBfrA7>40ZuW8qG>sa@zGh~omM@An;ZOHrrMyxaK#52Tv35=M4&DbjS=PsDG^rz zVxvk+a7~(3nDd9b-^l7Dx(1$0wxY|zhhv;5Y9x`55Df!q{h#^B*8aSK}m~0Tw z1%X1yVA{yWKng9jN@L29C1kB;q4s(;Vyp3c!eHp0#FLCE4_sp64skuZVj?mfvo00t z*Wllq;dv?~gn+KZu{8oLQH?H(Qw^vs)^{ZgiOl8i8&g?RR}QzXow0+l3{sr zVjP+HLA=sX#PX~09Cd{~WY~Nb?5akb)gY0T#&eDFQX--9gu7Sm@?US*7(=y?+4W^G zoeA*^+pT#uAoB$XQNw=)SqI3#jeNWKQiv{sA8v)6Szxt{G`*dVx+!2m0ju&Y9amV= zPJ5XCZBL^`-p!!Dx28-|ecMki%q?T$>b-7k5XqKp6Og2GVu})tk^y%$>?mLVv4;MS zuR}|WpxwYJ-3@*==ro%^kIII>mmhJy57`-T$39w)R#(%dKu7>%YpnM_gUE8+gA7mxz*AIj!gljFhW!1LtfkdLA_(Q9i-o6o1hhdC z>c9da{4+L@o_5>Z6JhGiLMvM(;II(v4#HCdmIjKM2hCQv`La<@6~a_l8Ixh22)SLb zl1@f)>R^Tnb|I8r=#5+46<2CXA8jh~FxvOvW{xz-#-N#k{%vWgU|mT{rb^;i(*(fR zpqVVK8m0C*g0_rIOi%(Yp6jTI=9PI^h~ORZvA+&@`39s$d&K@U$l2`aME~edGpFR5 za=%??#tc%b>a(Z0w21>q6bp^zqoFLolf}LBf*k*b-C1BUAB|RnP#IFOB%s*%`tn1N zHNMYIh=wRZkOCr@!;fnrY=iV)I_CileLmpcH@q_M6X3F~C!WFvN;rs*m?T3?0&r6* z=PAK>1l3*u47hVm2rx?sTdQGvLL7sfebzlTBv}xeydeQlFdI?Ne9A_YR&<;C%a203 zeKaLD)`pL8*=VAYctoask)=~7)XFAcON3y0fhuX+A0FP3unS(kSQ>OJdMi)*XIEsa zwaDRKv(vfC->LgI!eM7B+O;rM*{RSz+wdmmjUs` z+f}vMMakD_YtV2xh~`7)ccG>wP;VeydeZvzZ0q{(m*@kfG*T5Kxn{VA2JUI?xJ{{1?H*ojoAm^>UT@LyQM3-3z>#ZDZhUQ@Pwdb zpu1!R@FQ1gX9oK!gPU^N16UwP4gxID2=ar{+#d8$@S)t^`bWVivA6p&2oi!L$9k(i zN7dyv?VG4rtOns45GKnFVJEZ{gXSGw*MEY=1e8zc?U;dvt3VJNWS<58)5I#Stb6Z_ z9&EfjkkxxSs;6vUj~}`3*w3Eo7I5-WPq?7>%)VZ(qF2tWyI|2*@7-6Q)`#_ht1W#k z6QH%B@2Gn}cUAx0WBsR!`yc)6f9gGOJ~=o*J`f;he~x~vhyy_~Q1vJnD+i`k>{FmB z`&+P?V^96Xo>C@wzOT0|4TPvb^`n>1m;+_rJ*Sct2h)O2Co5W820iooiuZv~VHf16 ze$di?b)u(yK&{B^(VbM2OI{nUd}W$Gn0@V)zv`8*=2cbNAWd)3I&ZM<*x=lM217K1 zA><*Q@S%QYkH2WBlUdjKXo#mCVz2DKTwZQA(3 zlFA+eRZOLsotp1WKTP(?<3mF_|dn&Wvr~_4W=_{!lTG1oOG{quOrN}5GFjF*>2VxPOoR81;6usu%YXCUemV}m+{itW4!-~Ma$0Yy zqGKW`TyrsesyH`TyLG@{r3uq${<-ne$VqMDG*lEm)|4`S%V#tpua3I2e^L)UlL;Ii z_jWw$MgQqP)A(97(cSoHMB+FV!Oz^}^QO3EKs7L8zZmc>t5Oq+MjE^KHw@W2eC#>Y z=eOuVW!j)l$w#F1<0ZWTeE-WWmY?*^@TQ~zbTU5}{u)!?_)#}8 zT-Nxlyye|}$9~A?JGQrfm(PEv&VP@6(%&-h-RQ=6o6}&xME{-{Q;SM|nCeVDXiYi! wIQU8HPl9tT=>RRTgb~p!4KgeYpW~A`l^kS1_bXg(l(C7VPn%T$0Aa!Z0A8by%m4rY literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_header_r.gif b/code/web/api/data/css/skin_header_r.gif new file mode 100644 index 0000000000000000000000000000000000000000..c8711c2f5f1587017fa67e20c9c037e288242e91 GIT binary patch literal 977 zcmZ?wbhEHblwwd|I2OnN1cHKsLPA2qKqM?IA|fItCMF>vAt@;-B_$;-EiEG>BPS;( zFE6j4prELzsHCK%tgNh}qN1v*s-~ugwj^=I-w9;o;%w>FMR=+9#|=kMh59a z>z^=j5<^SCwCOWu&I*{)#Kg+P!ZM$QnRPKE|LFl++}6& z&1vEn6BM>$<6!6D;QYsFQlP@ZUNu)EWWs|6_9g*krwJO3Oh-9IwS*)dE?``!z$>cc za-h+{gI?w$$O5B=b{#lZ-TR5|1I=wRPGRt_Mi6P#KC5^)m=xoUr$)Xa!yeFL-&SVj?C-= zasjIMbXb@Ij+mR>nQ)lT=FNh`&3twphj}?41u!$1*Az4JS=y{{=Cdfcq1dtWc{%2p%H!C(ylF07L= literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_l.gif b/code/web/api/data/css/skin_l.gif new file mode 100644 index 0000000000000000000000000000000000000000..4ca369db55d140217b76dca67b0ab33bb7844a97 GIT binary patch literal 477 zcmZ?wbhEHbgwtm8XB6Kn%dghIyySKy1M%M`UVCDhK7d5#>OTlCKeVJ zmX?-wc6LrqPA)DkuCA^g9v)s^UOqlPK|w*m!NFl+Vd3H75fKrQk&)5S(Q$EciHV78 zRg{m>!;fF;_d`r(SPPr(wPwzrj!vm`w=Pvs>yy)7+wlBBB zizA#bTqrM`x1_VlHK~swZesmJo^a0A@Ro@=69s2Ph6~h$tAvX$j$SoUEnGTWC%k&1 z-qMM>;WFX;YYJl~3Wv`tES;D?Q8fJ2M5*=R65-n6>n5s)tDasxv18)o!i3|qA5T0` z*fufh-olfMCeD2Qv}a2Af{72G-LrFMBW8<5B)dq1##K{2?3OsW-YO eC*Ba{+V?4@Ym0`^uA2EqT7u6$PMD~`U=0B4tiwnE literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_r.gif b/code/web/api/data/css/skin_r.gif new file mode 100644 index 0000000000000000000000000000000000000000..3c821e89e4a67edf7d368131a588908ed5d46730 GIT binary patch literal 488 zcmZ?wbhEHbgpOA8k(A#T3TA#+S)ogI=Z^L`uh3?1_p+PhQ`Lm zCMG5p78aJ4mUeb_PEJlPE-tRFt{xs9US3{4K0ZM~LBYYnVPRq6;o%Vx5s{IR(b3T{ zF)?v*afykEYgVuRPaIJEC+J+1npl#WqEMb$lA+-4=^MbH_>+Z^i@}~j2jo4FM;X{Y z91v0vn!s3RpSZNbhsnTaNr7;w*D9wKfm{g*^W)!Nv;3jA@76MbPr3{CuU`M^^sia_ zroVrj{Uh$U6H`1(T5dd7JV!-)TLVK^Uv*!4A7}iuzN9RM+P=I#;nu#&KJ|Fbc#U}7 zc&T{Vc$x0SiOu#biIzi0N8-SLuThx^XPOqku#S3f&5 zX2$GEH{*HZo94x{Z|!U8<9j`O;l$}LYo1-1eY`LAP5htP^UX3JEjl;RT%B>JN{P_% xi5*paR*Y9l-+FiItL&@!A@qowqx;0ZJrU13rYdvC7g=gqoSV2!&5?n@8URHI!gK%t literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_t.gif b/code/web/api/data/css/skin_t.gif new file mode 100644 index 0000000000000000000000000000000000000000..aefc8416b8729639f13683008efe2d2c8ffbc3d2 GIT binary patch literal 315 zcmZ?wbhEHbY+&GEXc1um0zpARAt4|F0%2h=76t+lAOZpqAqqsIKqM+A21H`g($XFt z9&1*w{!au@{3qyKl$uzQnxasiS(2gP?&%xAp!k!8k&8i|K?h_#$RP}@iyx@>rDV>_ zShX(a^}Yg~^Ch|WE7rYNd+`6jf&vd6ss0m7iah67%)hXr#A|KT`WtJ?yk+^A8jmIx zXms;;w>s$tSV;6cA9`pZ!PDJt;aj%kaxxn;9}BMlA6F_bZ&^=94__fOcTY-sCR-A5G*1U)9LQh>7IA@-o~!37FjxJ$8Kl4=Yr(+6Ddn)xOOU}D E0EFKz)c^nh literal 0 HcmV?d00001 diff --git a/code/web/api/data/img/bg.jpg b/code/web/api/data/img/bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7d07d98c7305c75d6f8c4250fac185554f142997 GIT binary patch literal 50750 zcmb4qcU%+Ox9@;r?*alMsPwM%j*XH)f`ler1;l^>X-bD9*l3Z2A_T~h7K#w*oroO3 zfWRT49Ga9QKl6sLCe8;=rGq2_L$Z= zfRim8hYlU$)wigByfEaxl`J_!VT+vJh{rFboZ60 zvX8kl`(nQT*X+NB*&`z7|DBL+?$Cct%yFKRZS~M?vx|z4yszKc9|lex;$ScG(0M=) z*!h02sN45>1dQHaj#e_u&#pNCF1z9S@*Y65eJ|Z%!lm6OusYM)KP1^5yHVW#_oy=6qcDfpTL;prV>~oW7kG=t^Kb zX1enDG`w4$^Z~$507DtjrnioyO*~5@2wdP{Nw}^qMeK8dRz0w_()YHXJ|R z_mEbZd~=0NsHe_Ig$jDw__q0YTQtt^y|`46`LsZdN4ZwTDwPuM%Sv_ip?er?rOY7> z+`dh0Nsbi-+wKEI^4|~lfqbH`y|`>aF*^5wTJ*@Iplh7r6@$?f#QKl0VbmahAsr@vOn%%2 zQtNGjbi*-s9%4Nkct>N(9d@;^mm13(6-Wkz@~z#NjGQy@Sbk|av6#m5R!9t?)?q07 z0T$`8NZApj#rmrasuRvv7w6S)X|K8~-p92P`UXu#mjtsuQO4Z_p*Vi<@tFFv3g zc}aW{&+B}K-xbS;?_AgFYV)zTqbUfTZ%EaR;?;I%D0a|$$T{T%P;{*iI!>h3dV@Hc ziaRorSgr8l(U?WZiw8eld{UmQ-maCF_3khQRWBevz3qicfi2JO1K%A>Z;l_)_2(TE zBk62f|#glfMrv-Sg|5yW-uJo;n?`9d9Z^ zWdsZwHmPR|tFvC1= zb>bCQcysotdC^Ch$ivFt;rIWw^nbM+mdja#wI_+I-u-H!URyxnI%Y=^IBLRw4XNy= z?ICJDD$4w!hNvhAaQqAKYx~j=CxO8WXyx|0 z4`A(h4B((p0if7?b^FHE-}7)1#m1F<$y#|t z{&wz@TWnVTwnQ@ct?jZ@ zUpMyU1XK-DM9yNX1DwrLAPF(hVF|+_{jES znLjQ#=#SPVdgM+}#-7woCkoE5Rm-C*Qm1>;%wA2TAz(Vj7m`(JabTI8we64X+*#=l z)2)iNUT&vP-xbohyN4mQs$$TH%x4dj5DGM7M_oG!i|rN;!h-w=E|$@1AU{rj%v9lkrR_>Wrl90pUtH< zTte6LcA*=0_=X0oT5Gvzw%F+I(=%9i3V=s|R8wR$Xz4fTnDmPz>mumzq8_dB*{JPV#`3>EyA_|dco{j?`5N!<2l8o4r@2d6256Y-k)qKh(4wDF*fs~BmNNzg+KA$+fS(Gh z0x?wd^5_!du2`0iK#7$R!PA?&PS5$5|R z`XqVRa^cAXiV9d-zOmCQzF~Wwzp!aAyO$oytKn>;)WnMR$D_kiNV{GHiP@O>(M){5 zLgDJvYa+a(;yoeX$su>{dC-GCk;A(QIx;zd9#@jtwHr)rn5sb$E0<2DsjRYlz?PxNKPbcv()0qJm><34~kqNVBP z`B<)Z1XF|=_++ocpXi?g6@3~dmRAyD_li)g05m!@0 zXi~aJe51MVTbCI;3-|w;+@QVkDACd|q)S;A;B`K>b1A12BFkG644EV+$+YZtI>TMl zO)xW4rbtP}P)*7(uM3*mrs(WZg4CWs-YaWLGnA@82)PMdBN_1jhNFKU=}-lF;G(u- zu-*HGbkn!-KJDt=I;}$+kJP7I1rz4LJ$lp``Ep12Uz5r~jC;Sj&OH4E5**ed3g*O@ z+NYi_KSlZz`15~(!+#y}MsOA~ZUMkK_W6TcDN$+`W^wZZSP>2aNenX%vwN%NipgUf zfSq6TyhYl;;vWET5?WHZbPLdH1&+|7&DxJw3uKUBkiGfl2%xS%jQU@e4?Z}^N7QK@ zpR`N=!fxgI5h6bV+e=^n*SG~;rFiEYAb@8h*NLROHT;KbF!Bq6(7!e~{GCJr2iOR~ z{hFOuCmjCZ9B-26^6>j&KxpK*5e|Qc`W>z+v|r-^ldPgE9EN5fM}b4#UrQ|rh_7C8nKJK(?ijZCFEUK~0N%F8y(OHvE{ z3Bh+nL&Lx|!gCQy$wrf}jC~Q|X*xEUK5z84bLt=q?PPd?!REluLfp)y!{A?RtFtOgI*IM#(ZOy+OY&MPrPw~^pKv0ryfTh|9eo%A9bd(0^E;IZFswtjM^V?}j z7{OgnuY5|hYX36zS9j4Yg^;SZrbUf%)*u$&NeV8H=acH{Ff|)-q*z}my`zi1oIdP} zBK}S1)LWmmYK5v8b zAY#22ahe%0+Ia7!)%L@e$lRzJ1{y**X?)-gK+JG5Vc%K8%;oD-Q|X=~n$Iab{F2{< zh-lTz$fSM15W2JvTzi!0w%)QB6z+*Ep}i3pKq?e;Y25zo&$nq|im$83XHHBe4BNfT z^LiEBJ2L0IW@bO9Xge60b3-%EJ29kJw+9!8KdSK<(yz9uo9SeF87f`0Q69CcNlmL@ z6R9nm8$@wBNtJa{Y*MA(o8MRXp< z1|zqz>I1S!UZVqO%*1s(a`F{5)$X0634Sm~(oq%9zay0&(bCk3LaEtNy~9@Nwl}&_ z2K+UjKU8|YdkV-{Y?~bW*W~G4jpydMtyO45z=%?bj#kscv6E&cWAn|xp@3w)Vy@Iq z`Y^4fZc}k?%pu^*)!!GLoOsc}Wcl;!Yn-+12D_WHRyC_~z0lTaHKCrZblSxX ziYoS6GTqgEmONZU8v6|`#meY`{`JEE$Fm3ybNDbK;J_Y7UUsW_NJAk>k&6r+A^lC= z%pb|Ec*hR}tESONs?%}K&b~@M>EQTTCBzG+FpsNikPaZQn^D$GsHuQnUsBN4kZZiEV zCk~~Skvs#N4EZfaOB*{I{llQHmTPtqpDa+W@JGZy1~Y7&&&Qd zeAZsf{%~KuiAl+CB_1Fhk(;qU?Q*sx2Mp#M+_Vq&0jgFg9IKNt3 z>xo}9B6E`!;<#3$RwFG9ed8BW{~TBQ%ii1=l$r88 z90FG1PPc{#xv9HgUeRO`3~B{>Q}mI}y-!^7klOwcw?A01STm5Z$96{Oi+gj@pb8Xe zQOMrRm&mtWju+gjEO8#gNTZ|15qwnY+Qno;->^=@5NQ7;Ma|IuD7k7wgG4=ZeB|eA zZSr>Tz^upZZ^fZDI7z&K()#G?$GdaNiGIP}Eb#$~t(qX;wHgSR1q;0ZgOfY@195j4 zgPmdNN|dOZlB@34q2aZZ=Sg&7J2EwSFURw2r$$Yil0Ww@O372)W2S{ntoKB|&;xNN zX7>9%pn%5aLo+mTxA_{~$N5?A=RvDxL3rQxgwfi(@iMw~>FgSR)>K+FY9)X{gXCV0 z3msfs(TKm|P$1c696P4Ez2bV?`R$d8482FP?`uQrlgBPyz@R;NiwcyUQ3AeHciYu$ z&-FIEn3T6l=q+e9IJ;QOBbGVM@AXp;2V+XyMOjAS4O2goC&-xN`FME43v&IJ5 zKhfHSx4i3EPr^K!nQh9?|vF-THy$Y3SfRo16$u{1>=SHp?O^VWRX5*lR`Qy&b zSL6s|t~+3Po?IQ^ibZSPH(nCtfhDNTn70ljgN8^jVlpIg+d8RcC6n z_UNxtg9M#>xu+0CJNP3_ss1ExLlIK){9-pZTu>f%+JP2Nh8ajl?Y}#P z3XLnC_Z;2_bf*)3F(fXVKAlvd3Ds`Fw8;?7LowG1UbrUS`uz|eG{V*_E5`t__l?c- zD?JAHLhyG}=t22Q5FH6S zPm;l0tCZ3QNr1svVx)V-Z^K-W);tV5_%IQ8m1mI0X%4(RanS!$LlR8m5rdd-Sv&-| z{K16hR{}+(t*76y$12$CHDZ4j4;x!F9RoP)av?h(3hYLVf3sNNAs|BzCL~IE*N-u8 zvDFU9DF7UTp;6YhmbnK1cKz-LxHP}84>)s1a*Ek(7pS%j`nUf-?XeS7>Jp@S;Ja;M z(?^syI;IF(!QLJuYlv;2HV_$tP~>oJ1+605n8SI!oC_Rw2+V<^KL?A0lzar(vsGF8PL_}JMh8T3mk z8vc#nWvq?bFqY0*FCQGP)u&-_{KQq1sYAGPrYI$vk6zqlwGVVoP~P^bNfqdH+j{Nb zJVDM7P)%-;O3Ey1N!u|yP-v;bgJh7y2#8PVR8s5O$;e5x@b=3dr_Qt5@7$awfgCm& z!Ok&Jeb<|&8_{lp_hWJQZ3(*L5@hB-kD}#>l|}HttMTXF2;(%oCK$QVYF+hBKRf4h z6HH?<_m?CYV5pgh*)r>&I?G=sHPl+W@1&*ATkglZLYai4MWTXD-xm!CvdP~@Lyxhd z=o(VutndZzPV^4c7)&x^_@F{^HV2ZcVlHW;3YXm*_?yZZ1YA8g1$A0~{F2FEWuY2U zDqyYg(pa-M$0{1?%kIdiI?9D6EW7u1o7ye=Xm;?G5h-u!`d@5oQ4({bpGW6c_uJu#(;&m8@AFeVFc>jT z635$Msi`#h)=^14E4c7M#f(4J}NFF!CIVuy>I;QE=thD}@ z)BQmqGw@UuW+l)y!5zdb$|e;sW{!he=N$B+di2OX;{uy%0twwZBZ%*daTSf!ZI=g5 zr9W>xDD9Lbbi{b%JaYE*F|8b$V{V#5hb<|iLC-ATsIk(hnB;U?@vM8jlDvxZV06e}hl=R%VD01^xA+%zjNqGHQ0=V603B_Icn6bWHDfny zKjbq4M{z>`z5bl#{v4@kiCfqaC=d#`J++7I*txkL1N8|9$O|k_!WhIa;I{NYiL%$USRcY!a^B&cP zCBAGX<0VHwJ5?9WwwRlN1|#Dwf+zy5JRpzenU1*Z=491CmwMB6omw+$XWr3FqZUnL zJR0N5&vo_SaXpYjOB2MkMr{dN@t$c^s2*L3c6^GFQM9G8XHyQVry6EHU1K*dA$GVr z4PTo;m$$ecJ>$7+7~xBj_4Y~G=7!=J`W0uBC)hrsR85<9MxUjqZ}ziJ)%;s003I2* z^mzTB*PNy9fXzG=p=4;93jj#xklhEroCA)Unw|<><-U74)iI^}!DbHWwHqI^f*b zCQiM|p_0HO^lP^DP7znxtK@QT)q7~${|5)G8l*aYJFot4HZkQHd~>;RYllO{=|BYl zj{nVWPRub2LfBx$4j}w1(g<-hdEs@x-$H~12?BdL^A9_;>bLB4KsWyt&fKu45nO2x zrYEMeHgS-F*bL`6#rDHrq}cA|@YbO;Ke8p>-v!_>|8uNSl)$;;7!d);ruiV)AzS0- z{}_QQXH?|A%yR*_rZ%O_^M;|7`+({#8Hj2c{6im3N-}Sa$LKqcraLM8ESuGOiGy6+ zVJ}F=>)?b4fJZ_CT-R84mDe%|0)O%SG}H$JwS$XoUsY5-Fn^*y5J2q%O1Vu{!bWQT zt1GvDPx@1ZzmBMTT%SxCS>yvaEX}LP#U5;L;dF~&UfxtC7jdcLp##^?uV*6I>PL|W z04)$zQ=h{e_z?m8Y2hh;o+O(6`TTs;Wp;)^0?Uoa3HGi->Zy`%+B}wAex;`D6Ri^# ze+j+rCSTZ7owAf{_*OX3)ig|}E2yC}`c;zpaEZ>|^cTq~)?P_yebgmZ`82IlYHVxo zn{P!!HQhTDR7)UV+U@?C74kSM?vaxzS%Ms_%}7!EK0f9(r^EN9&1RrLuT~*4PA%EE zx+8u|OxEj+<+QeKXod(qJJZRUJ6movYwTu7!N!%wGiq^a^5a`xwi}wP_o2UhJ=#a( zVX$aOuDjK4@B8ixQ**`2g@ihd@dqWa{>HkEGv=23(w6H($YOO<^NJuHsLgb|2EA1p zT&GM|crP7YZEwB!MB+h;1WE^PGuLvqDALBl$IxBQA-g5{Bz6-Ul0~oV59UX+y8AO~ ztClMEragq9sso=Xx>^v=b^Yq%OS}PVKE80f7yeyI4_m+S&M1skIg^}6h+^z-v!IrR zi@7v%#>R<0K#bdM=;ThcFH^>hc|-9~k~>|H zo%2b2+4X+4U&=(^s)XoGuo-n~*r7b^(@Uhh4|1lEuA}Q%%-$JmvYv}{;=3E5q8dQ9?Mfb6yy87&nMAii2pB)=WMFP zvoGMLnQXmWzwMyLo%4O>29N1=zg7_X-GV6ScdXug(kcpNr{kC+ozY4PBMJpdT&cXY zGW0y?oih=7K8{}TV#i-Dh0f%7M~%f;SB^L5mj68+Fcd5@y!7f&W}y0A6lCz}$1-R@ zUy16@6$u{6if;ACtJHv;6rri_MRPYh%<@&dpg-JjZxj=~BCXuvRG+xMKl_atPrPYJ zO;3~uUh`1TTw*B;r&?=Z+*3NA=#1uU*ZU=>`b2nY7vxQ?i*{YRL1V)F`q*Udq4qvt zx`*ZVfmG$xbcLBFsc8p_#VutvnGzB{$3IANy1d)dJ(Fyh+7Vtr_LCJ0x_L($LJgjp zX9P7K*4zGohROvmtg>F@qSUJWErNDst)<$)=}8`=f314q&5h$T@V;G1LhU?!B)ZVE z{JGBNBq5Xhb($gi`k{6)lNtH$p)-mL*;jLZKgb775Fw8`IXBe+QqMGhKx+|wLg*li zVQz#DW%r=8JZ!ggOx?HH#9O=J%P)wa%gZ$Nt}EG4*p065Et>i++^;#wMa67H1Qgtp zh7QbeEsNQ!Tk2gZQyz4G2XL0Ge?C$~jX2QYu+1aEixvZ~0w*?CEylJi zZUKG={RhH{(6W8VVdsM&R*fS*oD@&Tn3+MCb$6sRM2DljswX12<{JLhEO1J@`tQ;I z-AY5DD8vrO$)Mu!!~c$)B|PWqm#g17uPI~p+v~UZ`UbTM4`e6IY$SNuc`{9S@t>zv za9dXzukqDtMkD&?C+OJ2ySh+*bw;j26=-AgP=d1rzm$Fjxnl4Y_u-ranhbj8-Y|{= zxK{50+MHDvpi7pZW173TMco9$9nmQfCTsb2u zi~V=Mvk(6Jw%OYZ_&dOv#lw-~_ea;2$4|1yc2y+ivc^HG!Q~SVR%_e4ktwgBa^xbz z#wUR{ywSTdTZ&2P2*V|hlol=Lp0m&a&>p79P%s$o9~K(R>Vcs9^jicc$0a=DZPfZ> zg9zq=y_73rBnKhw=Yc+L=a--f1A6386Z1Z|RsOu5mrNu`vX&K_;O(&(SJF5{5M3qI zWtN{RZ8lH=nYHsu=5nb>#4o|3X9w3#AtmzhjFKkPm$+}MEI!vvDTyPC60Gb^g`09A zJKka0+!Viw5}DEUAldWr>X1TIz2UuG!LqgoIje)w#hGkhPx?h)NJ*UHR{0x!iEnA1 z^+QNjAcER2VTH^uooF^*&f8wz(g^zT&uY+%($zF*TDkB=Va;_JtG3{dg2Sdx6H;4|Qv2A+v!vnFY5~P8UUD)~L=8;ys9V>4;-GI% z9%3qK1U*AagC9(%`PFGRWs^GsvQq?Tyziq|8F9*F>PzNcrp=R@z4$G?qxOzze2;UJ zB-9$2u`X-qjFuy)B@??HCD#0$j%lwkX~I5NK~}PzTYkxO4YZ~HD7tk6Y@fFii}tBg z!se1-weXDRd4a2~wa+#tUs*0e8zf4KGVh_s0z)w@9;+8`l2)G1qCJNT>4JM!cyh;z z*Pma+s)D70g~DyLpMU*nK!UCfg+cBW3C${pP{67GUTy+uJXW+mz9P(!znMB&L0eh#l%GChL%}O51U6u zF6z8JX_G$uQq0>9k}j5<-GNCOFZ=Ai7# zfq&NIq%z~hVqt)cQvy_y4bbikG-q{TCG8Z(ykF}6OzY;1!NdkikA;V8uVaUt( zXDl)YYbRRieL5mNsIN|GHNG95*osg>X!t_<3n5zL=?s~AX=B9RR3 zF-~Y7}`9IigAbHA@Ju348sX?yBjp<^%i#fw~;YW>1E+~D2HAxZm?L59|s)2S3hWE~x z(0NciA4m}e_UxPs?=7G}6=Rtj?7~KyHhE~0-_NmgJesDU@paBau&7Ub9pJ=%eCyyg zJ2LvOa28h-%P`ozq%k3XLxyyATu@s3Z%B6*2T(m6tyXHprT%VHi(o`{aqwAH^R6FApPS&q8_0kQcuB%)(fUx=^Rm z&VJuaH6}jYF^&DJK^0M8&3(Y9ZI$MYkl^aDj}P0$Eiy`}oyQqINjNGiwb8o3G3`ci zm%|QUr=V_LPF@yyi2#!*>`nveteUBXmXv7|N8Dla*^4X%n>ARgtOcq#z>>Pzly*{i z^s<>lt=`d5rXb2JGU`jNJ>Jcz^J1)yF7#%rO6TV!#FZPAv@{G+N^J_t404pz_~o%w zxbPe_{H#V6A6ZYVz8!C$kH!VVNNJ_@~=KSSg3Lc((-jXnX-2FIxUG%DSd2G zS3xFT%e&4=k|j)L81QgsEQXn4j>4MsxPu$DpHS8=>0ITryHn&In zK$J7sUzZubYLWh5m2?&s!PmZ_bR#m%)Ge=#=D+FEbk-WjwC4Va*7-Z?5qB0+Tz2Ss zO|^in<1{4=R^Qv!X@_?F;@e6rN{)YHQy?W-^lWu1axE~d%4i>WExb4Cv_)7`a;&2v zUnTjXUhQsc)kRrYp)6w7F7bCt8}@XJmWlMEpwQTsv*I5!l_{s>!5R3(m#s*;eR?fu zE37@BS%jbW&0PDbA#VT1?H4|t?(*Itb-0-gnG`7<JZV!{?${u-$%GBgQG^I7p55=i(d+^2~1OdSxa zmL*su!hTtGKWBOo=`FJ^`+$W@$^=%dg%{ope+(gRNFmDSrrsXINz;~mTV6kWedlc0 zMRvNc%+bj;w(q4D#3Hn@OEe*fT@ZM#m3L$|KeMQ>{jgkPIi*(5Jfj<$gtW|<$rv22 zGvouc=WYbxk03ng^J_yMoZqlsiG(4+-6Pz&Yd)G$JcM<_Q~2~mk?OtAi&%-jV{c05 zZonA3|Gc+dtF1NQD@=beSiY`NU?qxK9MLZOQChTQ@;I>!y6sX762hPpy(thP7UsR} zyn;-PR${Hj>lo+lHue-quD)_?t7W<2t7G)gGt<3HC9Iax!pK>91MgtBXBhPxe;+)? z{}GlGN$hj!j?!R)&{_J~oj`m5+u>mPhz7FjVxD-75S60PFO5rj4DKeiN=X@vSY$94 z21R;A(3;<;yGtLqsDN-41%5lJ%Af2i>PYL?{TAU-pHKW-1;(DDVza;7(h^~A zop(5VgpG&pN{JSzAQam-{~zH>VuwO4>e;NftZ3WLJ%!DVpR!Y1=-9-pVGlT-lU>T(-61hZ>o7v^zaX@-=qe}CA`PO9^&qknS3gIpZn1MRP_~>heLdp$%qN44{{iDc#etkWs&&7uaBcp(B&Rfh1MUs&A9uXJ zC}zw6PCxx*mRHa9>DDb<;NH`BgBt(_I`A=T0KeO1mxpn&);zAdb9p=>>xghaB35f;-a+-|% z5-l(Red#dBICAsHeZa!@#E&E$<+Wj+5_WRB_d@m9;k#hi6vZnBUK!-Ir+WL=X*+K- z1c@Ge`1N_%YXL|OiBa(3RHVu4b7sce=_qy-dYdBxo_&qCl8wujf!7e;#?cic1cklu znsZj4*>}lxPx{c)`HP9r(wl6I#vP(4lL$YN%4ZG4*(e6wZ3I`BNjJf+% zRqt}wuDPHSAEl;g&4fN(JwL;Gc`CqFHrf=ElU#u`+!Y|3;7O`X-`$xuA+ZXo=kTDZ9seot)?8W5FiX~$v0=+g~$ ztP9T~wqLNDyh7XyMM``op4zhiM7#})4r{X);jM*^1RIb1?1J9M@=Zm?iqr?A!xoa? z=0^HNLdKZ&hJBc5X3bQw@;Z89wbeOFdR%_FXj4r?(isZ(V&Wq&_4%#^*5v0G`WL-4 zTJiDP>289|q!Cph{d~w!HqFdwl{iYnw7&0f5O{^i&1u|?UwJJ7uV3eluX$c_vRZ<) z4~#A&1>WdysE>@7spl+L^RW9odlGdLRx1CLl(WX!qbxKjF%D>Y)x>jjjF)0PjmFrbqu9d@X zIdS4~PHoUk^*clTcbd)+pt}8x*LrV!8!WeOS{E5eDgW#))|V?3iCYu>;V9j~ptkaB zg_fjJ*VMOk_e?(}fOT32Yo~g=nxc}e8t|uT4f9BK&pKZdt6ywug8RlVkC)5Zd9j_m zRksIiMg!VPX%sHw!VML@+X*tLs`}o~fvXQakmKlXy3psaGGDkhJfxtQ_uh}dFG0Ep zb9`Em&Of^+V~c4pr+wgkZx>;(RUw1TL>mG{NK=G;;3Dj03$duykPIoYC#_-bgR_o zvRs+4!NE=qNs2Le&j!c$oWiG2Uv2rs-`kZrkgaPvCa3|1+!b_WWfO2rQm4H7M13_I z@Rp5*v)iR^7f>6!_JOR6Cnz!G$4vF)aH}ORX0xzNAM5>-4jTLCcE%U=$Zm;A={3(p z1!^i2k(bfsW3SG?vK)H%cspF^>^&I0SdU#FWKE|t!7^%6h<=fNOtx;yDeu;9#~1i- zN^=q(hER#v;nkowAv?=e!Aiz%Z37g|KvxcA?3XmD3!`bVT%}LQb6N%Wbyv&pFq0iye@~ zOI5CPnF@a51A`L>CHLeB|9l15s6Kp^bEL4^_y8-p2vtR0zk?h9S?x&)V%6MFX1*00 zvL2p?gH($h2W$L2*<}noswLRa59|`&MYI1XbNVfwbf>Qa4Ng4Leq-XdxR5*wwW^Ki ztkdgk72Yw+I=d_}&xrr1vty;6+RmVYKmSJKuXnP=D6$sog$ILW%Y!I}$F)!>anM@S31SOM!u&HA%c zP&+rvJG=Pl55lR0BEdP9?9EPbqdPK77_eH=HU7Nwc^K1XzK5s2SiQRqL*yh?Po6#P zp2@m)EAg(Q$rlx*Aj9cct#$SEyL(+=a$Z5PCC7;igP~0^f62&7rWprosY?>`o6H(D z7u<;@+RASal^HdFibL$5Ci=ruy#+o__o9mo1Y}edZRNO6^*+r#q+IM|U{gkIRljo) zmEUFWM2JvNmTLnWS1ew#E*EoklY&BhJz?mo@#I^!CdVv_bN`NW8tYdKUf>ASmDkK$ z&H|1kpp8!7`)^>+=KppyK#*lk2*AIol7#SkI8L=T{4fd{!+X7aEV|0Y4))V`%>|wEq49%dY zyC%paNqsiOO)O_Kwx*`@BZmW8lpX^zdQH$#F zNi^;yZ_nlSZ=Q-|lfGQPziR68y8j-{Fl{5OJdYagPtw)203)qH&J?~@y$rt}yQ%|( z$dlfX*~RD}xJ)^3rHG6m25h`8ry|~fkF@bw8OmXeUSIik6%Xo9;obG45EOMA_|H1l?qfqVqerm&3h( z`gP78dbRd|i4VtU$|i(CPN&o2<@S=Xb;5SSsX3sabh9O=f0DuF;OBlBJA#Z(!7PfT z-nR>DA50e^>=$23-hNbeZfktL59BqgjUc;}dgdB+)G2QQd>Em}SqI4-qbw<(%KQ&8r$ zB3LL;myz5$hIBN<|AJ*~Tfm={XH2&RV1Z)3ehs4WUzojrVKC-!W+uUh@p?>VrN}6` z(6nzQIx1|`qoO{A`pdOTyJX8<8nvzy;7xH4RFVPBPNMrC!raxf_JLhc0a7v6Wt@eH zwNUkoDy6w!XlIVl2i>04kfRv-p_NY8ncXyRm?cQ>A9}pKkG@7|lg;1}F3H{QB&R#~ zDX$5*_#LliY~quD)@0eC@tDdALTP7Tm%a*3P)s40Paot1uAZP^bZUdQuLOKncO!1t zt^_J}baf4@6Ejpu2EtElY))MLA3y@mnli`tfkx!UK41_U@|L)VVHZ7m@9hJ#Jw+dW z?K!PK*=-m)b5V<`Zqg91s9`iO!fzfs?EQS*w0S@#vmsSwxm-NS^^!oP)$dp_aP|XG zT-#L(9?huL*`vfzv#Q2mcAOkT76k={i|z$~UgdI_J;t8DKjaS&Ymb#%|FslOcHmeQ zZLw$c@A;wj?^V{;IV83}exmP_YED|BgYuw>M>M&9gdKM{kr8~3hgs*e#4-3vejVYQ zWB`NSNa{=ToBb;A_NZoh8nVvn`v874c^`-X4rBb1$|~5fw(|!^zPii|?^>b1$@jBg z|D8w%Q8iMv!%kyyAXYsr#+Y|Vlowl0mVaLTcbMIBXcp{A|v^NbCsu^cQ$G5DK2)hb{Xw^&ha`K1L%%7%GxTZ1a-bVX=> zaSfBcqm+p88ajE?%~34XYfGk%aO|s#i`?vYo{;k&0F@~sZzB4j49@?_uLe`)pT|1X zN4708Dk6xeRL*RWa!JMBscd*vLF0Al)+^53e<{q^`+85CH^bp+#EEwn zN2dJW6AuE~6=w~UdJgr*(#+^@4SV+T2!F*m_VwiQm^nqZ&fjcERm>fQrEOUfm=eNn z3VO^T?=|DDO&y`8(-48?S=s}iZ-TBGS|0h?{d2oo?#1%pQLK@F-~rQf-GLO& zQ<*^lAm@~0gB951z&|rJWFXeHbIFE$xT9C_I{fpSJ;BTmD9S0H#Ea3}Q$H6BQBn%`r~4jpW9ctnF8RY~?`yrm%Gt)B;@v0P#_CKxCZ=|+{1fh|Id+Nr zr^VvV{*sce>`Qsoa$-AU#9>Du<8jBgHJj4L8nxxtXUG8>WkY#z#R<274K0tQGps?H zUer;#|4*Shu(Wc~mTIGw*68(p;3l4_>*qJS_^WJqUTAQxRNaF8k|0t0y&=Xu#ZG(W z)vl@8h6XXb&*i}+>$<+DB5_Wfp#t}dQ{7yaMlL-Gd4!)7NzazIn3TClc3CZu#I4Uz zcTq0(jU(Z*eK+mx(_Np=$IHCNk57zatF;DKlaA^R54~rFk~)v>#_gIQR&w@2QWGs5 z({4V)LO|h|1rNh@7*Zqj@dY`~DFsqO)8YO{jeQ8q%mY(juB_$^9m7Vm~ zeEpXz0!rGiD&9 zu2f$i@CEx9!{enrvNV*ZIXV%GsDIWM|7@P;&7Cp<%i_PSe!jct@h1SVtM0UYLalY} z!@6}hX13E?mg|8_4-3eZLjX@xMN;_ltYL&W$!fm&0)k|9P|;-rrio`|VPBJWY#zxg z!MtJkvw25u0aqOB6j;fg@-^*o(!q<{2kaNfD{_bc{0@k6A1Sr~1Pac+dLn6yjqcQ8 z&_I&3C3~x8gEvXR^d7)|uR^3XBKYSJhh1M)c zZ{&!#H@%3&!KmH_bqe}=EW=PBd^(A=cgBmICxpJPEAnGUzqw2s9~@*gfxxnyF_LH1 zts`Z(DVRuaL|{w>JD9^^S2yo;Sk_s}iF-`OfAY5`aH1gsD7N$`pxBpjLEiyIjUVz) zM8{?uMU#|cv)*6~p9((qgT@YQ)zHPU5h&xAPq=#nFJ5j0lMNiBb6wrLe%S}bsyvZg zTxR%s4+TNZ3S;KotKv^zp<;T&GO{(t+ru&gzWJs_U8hNq4BSDD{y&jmSQI;KgnE&t zp~5>Z zx@7mPbsrFER%rX9*va83{YrZ8<8@vw$ywM5Td{>s5B(To%o0-4C&s!ThufopTW)** zsC0N!kSH!`j zx2U(^B4F9MbVzUZBsY}=s$!xTw|+-u=oe9%_qq%Ngkpo;4> zjDMaeP!B^dt`3XpSgFi8b2Ik_cG-a?8+Yv{oNzB#PF}%da$7L4t$?Hx-sdCboR=}| zo=i9zDJyur_=P`ZXdYJG<(MXdAoO7;C?Ntt* zOdtXWBYR(INU0YgSwc_4az3*%le6FFB&`p->6VDq&ZDq-*!i}Jy|dZ$#4zlckfQPO zcFFeZ+kX9n!W&9!V!Sx+zNL)f@4lpvN~RCxjlHLK!DeVLC0TtUkzh_Vjmqt{E})=( zN>`4J>|CL7&D|(KsO`pM;dmrQ-d+Pugg4UXkarT5^u_o5hwzr~iJ=llyN`Q^Nv=L& z{%R2m>MxMUGa1;zf6hL7n3klnQWc;BwNBBw9sZVUuy#7${^Kw^WeC+Zz1u2@)Am5S z58wPaIMR+n5a*j_nU64CDyJ9d__=k`>6V+5$NQDDlwN1sPZBhxXeIty-3GA{pk!+NIUfce7C!D zqS0IQNf`J8b14Mp5o zKIIdKPqu~qRgzILtgc;7Z%d&vA8)S^RctF)obVpG8{bD-g!JI?dJt*5IgEO{_5{7D zF=6mh;dAOwH5rFqGQ*#dX{guUHM3MFYq8k*3mRv5x{U-1-p+KwtJy!SoZM2T%>}IH z^0?_%?E~#l7wlTCH2Zy?QY5LbU)q&|lG!n0gzd0jtD%C`NiNo=_Mf!9yRL{=1k`Hu z<44zLVjSZ%iYO9zL?(ANG`zVaEVblI&01?11Y|IRhU7xBC~tJ7vqnTGc`T)!m%sJs zeoS}P%d0h~Utx3?fy8o#z6nn@`M^cD-Dkn>Hg-e_Nn`vUf%Wm$d-9;pNN+Q5Fh(0M z;!T+%Y7of0n`7w+J(^zv>h!IS@t67mJ9e`9FC?Kmihgpj~7yb?MLRXq(={i3_yS=|K}E<3#b z+5drEGVK+YJE`V!=sq;3FA*NRF-55TU^R-3$*IUca3eS?NLFc0O-2?Nx()l37owJH zdzCY19Q@sa6k~7h)l&)_{=F=oDiWmHmW}KVAk{=vsP6AA2mq|5l+lR%LMzrS<3DZt z#}{sK!9}s6d&g`!+qBUkDEx~jRSr&HLDe9;^;-fSjid++z%`H^!nIcYOz-g(>eyt)v* zN(sDWqGgGWO@0aTEg8WDf7dv1mxKF01v6cwjDvgMD~YQv*Rz(;z3RDq+9$C}scwCM zy4oO@i;)op@~w1k*0@pi5(?GS+wjj{Rmj*5X@q;c;+)`c46JipoTOE(x)ru%_w@?7 zD?c%quGue;ayz-{u6Lm(cHj8|7zf{kfIA8VZJSvd@E%mqP<4U)41)IEt52smru)XyhoAH9+M}IB(xnk$D z6hF(^}UoGl7H5G$u0nOyP%jbfryA;=CaJ zhKMQ?k{G#7))xiopRj+cc&3*Z6N808lyX`gIx~$qS?N9>dj&V7>Qn&kg(<+vIwy6| zU0%C?0|*bFOzsy|@Dg!Xzr%b?5X!L($qj1j2@tsZXZk-Nlp>!(x~otMwY3hy%WyFA zu?PcG%4q`_aLsO7U&oc@R!WbI=qd3*%@E0l=#(9^=0%;7-~&_gKcGnJUYZRzhNM!5 zwECGi(Q=NOGN;{erYMlsSQ|pU{xf1=^rYe=(B_TuZ+1Eps6CT$^8iHbdlKWie2 zC1=QDz6L+@A}{!=)})eE!Ip#KnhwvvcB5yB6>Md-gd_EDz1q1fEcAi+FPQgM>JxS!YVG4muSJjF;Y9^B1dBEiwBZ;-9lgF;2W=owOmgNz;li}0J zx)9 z77qq%Hm6hCRGM?q@#|3w!86F<0HJ{0wO}VMyDYWHt^keo_<*5-x*nNy9*fneZB=S# z>?|5JU9{IXi^Y%ZHO!NEmaELxmyAV|yuU~3(sra38Ji(O1KGK`#b5G(B(TccW5tPw z(|+r~MiG&mB&ug2cGo<8#pA*$X=d|86S_iimF=z8wyc(O}9m( zl1kg5GZ^a)t&Bpkw!+ubIcyLaKE5XPl=oi^`YDj$D@+UDHUPGMrE{I$SodRwPa0Ah zQEjC#I*zpyO>Bg&=1L;dZ};E-WJ&ND{y0%3H!u_KsH;_`C@^#?a`r$=G0pBUZ#u~{ zBOc*BM4o2;L87D$PfxWt5sJHIOfabUr%7PmY_Rq}Ail7rfi&Gf^}BlAEn|zU$U&k| zqefo{_nxV_&7T^D2Ij^3ZY>CJWHW9BNd7_ZJ#Ns*@KuK|ZmHjOu|=rt$!FVLLixr8 zHtM|oRWGsBd;vk}tKN~~aTO}2&1pWNOT^XscvjrL!*=6Htp3+v{-;Kmm!{^YepU8X z6}_SmPcNDnR=v~>iCp24r0oQ#K$ zN4-C*?R1ZGj*|=x?<7hBuDlW52v9_U z&c0jN0Nx2Sv!^Rv-1n`SceBK$#e{Z35Sve*Yg${0>Uy+jeOPaC(uV8_+`B$x9`K5g zMKmY*H*p-M4igd|5*w=1LMCimxHNo%TyrUc!~K^`!j!&w^T0jG^YLDqi$5ldl5|g+m(OX0o9FFI9Kq_Q`mrCCnb+^!eu5wji=l=JSF z{<62TxbEX0Dm%T0Xmlp)_cZ+YrSg{QW~1N=A=fU3_2ZzHs?M*tR7U(4`Z^4d{eSdX zmpxQ8x>eafs(jT|!ZIMP(vo&rA<;5nFw&^*?R<7z?IYOG^XeN5WLWlxX+M;v91?lu zo>{@K_E-`8SYaOADoip#-iw3lY`gjKQj>Gk^08YW+dTJ77E#Vr@kkT?Ps72D2DR<1 z0IL5emFl?un314CedF}&g$Dchy8T$qkh-N^)k#cZ^&Z7xp8nNP znM>T;O+wSDYI8P@)+&x`1GFm*lkr4A|J1@ zPBza96VN+pr$yi)r8?F%$gWDvgwHZDj|?=&<;#niRZPlin)0qQQhbMd?{V7}VK<#t z(T<5*^mb_D9xaQ*5y#L^*bC`T?@25;hr*H?H81Vi?r|uU$NpM#O$m0SXBGVes@@0< zx((loAWZDzQqvr58uubBZdW7uaTKRcX%ABe&0bEUVKJTB%t-zMdi+4A&_@WNsj7Ox zx?x80(ify@YP}Y|HfMQKERP2jAka9y&sRl_$)#0~H9COX?;eDXzmccD(t8-QzO(W`G4IB)64-6}V+k_SC)mohL zTF%Ge=|TIq7$%ER^8s0Y%$bnICA-E)hx!d?B({`A6JU$j$yM|!^~+p}QdpQhZyp

H99>k}TzJC8VOquNA^4DE7>_z4jS)uK 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 HI5&=x7E`Osn*XfZQXE|?ya?i_-T{j9RNnzS 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 literal 0 HcmV?d00001 diff --git a/code/web/api/data/img/lang/de.png b/code/web/api/data/img/lang/de.png new file mode 100644 index 0000000000000000000000000000000000000000..767abe088625c523ca3c3114faa767f325823330 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^VnEEt!3HF?4d0vvQY^(zo*^7SP{WbZ0pxQQctjQh z)n5l;MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1T&JY5_^ zEPAhAG!#9cz|-+oAKh(LZ(9#_LLviy^OfQ(f-{$^N44!5?rOG_RU%-yEHJq(AXws T{e`}CpluAEu6{1-oD!M3ZN00004b3#c}2nYxW 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 literal 0 HcmV?d00001 diff --git a/code/web/api/data/img/lang/ru.png b/code/web/api/data/img/lang/ru.png new file mode 100644 index 0000000000000000000000000000000000000000..53aaf57be4dab480ddd03e66d93f7977186a3b41 GIT binary patch literal 2886 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 literal 0 HcmV?d00001 diff --git a/code/web/api/data/img/lang/sp.png b/code/web/api/data/img/lang/sp.png new file mode 100644 index 0000000000000000000000000000000000000000..5ef5123baf49a626da76ae7d1ed3d577d36c7dbc GIT binary patch literal 62 zcmZ?wbhEHb6l36Hn8*ME|NsC0^N-;_GlLF@2NGvs5}(t*^7LE&xihxh>fU^B&u{*+ MiyqU`LKqmV0bcYL8UO$Q literal 0 HcmV?d00001 diff --git a/code/web/api/data/img/logo.gif b/code/web/api/data/img/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..adc59fd290006dd520a30c7ed83ac5bad30e815a GIT binary patch literal 6763 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 \ No newline at end of file diff --git a/code/web/api/player_auth.php b/code/web/api/player_auth.php new file mode 100644 index 000000000..984a96fe7 --- /dev/null +++ b/code/web/api/player_auth.php @@ -0,0 +1,44 @@ +. + */ + +require_once('ryzom_api.php'); +$cid = ryzom_get_param('cid'); +$name = ryzom_get_param('name'); +$authserver = ryzom_get_param('authserver'); +$authkey = ryzom_get_param('authkey'); + +if ($authserver) { + if (ryzom_authenticate_with_serverkey($cid, $name, $authserver, $authkey)) + die('1'); + die('0'); +} + +if (RYZOM_IG || ryzom_get_param('ig')) { + echo 'ig'; + if (ryzom_authenticate_ingame($cid, $name, $authkey)) { + echo 'ok'; + $user_infos = ryzom_user_get_info($cid); + echo ryzom_get_user_id($cid, $name, $user_infos['creation_date']); + die('1'); + } + die('0'); +} else { + echo ryzom_authenticate_with_session($name, $cid, $_RYZOM_API_CONFIG['base_url'].'index.php'); +} + +?> diff --git a/code/web/api/ryzom_api.php b/code/web/api/ryzom_api.php new file mode 100644 index 000000000..960405b03 --- /dev/null +++ b/code/web/api/ryzom_api.php @@ -0,0 +1,49 @@ +. + */ + +session_start(); + +// Global defines +if (!defined('ON_IPHONE')) { + if(isset($_SERVER['HTTP_USER_AGENT'])) + define('ON_IPHONE', strpos($_SERVER['HTTP_USER_AGENT'], 'Ryzom')); + else + define('ON_IPHONE', false); +} +if (!defined('RYZOM_IG')) { + if (isset($_SERVER['HTTP_USER_AGENT'])) + define('RYZOM_IG', strpos($_SERVER['HTTP_USER_AGENT'], 'Ryzom')); + else + define('RYZOM_IG', false); +} + +$includes = array('auth', 'config', 'utils', 'user'); + +foreach ($includes as $include) { + if ($_SERVER['HTTP_HOST'] == 'shard.nuneo.org' || $_SERVER['HTTP_HOST'] == 'app.ryzom.com') + require_once("server/$include.php"); + else + require_once("client/$include.php"); + + require_once("common/$include.php"); +} + +require_once("common/db_lib.php"); +require_once("common/render.php"); + +?> diff --git a/code/web/api/server/auth.php b/code/web/api/server/auth.php new file mode 100644 index 000000000..a8706fe8d --- /dev/null +++ b/code/web/api/server/auth.php @@ -0,0 +1,111 @@ +. + */ + +function ryzom_authenticate_with_serverkey($cid, $name, $authserver, $authkey) { + $rawkey = RYAPI_COOKIE_KEY.$name.$cid.$authserver; + $authkey = md5($rawkey); + if ($authkey != $authkey) return false; + return true; +} + +function ryzom_authenticate_ingame($cid, $name, $authkey) { + return file_get_contents(RYAPI_AUTH_SCRIPT) == '1'; +} + +// take the character name and the account password and check if it's valid +function ryzom_authenticate_with_char_and_password($character, $password, &$cid) { + $db = new ServerDatabase(RYAPI_NELDB_HOST, RYAPI_NELDB_LOGIN, RYAPI_NELDB_PASS, RYAPI_NELDB_RING); + $char = mysql_real_escape_string($character, $db->_connection); + $sql = "SELECT char_id, char_name, user_id, home_mainland_session_id FROM characters WHERE char_name = '$char'"; + $row = $db->query_single_row($sql); + $character = $row['char_name']; + $cid = $row['char_id']; + $uid = $row['user_id']; + mysql_select_db('nel', $db->_connection); + $sql = "SELECT Password FROM user WHERE UId = $uid"; + $row = $db->query_single_row($sql); + $ok = $row['Password'] == crypt($password, $row['Password']); + return $ok; +} + +function ryzom_authenticate_with_session(&$name, &$cid, &$error_message) { + $c = ''; + + $action = ryzom_get_param('action'); + if ($action == 'logout') { + unset($_SESSION['name']); + unset($_SESSION['cid']); + } + + if (isset($_SESSION['name']) && ($name == '' || $_SESSION['name'] == $name)) { + $name = $_SESSION['cid']; + $cid = $_SESSION['cid']; + return true; + } + + $char = ryzom_get_param('char'); + $password = ryzom_get_param('password'); + + if ($char && $password) { + // check credentials + if (ryzom_authenticate_with_char_and_password($char, $password, $cid)) { + $_SESSION['name'] = $char; + $_SESSION['cid'] = $cid; + return true; + } else { + $error_message = 'bad_auth'; + } + } + + return false; +} + + + +function ryzom_get_user_id($cid, $name, $creation_date) { + $name = strtolower($name); + + $db = ryDB::getInstance('webig'); + $db->setDbDefs('players', array('id' => SQL_DEF_INT, 'cid' => SQL_DEF_INT, 'name' => SQL_DEF_TEXT, 'creation_date' => SQL_DEF_DATE, 'deleted' => SQL_DEF_BOOLEAN)); + + $charProps = $db->querySingle('players', array('cid' => intval($cid), 'deleted' => 0)); + // new char => create record + if (!$charProps) { + $charProps = array('name' => $name, 'cid' => $cid, 'creation_date' => $creation_date, 'deleted' => 0); + $charProps['id'] = $db->insert('players', $charProps); + if (!$charProps['id']) + die('ryDb New Char Error'); + } else { + // char renamed => update record + if ($charProps['name'] != $name) + if (!$db->update('players', array('name' => $name), array('id' => $charProps['id']))) + die('ryDb Rename Char Error'); + + // char deleted and recreated => change to deleted + if ($charProps['creation_date'] != $creation_date) { + if (!$db->update('players', array('deleted' => 1), array('id' => $charProps['id']))) + die('ryDb Delete char Error: '.$db->getErrors()); + $charProps = array('name' => $name, 'cid' => $cid, 'creation_date' => $creation_date, 'deleted' => 0); + if (!$charProps['id'] = $db->insert('players', $charProps)) + die('ryDb New Char in Slot Error'); + } + } + return $charProps['id']; +} + +?> diff --git a/code/web/api/server/config.php.default b/code/web/api/server/config.php.default new file mode 100644 index 000000000..c55cf74f0 --- /dev/null +++ b/code/web/api/server/config.php.default @@ -0,0 +1,31 @@ +. + */ +define('RYAPI_WEBDB_HOST', 'localhost'); +define('RYAPI_WEBDB_LOGIN', 'localhost'); +define('RYAPI_WEBDB_PASS', 'localhost'); + +define('RYAPI_NELDB_HOST', 'localhost'); +define('RYAPI_NELDB_LOGIN', 'shard'); +define('RYAPI_NELDB_PASS', 'localhost'); +define('RYAPI_NELDB_RING', 'ring_open'); +define('RYAPI_NELDB_NEL', 'nel'); + +define('RYAPI_AUTH_SCRIPT', ''); +define('RYAPI_COOKIE_KEY', ''); + +?> diff --git a/code/web/api/server/user.php b/code/web/api/server/user.php new file mode 100644 index 000000000..9124191ae --- /dev/null +++ b/code/web/api/server/user.php @@ -0,0 +1,111 @@ +. + */ + +function ryzom_user_get_info($cid) { + // User information + global $_RYZOM_API_CONFIG; + $db = new ServerDatabase(RYAPI_NELDB_HOST, RYAPI_NELDB_LOGIN, RYAPI_NELDB_PASS, RYAPI_NELDB_RING); + $sql = "SELECT char_name, race, civilisation, cult, guild_id, creation_date, last_played_date FROM characters WHERE char_id = $cid"; + $result = $db->query($sql) or die('Could not query on ryzom_user_get_info'); + $found = $db->num_rows($result) >= 1; + if (!$found) + die('Could not found on ryzom_user_get_info'); + $row = $db->fetch_assoc($result); + $db->free_result($result); + if ($row) { + $row['race'] = substr($row['race'], 2); + $row['cult'] = substr($row['cult'], 2); + $row['civ'] = substr($row['civilisation'], 2); + if ($row['guild_id'] != '0') { + //$xml = @simplexml_load_file(ryzom_guild($row['guild_id'], false)); + $xml = false; + if ($xml !== false) { + $row['guild_icon'] = (string)$xml->icon; + $row['guild_name'] = (string)$xml->name; + $result = $xml->xpath("/guild/members/member[cid=$cid]"); + while(list( , $item) = each($result)) + $row['grade'] = (string)$item->grade; + } else { + $row['guild_name'] = 'UNKNOWN_GUILD_'.$row['guild_id']; // Unknow name (normal in yubo shard) + } + } + } + + $uid = intval($cid / 16); + $db = new ServerDatabase(RYAPI_NELDB_HOST, RYAPI_NELDB_LOGIN, RYAPI_NELDB_PASS, RYAPI_NELDB_NEL); + $sql = "SELECT Privilege FROM user WHERE UId = $uid"; + $result = $db->query($sql) or die("Could not query."); + $priv_row = $db->fetch_row($result, MYSQL_NUM); + $priv = $priv_row[0]; + $db->free_result($result); + $groups = array(); + + if (strpos($priv, ':DEV:') !== false) { + $groups[] = 'DEV'; + $groups[] = 'SGM'; + $groups[] = 'GM'; + $groups[] = 'EM'; + $groups[] = 'EG'; + $groups[] = 'VG'; + $groups[] = 'G'; + } + + if (strpos($priv, ':SGM:') !== false) { + $groups[] = 'SGM'; + $groups[] = 'GM'; + $groups[] = 'VG'; + $groups[] = 'G'; + } + + if (strpos($priv, ':GM:') !== false) { + $groups[] = 'GM'; + $groups[] = 'VG'; + $groups[] = 'G'; + } + + if (strpos($priv, ':VG:') !== false) { + $groups[] = 'VG'; + $groups[] = 'G'; + } + + if (strpos($priv, ':G:') !== false) { + $groups[] = 'G'; + } + + if (strpos($priv, ':SEM:') !== false) { + $groups[] = 'SEM'; + $groups[] = 'EM'; + $groups[] = 'EG'; + } + + if (strpos($priv, ':EM:') !== false) { + $groups[] = 'EM'; + $groups[] = 'EG'; + } + + if (strpos($priv, ':EG:') !== false) { + $groups[] = 'EG'; + } + + $groups[] = 'PLAYER'; + $row['groups'] = $groups; + + return $row; +} + +?> diff --git a/code/web/api/server/utils.php b/code/web/api/server/utils.php new file mode 100644 index 000000000..49860d24e --- /dev/null +++ b/code/web/api/server/utils.php @@ -0,0 +1,49 @@ +. + */ + + +function ryzom_name_to_file($name) +{ + $r = ''; + for ($i=0; $i= chr(127)) + $r .= sprintf("%%%02x", ord($name[$i])); + else + $r .= $name[$i]; + } + return $r; +} + +// ------------------------------------- +// get user home directory +// ------------------------------------- +function ryzom_get_user_dir($user) +{ + global $_RYZOM_API_CONFIG; + + if ($user == "") + die("INTERNAL ERROR CODE 1"); + + $user = ryzom_name_to_file($user); + return $_RYZOM_API_CONFIG['cookie_path'].'/'.$_RYZOM_API_CONFIG['shardid'].'/'.substr(strtolower($user), 0, 2).'/'.strtolower($user).'/'; +} + +?> diff --git a/code/web/app/app_test/favicon.png b/code/web/app/app_test/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..623a566634f032975e9ecd1bdd7a01fb34995cb3 GIT binary patch literal 2596 zcmWlbdpy(K1IL$yP|2fAk9%UIJXpx3h_Pve%tH^cWp0UFrgF`t$)#yL6dqQ}grD2w zHjOfpRu)T3%ca&(nvs}Xf2TjrIj`4web4t?KA+F~oGdq2r(LoKWFZj9E)>$i1GJjI zi;NVgW8&j~f@bGsq)!Y4BB%JfY#Sa+UI%^eP!4vU-ptB7r^8hRB}5AS3Z|v=(iPrw zVO(zHdyD<9wprRreFb)>Y;BRbw;g4&RI)~Cw!tw$-qC~KZth^2B2AHoj`w^Jjq;6J zI7tcn@1)2qQxZ=&=h`X4j1a8kI4P+;n)uYch37m!>6iUaq=Al#L7P^a9L;4bzYcm=G2CmfDw`x@7|(zVAnkw$7B{Vpsl zEMy1-cz@1gr{w}yX*ZbCmoq1ReZjTyHta3SHl=y3($Z2=Upx&EmSsT!0T2#+2)>K? z7qW^YziZd0wG#;m3E>eDw6-><+L8G7R2?wo2v4~DcM*O=@Y;N0y<3lxXtL@8@lV-k zSsilHVAzMRw`+C-H_EAg;woH z=4a@j9EMO5G{fx*2y#0&W%;KK27{{f$j!~wWJL#Gx+I(!Pubeo^6~Y}Jv1S{HeGf_ zH#0LcQm0^`BSAd(iGI{hL7~6t#R^;z3(ekhv4qIC_&okq3?XM!!0u89e*T0D;}WVo zs@M6M8p-WO%CbAYPEJm?gqvCM!dhg~AmE5}6z@{?lh?M6uy6!IVW7#t)29%lC-V{m zfr=cskGJ>J)=LZD8-RL1k=(pIwz`_y#@YLBxBmrtFvS}uUD0UksMy$y`q>#ei5dzj zEcBs=e)+X2m6F%Gt(O+R)iz|?`X??RYDNsc#+F><);BdbryH^!azcm9iP)PWDLdN} zlsndJxqs^3ZPk>PmcF}?XJb}9OAjgW=lZxS9rdI47Mlip`}^w^I!7&i!^}-|=Uw9Y z(qngGFe++lhYAJ)pi*b77bN|YmiE~xXrdHphJPT)u(6eul`m6M)XMnsDyoP6YntJZ zAYbQxjX{=!1ba~??RrET>+BhuzKmFlm$QM5494qc z&$f~H3W&Y*`k1L#DpONacgxH7@APfIoSJxo{o%ubN{=j9_Dw#N*BaW!gFJ#1;juh3 zP(h`LSOv*#R#sMDqK^j!1D9Ni?V`F}nWu$xKM%kHIXfBCFYia3QU$@T5$$3FT zH+erC4ab$}=IiX0+(r$>L7$@_U~O}A+=S53tfnU8G)>68(eNMqyptXVg_3V+h9`TL zK=(_536ID7*ZI&O<>VQ&(#o-j=EsjS@IK$?=6*~*+wLBgdR?^kbDyz{gqfMy8$wyQ z*=ZJb1^4f3t)^FMJgKRfp}Q&} zw8@LpY|iY`WmS;uU!O8H-VoIKqg*9xC$`trY-)FFWk>g9Fq!rsarS1VcpNS*&?F1* zQ=w(UP6(vApwSBbjon*YkjK1BadB}k0!@H!z>Fhdg%NFs$M@OXgUQ}Fl^WLaQoy=1 zAc+3>u3H3j#-hI5HDEoVbN~# z?`p~b*F|@{5>KQUIn2z=$bg8QJ9mmpux2v}W0{BMt@B{nP$&}Ep-Tgt-;J=oD70?D zeXrWAaGr2~XJ;qaNjNVEr)?CXf-t6rex@IFS8}gaGqr%q5eRFL`K+>!!d!!;ov3_Yb8%HHU~-gj&7qSFsNYHn^` zSY)3}nSFli&y*x#3wQHTXvvT;?uI8|e*>5Kmwe)c9vOMtxiZ7?zt-;?P4zI@GS|#= zb-KAZcpu;@;63rzD$3?k$8>q;F)OP-Pe-XXcXzW7H#{*p0f+w-8FjD!=>A5J$i%|d zC+FuI749U9mm2`GIjdb~Op0|V><2K}N)K>h^gR|X#h0;9ZmoBRwS1s7_;)8;96$bR zJ_Ni>bQw$U{<%QnKiM2UZM4Da>FL246gt0eJu=$5aT71cRNxZ6##+X90vzuq@vU*; zu1yD*t=VJa<6Rql%KqzZp(T{0^@V;XaN{pT?yi!SmQI|1COs8QNm{-NB~Hh5d^}}R zjIORR(9iyHQ*l`>VnRs7u5^}KkvN8h&ZXHE>+`F#4I;+cT<2hKZ?A|#T62!u+Dz*D zHT5SUDakKJ)#;PSn;J?CW|uF4pN?u$*jtXhn^N&LN!XXfJZbRkgP;(u4)v!3(*6(b CVj7bG literal 0 HcmV?d00001 diff --git a/code/web/app/app_test/index.php b/code/web/app/app_test/index.php new file mode 100644 index 000000000..95573dfe2 --- /dev/null +++ b/code/web/app/app_test/index.php @@ -0,0 +1,34 @@ +enable = true; + +// Debug log +p($user); + +// Update user acces on Db +$db = ryDB::getInstance(APP_NAME); +$db->setDbDefs('test', array('id' => SQL_DEF_INT, 'num_access' => SQL_DEF_INT)); + +$num_access = $db->querySingleAssoc('test', array('id' => $user['id'])); +if ($num_access) + $db->update('test', array('num_access' => ++$num_access['num_access']), array('id' => $user['id'])); +else + $db->insert('test', array('num_access' => $num_access['num_access']=1, 'id' => $user['id'])); + +// Content +$c = _t('access', $num_access['num_access']).'
'; + +echo ryzom_app_render(APP_NAME, $c); + +?> diff --git a/code/web/app/app_test/lang.php b/code/web/app/app_test/lang.php new file mode 100644 index 000000000..0a877c548 --- /dev/null +++ b/code/web/app/app_test/lang.php @@ -0,0 +1,15 @@ + + array ( + 'en' => 'User access this page %s times', + 'fr' => 'L\'utilisateur a accede a cette page %s fois', + 'de' => '', + 'ru' => '', + ), +); +if(isset($ryzom_texts)) + $ryzom_texts = array_merge ($__texts, $ryzom_texts); +else + $ryzom_texts = $__texts; +?> \ No newline at end of file diff --git a/code/web/app/config.php.default b/code/web/app/config.php.default new file mode 100644 index 000000000..0ecb2c302 --- /dev/null +++ b/code/web/app/config.php.default @@ -0,0 +1,26 @@ +. + */ + +define('RYAPP_URL', 'http://'); +define('RYAPP_PATH', dirname(__FILE__).'/'); +define('RYAPI_PATH', dirname(__FILE__).'/../api/'); + +include_once(RYAPI_PATH.'ryzom_api.php'); + +?> diff --git a/code/web/app/index.php b/code/web/app/index.php new file mode 100644 index 000000000..ed90c42b2 --- /dev/null +++ b/code/web/app/index.php @@ -0,0 +1,35 @@ +'._t('welcome', $user['char_name']).''; +} else { + if (!RYZOM_IG) { + if ($user['message']) + $c .= '

'._t($user['message']).'

'; + $c .= ryzom_render_login_form(ryzom_get_param('name')); + } +} + +foreach ($apps as $app) { + $c .= ''._t($app).'
'; +} + +if($logged) $c .= '
'._t('logout').''; + +echo ryzom_app_render('Ryzom', $c); + +?> \ No newline at end of file diff --git a/code/web/app/lang.php b/code/web/app/lang.php new file mode 100644 index 000000000..4780fcd00 --- /dev/null +++ b/code/web/app/lang.php @@ -0,0 +1,371 @@ + + array ( + 'en' => 'Welcome %s', + 'fr' => 'Bienvenue %s', + 'de' => 'Willkommen %s', + 'ru' => 'Добро пожаловать %s', + ), + 'latest_news_rp' => + array ( + 'en' => 'Latest RP news', + 'fr' => 'Dernières nouvelles RP', + 'de' => 'Letzte RP-Nachrichten', + 'ru' => 'Ролевые новости', + ), + 'latest_news_off' => + array ( + 'en' => 'Latest Ryzom news', + 'fr' => 'Dernières nouvelles de Ryzom', + 'de' => 'Letzte Ryzom-Nachrichten', + 'ru' => 'Последние новости Ризома', + ), + 'avail_apps' => + array ( + 'en' => 'Available applications', + 'fr' => 'Applications disponibles', + 'de' => 'Verfügbare Anwendungen', + 'ru' => 'Доступные приложения', + ), + 'home' => + array ( + 'en' => 'Home', + 'fr' => 'Accueil', + 'de' => 'Home', + 'ru' => 'К началу', + ), + 'logout' => + array ( + 'en' => 'Log out', + 'fr' => 'se déconnecter', + 'de' => 'Ausloggen', + 'ru' => 'Выйти', + ), + 'by' => + array ( + 'en' => 'by', + 'fr' => 'par', + 'de' => 'von', + 'ru' => 'сообщение', + ), + 'date_format' => + array ( + 'en' => '%1$s %2$s %3$s', + 'fr' => '%3$s %1$s %2$s', + 'de' => '%3$s %1$s %2$s', + 'ru' => '%1$s %2$s %3$s', + ), + 'ago' => + array ( + 'en' => 'ago', + 'fr' => 'il y a', + 'de' => 'Vor', + 'ru' => 'назад', + ), + 'to_go' => + array ( + 'en' => 'to go', + 'fr' => 'dans', + 'de' => 'In', + 'ru' => 'осталось', + ), + 'posted' => + array ( + 'en' => 'Posted', + 'fr' => 'Posté', + 'de' => 'Geschrieben', + 'ru' => 'Отправлено', + ), + 'error_auth' => + array ( + 'en' => 'Please press the Refresh button to display the homepage.', + 'fr' => 'Cliquez sur le bouton Rafraichir pour afficher la page d\'accueil.', + 'de' => 'Um auf die Hauptseite zu gelangen drücke bitte auf Aktualisieren.', + 'ru' => 'Для отображения домашней страницы нажмите кнопку "Обновить"', + ), + 'submit' => + array ( + 'en' => 'Submit', + 'fr' => 'Envoyer', + 'de' => 'Absenden', + 'ru' => 'Отправить', + ), + 'enter_key' => + array ( + 'en' => 'Please enter the full character API Key that you can find on your profile page', + 'fr' => 'Entrez la clé d\'API complète de votre personnage que vous trouverez sur votre page de profil', + 'de' => 'Gib bitte den lompletten Charakter-API-Schlüssel ein, diesen findest du auf deiner Profilseite', + 'ru' => 'Пожалуйста, введите полный API Ключ, который вы можете получить по адресу your profile page', + ), + 'enter_shard' => + array ( + 'en' => 'Select the server of your character', + 'fr' => 'Sélectionnez le serveur où se trouve votre personnage', + 'de' => 'Wähle den Server deines Charakters aus', + 'ru' => 'Выбрать сервер', + ), + 'enter_char' => + array ( + 'en' => 'Enter your CHARACTER name (*not* your account name)', + 'fr' => 'Saisissez le nom de votre PERSONNAGE (pas votre nom de compte)', + 'de' => 'Gib den Namen deines CHARAKTERS ein (*nicht* deinen Account-Namen)', + 'ru' => 'Введите имя ПЕРСОНАЖА (*не* имя пользователя)', + ), + 'enter_password' => + array ( + 'en' => 'Enter the password of your ACCOUNT', + 'fr' => 'Saisissez le mot de passe de votre COMPTE', + 'de' => 'Gib das Passwort deines ACCOUNTS ein', + 'ru' => 'Введите пароль своей УЧЕТНОЙ ЗАПИСИ', + ), + 'bad_login_password' => + array ( + 'en' => 'Cannot login. Perhaps you entered a bad password or you didn\'t use your CHARACTER name.', + 'fr' => 'Connexion impossible. Peut-être avez vous saisi un mauvais mot de passe ou vous n\'avez pas utilisé le nom de votre PERSONNAGE.', + 'de' => 'Login fehlgeschlagen. Vielleicht hast du ein falsches Passwort eingegeben oder du hast nicht deinen CHARAKTER-Namen verwendet.', + 'ru' => 'Невозможно подключиться. Возможно, вы использовали неверный пароль или имя ПЕРСОНАЖА.', + ), + 'app_notes' => + array ( + 'en' => 'Notepad', + 'fr' => 'Bloc Note', + 'de' => 'Notizblock', + 'ru' => 'Блокнот', + ), + 'app_news' => + array ( + 'en' => 'News', + 'fr' => 'Nouvelles', + 'de' => 'News', + 'ru' => 'Новости', + ), + 'app_mail' => + array ( + 'en' => 'Mail', + 'fr' => 'Courrier', + 'de' => 'Mail', + 'ru' => 'Почта', + ), + 'app_patch' => + array ( + 'en' => 'Atysmas', + 'fr' => 'Noel', + 'de' => 'Weihnachten', + 'ru' => 'Christmas', + ), + 'app_wiki' => + array ( + 'en' => 'Atys Wiki', + 'fr' => 'Lore & Chroniques', + 'de' => 'Atys Wiki', + 'ru' => 'Wiki Атиса', + ), + 'app_bots' => + array ( + 'en' => 'Bots', + 'fr' => 'Bots', + 'de' => 'Bots', + 'ru' => 'Боты', + ), + 'app_test' => + array ( + 'en' => 'Test Application', + 'fr' => 'Application de test', + 'de' => '', + 'ru' => '', + ), + 'app_forum' => + array ( + 'en' => 'Forums', + 'fr' => 'Forums', + 'de' => 'Foren', + 'ru' => 'Форумы', + ), + 'app_translate' => + array ( + 'en' => 'Translate', + 'fr' => 'Traduction', + 'de' => 'Übersetzen', + 'ru' => 'Перевод', + ), + 'app_race' => + array ( + 'en' => 'Race', + 'fr' => 'Course', + 'de' => 'Rennen', + 'ru' => 'Гонка', + ), + 'app_poll' => + array ( + 'en' => 'Polls', + 'fr' => 'Sondages', + 'de' => 'Polls', + 'ru' => 'Голосование', + ), + 'app_zapping' => + array ( + 'en' => 'Atysmas', + 'fr' => 'Atysmas', + 'de' => 'Atysmas', + 'ru' => 'Атисмас', + ), + 'latest_blog' => + array ( + 'en' => 'Latest news from the dev blog', + 'fr' => 'Dernières nouvelles du blog des dév', + 'de' => 'Aktuelles aus dem Dev-Blog', + 'ru' => 'Последние новости Дневника разработчиков', + ), + 'app_profile' => + array ( + 'en' => 'Profile', + 'fr' => 'Profil', + 'de' => 'Profile', + 'ru' => 'Личные данные', + ), + 'next_events' => + array ( + 'en' => 'Next events', + 'fr' => 'Prochains événements', + 'de' => 'Nächste Events', + 'ru' => 'Ближайшие события', + ), + 'absolute_date_format' => + array ( + 'en' => '%2$s, %1$s %3$s', + 'fr' => '%2$s %1$s %3$s', + 'de' => '%2$s %1$s %3$s', + 'ru' => '%2$s, %1$s %3$s', + ), + 'app_craft' => + array ( + 'en' => 'Craft: Recipe-Book', + 'fr' => 'Craft : Livre de recettes', + 'de' => 'Craft: Recipe-Book', + 'ru' => 'Ремесло: чертежи', + ), + 'app_ryzhome' => + array ( + 'en' => 'RyzHome', + 'fr' => 'Mon appart', + 'de' => 'Meine Wohnung', + 'ru' => 'Мой Дом', + ), + 'app_event' => + array ( + 'en' => 'Event Pad', + 'fr' => 'Pad Event', + 'de' => 'Event-Pad', + 'ru' => 'События', + ), + 'app_calendar' => + array ( + 'en' => 'Calendar', + 'fr' => 'Calendrier', + 'de' => 'Kalender', + 'ru' => 'Календарь', + ), + 'app_contest' => + array ( + 'en' => 'Contest', + 'fr' => 'Concours', + 'de' => 'Contest', + 'ru' => 'конкурс', + ), + 'app_rpjobs_v2' => + array ( + 'en' => 'Occupations', + 'fr' => 'Métiers', + 'de' => 'Berufe', + 'ru' => 'Занятия', + ), + 'app_rewards' => + array ( + 'en' => 'Rewards', + 'fr' => 'Récompenses', + 'de' => 'Belohnungen', + 'ru' => 'Награды', + ), + 'admin_apps' => + array ( + 'en' => 'Ryzom Team Apps', + 'fr' => 'Applications Pour L\'équipe Ryzom', + 'de' => 'Ryzom Team Apps', + 'ru' => 'Ryzom Team Apps', + ), + 'dev_apps' => + array ( + 'en' => 'Devs Apps (don\'t use!)', + 'fr' => 'Applications Devs (Ne pas utiliser !)', + 'de' => 'Devs Apps (don\'t use!)', + 'ru' => 'Devs Apps (don\'t use!)', + ), + 'app_admin' => + array ( + 'en' => 'Administration', + 'fr' => 'Administration', + 'de' => '{app_admin}', + 'ru' => '{app_admin}', + ), + 'testing_apps' => + array ( + 'en' => 'Testing Apps (don\'t use without permission)', + 'fr' => 'Applications en test (N\'utilisez que si vous y êtes invité)', + 'de' => 'Testing Apps (don\'t use without permission)', + 'ru' => 'Testing Apps (don\'t use without permission)', + ), + 'app_arcc' => + array ( + 'en' => 'A.R.C.C.', + 'fr' => 'A.R.C.C.', + 'de' => 'A.R.C.C.', + 'ru' => 'A.R.C.C.', + ), + 'link_to_forum' => + array ( + 'en' => 'Show details in forum', + 'fr' => 'Voir détails sur le forum', + 'de' => 'Zeige Details im Forum', + 'ru' => '', + ), + 'aura_and_powers_reseted' => + array ( + 'en' => 'Your auras and powers have been reset. They can be reset again in 2 hours.', + 'fr' => 'Vos auras et pouvoirs ont été remis à zéro. Prochaine remise à zéro dans 2h.', + 'de' => 'Deine Auren und Kräfte wurden zurückgesetzt. Sie können erst in 2 Stunden erneut zurückgesetzt werden.', + 'ru' => '', + ), + 'pvp_reseted' => + array ( + 'en' => 'Your PvP timers have been reset. ', + 'fr' => 'Votre tag pvp à été remis à zéro.', + 'de' => 'Deine PvP-Timer wurden zurückgesetzt.', + 'ru' => '', + ), + 'temporary_fixes' => + array ( + 'en' => 'Temporary Fixes', + 'fr' => 'Correctifs temporaires', + 'de' => 'Temporäre Fixes', + 'ru' => '', + ), + 'aura_and_powers_wait' => + array ( + 'en' => 'Please wait %d min for next reset', + 'fr' => 'Merci d\'attendre %d minutes avant une nouvelle remise à zéro', + 'de' => 'Please wait %d min for next reset', + 'ru' => '', + ), + 'app_power_reset' => + array ( + 'en' => 'Reset of Aura and Powers', + 'fr' => 'Reset des Auras et Pouvoirs', + 'de' => 'Auren und Kräfte zurücksetzen', + 'ru' => '', + ), +); +if(isset($ryzom_texts)) + $ryzom_texts = array_merge ($__texts, $ryzom_texts); +else + $ryzom_texts = $__texts;