2014 dxdy logo

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

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




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


16/07/14
9214
Цюрих
Mihaylo, а кто говорил о наследовании?
george66 в сообщении #1478724 писал(а):
Достаточно ли этого?
Если всё синхронно - то достаточно. Иначе надо еще например добавить номер сигнала.

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 03:10 
Заслуженный участник


31/12/15
945
Mihaylo в сообщении #1479036 писал(а):
Точка не является наследником прямой.

Я не говорю о наследовании в смысле C++, тут слово "родитель" в смысле Qt (где можно любой объект назначить родителем любому другому). Смысл в том, что если родитель исчезает, все его дети тоже исчезают (вот так погибли белые ходоки).

-- 14.08.2020, 03:15 --

mihaild в сообщении #1479060 писал(а):
Mihaylo, а кто говорил о наследовании?
george66 в сообщении #1478724 писал(а):
Достаточно ли этого?
Если всё синхронно - то достаточно. Иначе надо еще например добавить номер сигнала.

Да, склоняюсь к тому, чтобы бросить затею и организовать всё через единый центр. Фигура, меняясь, шлёт сигнал центру, тот по списку всех фигур находит её потомков и шлёт им сигналы "меняйтесь", а потом один раз перерисовывает. Жалко, распределённая система была бы красивее.

-- 14.08.2020, 03:40 --

Но и тут сомнения. Допустим, у каждого объекта есть список его детей, дети туда добавляются по мере их создания. Более поздние дети могут зависеть от более ранних, поэтому менять их надо по очереди. А с внуками что делать? Там порядок создания уже совершенно произвольный, может кто угодно зависеть от кого угодно. Или для каждого объекта хранить список всех его потомков (детей, внуков и т.д.) в порядке их создания? Тогда что делать, если мы удаляем объект, как эти списки менять.

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 10:07 
Заслуженный участник


31/12/15
945
А вот такая идея. Допустим, для каждого объекта мы храним натуральное число и это число сигналов, которое будет послано, если объект изменится. Например, если у объекта A дети B и C, а у них общий ребёнок D, то при изменении A будет послано пять сигналов: один пошлёт A, один B, один C и два D (его толкнут два раза). Тогда рисовальная машинка, получив сигнал от A, должна подождать, пока придут все пять, а потом перерисовывать. Эти числа легко обновлять. Если мы создаём новый объект, он шлёт сигнал своим родителям "прибавьте единицу", они прибавляют и шлют такой же сигнал своим родителям. Например, при создании объекта D к числам объектов B и C прибавится по единице, а к числу объекта A двойка.

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 10:52 
Заслуженный участник
Аватара пользователя


16/07/14
9214
Цюрих
Если делать централизовано, то можно просто каждый раз обходить граф (вы случайно не по этому поводу «Рекурсия в C++» создали?).
Вообще это задача динамической топологической сортировки, для которой про совсем простые эффективные алгоритмы я не слышал, а не совсем простой описан например в статье.

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 12:46 
Заслуженный участник


20/08/14
11867
Россия, Москва
По моему на сигналах задача решается двумя сигналами invalidate и done и двумя глобальными счётчиками signals и objects (их модификация должна быть защищена разделением доступа) и локальным счётчиком my.local принятых сигналов в каждом объекте и глобальным указателем ObjectStart на изначальный изменённый объект (ему защита не обязательна) (он заменяет пустой цикл ожидания обнуления signals в ModifyObject() перед посылкой себе сигнала done для начала пересчёта).

Алгоритм действий каждого объекта:
код: [ скачать ] [ спрятать ]
Используется синтаксис C
//Начальные значения всех переменных нулевые (а ObjectStart=nul, впрочем для него несущественно).
void ModifyObject() {
        ObjectStart = My;//Ссылка на изначальный изменённый объект
        signals = 1;//Сигнал от фиктивного родителя
        SendSignal(My, INVALIDATE);//Оповещаем самого себя от фиктивного родителя о планируемом пересчёте
}

