aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/install/install_update.php
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/install/install_update.php')
-rw-r--r--phpBB/install/install_update.php348
1 files changed, 164 insertions, 184 deletions
diff --git a/phpBB/install/install_update.php b/phpBB/install/install_update.php
index 2f3ee1c55a..a00280a925 100644
--- a/phpBB/install/install_update.php
+++ b/phpBB/install/install_update.php
@@ -1,16 +1,20 @@
<?php
/**
*
-* @package install
-* @version $Id$
-* @copyright (c) 2006 phpBB Group
-* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
*
-* @todo check for writable cache/store/files directory
*/
/**
+* @todo check for writable cache/store/files directory
*/
+
if (!defined('IN_INSTALL'))
{
// Someone has tried to access the file directly. This is not a good idea, so exit
@@ -20,16 +24,7 @@ if (!defined('IN_INSTALL'))
if (!empty($setmodules))
{
// If phpBB is not installed we do not include this module
- if (@file_exists($phpbb_root_path . 'config.' . $phpEx) && !@file_exists($phpbb_root_path . 'cache/install_lock'))
- {
- include_once($phpbb_root_path . 'config.' . $phpEx);
-
- if (!defined('PHPBB_INSTALLED'))
- {
- return;
- }
- }
- else
+ if (!phpbb_check_installation_exists($phpbb_root_path, $phpEx) || file_exists($phpbb_root_path . 'cache/install_lock'))
{
return;
}
@@ -40,14 +35,13 @@ if (!empty($setmodules))
'module_filename' => substr(basename(__FILE__), 0, -strlen($phpEx)-1),
'module_order' => 30,
'module_subs' => '',
- 'module_stages' => array('INTRO', 'VERSION_CHECK', 'UPDATE_DB', 'FILE_CHECK', 'UPDATE_FILES'),
+ 'module_stages' => array('INTRO', 'VERSION_CHECK', 'FILE_CHECK', 'UPDATE_FILES', 'UPDATE_DB'),
'module_reqs' => ''
);
}
/**
* Update Installation
-* @package install
*/
class install_update extends module
{
@@ -72,6 +66,25 @@ class install_update extends module
function main($mode, $sub)
{
global $template, $phpEx, $phpbb_root_path, $user, $db, $config, $cache, $auth, $language;
+ global $request, $phpbb_admin_path, $phpbb_adm_relative_path, $phpbb_container, $phpbb_config_php_file;
+
+ // We must enable super globals, otherwise creating a new instance of the request class,
+ // using the new container with a dbal connection will fail with the following PHP Notice:
+ // Object of class phpbb_request_deactivated_super_global could not be converted to int
+ $request->enable_super_globals();
+
+ // Create a normal container now
+ $phpbb_container_builder = new \phpbb\di\container_builder($phpbb_config_php_file, $phpbb_root_path, $phpEx);
+ $phpbb_container_builder->set_dump_container(false);
+ $phpbb_container_builder->set_use_extensions(false);
+ if (file_exists($phpbb_root_path . 'install/update/new/config'))
+ {
+ $phpbb_container_builder->set_config_path($phpbb_root_path . 'install/update/new/config');
+ }
+ $phpbb_container = $phpbb_container_builder->get_container();
+
+ // Writes into global $cache
+ $cache = $phpbb_container->get('cache');
$this->tpl_name = 'install_update';
$this->page_title = 'UPDATE_INSTALLATION';
@@ -80,8 +93,7 @@ class install_update extends module
$this->new_location = $phpbb_root_path . 'install/update/new/';
// Init DB
- require($phpbb_root_path . 'config.' . $phpEx);
- require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
+ extract($phpbb_config_php_file->get_all());
require($phpbb_root_path . 'includes/constants.' . $phpEx);
// Special options for conflicts/modified files
@@ -90,7 +102,9 @@ class install_update extends module
define('MERGE_NEW_FILE', 3);
define('MERGE_MOD_FILE', 4);
- $db = new $sql_db();
+ $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
+
+ $db = new $dbms();
// Connect to DB
$db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false);
@@ -98,17 +112,10 @@ class install_update extends module
// We do not need this any longer, unset for safety purposes
unset($dbpasswd);
- $config = array();
-
- $sql = 'SELECT config_name, config_value
- FROM ' . CONFIG_TABLE;
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $config[$row['config_name']] = $row['config_value'];
- }
- $db->sql_freeresult($result);
+ // We need to fill the config to let internal functions correctly work
+ $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
+ set_config(null, null, null, $config);
+ set_config_count(null, null, null, $config);
// Force template recompile
$config['load_tplcompile'] = 1;
@@ -123,7 +130,7 @@ class install_update extends module
$config['default_lang'] = $language;
$user->data['user_lang'] = $language;
- $user->setup(array('common', 'acp/common', 'acp/board', 'install', 'posting'));
+ $user->add_lang(array('common', 'acp/common', 'acp/board', 'install', 'posting'));
// Reset the default_lang
$config['default_lang'] = $config_default_lang;
@@ -136,10 +143,14 @@ class install_update extends module
}
// Set custom template again. ;)
- $template->set_custom_template('../adm/style', 'admin');
-
- // still, the acp template is never stored in the database
- $user->theme['template_storedb'] = false;
+ $paths = array($phpbb_root_path . 'install/update/new/adm/style', $phpbb_admin_path . 'style');
+ $paths = array_filter($paths, 'is_dir');
+ $template->set_custom_style(array(
+ array(
+ 'name' => 'adm',
+ 'ext_path' => 'adm/style/',
+ ),
+ ), $paths);
$template->assign_vars(array(
'S_USER_LANG' => $user->lang['USER_LANG'],
@@ -150,14 +161,23 @@ class install_update extends module
));
// Get current and latest version
- if (($latest_version = $cache->get('_version_info')) === false)
+ $version_helper = $phpbb_container->get('version_helper');
+ try
{
- $this->latest_version = $this->get_file('version_info');
- $cache->put('_version_info', $this->latest_version);
+ $this->latest_version = $version_helper->get_latest_on_current_branch(true);
}
- else
+ catch (\RuntimeException $e)
{
- $this->latest_version = $latest_version;
+ $this->latest_version = false;
+
+ $update_info = array();
+ include($phpbb_root_path . 'install/update/index.' . $phpEx);
+ $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info;
+
+ if ($info !== false)
+ {
+ $this->latest_version = (!empty($info['version']['to'])) ? trim($info['version']['to']) : false;
+ }
}
// For the current version we trick a bit. ;)
@@ -219,12 +239,6 @@ class install_update extends module
if ($this->test_update === false)
{
- // Got the updater template itself updated? If so, we are able to directly use it - but only if all three files are present
- if (in_array('adm/style/install_update.html', $this->update_info['files']))
- {
- $this->tpl_name = '../../install/update/new/adm/style/install_update';
- }
-
// What about the language file? Got it updated?
if (in_array('language/' . $language . '/install.' . $phpEx, $this->update_info['files']))
{
@@ -252,7 +266,7 @@ class install_update extends module
$this->include_file('includes/diff/renderer.' . $phpEx);
// Make sure we stay at the file check if checking the files again
- if (!empty($_POST['check_again']))
+ if ($request->variable('check_again', false, false, \phpbb\request\request_interface::POST))
{
$sub = $this->p_master->sub = 'file_check';
}
@@ -269,6 +283,7 @@ class install_update extends module
// Make sure the update list is destroyed.
$cache->destroy('_update_list');
+ $cache->destroy('_update_list_time');
$cache->destroy('_diff_files');
$cache->destroy('_expected_files');
break;
@@ -277,15 +292,14 @@ class install_update extends module
$this->page_title = 'STAGE_VERSION_CHECK';
$template->assign_vars(array(
- 'S_UP_TO_DATE' => $up_to_date,
'S_VERSION_CHECK' => true,
- 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
- 'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_db"),
+ 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
+ 'S_UP_TO_DATE' => $up_to_date,
'LATEST_VERSION' => $this->latest_version,
- 'CURRENT_VERSION' => $this->current_version)
- );
+ 'CURRENT_VERSION' => $this->current_version,
+ ));
// Print out version the update package updates to
if ($this->latest_version != $this->update_info['version']['to'])
@@ -306,30 +320,6 @@ class install_update extends module
break;
case 'update_db':
-
- // Make sure the database update is valid for the latest version
- $valid = false;
- $updates_to_version = '';
-
- if (file_exists($phpbb_root_path . 'install/database_update.' . $phpEx))
- {
- include_once($phpbb_root_path . 'install/database_update.' . $phpEx);
-
- if ($updates_to_version === $this->update_info['version']['to'])
- {
- $valid = true;
- }
- }
-
- // Should not happen at all
- if (!$valid)
- {
- trigger_error($user->lang['DATABASE_UPDATE_INFO_OLD'], E_USER_ERROR);
- }
-
- // Just a precaution
- $cache->purge();
-
// Redirect the user to the database update script with some explanations...
$template->assign_vars(array(
'S_DB_UPDATE' => true,
@@ -337,8 +327,14 @@ class install_update extends module
'U_DB_UPDATE' => append_sid($phpbb_root_path . 'install/database_update.' . $phpEx, 'type=1&amp;language=' . $user->data['user_lang']),
'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_db"),
'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
+ 'L_EVERYTHING_UP_TO_DATE' => $user->lang('EVERYTHING_UP_TO_DATE', append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login'), append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login&amp;redirect=' . $phpbb_adm_relative_path . 'index.php%3Fi=send_statistics%26mode=send_statistics')),
));
+ // Do not display incompatible package note after successful update
+ if ($config['version'] == $this->update_info['version']['to'])
+ {
+ $template->assign_var('S_ERROR', false);
+ }
break;
case 'file_check':
@@ -359,8 +355,8 @@ class install_update extends module
$action = request_var('action', '');
// We are directly within an update. To make sure our update list is correct we check its status.
- $update_list = (!empty($_POST['check_again'])) ? false : $cache->get('_update_list');
- $modified = ($update_list !== false) ? @filemtime($cache->cache_dir . 'data_update_list.' . $phpEx) : 0;
+ $update_list = ($request->variable('check_again', false, false, \phpbb\request\request_interface::POST)) ? false : $cache->get('_update_list');
+ $modified = ($update_list !== false) ? $cache->get('_update_list_time') : 0;
// Make sure the list is up-to-date
if ($update_list !== false)
@@ -389,6 +385,7 @@ class install_update extends module
{
$this->get_update_structure($update_list, $expected_files);
$cache->put('_update_list', $update_list);
+ $cache->put('_update_list_time', time());
// Refresh the page if we are still not finished...
if ($update_list['status'] != -1)
@@ -401,7 +398,7 @@ class install_update extends module
'S_COLLECTED' => (int) $update_list['status'],
'S_TO_COLLECT' => sizeof($this->update_info['files']),
'L_IN_PROGRESS' => $user->lang['COLLECTING_FILE_DIFFS'],
- 'L_IN_PROGRESS_EXPLAIN' => sprintf($user->lang['NUMBER_OF_FILES_COLLECTED'], (int) $update_list['status'], sizeof($this->update_info['files'])),
+ 'L_IN_PROGRESS_EXPLAIN' => sprintf($user->lang['NUMBER_OF_FILES_COLLECTED'], (int) $update_list['status'], sizeof($this->update_info['files']) + sizeof($this->update_info['deleted'])),
));
return;
@@ -427,7 +424,7 @@ class install_update extends module
// Now assign the list to the template
foreach ($update_list as $status => $filelist)
{
- if ($status == 'no_update' || !sizeof($filelist) || $status == 'status')
+ if ($status == 'no_update' || !sizeof($filelist) || $status == 'status' || $status == 'status_deleted')
{
continue;
}
@@ -494,7 +491,7 @@ class install_update extends module
$all_up_to_date = true;
foreach ($update_list as $status => $filelist)
{
- if ($status != 'up_to_date' && $status != 'custom' && $status != 'status' && sizeof($filelist))
+ if ($status != 'up_to_date' && $status != 'custom' && $status != 'status' && $status != 'status_deleted' && sizeof($filelist))
{
$all_up_to_date = false;
break;
@@ -505,65 +502,29 @@ class install_update extends module
'S_FILE_CHECK' => true,
'S_ALL_UP_TO_DATE' => $all_up_to_date,
'S_VERSION_UP_TO_DATE' => $up_to_date,
+ 'S_UP_TO_DATE' => $up_to_date,
'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
'U_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files"),
'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_db"),
));
- if ($all_up_to_date)
+ // Since some people try to update to RC releases, but phpBB.com tells them the last version is the version they currently run
+ // we are faced with the updater thinking the database schema is up-to-date; which it is, but should be updated none-the-less
+ // We now try to cope with this by triggering the update process
+ if (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->update_info['version']['to'])), '<'))
{
- // Add database update to log
- add_log('admin', 'LOG_UPDATE_PHPBB', $this->current_version, $this->update_to_version);
-
- // Refresh prosilver css data - this may cause some unhappy users, but
- $sql = 'SELECT *
- FROM ' . STYLES_THEME_TABLE . "
- WHERE LOWER(theme_name) = 'prosilver'";
- $result = $db->sql_query($sql);
- $theme = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if ($theme)
- {
- $recache = (empty($theme['theme_data'])) ? true : false;
- $update_time = time();
-
- // We test for stylesheet.css because it is faster and most likely the only file changed on common themes
- if (!$recache && $theme['theme_mtime'] < @filemtime("{$phpbb_root_path}styles/" . $theme['theme_path'] . '/theme/stylesheet.css'))
- {
- $recache = true;
- $update_time = @filemtime("{$phpbb_root_path}styles/" . $theme['theme_path'] . '/theme/stylesheet.css');
- }
- else if (!$recache)
- {
- $last_change = $theme['theme_mtime'];
- $dir = @opendir("{$phpbb_root_path}styles/{$theme['theme_path']}/theme");
-
- if ($dir)
- {
- while (($entry = readdir($dir)) !== false)
- {
- if (substr(strrchr($entry, '.'), 1) == 'css' && $last_change < @filemtime("{$phpbb_root_path}styles/{$theme['theme_path']}/theme/{$entry}"))
- {
- $recache = true;
- break;
- }
- }
- closedir($dir);
- }
- }
+ $template->assign_vars(array(
+ 'S_UP_TO_DATE' => false,
+ ));
+ }
- if ($recache)
- {
- // Instead of re-caching here, we simply remove theme_data... HAR HAR HAR (think about a carribean pirate)
- $sql = 'UPDATE ' . STYLES_THEME_TABLE . " SET theme_data = ''
- WHERE theme_id = " . $theme['theme_id'];
- $db->sql_query($sql);
+ if ($all_up_to_date)
+ {
+ global $phpbb_container;
+ $phpbb_log = $phpbb_container->get('log');
- $cache->destroy('sql', STYLES_THEME_TABLE);
- $cache->destroy('sql', STYLES_TABLE);
- }
- }
+ // Add database update to log
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_UPDATE_PHPBB', time(), array($this->current_version, $this->update_to_version));
$db->sql_return_on_error(true);
$db->sql_query('DELETE FROM ' . CONFIG_TABLE . " WHERE config_name = 'version_update_from'");
@@ -715,7 +676,7 @@ class install_update extends module
{
$cache->put('_diff_files', $file_list);
- if (!empty($_REQUEST['download']))
+ if ($request->variable('download', false))
{
$params[] = 'download=1';
}
@@ -830,7 +791,7 @@ class install_update extends module
$file_list['status'] = -1;
$cache->put('_diff_files', $file_list);
- if (!empty($_REQUEST['download']))
+ if ($request->variable('download', false))
{
$this->include_file('includes/functions_compress.' . $phpEx);
@@ -872,7 +833,7 @@ class install_update extends module
foreach ($update_list as $status => $files)
{
- if ($status == 'up_to_date' || $status == 'no_update' || $status == 'status')
+ if ($status == 'up_to_date' || $status == 'no_update' || $status == 'status' || $status == 'status_deleted')
{
continue;
}
@@ -923,7 +884,14 @@ class install_update extends module
$test_connection = false;
if ($test_ftp_connection || $submit)
{
- $transfer = new $method(request_var('host', ''), request_var('username', ''), request_var('password', ''), request_var('root_path', ''), request_var('port', ''), request_var('timeout', ''));
+ $transfer = new $method(
+ request_var('host', ''),
+ request_var('username', ''),
+ htmlspecialchars_decode($request->untrimmed_variable('password', '')),
+ request_var('root_path', ''),
+ request_var('port', ''),
+ request_var('timeout', '')
+ );
$test_connection = $transfer->open_session();
// Make sure that the directory is correct by checking for the existence of common.php
@@ -964,7 +932,7 @@ class install_update extends module
'DATA' => $data,
'NAME' => $user->lang[strtoupper($method . '_' . $data)],
'EXPLAIN' => $user->lang[strtoupper($method . '_' . $data) . '_EXPLAIN'],
- 'DEFAULT' => (!empty($_REQUEST[$data])) ? request_var($data, '') : $default
+ 'DEFAULT' => $request->variable($data, (string) $default),
));
}
@@ -1009,7 +977,14 @@ class install_update extends module
}
else
{
- $transfer = new $method(request_var('host', ''), request_var('username', ''), request_var('password', ''), request_var('root_path', ''), request_var('port', ''), request_var('timeout', ''));
+ $transfer = new $method(
+ request_var('host', ''),
+ request_var('username', ''),
+ htmlspecialchars_decode($request->untrimmed_variable('password', '')),
+ request_var('root_path', ''),
+ request_var('port', ''),
+ request_var('timeout', '')
+ );
$transfer->open_session();
}
@@ -1090,6 +1065,14 @@ class install_update extends module
$transfer->write_file($file_struct['filename'], $contents);
}
break;
+
+ case 'deleted':
+
+ if ($update_mode != 'download')
+ {
+ $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
+ }
+ break;
}
}
}
@@ -1124,16 +1107,10 @@ class install_update extends module
*/
function show_diff(&$update_list)
{
- global $phpbb_root_path, $template, $user;
+ global $phpbb_root_path, $template, $user, $phpbb_adm_relative_path;
$this->tpl_name = 'install_update_diff';
- // Got the diff template itself updated? If so, we are able to directly use it
- if (in_array('adm/style/install_update_diff.html', $this->update_info['files']))
- {
- $this->tpl_name = '../../install/update/new/adm/style/install_update_diff';
- }
-
$this->page_title = 'VIEWING_FILE_DIFF';
$status = request_var('status', '');
@@ -1254,6 +1231,16 @@ class install_update extends module
$this->page_title = 'VIEWING_FILE_CONTENTS';
break;
+
+ case 'deleted':
+
+ $diff = $this->return_diff(array(), $phpbb_root_path . $original_file);
+
+ $template->assign_var('S_DIFF_NEW_FILE', true);
+ $diff_mode = 'inline';
+ $this->page_title = 'VIEWING_FILE_CONTENTS';
+
+ break;
}
$diff_mode_options = '';
@@ -1299,7 +1286,9 @@ class install_update extends module
'new_conflict' => array(),
'conflict' => array(),
'no_update' => array(),
+ 'deleted' => array(),
'status' => 0,
+ 'status_deleted'=> 0,
);
}
@@ -1360,7 +1349,7 @@ class install_update extends module
}
}*/
- if (file_exists($phpbb_root_path . dirname($file)) || (strpos($file, 'styles/') !== 0 && strpos($file, 'language/') !== 0))
+ if (!phpbb_ignore_new_file_on_update($phpbb_root_path, $file))
{
$this->get_custom_info($update_list['new'], $file);
$update_list['new'][] = array('filename' => $file, 'custom' => false);
@@ -1378,7 +1367,31 @@ class install_update extends module
$update_list['status']++;
}
+ foreach ($this->update_info['deleted'] as $index => $file)
+ {
+ if (is_int($update_list['status_deleted']) && $index < $update_list['status_deleted'])
+ {
+ continue;
+ }
+
+ if ($num_bytes_processed >= 500 * 1024)
+ {
+ return;
+ }
+
+ if (file_exists($phpbb_root_path . $file))
+ {
+ $update_list['deleted'][] = array('filename' => $file, 'custom' => false, 'as_expected' => false);
+ $num_bytes_processed += filesize($phpbb_root_path . $file);
+ }
+
+ $update_list['status_deleted']++;
+ $update_list['status']++;
+ }
+
+ $update_list['status_deleted'] = -1;
$update_list['status'] = -1;
+
/* if (!sizeof($this->update_info['files']))
{
return $update_list;
@@ -1655,37 +1668,6 @@ class install_update extends module
switch ($mode)
{
- case 'version_info':
- global $phpbb_root_path, $phpEx;
-
- $info = get_remote_file('version.phpbb.com', '/phpbb',
- ((defined('PHPBB_QA')) ? '30x_qa.txt' : '30x.txt'), $errstr, $errno);
-
- if ($info !== false)
- {
- $info = explode("\n", $info);
- $info = trim($info[0]);
- }
-
- if ($this->test_update !== false)
- {
- $info = $this->test_update;
- }
-
- // If info is false the fsockopen function may not be working. Instead get the latest version from our update file (and pray it is up-to-date)
- if ($info === false)
- {
- $update_info = array();
- include($phpbb_root_path . 'install/update/index.' . $phpEx);
- $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info;
-
- if ($info !== false)
- {
- $info = (!empty($info['version']['to'])) ? trim($info['version']['to']) : false;
- }
- }
- break;
-
case 'update_info':
global $phpbb_root_path, $phpEx;
@@ -1707,9 +1689,9 @@ class install_update extends module
$info['custom'] = array();
/*
// Get custom installed styles...
- $sql = 'SELECT template_name, template_path
- FROM ' . STYLES_TEMPLATE_TABLE . "
- WHERE LOWER(template_name) NOT IN ('subsilver2', 'prosilver')";
+ $sql = 'SELECT style_name, style_path
+ FROM ' . STYLES_TABLE . "
+ WHERE LOWER(style_name) NOT IN ('subsilver2', 'prosilver')";
$result = $db->sql_query($sql);
$templates = array();
@@ -1728,7 +1710,7 @@ class install_update extends module
{
foreach ($templates as $row)
{
- $info['custom'][$filename][] = str_replace('/prosilver/', '/' . $row['template_path'] . '/', $filename);
+ $info['custom'][$filename][] = str_replace('/prosilver/', '/' . $row['style_path'] . '/', $filename);
}
}
}
@@ -1798,5 +1780,3 @@ class install_update extends module
return $diff;
}
}
-
-?> \ No newline at end of file