2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3, 4, 5, 6, 7  След.
 
 
Сообщение13.12.2005, 11:52 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
Вопросик во всем: кто-нибудь знает, как оптимизировать алгоритм транспонирования так, что бы он жрал меньше памяти?

Лобовой путь - создать вторую матрицу, "поставленную на попа", туды все скопировать, переставив индексы местами, потом первую удалить.

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

 Профиль  
                  
 
 
Сообщение13.12.2005, 12:20 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
Sanyok писал(а):
На очевидных проще... :) И еще... Сдается мне: то, что для одного "очевидно" - может быть совсем не очевидно для другого. И дело не в том, что второй туупее первого - просто у них образ мышления разный.

последнее было не в упрек - просто я уверен, что программа, как приведена, не скомпилируется. Это скорее псевдокод, основанный на C++. И просьба была обращать внимание на концептуальные ляпы, а не на очевидные синтактические ошибки. Я, как обычно, высказался неясно.

 Профиль  
                  
 
 
Сообщение13.12.2005, 12:28 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
Sanyok писал(а):
Вопросик во всем: кто-нибудь знает, как оптимизировать алгоритм транспонирования так, что бы он жрал меньше памяти?

Либо у Вирта (Алгоритмы и структуры данных), а даже скорее - у Д. Гриса (Наука программирования) приведен алгоритм перестановки сегментов массива на месте (т.е. поменять местами a[1:k] и a[k+1:n]). Чем-то похоже, нет? Может, удастся адаптировать?

 Профиль  
                  
 
 
Сообщение13.12.2005, 13:09 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
Эти книжки есть в нашей электронной библиотеке? Попробую посмотреть, когда высплюсь... :)

 Профиль  
                  
 
 
Сообщение13.12.2005, 15:22 


13/09/05
153
Москва
Насколько я себе это представляю, транспонировать матрицу без создания промежуточной нельзя. Тут возможны два варианта - или создавать полную матрицу (что накладно при очень большой исходной матрице), или создавать матрицу битов (флажков), указывающих меняли ли мы этот элемент, и в цикле менять элемент на элемент, пока есть что менять (по матрице флажков).
Простой замены temp <-- (i, j); (i, j) <-- (j, i); (j, i) <-- temp для прямоугольной матрицы не получается.

 Профиль  
                  
 
 
Сообщение13.12.2005, 15:43 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
А по-моему, можно и для прямоугольной матрицы! Я кажись, только что сообразил, как это сделать... Еще надо немножко покумекать... Вот только как доказать, что этот алгоритм будет работать, я не знаю... Похоже, даже без матрицы флажков удастся обойтись...

 Профиль  
                  
 
 
Сообщение13.12.2005, 17:28 


13/09/05
153
Москва
Тут есть идея -
нам нужно поменять (1,2) <-> (2,1) в квадратной матрице - все просто меняем оба и все.
В прямоугольной все нет так просто.

есть матрица A
1 2 3 4
5 6 7 8
хотим получить A'
1 5
2 6
3 7
4 8

если матрицы хранятся линейно, то
A 1 2 3 4 5 6 7 8
A' 1 5 2 6 3 7 4 8
из этого получаются следующие перестановки
1 -> 1
2 -> 5
3 -> 2
4 -> 6
5 -> 3
6 -> 7
7 -> 4
8 -> 8

то есть крайние мы не трогаем, а остальные можно циклично заменить
начинаем с индекса 2 -
temp = A[2];
A[2] = A[5];
A[5] = A[3];
A[3] = A[2] - но с этого мы начинали и его сохранили в temp - A[3] = temp;
мы обработали только часть массива. То, что осталось можно отследить с помощью массива флажков (битов), показывающего меняли ли мы уже этот элемент.
если так, то матрица флажков M
1 2 3 4 5 6 7 8
1 1 1 0 1 0 0 1

после первого прохода первым непройденным будет индекс 4. Начинаем с него
temp = A[4];
A[4] = A[6];
A[6] = A[7];
A[7] = A[4] - но опять - 4 уже обработали, т.е. M[4] = 1 и тогда A[7] = temp;
после этого мы обработали всю матрицу - в M нет нулей - и значит преобразование закочено.