void ReceiveSignal(int s) {
        switch (s) {
        case INVALIDATE:
                if (My.local == 0) {
                        objects++;//Счётчик затронутых объектов
                        //При желании здесь можно добавлять данный объект в список затронутых для пересчёта
                }
                My.local++;//Подсчитываем количество сигналов от родителей
                signals += My.Nchild - 1;//Учитываем сигналы потомкам и "поглощаем" свой входной сигнал
                for (int i = 1; i <= My.Nchild; i++) SendSignal(i, INVALIDATE);
                if (signals == 0) {//Оповещение всей сети закончено
                        //В этот момомент в objects количество затронутых объектов, если для чего-то нужно
                        SendSignal(ObjectStart, DONE);//Посылаем изначальному объекту сигнал о начале пересчёта якобы от единственного родителя
                        ObjectStart = nul;//Просто для надёжности
                }
                break;
        case DONE:
                My.local--;//Учёт количества готовых родителей
                if (My.local == 0) {//Ожидание окончания пересчёта всех родителей
                        Solve();//Медленный пересчёт параметров данного объекта
                        for (int i = 1; i <= My.Nchild; i++) SendSignal(i, DONE);//Оповестим потомков
                        //Если надо, можно здесь сделать перерисовку данного объекта или добавление его в список затронутых объектов для будущей перерисовки
                        objects--;//Ещё один объект (мы) пересчитан
                        if (objects == 0) SendSignal(SYSTEM, GLOBAL_REPAINT);//Все затронутые объекты пересчитаны, можно перерисовывать
                }
                break;
        }
}

Получилось сложновато, но в условиях сложного графа связей и возможных "гонок" сигналов и пересчётов не уверен что можно упростить. Именно из-за "гонок" понадобилось чётко разделить фазы быстрого оповещения о планируемом пересчёте (увеличение objects) и самом реальном пересчёте (уменьшение objects). Иначе может получиться что objects обнулится при ещё не дошедших сигналах потомкам.

Ещё неоптимальность что сигналы done тоже рассылаются по всем возможным путям вместо того чтобы слать лишь по самому длинному. Но жалко заводить в сигналах счётчик длины пути и локально в объектах строить список родителей с наидлиннейшими путями. Считаем что обмен сигналами почти бесплатен по отношению к пересчёту всех затронутых объектов.

