Модераторы: skyboy, MoLeX, Aliance, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> пишем класс для работы с файлами как с бд, дружненько ! 
:(
    Опции темы
Mark.dll
Дата 25.4.2003, 08:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 134
Регистрация: 28.2.2003
Где: Эстония, Нарва

Репутация: нет
Всего: нет



Может быть когда-нибудь научимся на C писать классы и функции для php smile.gif
--------------------
"I wish I could change the world..."
PM MAIL WWW ICQ   Вверх
Mark.dll
Дата 25.4.2003, 09:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 134
Регистрация: 28.2.2003
Где: Эстония, Нарва

Репутация: нет
Всего: нет



Кстати... я подумал, может это в winде так for плохо работает. Проверь на хосте, где unix система.
--------------------
"I wish I could change the world..."
PM MAIL WWW ICQ   Вверх
Sardar
Дата 25.4.2003, 12:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 4
Всего: 317



По моему я опять не в тему smile.gif smile.gif smile.gif ...

Чем отличается БД от простой записи данныx в файл? Тем что можно искать в ниx по условию.
Чем отличается реляционная БД от простой? Тем что можно связывать несколько таблиц по условию для получения смежного результата wink.gif .
Чего уже достигли? Можем выводить данные практически без условий, изменив одну букву в неком поле перепишем всю таблицу, если скрипт сдоxнет на пол пути, то потеряем все данные omg.gif .

Кажется это не совсем то что нужно...

На счет for я не согласен. For позволяет писать мощные циклы. Если он и тормозит, то на несколько сотыx долей секунды. На что действительно нужно обратить внимание это на работу с массивами.
Есть люди подгружающие многомегабайтные файлы через file() confused.gif confused.gif , а затем применяют array_reverse. PHP приседает в такиx случаяx...


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Sardar
Дата 25.4.2003, 12:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 4
Всего: 317



Есть идея придумать велосипед biggrin.gif.

Задача: xотим создать некую прогу, которая по функциональности поxодила бы на MySQL, т.е. задуманная специально для людей не желающиx платить 25$ за MySQL БД smile.gif .

Структуру БД можно сделать как в MySQL, с иммитировать ISAM таблицы конечно не удастся.

Пусть наша таблица будет иметь неограниченное число полей. Таблица может иметь не ограниченное число записей. Каждое поле имеет свой определенный тип.
Типы полей: BOOL(1 байт), INT(4 байта), STRINT, REAL(8 байт), STRREAL, CHAR, TEXT.

Все поля кроме ТЕXТ имеют определенную длинну, которую, после создания таблицы, нельзя более изменить.

Поле текст может быть двуx типов: простое и константа.

+Теперь можем изменять поля непросредственно в таблице, xоть в середине файла smile.gif .

Все поля текст выносим в отдельный файл. В самой же таблице xраним ссылку. Константное поле соxраняется не посредственно в таблице.

Для быстрого доступа создаем индексы.

И так таблица состоит из треx файлов (третий опционален): name.frm, name.phd, name.pad.

где в .frm xраним структуру таблицы, имена полей, индексы и.т.д.
.phd - сама таблица
.pad - добавочный файл где xраним изменяемые поля ТЕXТ

При работе с таблицей грузим только .frm. Файлы открываем как 'a+', для доступа к полям используем fseek().

Функции:
query_select($query) -Работает с таблицей не изменяя ее (SELECT)
query_change($guery) - Работает с командами UPDATE, REMOVE

Запрос содержит наш простой синтаксис. Я написал недавно парсер который разбирает 500 длинныx и сложныx выражений за 10 секунд. Это же время будет стоить 1000 выражений: SELECT colum,colum FROM table,table WHERE id1=id2. Здесь проблем нет.


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
IZ@TOP
Дата 25.4.2003, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Панда-бир!
****


Профиль
Группа: Участник
Сообщений: 4795
Регистрация: 3.2.2003
Где: Бамбуковый лес

Репутация: 44
Всего: 73



Цитата
Есть люди подгружающие многомегабайтные файлы через file()

И я один из них ... можно конечно читать посимвольно, и определять конец строки знаком \n,\r or \n\r, и тому подобным ... но я если честно так и не могу сооброзить, почему мы тут говорим о скорости ? Неужели так сложно все протестировать ? Ну все, я в выходные все таки допишу этот класс ... будет Вам и резервное копиравание ... и тому подобное !!!!


--------------------
Один из розовых плюшевых-всадников апокалипсиса... очень злой...

Семь кругов ада для новых элементов языка
Мои разрозненные мысли
PM MAIL WWW ICQ Skype GTalk   Вверх
Mark.dll
Дата 25.4.2003, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 134
Регистрация: 28.2.2003
Где: Эстония, Нарва

Репутация: нет
Всего: нет



Я бы на вашем месте не забивал себе голову созданием этого класса. В итоге выйдет, что его использование будет никуда не годиться. Юзайте mysql и спите спокойно ночью.
--------------------
"I wish I could change the world..."
PM MAIL WWW ICQ   Вверх
IZ@TOP
Дата 25.4.2003, 16:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Панда-бир!
****


Профиль
Группа: Участник
Сообщений: 4795
Регистрация: 3.2.2003
Где: Бамбуковый лес

Репутация: 44
Всего: 73



Цитата
Юзайте mysql и спите спокойно ночью.

Я уже не раз говорил, и говорю еще раз:
Не у всех бесплатных хостингов есть бесплатный маскуэль ( на моем хостинге надо просто напросто заплатить 5 зеленых чтоб получить доступ, и платить каждый месяц ...) ...


--------------------
Один из розовых плюшевых-всадников апокалипсиса... очень злой...

Семь кругов ада для новых элементов языка
Мои разрозненные мысли
PM MAIL WWW ICQ Skype GTalk   Вверх
arial
  Дата 25.4.2003, 17:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 772
Регистрация: 11.3.2003
Где: Архангельская обл .

Репутация: 6
Всего: 7



Всетаки продолжаю тему надежной, быстрой ФБД.
Мной написан абсолютно рабочий класс.

В чем смысл его работы:
1. Одно сообщение/новость - один файл (залог надежности)
2. Имя файла - его номер по порядку (без расширения)
3. Файл с индексами либо смещениями больше не нужен.
Код
class fdb {
var $db_dir; // Директория базы данных
var $exp;  // Разделитель
var $rev;  // Реверсировать ли базу (1/0) (новые записи вверху/внизу)
var $db;  // Вывод базы данных

function fatal_error(){
 if(empty($this->db_dir)){
  echo"<b>Неустранимая ошибка!</b><br>Не объявлено значение переменной \$db_dir.<br>";
  exit;
 }else{
  return(0);
 }
}
function fdb_read(){
 $this->fatal_error(); // Проверяем переменные
 if(empty($this->exp)) $this->exp="|"; // Если не задан разделитель, используем |
 $handle=opendir($this->db_dir); // Читаем список файлов в директории БД
 while(($tmp=readdir($handle))!==FALSE){
  $tmp=(int)$tmp; // Этой и следующей строкой отфильтровываем несоответствующие файлы
  if(!empty($tmp)) $file[]=$tmp;
 }
 closedir($handle);
 if(!empty($file)) sort($file); // Сортируем по возрастанию...
 if($this->rev==1&&!empty($file)) $file=array_reverse($file); // И если нужно переворачиваем БД
 $count=count($file); // Записываем содержимое в массив $db (Iz@top TM)
 $i=0;
 while($i<$count){
   $open_file=fopen($this->db_dir.$file[$i],"r");
   $tmp=fread($open_file,filesize($this->db_dir.$file[$i]));
   fclose($open_file);
   $etmp=explode($this->exp,$tmp);
   $ei=0;
   $count_etmp=count($etmp);
   while($ei<$count_etmp){
    $this->db[$i][$ei]=$etmp[$ei];
    $ei++;
   }  
  $i++;
 }
}

function fdb_rec($array){
 // $array - массив данных, подлежащих записи
 $this->fatal_error();
 if(empty($this->exp)) $this->exp="|";
 $handle=opendir($this->db_dir);
 while(($tmp=readdir($handle))!==FALSE){
  $tmp=(int)$tmp;
  if(!empty($tmp)) $file[]=$tmp;
 }
 closedir($handle);
 if(!empty($file)) sort($file);
 $file_name=$file[count($file)-1]; // Выщемляем последнее имя файла
 $file_name++; // Новое имя файла будет на единичку больше (что говорит что данные более новые)
 $i=0;
 $count=count($array); // Создаем строку из переданного в ф-ию массива данных
 $new_data=$file_name.$this->exp."\n"; // Не забывая записать имя файла в самое начало строки!
 while($i<$count){                     // (имя файла сможем передавать в форму для обработки)
  $new_data.=$array[$i].$this->exp."\n"; // Дописываем \n после каждого значения для
  $i++;                                  // удобства просмотра самого файла. Если не
 }                                          // хотите - не пишите
 $open_file=fopen($this->db_dir.$file_name,"w"); // Записываем новый файл с новыми данными
 flock($open_file,2);
 @fwrite($open_file,$new_data) or die("Невозможно записать в файл");
 flock($open_file,3);
 fclose($open_file);
}

function fdb_del($array){
 // $array - в данном случае массив имен файлов, подлежащих удалению,
 // полученный из формы (вот зачем надо было записывать имя файла в
 // в начало строки данных)
 $this->fatal_error();
 $i=0;
 $count=count($array);
 while($i<$count) { // Удаляем файлы
  if(file_exists($this->db_dir.$array[$i])) unlink($this->db_dir.$array[$i]);
  $i++;
 }
}

function fdb_edit($array){
 // редактирование - то же что добавление новой записи, только в уже существующий файл
 // описывать не буду
 $this->fatal_error();
 if(empty($this->exp)) $this->exp="|";
 $i=0;
 $count=count($array);
 while($i<$count){
  $new_data.=$array[$i].$this->exp."\n";
  $i++;
 }
 $open_file=fopen($this->db_dir.$array[0],"w");
 flock($open_file,2);
 @fwrite($open_file,$new_data) or die("Невозможно записать в файл");
 flock($open_file,3);
 fclose($open_file);
}
}


P.S.
Я абсолютно доволен работой этого класса! wink.gif


--------------------
Есть люди, в которых живет Бог. Есть люди, в которых живет дьявол. А есть люди, в которых живут только глисты. (Ф. Раневская)
PM ICQ   Вверх
Mark.dll
Дата 25.4.2003, 18:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 134
Регистрация: 28.2.2003
Где: Эстония, Нарва

Репутация: нет
Всего: нет



Цитата(Iz @ 25.4.2003, 16:00)
Я уже не раз говорил, и говорю еще раз:
Не у всех бесплатных хостингов есть бесплатный маскуэль ( на моем хостинге надо просто напросто заплатить 5 зеленых чтоб получить доступ, и платить каждый месяц ...) ...

Раскашелься тогда wink.gif Кстати в моей стране можно хост со всеми прибамбасами за 6$
--------------------
"I wish I could change the world..."
PM MAIL WWW ICQ   Вверх
Sardar
Дата 28.4.2003, 10:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 4
Всего: 317



Цитата
Я бы на вашем месте не забивал себе голову созданием этого класса. В итоге выйдет, что его использование будет никуда не годиться. Юзайте MySQL и спите спокойно ночью.

Согласен!


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Sardar
Дата 28.4.2003, 10:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 4
Всего: 317



Цитата
1. Одно сообщение/новость - один файл (залог надежности)

Серьезно засоряем каталог маленькими файлами
Цитата
2. Имя файла - его номер по порядку (без расширения)

Что бы открыть файл пхп требуется большое время. Я что то не уверен в космической скорости.

Попробую на выxодныx написать свою прогу которая будет максимально поxодить на MySQL.




--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
IZ@TOP
Дата 28.4.2003, 11:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Панда-бир!
****


Профиль
Группа: Участник
Сообщений: 4795
Регистрация: 3.2.2003
Где: Бамбуковый лес

Репутация: 44
Всего: 73



Вот я и обобщенный вариант сделал ...

Вобщем все конечно хорошо, только вот есть некоторое ограничение в использовании:
Файл бд не должен быть больше 5мб (примерно в среднем 100000 записей), при этом скорость обработки около секунды. (поиск по 5мегам я не пробовал ...) ... и осталось только доделать функцию update ...

Код

<?php
/*********************************************
** класс обработки и записи данных в файл . **
** Powered by FORUM VINGRAD RU 2003         **
** http://forum.vingrad.ru / форум          **
** программистов 2003 год.                  **
*********************************************/

class fdb {

var $db_dir; // папка в которой хранится файл дб
var $db_file; // файл который будет обрабатываться
var $reverse; // надо ли перевернуть массив или нет (по умолчанию массив переворачивается)
var $exp; // разделитель значений в файле бд (по умолчанию ]%[ )
var $db; //  массив в который запишутся данные из файла бд
var $data; // массив с данными которые надо занести в файл бд
var $_error; // массив в котором сохраняются ошибки
var $count_start; // начаоьное значение перебора массива строк из файла (определяет с какого индекса будут занесены данные в массив db)
var $count_end; // конечный индекс перебора массива строк (определяет по какой индекс будут занесены данные в массив db)
var $search_data; // занчение которое надо найти
var $search_result; // в этом массиве будут передаватся найденные значения, и дополнительные данные
var $search_db_index; // в какой строке разделителя искать значения

function fdb_load() { //  начало функции загрузки файла бд
 
 if(empty($this->db_dir)) { $this->_error[] = "empty string db dir"; }
 // проверка на пустое значение имени каталога
 if(empty($this->db_file)) { $this->_error[] = "empty string db file"; }
 // проверка на пустое имя файла бд
 else if(!@file_exists($this->db_dir.$this->db_file)) { $this->_error[] = "none exists dir or file db"; }
 // проверка существования файла бд
 if(empty($this->exp)) { $this->exp = "]%["; } // разделитель между данными по умолчанию
 
 $line = @file($this->db_dir.$this->db_file); // создается массив строк из фйла бд
 
 if(count($line) < 1) { // проверка на наличие записей в файле бд
  $this->_error[] = "none data in db";
 }  
 if(empty($this->_error)) { // проверка на существование ошибок
  // ---------------------------------------------------
  // <<<<<<<<<<<<<<<... loading db ... >>>>>>>>>>>>>>>>>
  // ---------------------------------------------------
  $li = 0;
  $c = count($line);
  if(empty($this->count_start) and empty($this->count_end)) { // обработка количества записей в массиве $db
   if($c > 100) { $c = 100; }
   $i = 0;
  } else {
   if($this->count_start > $c) {
    if($c > 100) {
     $i = $c - $this->count_end;
    } else {
     $i = 0;
    }
   } else {
    $i = $this->count_start;
   }
   if($this->count_end > $c) {
    $this->count_end = $c;
   } else {
    $c = $this->count_end;
   }
  }
  /**************************************************************
  ** далее следует разбор строк файла бд на сосиавляющие части **
  **************************************************************/
  while($i < $c) {
   $ltmp = explode($this->exp,$line[$i]);
   $lc = count($ltmp);
   if($li < $lc) {
    $this->db[$i][$li] = $ltmp[$li++];
   } else {
    $i++;
    $li = 0;
    unset($ltmp);
   }
  }
  if(empty($this->reverse)) { $this->db = array_reverse($this->db); } // по умолчанию реверсировать массив $db
  else if($this->reverse = 1) { $this->db = array_reverse($this->db); }
 
 } else { // вывод ошибок пользователю
 
  $c = count($this->_error);
  echo "<B style=\"color:#660000; font-size:8pt; font-family:Courier new;\">------ * count errors ".$c.":</B><br>";
  $i = 0;
  while($i < $c) {
   echo "<B style=\"color:#990000; font-size:8pt; font-family:Courier new;\">------ error: ".$this->_error[$i++]."  *</B><br>";
  }
  unset($this->_error);
 }
} //

function fdb_save() { // начало функции сохранения данных в файле бд

 if(empty($this->db_dir)) { $this->_error[] = "empty string db dir"; }
 // проверка на пустое значение имени каталога в котором храгнятся файл бд
 if(empty($this->db_file)) { $this->_error[] = "empty string db file"; }
 // проверка на пустое значение имени файла
 else if(!@file_exists($this->db_dir.$this->db_file) and is_dir($this->db_dir))
 { $fop = @fopen($this->db_dir.$this->db_file,"w"); @fclose($fop); chmod($this->db_dir.$this->db_file,0660); }
 // если файл бд не существует то он создается
 if(empty($this->exp)) { $this->exp = "]%["; } // по умолчанию разделитель между значениями в файле бд

 if(empty($this->_error)) { // проверка на наличие ошибок
  // ---------------------------------------------------
  // <<<<<<<<<<<<< ... saving in db ... >>>>>>>>>>>>>>>>
  // ---------------------------------------------------
  if(@copy($this->db_dir.$this->db_file,$this->db_dir."temp.fdb")) {
   $size = filesize($this->db_dir.$this->db_file);
   if($size < 5000000) { // если файл бд больше 5мб то запись в файл не производится
       $rfs = filesize($this->db_dir."temp.fdb");
       // далее производится запись в файл бд
          $i = 0;
          $save_data = "";
          $c = count($this->data);
          while($i < $c) {
           str_replace($this->exp,"!",$this->data[$i]);
        if($i == $c-1) {
            $save_data .= $this->data[$i++];
        } else {
         $save_data .= $this->data[$i++].$this->exp;
        }
         
          }
       
          $fop = @fopen($this->db_dir.$this->db_file,"a+");
          @flock($fop,LOCK_EX + LOCK_NB);
          @fputs($fop, $save_data."\n");
          @flock($fop, LOCK_UN + LOCK_NB);
          @fclose($fop);
       
       $ofs = filesize($this->db_dir.$this->db_file);
       if($rfs > $ofs) {
        unlink($this->db_dir.$this->db_file);
        copy($this->db_dir."temp.fdb",$this->db_dir.$this->db_file);
     unlink($this->db_dir."temp.fdb");
        chmod($this->db_dir.$this->db_file,0660);
       } else {
        unlink($this->db_dir."temp.fdb");
       }
   } else {
    echo "<B style=\"color:#660000; font-size:8pt; font-family:Courier new;\">------ warning: db size = 5mb ! please create new db file !</B><br>";
   
   }
   
  } else {
   echo "<B style=\"color:#660000; font-size:8pt; font-family:Courier new;\">------ error: none create restore copy db file !</B><br>";
  }
 
 } else {
 
  $c = count($this->_error);
  echo "<B style=\"color:#660000; font-size:8pt; font-family:Courier new;\">------ * count errors ".$c.":</B><br>";
  $i = 0;
  while($i < $c) {
   echo "<B style=\"color:#990000; font-size:8pt; font-family:Courier new;\">------ error: ".$this->_error[$i++]."  *</B><br>";
  }

 }
} //

function fdb_search() { // начало функции поиска в бд
 if(empty($this->search_db_index)) {
  $i = 0;
  $li = 0;
  $ir = 0;
  $c = count($this->db);
  while($i < $c) {
   $lc = count($this->db[$i]);
   if($li < $lc) {
       if(eregi($this->search_data,$this->db[$i][$li])) {
        $this->search_result[$ir]['data'] = $this->db[$i][$li];
     $this->search_result[$ir]['line'] = $i;
     $this->search_result[$ir]['line_row'] = $li;
     $this->search_result[$ir]['db'] = $this->db[$i];
     $ir++;
     $li = 0;
        $i++;
       } else {
        $li++;
       }
   } else {
    $i++;
    $li = 0;
   }
     }
 } else {
  $i = 0;
  $c = count($this->db);
  $ir = 0;
 
  while($i < $c) {
      if(eregi($search_data,$this->db[$i][$this->search_db_index])) {
       $this->search_result[$ir]['data'] = $this->db[$i][$this->search_db_index];
    $this->search_result[$ir]['line'] = $i;
    $this->search_result[$ir]['line_row'] = $this->search_db_index;
    $this->search_result[$ir]['db'] = $this->db[$i];
       $i++;
      } else {
       $i++;
      }
     }
 }
}
}

// end class
?>


Вот собственно smile.gif)))


--------------------
Один из розовых плюшевых-всадников апокалипсиса... очень злой...

Семь кругов ада для новых элементов языка
Мои разрозненные мысли
PM MAIL WWW ICQ Skype GTalk   Вверх
Страницы: (3) Все 1 2 [3] 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "PHP"
Aliance
IZ@TOP
skyboy
SamDark
MoLeX

Новичкам:

  • PHP редакторы собираются и обсуждаются здесь
  • Электронные книги по PHP, документацию можно найти здесь
  • Интерпретатор PHP, полную документацию можно скачать на PHP.NET

Важно:

  • Не брезгуйте пользоваться тегами [code=php]КОД[/code] для повышения читабельности текста/кода.
  • Перед созданием новой темы воспользуйтесь поиском и загляните в FAQ
  • Действия модераторов можно обсудить здесь

Внимание:

  • Темы "ищу скрипт", "подскажите скрипт" и т.п. будут переноситься в форум "Web-технологии"
  • Темы с именами: "Срочно", "помогите", "не знаю как делать" будут УДАЛЯТЬСЯ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0811 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.