Если храним double или float или что-нить еще, то получается значительная экономия памяти в ущерб производительности.
Код:
void Transpose(double*& matr, int nRow, int nCol)
{
   int nTotalSize = nRow*nCol;
   BYTE* M = new BYTE [nTotalSize];
   memset(M, 0, sizeof(BYTE)*nTotalSize);
   M[0] = 1;
   M[nTotalSize - 1] = 1;
   for (int i = 1; i < nTotalSize - 1; i++)
   {
      int nStartIndex = i;
      if (!M[nStartIndex])
      {
         double temp = matr[nStartIndex];
         int nLastIndex = nStartIndex;
         int nNextIndex = nStartIndex;
         while (!M[nNextIndex])
         {
            M[nNextIndex] = 1;
            nLastIndex = nNextIndex;
            int nNextRow = nLastIndex % nRow;
            int nNextCol = nLastIndex / nRow;
            nNextIndex = nNextRow*nCol + nNextCol;
            matr[nLastIndex] = matr[nNextIndex];
         }
         matr[nLastIndex] = temp;
      }
   }
}



В функции транспозиции можно сделать проверку - если если выгоды от такой ерунды, что выше написана нету, то есть проще создать новый массив, то просто создаем новый, переписываем содержимое с учетом транспозиции, убиваем старый массив, возвращаем указатель на новый.

 Профиль  
                  
 
 
Сообщение13.12.2005, 17:54 
Заслуженный участник


28/10/05
1368
Не буду цитировать.
Он не преподаватель, а программист :lol:.
Может он хочет, чтобы я так их функционально подробила, чтобы ему экранно читать было удобно. Я прощаю, пусть даже нечестно.
Совершенно верно сказали по поводу динамического состояния разработки программы. Было сказано: "Если будет больше двух функций, стирать код до тех пор, пока не выйдет! Попозже всё станет ясно." И ещё злоупотреблять printf.
По поводу "камо грядеши". Какие провокации! Отлично знаю, куда иду.
Да поймите Вы меня, сказано - "С"услики. Точка.

У меня такой вопрос: какие еще корявые случаи могут быть, кроме тех, что я сказала? (Имею ввиду рассеянного пользователя.) Хоть на данном этапе мне это и не надо.

 Профиль  
                  
 
 
Сообщение13.12.2005, 18:52 
Заслуженный участник


28/10/05
1368
Идиотизм.

Хочу написать, что я буду делать и поняла, - это почти безнадежно. Может связано с тем, что читала книгу на англ. и теперь не шарю, как переводятся термины. Или программисты и так всё поймут.

 Профиль  
                  
 
 
Сообщение13.12.2005, 18:53 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
"шизофрения, как и было сказано"

LynxGAV писал(а):
Было сказано: "... Попозже всё станет ясно." И ещё злоупотреблять printf.

Как и было сказано, пытается учить неуклюже. А совет злоупотреблять printf() - это сужденье из времен очаковских и покоренья Крыма. Лучше бы про GDB поучил...

LynxGAV писал(а):
По поводу "камо грядеши". Какие провокации! Отлично знаю, куда иду.
Да поймите Вы меня, сказано - "С"услики. Точка.

Куда идете Вы, я понимаю. Но, Вы, простите, на Domine не тянете. Вопрос - куда Вас ведут? и чего от Вас хотят? - относился к преподователю. Его я понять не могу. А впрочем - "Кто может, делает. Кто не может - учит."

Сурьезно - попробуйте узнать про C++. И попробуйте пользоваться GDB. И, если получиться с GDB - не злоупотребляйте printf. У незлоупотребления есть несколько весских причин, если интересно, поделюсь.

 Профиль  
                  
 
 
Сообщение13.12.2005, 18:57 
Заслуженный участник


28/10/05
1368
Поделитесь только не занудствуйте.