PS. Писалось без проверки для иллюстрации идеи, могут быть логические ошибки и/или опечатки. :-(

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 13:23 
Заслуженный участник
Аватара пользователя


16/07/14
9214
Цюрих
Сигналы шлются просто конкретному ребенку? Тогда можно гораздо проще.
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
TAtomic Processing = 0;
void Update(TObject object) {
    ++Processing;
    object.Update();
}
TObject::Update() {
    Recalc();
    for (auto& child : children) {
        ++Processing;
        child.Update();
    }
    if (--Processing == 0) {
        Redraw();
    }
}
 

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 13:55 
Заслуженный участник


20/08/14
11867
Россия, Москва
mihaild в сообщении #1479154 писал(а):
Сигналы шлются просто конкретному ребенку? Тогда можно гораздо проще.
Проще, но сильно медленнее: это вызовет множественный пересчёт объектов если они зависят более чем от одного родителя (по каждому сигналу от каждого родителя). И всех их потомков, даже если у тех ровно один родитель. И особенно если есть пути разной длины (в количестве объектов) между объектами. Именно это и хотелось исключить ТС изначально.
Разумеется подразумеваю что сигналы объектам могут обрабатываться асинхронно и в любом порядке, иначе хватит обычного обхода дерева/графа по слоям одинаковой глубины от исходного узла.

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 14:06 
Заслуженный участник
Аватара пользователя


16/07/14
9214
Цюрих
А я с первого раза неправильно логику прочитал. Да, с двумя проходами можно сделать пересчет только один раз.
(прада тут важно, что не могут придти две модификации подряд, до отрисовки)

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 14:33 
Заслуженный участник


06/07/11
5627
кран.набрать.грамота
В порядке "пятничного бреда".
Каждому объекту создаем поле isValid (true/false) и invalidParents (количество непересчитанных родителей).
Когда какой-то объект меняется, ставим ему и всем его потомкам isValid = false. При каждом изменении isValid всем прямым потомкам увеличиваем invalidParents на 1. Также в отдельный плоский список запихиваем ссылки на все инвалидные объекты. Потом пересчитываем корневой объект, ставим isValid = true, у прямых потомков invalidParents уменьшаем на 1. Потом в цикле:
- проходим по списку "инвалидов", все валидные объекты выкидываем
- невалидные с invalidParents = 0 пересчитываем, ставим isValid = true, у прямых потомков invalidParents уменьшаем на 1
- остальные пропускаем.
И так пока список не опустеет. Рано или поздно должен, как мне кажется...

george66 в сообщении #1479092 писал(а):
Да, склоняюсь к тому, чтобы бросить затею и организовать всё через единый центр. Фигура, меняясь, шлёт сигнал центру, тот по списку всех фигур находит её потомков и шлёт им сигналы "меняйтесь", а потом один раз перерисовывает. Жалко, распределённая система была бы красивее.
Красота - в глазах смотрящего. Мне кажется наоборот - централизованный пересчет красивее.

-- 14.08.2020, 12:36 --

Ах, да, я не обозначил явно: мой алгоритм выше написан для случая, когда сами объекты ничего никому не шлют. Измененный объект извещает "центральный объект", и дальше все решения принимает "центр".

-- 14.08.2020, 12:40 --

george66 в сообщении #1478736 писал(а):
Вообще, должна быть какая-то наука на эту тему.

Да, как говорил кто-то из великих, "нет ничего практичнее, чем хорошая теория". Но увы, пока ничего нет. Есть только best practices, коих кличут "петтерны проектирования" или "паттерны программирования" или просто "паттерны", и для вашего случая подойдет паттерн MVC и/или его аналоги. Но вы его уже почти изобрели самостоятельно.

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 14:46 
Аватара пользователя


11/12/16
14042
уездный город Н
Удалил. То, что было, при гонках может более одного раза пересчитаться и даже перерисоваться.

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 15:30 
Заслуженный участник


20/08/14
11867
Россия, Москва
mihaild в сообщении #1479159 писал(а):
(прада тут важно, что не могут придти две модификации подряд, до отрисовки)
Правы, мой вариант от такого валится. Можно доработать чтобы события вызывающие изменения объектов не обрабатывались (оставаясь в очереди событий) пока objects>0 (т.е. не завершена обработка предыдущего события).
Иначе делать список "корневых" объектов (можно в виде фиктивного узла с потомками на модифицируемые объекты), выставлять приоритет сигналам invalid перед done, и может что-то ещё придётся.
В общем доработать можно, даже кажется не слишком сложно, но надо аккуратно додумать. Плюс не очень понятны условия задачи: что может срабатывать параллельно, есть ли приоритеты, нужно ли отрисовывать хоть что-то хоть иногда если события модификации идут непрерывно (чаще завершения обработки предыдущих), и тому подобное.

rockclimber
Решение неплохое, но есть несколько "но": у меня хватает статически выделенной памяти при любом количестве объектов, Вам же потребуется динамический список (можно и без него, но тогда перебирать все объекты); у Вас нужен доступ к свойствам чужих объектов, у меня только к локальным и глобальным; у меня (и видимо ТС хотел) всё сделано на сигналах между объектами (и тройке статических глобальных переменных), у Вас же централизованно; как следствие у меня можно обработку объектов параллелить (с атомизацией доступа лишь к двум глобальным переменным), у Вас поток выполнения похоже принципиально должен быть один. Это все не недостатки, скорее особенности. Но ТС вроде хотел распределённой системы на сигналах ...

-- 14.08.2020, 15:40 --

rockclimber
Поправьте меня, но кажется при трёх объектах A,B,C и связях A-B, A-C, B-C объект C будет пересчитан дважды, ведь он получит invalidParents=1 от A, потом не получив invalidParents=2 от B он получит invalidParents=0 снова от A и будет пересчитан до пересчёта B (это наверное зависит от порядка добавления объектов в список и его обработки, т.е. от "гонок") и потом ещё раз всё тоже самое, но от объекта B.
Думаю Вам надо было тоже разделить фазы инвалидации всех возможных объектов (и подсчёта родителей каждого) и их пересчёта. Ровно как и я ...

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 16:09 
Аватара пользователя


11/12/16
14042
уездный город Н
Dmitriy40 в сообщении #1479175 писал(а):
у меня хватает статически выделенной памяти при любом количестве объектов, Вам же потребуется динамический список (можно и без него, но тогда перебирать все объекты);


Если так можно:
rockclimber в сообщении #1479163 писал(а):
Когда какой-то объект меняется, ставим ему и всем его потомкам isValid = false.

то это решает проблему гонок в моем варианте.

Тогда так:

1. У объектов есть флаг isValid, доступен на чтение потомкам.
2. У каждого объекта есть потомок. Если "обычных" потомков нет, то его потомок - специальный объект "сцена"
3. Объект может генерировать сигнал "я стал хорошим".

Объект работает так:

1. Если объект изменился, то
а) инвалидируется он и все его потомки.
б) проверяется валидность родителей первого уровня. Если есть невалидные, ждем дальше. Если нет невалидных - объект пересчитывается.

