Fixing the metadata table due the new database changes (single database) see #3910

skala
Julio Montoya 14 years ago
parent 0714f0c565
commit 15f73cd1e7
  1. 15
      main/inc/lib/add_course.lib.inc.php
  2. 2
      main/install/update-db-1.8.8-1.9.0.inc.php
  3. 36
      main/metadata/index.php
  4. 374
      main/metadata/md_funcs.php

@ -437,6 +437,8 @@ function update_Db_course($course_db_name = null) {
$TBL_THEMATIC_PLAN = $course_db_name . 'thematic_plan'; $TBL_THEMATIC_PLAN = $course_db_name . 'thematic_plan';
$TBL_THEMATIC_ADVANCE = $course_db_name . 'thematic_advance'; $TBL_THEMATIC_ADVANCE = $course_db_name . 'thematic_advance';
$TBL_METADATA = $course_db_name . 'metadata';
$add_to_all_tables = ' c_id INT NOT NULL, '; $add_to_all_tables = ' c_id INT NOT NULL, ';
/* Announcement tool */ /* Announcement tool */
@ -2002,6 +2004,19 @@ function update_Db_course($course_db_name = null) {
$sql = "ALTER TABLE `".$TBL_THEMATIC_ADVANCE."` ADD INDEX (thematic_id)"; $sql = "ALTER TABLE `".$TBL_THEMATIC_ADVANCE."` ADD INDEX (thematic_id)";
Database::query($sql); Database::query($sql);
$sql = "CREATE TABLE IF NOT EXISTS " . $TBL_METADATA . " ( " .
$add_to_all_tables.
"eid VARCHAR(250) NOT NULL," . // entry-id, e.g. doc.1
"mdxmltext TEXT default ''," . // MD-text, XML-formatted
"md5 CHART(32) default ''," . // hash-validator
"htmlcache1 TEXT default ''," . // cached HTML, part 1
"htmlcache2 TEXT default ''," . // cached HTML, part 2
"indexabletext TEXT default ''," . // indexable for search
"PRIMARY KEY (c_id, eid) )".$charset_clause;
Database::query($sql);
return 0; return 0;
} }