И еще скажите, если я напишу "аллокировать" меня поймут? Или надо как-то "размещать, распределять, назначать"?

... до трёх лет с ребёнком надо обращаться особенно, его обламывать нельзя... ха-ха-ха

PS Меня не учат. Мне не читают лекций. Мне даже советов не дают, а если дают, то по Вашим же словам - дЫбильные.

 Профиль  
                  
 
 
Сообщение13.12.2005, 19:25 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
LynxGAV писал(а):
И еще скажите, если я напишу "аллокировать" меня поймут? Или надо как-то "размещать, распределять, назначать"?

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

 Профиль  
                  
 
 
Сообщение13.12.2005, 22:19 
Заслуженный участник


28/10/05
1368
Нужна библиотека функций для управления матрицами. Определяю новый тип, чтобы представить структуру. Необходимо сохранять значения матрицы в двухразмерной таблице. Кроме значений матрицы, можно хранить в той же переменной ее размерности (число строк и столбцов матрицы). Таким образом удастся уменьшить число аргументов в функциях, которые будут оперировать матрицами. (Пример, функция умножения двух матриц получает только два аргумента, а не шесть.)
Функция NewMatrix, которая исходя из размерностей матрицы аллокирует достаточно места в памяти для сохранения матрицы. Функция возвращает указатель для новой матрицы.
Функция FillMatrix, которая получает матрицу и численное значение и возвращает ту же самую матрицу, заполненную значением.
Функция ShowMatrix, которая показывает содержание матрицы на экране.
Функция SaveMatrix получает два аргумента: указатель для уже открытого файла (вида FILE *) и указатель для матрицы. Функция должна сохранять в файле размерности и данные матрицы. Можно использовать формат одно значение в строку или все значения в той же строки, не важно.
Функция ReadMatrix, которая получает как аргумент указатель для уже открытого файла и читает содержимое матрицы. В первую очередь она должна считывать размерности матрицы, потом аллокировать новую матрицу с этими размерностями, используя NewMatrix, после чего считывает данные файла, заполняя новую матрицу, в конце возвращается новая матрица.

Наборы матриц при матричных вычислениях. Пользователю легче называть матрицу по имени, чем числом. Создать новый тип "Var", который соответствует переменной, представленной структурой из указателя для матрицы, значение переменной; стринг, которая представляет имя переменной. Все переменные содержать в списке. Следовательно, надо добавить поле к структуре, которое указывает на сл. элемент. Указатель типа "pointer for Var".

Определить функцию, которая создает переменную:

Var * NewVar (char * name, Matrix * m)

Определить функцию, которая добавляет переменную к списку переменных.

Var * AddVar (Var * list, Var * v)

Написать функцию, которая ищет переменную в списке. Функция должна получать список и имя переменной, пробегать по списку, пока не наткнется на переменную и, se está tudo bem, возвращает ее, если в списке нет переменной с таким именем, возвращает NULL.

Var * SearchVar (Var * list, char * name)

Млин, устала уже..
Только сейчас догадалась открыть Lingvo, но тоже многовато вариантов перевода компьютерных терминов.

Хотела бы услышать комментарии по поводу выше написанного. Что можно сделать проще, что подправить.

Такой вопрос: какие еще корявые случаи могут быть, кроме тех, что я сказала? (Имею ввиду рассеянного пользователя.)
Хоть на данном этапе мне это и не надо...

 Профиль  
                  
 
 
Сообщение14.12.2005, 09:10 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
Прочитал... Вроде усе логично, и очень даже ничего... Только некоторые из этих функций я бы сделал статическими...
А именно - NewVar(), AddVar() и SearchVar(). Тип я бы обозвал не var, а как-нибудь по-другому. По сути дела переменная такого типа - это узел дерева. Вот и назвать его надо примерно в таком ключе... Что-то типа TMatrNode... Функции NewVar() и AddVar() я бы, скорей всего, объединил в одну - все равно одна без другой использоваться не будет... Но энто в зависимости от сложности. Если одна ф-ция будет слишком сложной, возможно придется-таки ее на 2 расколоть..

 Профиль  
                  
 
 