2. Если объект успешно пересчитался, то он выставлет флаг "валиден" и шлет сигнал (бродкаст) "я стал хорошим".

3. Если объект получает сигнал, то он проверяет валидность родителей первого уровня. Если есть невалидные, ждем дальше. Если нет невалидных - объект пересчитывается.

4. Сцена делает всё тоже самое, но вместо пересчета запускает отрисовку. Может не посылать сигналы и не иметь флага.

-- 14.08.2020, 16:56 --

Уточнение:
EUgeneUS в сообщении #1479180 писал(а):
Если объект получает сигнал,

не любой сигнал, конечно, а сигнал от какого-то родителя первого уровня.

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 17:06 
Заслуженный участник


20/08/14
11867
Россия, Москва
EUgeneUS
Тоже те же гонки: для объектов A,B,C,D и связей между ними A-B, B-C, C-D, A-D при инвалидации A инвалидируются и B с D, но вот дальше если A будет валидирован до инвалидации C и запустится проверка объектом D, то последний получит всех валидных родителей и станет пересчитаться, хотя C ещё не пересчитан. Т.е. проблема (как и у rockclimber) в том что куда-то далеко сигнал о валидации части родителей может дойти раньше сигнала о инвалидации другой части родителей и тогда объект будет пересчитан ошибочно.

-- 14.08.2020, 17:30 --

Проанализировав ещё несколько сценариев я уже уверен что без посылки двух отдельных волн (инвалидации и валидации) сделать на сигналах не получится. Причём вторая волна, валидации, должна посылаться почти всегда строго после полного затухания первой. Исключения возможны, но как определить их возможность в realtime (да ещё и на не обязательно статическом графе связей), а не априори, не вижу. Т.е. можно конечно, но фактически тогда будет происходить построение дерева взаимосвязей от начального узла до всех конечных. А это затратно, причём в каждом узле/объекте. Обмен сигналами почти наверняка менее требователен.

-- 14.08.2020, 17:37 --