@ -338,6 +338,7 @@ if (defined('SYSTEM_INSTALLATION')) {
'lp_iv_objective', 'lp_iv_objective',
'lp_view', 'lp_view',
'notebook', 'notebook',
'metadata',
'online_connected', 'online_connected',
'online_link', 'online_link',
'permission_group', 'permission_group',
@ -385,7 +386,6 @@ if (defined('SYSTEM_INSTALLATION')) {
$course_id = $row_course['id']; $course_id = $row_course['id'];
$new_table = DB_COURSE_PREFIX.$table; $new_table = DB_COURSE_PREFIX.$table;
if (!$singleDbForm) { if (!$singleDbForm) {
// otherwise just use the main one // otherwise just use the main one
Database::select_db($row_course['db_name']); Database::select_db($row_course['db_name']);

@ -1,4 +1,6 @@
<?php <?php
/* For licensing terms, see /license.txt */
/** /**
* Chamilo metadata/index.php * Chamilo metadata/index.php
* 2005/05/19 * 2005/05/19
@ -14,11 +16,10 @@
* - dbg= debuginfo start number, e.g. 10000 * - dbg= debuginfo start number, e.g. 10000
* *
*/ */
// PRELIMS -------------------------------------------------------------------->
require_once '../inc/global.inc.php'; require_once '../inc/global.inc.php';
require("md_funcs.php"); require "md_funcs.php";
getpar('EID', 'Entry IDentifier'); // e.g. 'Document.12' or 'Scorm.xx' getpar('EID', 'Entry IDentifier'); // e.g. 'Document.12' or 'Scorm.xx'
if (!($dotpos = strpos(EID, '.'))) give_up('No . in ' . EID); if (!($dotpos = strpos(EID, '.'))) give_up('No . in ' . EID);
@ -40,27 +41,25 @@ if (DBG) $urlp .= '&dbg=' . urlencode(DBG);
// name of the language file that needs to be included // name of the language file that needs to be included
$language_file = LFN; $language_file = LFN;
require("../inc/global.inc.php"); require_once "../inc/global.inc.php";
$this_section=SECTION_COURSES;
$this_section = SECTION_COURSES;
$nameTools = get_lang('Tool'); $nameTools = get_lang('Tool');
($nameTools && get_lang('Sorry')) ($nameTools && get_lang('Sorry')) or give_up('Language file ' . LFN . " doesn't define 'Tool' and 'Sorry'");
or give_up('Language file ' . LFN . " doesn't define 'Tool' and 'Sorry'");
$_course = api_get_course_info(); isset($_course) or give_up(get_lang('Sorry')); $_course = api_get_course_info(); isset($_course) or give_up(get_lang('Sorry'));
require(api_get_path(LIBRARY_PATH) . 'xmd.lib.php'); require api_get_path(LIBRARY_PATH) . 'xmd.lib.php';
require(api_get_path(LIBRARY_PATH) . 'xht.lib.php'); require api_get_path(LIBRARY_PATH) . 'xht.lib.php';
$mdObj = new mdobject($_course, EID_ID); // see 'md_' . EID_TYPE . '.php' $mdObj = new mdobject($_course, EID_ID); // see 'md_' . EID_TYPE . '.php'
// Construct assoclist $langLangs from language table -------------------------> // Construct assoclist $langLangs from language table ------------------------->
$result = Database::query("SELECT isocode FROM " . $result = Database::query("SELECT isocode FROM " .Database :: get_main_table(TABLE_MAIN_LANGUAGE) ." WHERE available='1' ORDER BY isocode ASC");
Database :: get_main_table(TABLE_MAIN_LANGUAGE) .
" WHERE available='1' ORDER BY isocode ASC");
$sep = ":"; $langLangs = $sep . "xx" . $sep . "xx"; $sep = ":"; $langLangs = $sep . "xx" . $sep . "xx";
@ -99,27 +98,24 @@ $xhtDoc->xht_xmldoc = $xhtxmldoc;
if ($is_allowed_to_edit) $xhtDoc->xht_param['isallowedtoedit'] = 'TRUE'; if ($is_allowed_to_edit) $xhtDoc->xht_param['isallowedtoedit'] = 'TRUE';
if ($is_allowed_to_edit && isset($_POST['mda'])) // MD updates to Doc and DB // MD updates to Doc and DB
{ if ($is_allowed_to_edit && isset($_POST['mda'])) {
$mdt = $mdStore->mds_update_xml_and_mdt($mdObj, $xhtDoc->xht_xmldoc, $mdt = $mdStore->mds_update_xml_and_mdt($mdObj, $xhtDoc->xht_xmldoc,
get_magic_quotes_gpc() ? stripslashes($_POST['mda']) : $_POST['mda'], get_magic_quotes_gpc() ? stripslashes($_POST['mda']) : $_POST['mda'],
EID, $xhtDoc->xht_param['traceinfo'], $mdt_rec !== FALSE); EID, $xhtDoc->xht_param['traceinfo'], $mdt_rec !== FALSE);
if ($mdt_rec !== FALSE) if ($mdt_rec !== FALSE) {
{
if (strpos($xhtDoc->xht_param['traceinfo'], 'DELETE') !== FALSE) if (strpos($xhtDoc->xht_param['traceinfo'], 'DELETE') !== FALSE)
$xhtDoc->xht_param['dbrecord'] = ''; $xhtDoc->xht_param['dbrecord'] = '';
} } else if (strpos($xhtDoc->xht_param['traceinfo'], 'INSERT') !== FALSE)
else if (strpos($xhtDoc->xht_param['traceinfo'], 'INSERT') !== FALSE)
$xhtDoc->xht_param['dbrecord'] = 'TRUE'; $xhtDoc->xht_param['dbrecord'] = 'TRUE';
if (method_exists($mdObj, 'mdo_storeback')) if (method_exists($mdObj, 'mdo_storeback'))
$mdObj->mdo_storeback($xhtDoc->xht_xmldoc); $mdObj->mdo_storeback($xhtDoc->xht_xmldoc);
$mdt_rec = FALSE; // cached HTML obsolete, must re-apply templates $mdt_rec = FALSE; // cached HTML obsolete, must re-apply templates
} } elseif ($is_allowed_to_edit && $_POST['mdt']) {
elseif ($is_allowed_to_edit && $_POST['mdt']) // md_editxml.htt // md_editxml.htt
{
$mdStore->mds_put(EID, $mdStore->mds_put(EID,
get_magic_quotes_gpc() ? stripslashes($_POST['mdt']) : $_POST['mdt'], get_magic_quotes_gpc() ? stripslashes($_POST['mdt']) : $_POST['mdt'],
'mdxmltext', '?'); 'mdxmltext', '?');

@ -4,7 +4,8 @@
* 2006/12/15 * 2006/12/15
* Copyright (C) 2006 rene.haentjens@UGent.be - see note at end of text --> * Copyright (C) 2006 rene.haentjens@UGent.be - see note at end of text -->
* @package chamilo.metadata * @package chamilo.metadata
*/ */
/** /**
* Chamilo Metadata: common functions and mdstore class * Chamilo Metadata: common functions and mdstore class
* *
@ -25,25 +26,26 @@
* assign value to subpath (see also xmd_update_many) * assign value to subpath (see also xmd_update_many)
* *
*/ */
// FETCH GET/POST-DATA; GENERAL FUNCTIONS ------------------------------------->
// FETCH GET/POST-DATA; GENERAL FUNCTIONS
define('MDS_TABLE', Database::get_course_table(TABLE_METADATA));
if (isset($getpostvars) && is_array($getpostvars)) if (isset($getpostvars) && is_array($getpostvars))
foreach ($getpostvars as $gpvar) foreach ($getpostvars as $gpvar)
if (is_string($gpvar) && (isset($_POST[$gpvar]) || isset($_GET[$gpvar]))) if (is_string($gpvar) && (isset($_POST[$gpvar]) || isset($_GET[$gpvar]))) {
{
$val = isset($_POST[$gpvar]) ? $_POST[$gpvar] : $_GET[$gpvar]; $val = isset($_POST[$gpvar]) ? $_POST[$gpvar] : $_GET[$gpvar];
$GLOBALS[$gpvar] = get_magic_quotes_gpc() ? stripslashes($val) : $val; $GLOBALS[$gpvar] = get_magic_quotes_gpc() ? stripslashes($val) : $val;
} }
function fgc($filename) function fgc($filename) {
{
$fp = fopen($filename, 'rb'); $buffer = fread($fp, filesize($filename)); $fp = fopen($filename, 'rb'); $buffer = fread($fp, filesize($filename));
fclose($fp); return $buffer; // file_get_contents: PHP >= 4.3.0 fclose($fp); return $buffer; // file_get_contents: PHP >= 4.3.0
} }
function give_up($msg) function give_up($msg) {
{
global $charset; global $charset;
echo '<p align="center">MetaData:<br /><b>? ', echo '<p align="center">MetaData:<br /><b>? ',
htmlspecialchars($msg, ENT_QUOTES, $charset), '</b></p>'; exit; htmlspecialchars($msg, ENT_QUOTES, $charset), '</b></p>'; exit;
@ -62,19 +64,16 @@ function getpar($name, $description, $default = '')
} }
function get_course_path() function get_course_path() {
{
return api_get_path(SYS_COURSE_PATH); return api_get_path(SYS_COURSE_PATH);
} }
function get_course_web() function get_course_web() {
{
return api_get_path(WEB_COURSE_PATH); return api_get_path(WEB_COURSE_PATH);
} }
function define_htt($htt_file, $urlp, $course_path) function define_htt($htt_file, $urlp, $course_path) {
{
global $charset; global $charset;
($htt_file_contents = @fgc($htt_file)) ($htt_file_contents = @fgc($htt_file))
@ -102,8 +101,7 @@ function define_htt($htt_file, $urlp, $course_path)
} }
function make_uri() function make_uri() {
{
$regs = array(); // for use with ereg() $regs = array(); // for use with ereg()
$uri = strtr(ereg_replace( $uri = strtr(ereg_replace(
@ -200,10 +198,8 @@ $ieee_dcmap_v = array(
// maps Dublin Core elements to xmd paths for values (not yet complete) // maps Dublin Core elements to xmd paths for values (not yet complete)
// KEYWORD TREE ---------------------------------------------------------------> // KEYWORD TREE
function define_kwds($mdo) {
function define_kwds($mdo)
{
if (!($newtext = trim(@fgc(get_course_path() . $mdo->mdo_course['path'] . if (!($newtext = trim(@fgc(get_course_path() . $mdo->mdo_course['path'] .
'/document' . $mdo->mdo_path )))) '/document' . $mdo->mdo_path ))))
{ {
@ -247,216 +243,164 @@ EOD
} }
// METADATA STORE -------------------------------------------------------------> // METADATA STORE
/** /**
* mdstore class * mdstore class
* @package chamilo.metadata * @package chamilo.metadata
*/ */
class mdstore class mdstore {
{
var $mds_something;
var $mds_something;
function __construct($allow_create) {
function mds_get($eid, $column = 'mdxmltext', $must_exist = '') // none: FALSE global $_course;
{ $this->course_id = api_get_course_int_id();
if (($mdt = Database::fetch_array($this->_query("SELECT " . $column . if (!isset($_course)) return;
" FROM " . MDS_TABLE . " WHERE ", $eid)))) return $mdt[$column];
if ($must_exist) give_up($must_exist . $this->_coldat('eid', $eid));
return FALSE;
}
function mds_get_dc_elements($mdo) // no record: FALSE
{
if (!($mdt = $this->mds_get($mdo->mdo_eid))) return FALSE;
$xmlDoc = new xmddoc(explode("\n", $mdt)); if ($xmlDoc->error) return FALSE;
$result = array();
foreach ($mdo->mdo_dcmap_v as $dce => $xp)
{
$result[$dce] = $xmlDoc->xmd_value($xp);
} }
return $result; function mds_get($eid, $column = 'mdxmltext', $must_exist = '') {
} // none: FALSE
if (($mdt = Database::fetch_array(Database::query("SELECT " . $column ." FROM ".MDS_TABLE." WHERE eid = '$eid' AND c_id = {$this->course_id} "))))
function mds_get_many($columns, $where_clause) return $mdt[$column];
{ if ($must_exist) give_up($must_exist . $this->_coldat('eid', $eid));
$cols = '';
foreach (explode(',', $columns) as $col) $cols .= "," . trim($col); return FALSE;
if (!$cols) return;
return $this->_query("SELECT " . api_substr($cols, 1) .
" FROM " . MDS_TABLE . " WHERE ". $where_clause);
}
function mds_put($eid, $data, $column = 'mdxmltext', $exists = TRUE)
{
if ($exists === TRUE)
return $this->_query("UPDATE " . MDS_TABLE . " SET " .
$this->_coldat($column, $data) . " WHERE ", $eid);
elseif ($exists === FALSE)
return $this->_query("INSERT INTO " . MDS_TABLE . " SET " .
$this->_coldat($column, $data) . ", ", $eid);
else // user doesn't know, check first whether the record exists
return $this->mds_put($eid, $data, $column,
!($this->mds_get($eid) === FALSE));
}
function mds_put_dc_elements($mdo, $dcelem)
{
if (($mdt = $this->mds_get($mdo->mdo_eid)) === FALSE)
{
$mdt = $mdo->mdo_generate_default_xml_metadata(); $exists = FALSE;
} }
else $exists = TRUE;
function mds_get_dc_elements($mdo) // no record: FALSE
$xmlDoc = new xmddoc(explode("\n", $mdt)); if ($xmlDoc->error) return FALSE;
foreach ($dcelem as $dce => $value)
{ {
$xmlDoc->xmd_update($mdo->mdo_dcmap_v[$dce], (string) $value); if (!($mdt = $this->mds_get($mdo->mdo_eid))) return FALSE;
$xmlDoc = new xmddoc(explode("\n", $mdt)); if ($xmlDoc->error) return FALSE;
$result = array();
foreach ($mdo->mdo_dcmap_v as $dce => $xp) {
$result[$dce] = $xmlDoc->xmd_value($xp);
}
return $result;
} }
$this->mds_put($mdo->mdo_eid, '', 'md5', $exists); function mds_get_many($columns, $where_clause) {
$cols = '';
return $this->mds_put($mdo->mdo_eid, $xmlDoc->xmd_xml()); foreach (explode(',', $columns) as $col) $cols .= "," . trim($col);
} if (!$cols) return;
return $this->_query("SELECT " . api_substr($cols, 1) ." FROM " . MDS_TABLE . " WHERE c_id = {$this->course_id} AND ". $where_clause);
function mds_append($eid, $moredata, $column = 'indexabletext') }
{
if (($olddata = $this->mds_get($eid, $column)) === FALSE) return FALSE; function mds_put($eid, $data, $column = 'mdxmltext', $exists = TRUE) {
$this->mds_put($eid, $olddata . $moredata, $column); return $olddata; if ($exists === TRUE)
} return $this->_query("UPDATE " . MDS_TABLE . " SET " .$this->_coldat($column, $data) . " WHERE c_id = {$this->course_id} AND ", $eid);
elseif ($exists === FALSE)
function mds_delete($eid) return $this->_query("INSERT INTO " . MDS_TABLE . " SET c_id = {$this->course_id} , ".$this->_coldat($column, $data).", ", $eid);
{ else // user doesn't know, check first whether the record exists
return $this->_query("DELETE FROM " . MDS_TABLE . " WHERE ", $eid); return $this->mds_put($eid, $data, $column, !($this->mds_get($eid) === FALSE));
} }
function mds_delete_offspring($eid, $sep = '.') function mds_put_dc_elements($mdo, $dcelem) {
{ if (($mdt = $this->mds_get($mdo->mdo_eid)) === FALSE) {
return $this->_query("DELETE FROM " . MDS_TABLE . " WHERE ", $eid, $sep); $mdt = $mdo->mdo_generate_default_xml_metadata(); $exists = FALSE;
} } else
$exists = TRUE;
function mds_delete_many($idarray)
{ $xmlDoc = new xmddoc(explode("\n", $mdt)); if ($xmlDoc->error) return FALSE;
if (!is_array($idarray) || count($idarray) == 0) return FALSE; foreach ($dcelem as $dce => $value) {
$xmlDoc->xmd_update($mdo->mdo_dcmap_v[$dce], (string) $value);
return $this->_query("DELETE FROM " . MDS_TABLE . " WHERE eid IN ('" . }
implode("','", array_map('addslashes', $idarray)) . "')"); $this->mds_put($mdo->mdo_eid, '', 'md5', $exists);
} return $this->mds_put($mdo->mdo_eid, $xmlDoc->xmd_xml());
}
function mds_update_xml_and_mdt($mdo, &$xmlDoc, $mda, $eid, &$traceinfo,
$exists = TRUE) // note: $xmlDoc and $traceinfo passed by reference function mds_append($eid, $moredata, $column = 'indexabletext') {
{ if (($olddata = $this->mds_get($eid, $column)) === FALSE) return FALSE;
foreach (explode("\n", $this->mds_put($eid, $olddata . $moredata, $column); return $olddata;
str_replace("\r", "\n", str_replace("\r\n", "\n", $mda))) as $update) }
function mds_delete($eid) {
return $this->_query("DELETE FROM " . MDS_TABLE . " WHERE c_id = {$this->course_id} AND ", $eid);
}
function mds_delete_offspring($eid, $sep = '.') {
return $this->_query("DELETE FROM " . MDS_TABLE . " WHERE c_id = {$this->course_id} AND ", $eid, $sep);
}
function mds_delete_many($idarray) {
if (!is_array($idarray) || count($idarray) == 0) return FALSE;
return $this->_query("DELETE FROM " . MDS_TABLE . " WHERE c_id = {$this->course_id} AND eid IN ('" .
implode("','", array_map('addslashes', $idarray)) . "')");
}
function mds_update_xml_and_mdt($mdo, &$xmlDoc, $mda, $eid, &$traceinfo,
$exists = TRUE) // note: $xmlDoc and $traceinfo passed by reference
{ {
if (!$update) continue; foreach (explode("\n",
str_replace("\r", "\n", str_replace("\r\n", "\n", $mda))) as $update)
if (($nameLth = strpos($update, '='))) // e.g. 'gen/tit/str=new'
{ {
if (($text = api_substr($update, $nameLth + 1)) === FALSE) $text = ''; if (!$update) continue;
if (!($path = trim(api_substr($update, 0, $nameLth)))) continue; if (($nameLth = strpos($update, '='))) // e.g. 'gen/tit/str=new'
if (($sc = api_strpos($path, ';'))) // e.g. 'gen/tit,gen/des;str@lang'
$xmlDoc->xmd_update_many(api_substr($path, 0, $sc),
api_substr($path, $sc + 1), $text);
else
$xmlDoc->xmd_update($path, $text);
}
elseif ($nameLth === FALSE) // e.g. 'gen/tit/str[-1]~'
{
if ($update == '~~')
{ {
$update = 'DELETE ' . $eid; if (($text = api_substr($update, $nameLth + 1)) === FALSE) $text = '';
if ($exists === FALSE) $update = '';
else $this->mds_delete($eid); if (!($path = trim(api_substr($update, 0, $nameLth)))) continue;
$mda = ''; $exists = TRUE;
foreach ($xmlDoc->children[0] as $key => $child) if (($sc = api_strpos($path, ';'))) // e.g. 'gen/tit,gen/des;str@lang'
unset($xmlDoc->children[0][$key]); $xmlDoc->xmd_update_many(api_substr($path, 0, $sc),
api_substr($path, $sc + 1), $text);
else
$xmlDoc->xmd_update($path, $text);
} }
elseif ($update == '!!') elseif ($nameLth === FALSE) // e.g. 'gen/tit/str[-1]~'
{ {
define_kwds($mdo); if ($update == '~~')
$update = ''; $mda = ''; $exists = TRUE; {
} $update = 'DELETE ' . $eid;
else if ($exists === FALSE) $update = '';
{ else $this->mds_delete($eid);
$x = $xmlDoc->xmd_update(trim($update), ''); $mda = ''; $exists = TRUE;
} foreach ($xmlDoc->children[0] as $key => $child)
unset($xmlDoc->children[0][$key]);
}
elseif ($update == '!!')
{
define_kwds($mdo);
$update = ''; $mda = ''; $exists = TRUE;
}
else
{
$x = $xmlDoc->xmd_update(trim($update), '');
}
}
if ($update) $traceinfo .= $update . '- ';
} }
if ($update) $traceinfo .= $update . '- '; $mdt = $xmlDoc->xmd_xml();
if ($exists === FALSE)
{
$this->mds_put($eid, $mdt, 'mdxmltext', FALSE);
$traceinfo .= 'INSERT ' . $eid . '- ';
}
elseif($mda)
{
$this->mds_put($eid, $mdt, 'mdxmltext');
$traceinfo .= 'UPDATE ' . $eid . '- ';
}
return $mdt;
} }
$mdt = $xmlDoc->xmd_xml();
function _coldatstart($column, $data) {
if ($exists === FALSE) return $column . " LIKE '" . Database::escape_string($data) . "%'";
{
$this->mds_put($eid, $mdt, 'mdxmltext', FALSE);
$traceinfo .= 'INSERT ' . $eid . '- ';
} }
elseif($mda)
{ function _coldat($column, $data) {
$this->mds_put($eid, $mdt, 'mdxmltext'); return $column . "='" . Database::escape_string($data) . "'";
$traceinfo .= 'UPDATE ' . $eid . '- '; }
function _query($sql, $eid = '', $sep = '') {
if ($eid) $sql .= $sep ? $this->_coldatstart('eid', $eid . $sep) :
$this->_coldat('eid', $eid);
return Database::query($sql);
} }
return $mdt; }
}
function mdstore($allow_create)
{
global $_course; if (!isset($_course)) return;
define('MDS_TABLE', Database::get_course_table(TABLE_METADATA));
$this->_query("CREATE TABLE IF NOT EXISTS " . MDS_TABLE . " ( " .
"eid varchar(250) NOT NULL," . // entry-id, e.g. doc.1
"mdxmltext text default ''," . // MD-text, XML-formatted
"md5 char(32) default ''," . // hash-validator
"htmlcache1 text default ''," . // cached HTML, part 1
"htmlcache2 text default ''," . // cached HTML, part 2
"indexabletext text default ''," . // indexable for search
"PRIMARY KEY (eid) )");
}
function _coldatstart($column, $data)
{
return $column . " LIKE '" . addslashes($data) . "%'";
}
function _coldat($column, $data)
{
return $column . "='" . addslashes($data) . "'";
}
function _query($sql, $eid = '', $sep = '')
{
if ($eid) $sql .= $sep ? $this->_coldatstart('eid', $eid . $sep) :
$this->_coldat('eid', $eid);
return Database::query($sql);
}
}
/*
<!--
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
-->
*/
?>
Loading…
Cancel
Save