Сообщение19.12.2005, 20:03 
Заслуженный участник


28/10/05
1368
[b]matprog.c[/b] комп. [b]GCC[/b]
код: [ скачать ] [ спрятать ]
Используется синтаксис C
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>


typedef struct marix_type
{
        char*   Name;
        int             Rows;
        int             Cols;
        float*  Values;
} MATRIX;

typedef struct matrix_list_type
{
        int                     Num_matrixes;
        MATRIX**        Matrixes;
} MATRIX_LIST;



MATRIX* new_matrix(MATRIX_LIST* matrix_list, char* name, int rows, int cols)
{
        MATRIX* matrix;

        matrix = (MATRIX*)malloc(sizeof(MATRIX));


        matrix->Name = (char*)malloc(strlen(name) + 1);
        strcpy(matrix->Name, name);

        matrix->Rows = rows;
        matrix->Cols = cols;

        matrix->Values = (float*)malloc(rows * cols * sizeof(float));


        if (matrix_list->Num_matrixes == 0)
                matrix_list->Matrixes = (MATRIX**)malloc(sizeof(MATRIX*));
        else
                matrix_list->Matrixes =
                        (MATRIX**)realloc(matrix_list->Matrixes, (matrix_list->Num_matrixes + 1) * sizeof(MATRIX*));

        matrix_list->Matrixes[matrix_list->Num_matrixes] = matrix;

        matrix_list->Num_matrixes++;

        return matrix;
}


int is_epmty(MATRIX_LIST* matrix_list)
{
        if (matrix_list->Num_matrixes == 0)
        {
                puts("List of matrixes is empty!");
                return 1;
        }
        return 0;
}


void show_matrix_list(MATRIX_LIST* matrix_list)
{
        int i;

        for(i=0; i<matrix_list->Num_matrixes; i++)
                printf("%s(%dx%d) ", matrix_list->Matrixes[i]->Name,
                        matrix_list->Matrixes[i]->Rows, matrix_list->Matrixes[i]->Cols);
}


MATRIX* search_matrix(MATRIX_LIST* matrix_list, char* name)
{
        int i;

        for(i=0; i<matrix_list->Num_matrixes; i++)
                if (!strcmp(matrix_list->Matrixes[i]->Name, name))
                        return matrix_list->Matrixes[i];

        return NULL;
}


void show_matrix(MATRIX_LIST* matrix_list)
{
        char name[10];
        MATRIX* matrix;
        int i, j;

        printf("indicate the name of variable:\n> ");
        gets(name);

        matrix = search_matrix(matrix_list, name);
        if (!matrix)
        {
                puts("Variable not found!");
                return;
        }

        printf("%s:\n", matrix->Name);
        printf("%d x %d\n", matrix->Rows, matrix->Cols);

        for(i=0; i<matrix->Rows; i++)
        {
                for(j=0; j<matrix->Cols; j++)
                        printf("   %.4f", matrix->Values[i * matrix->Cols + j]);
                putchar('\n');
        }
}


void add_new_matrix(MATRIX_LIST* matrix_list)
{
        char name[10], dimensions[10];
        int rows, cols;
        char* ptr;
        MATRIX* matrix;
        int i, j;

        printf("What are the dimensions of the matrix?\n(number of lines and columns separated by a space)\n> ");
        gets(dimensions);
        ptr = strchr(dimensions, ' ');
        if (!ptr)
        {
                puts("Wrong dimensions!");
                return;
        }
        ptr++;
        rows = atoi(dimensions);
        cols = atoi(ptr);
        if ((rows < 1) || (cols < 1))
        {
                puts("Wrong dimensions!");
                return;
        }

        printf("indicate the name of variable:\n> ");
        gets(name);
        if (search_matrix(matrix_list, name))
        {
                puts("This name is already in used!");
                return;
        }

        matrix = new_matrix(matrix_list, name, rows, cols);

        srand(time(NULL));

        for(i=0; i<rows; i++)
                for(j=0; j<cols; j++)
                        matrix->Values[i * cols + j] = (float)rand() / RAND_MAX;
}