Ещё момент, мой вариант можно оптимизировать, слав сигналы инвалидации только если My.local==0, т.е. при получении первого же сигнала инвалидации от любого родителя. Надо только правильно подсчитывать количество сигналов в сети если входной сигнал от родителя поглощается. Т.е. первый case в моём примере будет выглядеть так:
код: [ скачать ] [ спрятать ]
Используется синтаксис C
        case INVALIDATE:
                if (My.local == 0) {
                        objects++;//Счётчик затронутых объектов
                        //При желании здесь можно добавлять данный объект в список затронутых для пересчёта
                        signals += My.Nchild;//Учитываем сигналы потомкам
                        for (int i = 1; i <= My.Nchild; i++) SendSignal(i, INVALIDATE);
                }
                My.local++;//Подсчитываем количество сигналов от родителей
                signals--;//"Поглощаем" входной сигнал от родителя
                if (signals == 0) {//Оповещение всей сети закончено
                        //В этот момомент в objects количество затронутых объектов, если для чего-то нужно
                        SendSignal(ObjectStart, DONE);//Посылаем изначальному объекту сигнал о начале пересчёта якобы от единственного родителя
                        ObjectStart = nul;//Просто для надёжности
                }
                break;
 
Так не будет сигналов invalidate кроме как на фронте волны инвалидации.

PS. Везде уменьшение и последующую проверку на ноль можно объединить, я оставил раздельно для большей ясности (комментариев).

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 17:38 
Аватара пользователя


11/12/16
14042
уездный город Н
Dmitriy40
Да, действительно. Словами-то написано, что объект А пересчитывается после инвалидизации всех потомков, но механизма для этого нет

Можно предложить такой: ввести счетчик "активных инвалидизаций".
Когда все объекты валидны - счетчик ноль.
При инвалидизации объекта к счетчку добавлется:
а) Если валидный объект инвалидизуруется из-за изменения, то количество валидных потомков.
б) Если валидный объект инвалидизуруется из-за инвалидизации родителя. то количество валидных потомков минус один.
в) сцена в этом механизме не добавляется к количеству валидных потомков.

Пересчет объектов разрешается, если счетчик равен нулю.

 Профиль  
                  
 
 Re: Зависимые объекты и цепочка обновлений
Сообщение14.08.2020, 17:40 
Заслуженный участник


06/07/11
5627
кран.набрать.грамота
Dmitriy40
Возможно, я не совсем точно выразился, а может, просто вы не так поняли. Вот код на жабе, ибо я не умею в с++:
код: [ скачать ] [ спрятать ]
Используется синтаксис Java
// "Фигура":
import java.util.ArrayList;
import java.util.List;

public class Figure {
    private String name;
    private int invalidParents = 0;
    private boolean isValid = true;
    private List<Figure> children;

    Figure(String name) {
        this.name = name;
        children = new ArrayList<>();
    }

    public boolean isValid() {
        return isValid;
    }

    public int invalidParentsCount() {
        return invalidParents;
    }

    public void introduceYourselfPlease() {
        System.out.println("I am object " + name + ", is valid: " + isValid + ", invalid parents: " + invalidParents);
    }

    public void update(boolean fromParent) {
        isValid = false;
        for (int i = 0; i < children.size(); i++) {
            children.get(i).update(true);
        }
        if (fromParent) {
            invalidParents++;
        }
    }

    public void parentRecalculated() {
        invalidParents--;
    }

    public void recalculate() {
        System.out.println("Object " + name + " is updated");
        isValid = true;
        for (int i = 0; i < children.size(); i++) {
            children.get(i).parentRecalculated();
        }
    }

    public void addChild(Figure child) {
        children.add(child);
    }
}

// Управляющий класс:
import java.util.ArrayList;
import java.util.List;

public class Demo {
    static List<Figure> figures = new ArrayList<>();
    static List<Figure> invalidFigures = new ArrayList<>();

    public static void main (String[] args) {
        Figure a = new Figure("A");
        Figure b = new Figure("B");
        Figure c = new Figure("C");

        a.addChild(b);
        a.addChild(c);
        b.addChild(c);

        figures.add(a);
        figures.add(b);
        figures.add(c);
        printInfo();

        a.update(false);  // update by user
        checkObjects();
        System.out.println("User changed A");
        printInfo();

        recalculate();
        System.out.println("Objects recalculated");
        printInfo();

    }

    public static void recalculate() {
        while (invalidFigures.size() > 0) {
            for (int i = invalidFigures.size() - 1; i >= 0; i--) {
                Figure f = invalidFigures.get(i);
                if (f.invalidParentsCount() == 0) {
                    f.recalculate();
                    invalidFigures.remove(f);
                }
            }
        }
    }

    public static void checkObjects() {
        for (int i = 0; i < figures.size(); i++) {
            if (!figures.get(i).isValid()) {
                invalidFigures.add(figures.get(i));
            }
        }
    }

    public static void printInfo() {
        for (int i = 0; i < figures.size(); i++) {
            figures.get(i).introduceYourselfPlease();
        }
    }
}
 


Вот вывод:
Код:
I am object A, is valid: true, invalid parents: 0
I am object B, is valid: true, invalid parents: 0
I am object C, is valid: true, invalid parents: 0
User changed A
I am object A, is valid: false, invalid parents: 0
I am object B, is valid: false, invalid parents: 1
I am object C, is valid: false, invalid parents: 2
Object A is updated
Object B is updated
Object C is updated
Objects recalculated
I am object A, is valid: true, invalid parents: 0
I am object B, is valid: true, invalid parents: 0
I am object C, is valid: true, invalid parents: 0
Как видите, никаких дубликатов.
В принципе, у меня объекты сообщают своим потомкам о том, что они стали невалидны, но это с тем же успехом и точно так же можно делать и снаружи, разницы не будет вообще никакой (только список потомков объекта сделать публичным). А вот уже управление порядком пересчета - оно строго снаружи.

Теперь по пунктам:
Цитата:
у меня хватает статически выделенной памяти при любом количестве объектов, Вам же потребуется динамический список (можно и без него, но тогда перебирать все объекты);
Ничего не знаю по С++ и уж тем более про полный перебор списка, поэтому ничего не могу сказать.
Цитата:
у Вас нужен доступ к свойствам чужих объектов, у меня только к локальным и глобальным;
Непонятно, чего в этом плохого. Проблема издревле решается через геттеры и сеттеры, все так делают (и я так сделал) и ни один процесс(ор) пока от этого не умер.
Цитата:
у меня (и видимо ТС хотел) всё сделано на сигналах между объектами (и тройке статических глобальных переменных), у Вас же централизованно;
Я ж говорю - MVC! Рекомендации лучших собаководов специалистов по ООП.
Цитата:
как следствие у меня можно обработку объектов параллелить (с атомизацией доступа лишь к двум глобальным переменным), у Вас поток выполнения похоже принципиально должен быть один.
В общем случае и в теории - наверно да, а на практике у нас тут большая куча объектов с непойми какими зависимостями между ними, и все равно как-то надо управлять порядком пересчета, чтобы не было долгих ожиданий, когда параллельный процесс досчитает родителя. Если у вас в С++ с системой "на сигналах" можно сказать компилятору "посчитай всю эту кучу в 4 потока", и он посчитает без лишних ожиданий, то я снимаю шляпу, застываю в немом восхищении и досрочно потихоньку ползу в сторону дома престарелых. Хотя что-то мне подсказывает, что так и так придется писать свой менеджер обработки этой кучи, и большую часть времени потоки будут ждать друг друга.

-- 14.08.2020, 15:54 --

Dmitriy40 в сообщении #1479175 писал(а):
Думаю Вам надо было тоже разделить фазы инвалидации всех возможных объектов (и подсчёта родителей каждого) и их пересчёта. Ровно как и я ...
Я предлагал "однопоточную" идею, там нет никаких фаз. Пока инвалидация не закончится, пересчет не начнется.

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

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



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

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


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

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