void delete_matrix(MATRIX_LIST* matrix_list)
{
        char name[10];
        MATRIX* matrix;
        MATRIX** matrix_list_temp;
        int i, j;

        printf("indicate the name of variable:\n> ");
        gets(name);

        matrix = search_matrix(matrix_list, name);
        if (!matrix)
        {
                puts("Variable not found!");
                return;
        }

        printf("remove var: %s(%dx%d)\n", matrix->Name, matrix->Rows, matrix->Cols);

        free(matrix->Values);
        free(matrix->Name);

        if (matrix_list->Num_matrixes == 1)
                matrix_list_temp = NULL;
        else
        {
                matrix_list_temp = (MATRIX**)malloc((matrix_list->Num_matrixes - 1) * sizeof(MATRIX*));

                j = 0;
                for(i=0; i<matrix_list->Num_matrixes; i++)
                {
                        if (matrix_list->Matrixes[i] == matrix)
                                continue;
                        matrix_list_temp[j] = matrix_list->Matrixes[i];
                        j++;
                }
        }
        free(matrix);
        free(matrix_list->Matrixes);
        matrix_list->Matrixes = matrix_list_temp;
        matrix_list->Num_matrixes--;
}


void transponse_matrix(MATRIX_LIST* matrix_list)
{
        char name[10];
        MATRIX *matrix, *trans_matrix;
        int i, j;

        printf("indicate the name of variable:\n> ");
        gets(name);

        matrix = search_matrix(matrix_list, name);
        if (!matrix)
        {
                puts("Variable not found!");
                return;
        }


        printf("indicate the name of variable for the result:\n> ");
        gets(name);
        if (search_matrix(matrix_list, name))
        {
                puts("This name is already in use!");
                return;
        }

        trans_matrix = new_matrix(matrix_list, name, matrix->Cols, matrix->Rows);

        for(i=0; i<trans_matrix->Rows; i++)
                for(j=0; j<trans_matrix->Cols; j++)
                        trans_matrix->Values[i * trans_matrix->Cols + j] = matrix->Values[i + trans_matrix->Rows * j];
}


void sum_matrixes(MATRIX_LIST* matrix_list)
{
        char name[10];
        MATRIX *matrix1, *matrix2, *res_matrix;
        int i, j;

        printf("indicate the name of variable: (1st operated):\n> ");
        gets(name);

        matrix1 = search_matrix(matrix_list, name);
        if (!matrix1)
        {
                puts("Variable not found!");
                return;
        }

        printf("indicate the name of variable: (2nd operated):\n> ");
        gets(name);

        matrix2 = search_matrix(matrix_list, name);
        if (!matrix2)
        {
                puts("Variable not found!");
                return;
        }

        if ((matrix1->Rows != matrix2->Rows) || (matrix1->Cols != matrix2->Cols))
        {
                puts("Matrixes have different dimensions!");
                return;
        }


        printf("indicate the name of variable for the result:\n> ");
        gets(name);
        if (search_matrix(matrix_list, name))
        {
                puts("This name is already in use!");
                return;
        }

        res_matrix = new_matrix(matrix_list, name, matrix1->Rows, matrix1->Cols);

        for(i=0; i<res_matrix->Rows; i++)
                for(j=0; j<res_matrix->Cols; j++)
                        res_matrix->Values[i * res_matrix->Cols + j] =
                                matrix1->Values[i * res_matrix->Cols + j] + matrix2->Values[i * res_matrix->Cols + j];
}



void read_from_file(char filename[20], MATRIX_LIST* matrix_list)
{
        FILE* f;
        MATRIX* matrix;
        char line[1024];
        int i, j, rows, cols;
        char *ptr, *ptr1;

        f = fopen(filename, "r");
        if (!f)
                return;

        while (!feof(f))
        {
                fgets(line, 1024, f);

                ptr = strchr(line, ';');
                if (!ptr)
                        continue;
                *ptr = 0;
                ptr1 = ptr + 1;

                ptr = strchr(ptr1, ';');
                if (!ptr)
                        continue;
                rows = atoi(ptr1);
                ptr1 = ptr + 1;

                ptr = strchr(ptr1, ';');
                if (!ptr)
                        continue;
                cols = atoi(ptr1);
                ptr1 = ptr + 1;

                matrix = new_matrix(matrix_list, line, rows, cols);

                for(i=0; i<rows; i++)
                        for(j=0; j<cols; j++)
                        {
                                ptr = strchr(ptr1, ';');
                                if (!ptr)
                                        continue;
                                matrix->Values[i * cols + j] = atof(ptr1);
                                ptr1 = ptr + 1;
                        }
        }
        fclose(f);
}


void write_to_file(char filename[20], MATRIX_LIST* matrix_list)
{
        FILE* f;
        int k, i, j;

       

        f = fopen(filename, "w");

        for(k=0; k<matrix_list->Num_matrixes; k++)
        {
                fprintf(f, "%s;%d;%d;", matrix_list->Matrixes[k]->Name,
                        matrix_list->Matrixes[k]->Rows, matrix_list->Matrixes[k]->Cols);

                for(i=0; i<matrix_list->Matrixes[k]->Rows; i++)
                        for(j=0; j<matrix_list->Matrixes[k]->Cols; j++)
                                fprintf(f, "%.4f;", matrix_list->Matrixes[k]->Values[i * matrix_list->Matrixes[k]->Cols + j]);

                fprintf(f, "\n");
        }
        fclose(f);

}


void free_matrix_list(MATRIX_LIST* matrix_list)
{
        int i;

        if (matrix_list->Num_matrixes == 0)
          return;

        for(i=0; i<matrix_list->Num_matrixes; i++)
        {
                free(matrix_list->Matrixes[i]->Values);
                free(matrix_list->Matrixes[i]->Name);

                free(matrix_list->Matrixes[i]);
        }
        free(matrix_list->Matrixes);
}


int main()
{
        MATRIX_LIST matrix_list;
        char filename[] = "matrizes.dat";
        int choice;
        char str[5];

        puts("$ matprog");
        matrix_list.Num_matrixes = 0;

        read_from_file(filename, &matrix_list);
        if (matrix_list.Num_matrixes)
                show_matrix_list(&matrix_list);

        for (;;)
        {
                puts("\nShow matixes..................1");
                puts("Show matrix...................2");
                puts("Remove matrix.................3");
                puts("New arbitrary matrix..........4");
                puts("Transponse....................5");
                puts("Sum...........................6");
                puts("Exit..........................x");
                putchar('>');
                gets(str);

                if ((str[0] == 'x') || (str[0] == 'X'))
                        break;

                choice = atoi(str);

                switch (choice)
                {
                        case 1:
                                if (!is_epmty(&matrix_list))
                                        show_matrix_list(&matrix_list);
                                break;
                        case 2:
                                if (!is_epmty(&matrix_list))
                                        show_matrix(&matrix_list);
                                break;
                        case 3:
                                if (!is_epmty(&matrix_list))
                                        delete_matrix(&matrix_list);
                                break;
                        case 4:
                                add_new_matrix(&matrix_list);
                                break;
                        case 5:
                                if (!is_epmty(&matrix_list))
                                        transponse_matrix(&matrix_list);
                                break;
                        case 6:
                                if (!is_epmty(&matrix_list))
                                        sum_matrixes(&matrix_list);
                                break;
                        default:
                                puts("Wrong choice!");
                }
        }
        write_to_file(filename, &matrix_list);
       
        free_matrix_list(&matrix_list);
        return 0;
}
 



11 лет.
- "А., ты [i]сделала[/i] уроки?"
- "Па, я [i]делала[/i].."

[b]Очень нужны отзывы и критические замечания. Всё правильно? Что не правильно? Какие будут предложения? Поправьте меня. Грустное "мур-мяу" :(. [/b]

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 105 ]  На страницу Пред.  1, 2, 3, 4, 5, 6, 7  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group