Форум программистов, компьютерный форум, киберфорум
ООП и паттерны
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.77/22: Рейтинг темы: голосов - 22, средняя оценка - 4.77
Заблокирован
1

Зачем нужен паттерн визитор?

09.03.2017, 16:09. Показов 4114. Ответов 50
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Выражение типа
Код
foo.bar(baz)
мы можем трактовать как то, что bar посещает foo. Зачем поверх этого еще что-то лепить?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
09.03.2017, 16:09
Ответы с готовыми решениями:

Нужен ли паттерн состояние?
прочитал вот тут: http://cpp-reference.ru/patterns/behavioral-patterns/state/ Ну, а если язык...

Зачем нужен стек?
На первый взгляд такая структура кажется немного неудобной. Объясните преимущества, пожалуйста.

Паттерн "Стратегия". Зачем нужен контекст
Здравствуйте, у меня вопрос про паттерн "Стратегия". Я понимаю что он используется для...

Паттерн Утка или стратегия зачем вообще паттерны?
Начал ознакамливаться с ООП паттернами программирования, все, конечно, красиво, но разрастается все...

50
Заблокирован
14.03.2017, 00:32  [ТС] 21
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от Shamil1 Посмотреть сообщение
Я же Вам показываю аналог в общепринятом смысле этого слова.
Ваш "общепринятый смысл" означает вот это:
Цитата Сообщение от Shamil1 Посмотреть сообщение
console.writeln(bla-bla-bla)
Я вам уже говорил.

В общем, я бы хотел вернуться к разговору о визиторе. Вы, таки сможете наконец обосновать его применимость? Можете показать код, где его применение обосновано, и где без него хуже чем с ним? Этот код должен показывать решение задачи проектирования, а не преодоления ограничений статической типизации и прочих слабостей. Я пока такого примера не видел

Добавлено через 56 секунд
Цитата Сообщение от Shamil1 Посмотреть сообщение
Основы ООП: Должна быть возможность вместо базового типа подставить любой его подтип.
Это ваши "основы", из вашей головы. Ничего подобного в ООП нет. Это касается, разве что принципа подстановки лисков

Добавлено через 4 минуты
Цитата Сообщение от oopguru Посмотреть сообщение
Это касается, разве что принципа подстановки лисков
а имеет ли лисков какое то отношение к ООП, помимо того, что она это сама говорила -- это большой вопрос.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
14.03.2017, 01:27 22
Цитата Сообщение от oopguru Посмотреть сообщение
Это ваши "основы", из вашей головы. Ничего подобного в ООП нет. Это касается, разве что принципа подстановки лисков
занавес...
Миниатюры
Зачем нужен паттерн визитор?  
0
Заблокирован
14.03.2017, 01:35  [ТС] 23
hoggy, если что ООП не сводиться к принципу подстановки лисков. И, более того, в каноническом определении его вообще нет. Какая то баба что то там напела, что и без нее ясно было, что в каких то случаях это применимо, частный случай реализации полиморфизма не более того. Кого это должно волновать?

Добавлено через 4 минуты
Цитата Сообщение от oopguru Посмотреть сообщение
что в каких то случаях это применимо
может напомнить про проблему квадрата? Или сами уже поняли все?
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
14.03.2017, 07:53 24
Цитата Сообщение от oopguru Посмотреть сообщение
Или сами уже поняли все?
Всем всё было уже понятно с вашего прошлого аккаунта.

Вопрос данной темы в чём? Зачем нужен паттерн "Визитёр" или почему все языки - говно в сравнении с Io?
0
Заблокирован
14.03.2017, 08:58  [ТС] 25
Цитата Сообщение от Usaga Посмотреть сообщение
Зачем нужен паттерн "Визитёр"
это.

Добавлено через 4 минуты

Не по теме:

Цитата Сообщение от Usaga Посмотреть сообщение
или почему все языки - говно в сравнении с Io?
а по этому вопросу есть отдельная тема
Питон vs Io(iolanguage)
можете заглянуть, если интересуетесь:) Там про визитор тоже есть



Добавлено через 6 минут

Не по теме:

Цитата Сообщение от oopguru Посмотреть сообщение
Там про визитор тоже есть
например, реализация визитора на Io
Код
Visitable := Object clone do(
   create := method(n, o := self clone; o count := n; o)
   remove := method(if(count > 0, count = count - 1) )
)

MilitaryFacility := Object clone do(
   accept := method(spy, spy visit(self))
)

MilitaryBase := MilitaryFacility clone do(
   init := method(self secretDraftings := Visitable create(1); self nuclearSubmarines := Visitable create(1))
   print := method(write("На военной базе находится " .. secretDraftings count .. " секретных чертежей и " .. nuclearSubmarines count .. " подводных лодок"))
)

HeadQuarters := MilitaryFacility clone do(
   init := method(self generals := Visitable create(3); self secretDocuments := Visitable create(2))
   print := method(writeln("В штабе находится " .. generals count .. " генералов  и " .. secretDocuments count .. " секретных документов" ))
)

JamesBond := Object clone do(
   visit := method(facility,
     facility foreachSlot(n, v, if(getSlot("v") type == "Visitable", 
       while(v count > 0, v remove)
     ))
   )
)

0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
14.03.2017, 16:43 26
Лучший ответ Сообщение было отмечено oopguru как решение

Решение

oopguru, к сожалению (хотя врядли) я в Io не шарю, потому не могу сказать, что именно я в вашем примере вижу. Могу продемонстрировать как может выглядеть данный паттерн на C#:

C#
1
2
interface ISomething {
}
Добавлено через 6 минут
oopguru, к сожалению (хотя врядли) я в Io не шарю, потому не могу сказать, что именно я в вашем примере вижу. Могу продемонстрировать как может выглядеть данный паттерн на C#:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
interface ISomething {
   void Accept(ISomethingVisitor visitor);
}
 
interface ISomethingVisitor {
   void DoA(A a);
   void DoB(B b);
}
 
class ConcreteVisitor : ISomethingVisitor {
   public void DoA(A a) {
       // что-то полезное с участием A
   }
 
   public void DoB(B b) {
      // что-то полезное с участием B
   }
}
 
class A : ISomething {
    public void Accept(ISomethingVisitor visitor) {
        visitor.DoA(this);
    }
}
 
class B : ISomething {
    public void Accept(ISomethingVisitor visitor) {
        visitor.DoB(this);
    }
}
 
//... где-то в коде
ISomethigVisitor visitor = new ConcreteVisitor();
//...
foreach(ISomething item in someCollection) {
    item.Accept(visitor);
}
Добавлено через 4 минуты
Как видите, посетитель (визитёр) не знает с какими конкретно объектами имеет дело, а ISomething-ги не знают, что за визитёр к ним пожаловал (кроме его интерфейса ISomethingVisitor). Соответственно, всё это дело может комбинировтася в рантайме.

Гибко и удобно.

Такой подход широко используется в компиляторах. Да и просто при обходе какого-нибудь дерева\коллекции может быть полезен.
1
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
14.03.2017, 17:28 27
Цитата Сообщение от oopguru Посмотреть сообщение
Ваш "общепринятый смысл" означает вот это:
Вы передёргиваете. Пишете заведомую ложь.

Цитата Сообщение от oopguru Посмотреть сообщение
где без него хуже чем с ним?
По каким критериям будем оценивать, с ним хуже или без него? Или, как всегда, Вы покажете какой-нибудь ужасный (с моей точки зрения) код и скажете, что так лучше?

Цитата Сообщение от oopguru Посмотреть сообщение
Это ваши "основы", из вашей головы. Ничего подобного в ООП нет.
Прежде, чем переходить к изучению шаблонов программирования, Вам следует изучить хотя бы основы ООП. Без этого Вы не сможете понять ОО шаблоны.

И не надо путать ООП и Ваше загадочное "тру ООП", про которое известно только то, что его можно использовать только на "нормальных ЯП". Вы тщательно скрываете от нас источник своих знаний о "тру ООП". Впрочем, учитывая, что группа "нормальных ЯП" включает только на Ё, эти знания бесполезны для читателей данного форума.


И вот Вам аналог того Вашего кода, который Вы по недоразумению назвали реализацией множественной диспетчеризацией.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
    class Program
    {
        static void Main(string[] args)
        {
            var one = new One();
            var two = new Two();
            var three = new Three();
 
            var p = new MyPseudo();
            p.Collide(one);
            p.Collide(two);
            p.Collide(three);
            p.Collide(one, two);
            p.Collide(two, one);
            p.Collide(three, two, one);
 
            Console.ReadKey();
        }
    }
 
    class One { }
    class Two { }
    class Three { }
 
    class MyPseudo : PseudoMultiMethod
    {
        public MyPseudo()
        {
            Target = new Action<One>(one => Console.WriteLine(1)).Target;
            Add((new Action<One>(one => Console.WriteLine(1))).Method);
            Add((new Action<Two>(two => Console.WriteLine(2))).Method);
            Add((new Action<Three>(three => Console.WriteLine(3))).Method);
            Add((new Action<One, Two>((one, two) => Console.WriteLine(12))).Method);
            Add((new Action<Two, One>((two, one) => Console.WriteLine(21))).Method);
            Add((new Action<Three, Two, One>((three, two, one) => Console.WriteLine(321))).Method);
        }
 
        public void Collide(params object[] args) => Invoke(Target, Methods, args);
    }
 
    class PseudoMultiMethod
    {
        protected List<MethodInfo> Methods = new List<MethodInfo> { };
        protected object Target;
 
        protected void Add(MethodInfo m) => Methods.Add(m);
 
        protected static void Invoke(object target, IEnumerable<MethodInfo> methods, params object[] args) =>
            methods.First(m => Fit(args.Select(t => t.GetType()).ToArray(), m.GetParameters())).Invoke(target, args);
 
        protected static bool Fit(Type[] types, ParameterInfo[] parameters) =>
            types.Length == parameters.Length && Enumerable.Range(0, types.Length).All(i => types[i] == parameters[i].ParameterType);
            
    }
Я не стал засовывать Collide в класс One, так как, исходя из сути множественной диспетчеризации, классы One/Two/Three равноправны, и нет смысла выделять One.

Добавлено через 7 минут
Цитата Сообщение от oopguru Посмотреть сообщение
Можно сделать версию, которая обрабатывает и все подтипы, но я не считаю нужным, потому что код все равно наколеночный, и не в этом суть вопроса.
Я верю, что можно сделать правильно работающую версию. Но я сомневаюсь, что Вы способны это сделать без посторонней помощи. Да, Вы что-то напишете, но там опять будут ошибки. Ваша проблема в том, что весь Ваш код "наколеночный". От него не требуется работать правильно и тем более не требуется работать хорошо. Вы оцениваете свой код по каким-то важным только для Вас критериям.
Поэтому Вам нет смысла следить за областью видимости слотов и переменных, думать о модульности и производительности, использовать приёмы, повышающие качество кода.
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
14.03.2017, 18:48 28
Цитата Сообщение от Shamil1 Посмотреть сообщение
Вам нет смысла следить за областью видимости слотов и переменных, думать о модульности и производительности, использовать приёмы, повышающие качество кода.
... а тихо и спокойно писать на Io, где не нужны паттерны и всегда светит солнце...
0
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
14.03.2017, 20:22 29
Цитата Сообщение от Usaga Посмотреть сообщение
... а тихо и спокойно писать на Io, где не нужны паттерны и всегда светит солнце...
Ага. Как первые два поросёнка смотрели на третьего и думали: "Ну что за идиот? Из нормальных материалов дом строится за 5 минут! А отвес и уровень используют дураки для преодоления ограничений кирпича и других убогих материалов."
0
Заблокирован
15.03.2017, 00:07  [ТС] 30
Shamil1, Проблема в том, что Вы сами с собой разговариваете. Все что Вы пишете на недоязыках лишь бледная тень того что Вы пытаетесь имитировать, но это за пределами Вашего понимания, я тут ничем не могу помочь. Вы видите лишь то, что хотите видеть.

Добавлено через 3 минуты
Цитата Сообщение от Usaga Посмотреть сообщение
и всегда светит солнце
солнце светит не всегда, но простое является простым, а сложное -- возможным.

Добавлено через 12 минут
Цитата Сообщение от Shamil1 Посмотреть сообщение
А отвес и уровень используют дураки для преодоления ограничений кирпича и других убогих материалов
проблема языков для быдла в том, что они заставляют использовать отвес и уровень еще до того, как готов проект, или даже эскиз этого дома, и материалы предоставляются еще до того, как станет ясно, какой материал подходит для строительства

Добавлено через 1 час 50 минут
Цитата Сообщение от Usaga Посмотреть сообщение
oopguru, к сожалению (хотя врядли) я в Io не шарю, потому не могу сказать, что именно я в вашем примере вижу. Могу продемонстрировать как может выглядеть данный паттерн на C#:
К счастью, я не пишу на С#, но читать умею. Ваш код на Io будет выглядеть примерго так:
Код
interface := nil // no interface need
collection foreach(anyCallbackThatInteractsWithCollectionItems)
Добавлено через 10 минут
Цитата Сообщение от Usaga Посмотреть сообщение
не могу сказать, что именно я в вашем примере вижу.
А в моем примере всего лишь переписанный на Io пример с википедии, который в оригинале написан на пистоне. Версия на Io компактней ~ в 3 раза. Если бы пример был на С# цифра бы еще увеличилась
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
15.03.2017, 08:39 31
Цитата Сообщение от oopguru Посмотреть сообщение
К счастью, я не пишу на С#, но читать умею. Ваш код на Io будет выглядеть примерго так:
Код
interface := nil // no interface need
collection foreach(anyCallbackThatInteractsWithCollectionItems)
Что-то это ниразу не похоже на то, что я продемонстрировал. Вы один коллбек передаёте элементам коллекции, мой же вариант демонстрирует иное: элементы коллекции выбирают (из множества) и вызывают нужный им метод переданной им абстракции. Совсем не тоже самое, что в вашем примере.

Цитата Сообщение от oopguru Посмотреть сообщение
проблема языков для быдла в том
Вот именно об этом я и спрашивал, когда уточнял настоящий смысл данной темы: понять предназначение паттерна или облить говном всё, что не Io.

Добавлено через 14 минут
Цитата Сообщение от oopguru Посмотреть сообщение
Shamil1, Проблема в том, что Вы сами с собой разговариваете. Все что Вы пишете на недоязыках лишь бледная тень того что Вы пытаетесь имитировать, но это за пределами Вашего понимания, я тут ничем не могу помочь. Вы видите лишь то, что хотите видеть.
Единственное, что здесь имитируется - осмысленное и конструктивное обсуждение. Причём вами.

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

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

Рекомендую пользоваться положением знатока в Io и "ворочать горы", а не тратить своё (ценное) время на указывание дурачкам на их неполноценность.
1
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
15.03.2017, 12:02 32
Цитата Сообщение от oopguru Посмотреть сообщение
Проблема в том, что Вы сами с собой разговариваете.
Я, действительно, разговариваю сам с собой, потому что Вы не можете или не хотите понять того, что я пишу. Но для меня это не проблема, так как у меня нет цели переубедить Вас. Подобные дискуссии я использую для того, чтобы узнать что-то новое и/или освежить в памяти что-то редко используемое. Разумеется, новое я узнаю не от Вас, а из своих экспериментов с кодом.

Цитата Сообщение от oopguru Посмотреть сообщение
Все что Вы пишете на недоязыках лишь бледная тень того что Вы пытаетесь имитировать
Это лишь Ваши слова, за которыми нет никакого обоснования. И от постоянного повторения они не станут правдой. Если хотите поговорить об этом, то создавайте отдельную тему в разделе холиваров.

Цитата Сообщение от oopguru Посмотреть сообщение
проблема языков для быдла в том
Вы считаете себя непризнанным гением? Только Вы знаете, как надо, а все эти учёные, эксперты и прочие программисты не доросли до Вашего уровня и поэтому не в состоянии понять, что Вы им объясняете?
0
Заблокирован
15.03.2017, 12:42  [ТС] 33
Цитата Сообщение от Usaga Посмотреть сообщение
Что-то это ниразу не похоже на то, что я продемонстрировал. Вы один коллбек передаёте элементам коллекции, мой же вариант демонстрирует иное: элементы коллекции выбирают (из множества) и вызывают нужный им метод переданной им абстракции. Совсем не тоже самое, что в вашем примере.
Да, чуток ошибся, пардон.
Вот аналог
Код
A := Object clone do(
    a := 0
    accept := method(visitor, visitor doA(self))
)
B := Object clone do(
    b := 0
    accept := method(visitor, visitor doB(self))
)

Visitor := Object clone do(
   doA := method(acceptor, acceptor a = acceptor a + 1)
   doB := method(acceptor, acceptor b = acceptor b + 1)
)

a := A clone
b := B clone
visitor := Visitor clone

list(a, b) foreach(acceptor, acceptor accept(visitor)) 

writeln(a a, b b) #>>>>11
В целом, до меня вроде начал доходить смысл этого паттерна. Спасибо за ответы

Добавлено через 3 минуты
Shamil1, Мне просто надоело тратить на Вас время. Вы, вместо того, чтобы пытаться понять что-то, ведете себя агрессивно, и вываливаете какие-то совершенно неадекватные куски кода.

Добавлено через 11 минут
Usaga, кстати, питоновская версия, которую я сразу взялся расматривать, с википедии, неадекватна, поэтому я и был введен в заблуждение Там не раскрывается суть этого паттерна, по-моему.
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
15.03.2017, 12:44 34
Цитата Сообщение от oopguru Посмотреть сообщение
питоновская версия, которую я сразу взялся расматривать, с википедии, неадекватна, поэтому я и был введен в заблуждение Там не раскрывается суть этого паттерна, по-моему.
Такое не исключено. Википедия - открытый для редактирования всеми желающими ресурс.

Рекомендую больше полагаться на литературу, нежели на статьи в сети. Рис напороться на фигню в книгах намного ниже (хоть и не исключается ниразу).
1
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
15.03.2017, 13:20 35
Цитата Сообщение от oopguru Посмотреть сообщение
Мне просто надоело тратить на Вас время.
В прошлый раз Вы выдержали только 15 минут.
Цитата Сообщение от oopguru Посмотреть сообщение
Все, с меня довольно. <...>
.

Добавлено через 15 минут
Цитата Сообщение от oopguru Посмотреть сообщение
вываливаете какие-то совершенно неадекватные куски кода
О! Ещё один новый термин. Правильно я понимаю, что код называется "неадекватным-по-оопгуру", если он делает то же самое, что и код, написанный самим оопгуру на Ё?
0
Заблокирован
15.03.2017, 13:25  [ТС] 36
Shamil1, не можете Вы то же самое делать что на Ё по определению. Ё -- динамически типизированный язык, с первоклассными типами, с динамическим связыванием, с полной интроспекцией и рефлексией, множественным наследованием, ленью, и тд и тп. Успокойтесь уже наконец.
0
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
15.03.2017, 15:51 37
Цитата Сообщение от oopguru Посмотреть сообщение
не можете Вы то же самое делать что на Ё по определению
Ваши определения, как всегда, весьма своеобразные.
Вы сейчас имеете ввиду, что на C# нельзя склеивать строки оператором ".."? Тут я согласен, что нельзя. А зачем мне это нужно, если я могу склеивать строки оператором "+"? С моей точки зрения, это то же самое.
Если я использую классы вместо прототипов, то не означает, что мой код не делает то же самое.
Для того, чтобы летать, не обязательно махать крыльями.

Цитата Сообщение от oopguru Посмотреть сообщение
Ё -- динамически типизированный язык, с первоклассными типами, с динамическим связыванием, с полной интроспекцией и рефлексией, множественным наследованием, ленью, и тд и тп.
Какой вывод Вы из этого делаете?

Цитата Сообщение от oopguru Посмотреть сообщение
Успокойтесь уже наконец.
Чтобы начать успокаиваться, нужно сначала взволноваться. Поэтому Ваш совет бесполезный.
0
Заблокирован
15.03.2017, 17:50  [ТС] 38
Цитата Сообщение от Shamil1 Посмотреть сообщение
Какой вывод Вы из этого делаете?
там много выводов.Вы не можете манипулировать типами в рантайме, не можете иметь MOP, не можете создавать управляющие конструкции, не можете интроспектировать и менять код..., полиморфизм Вам доступен только в виде перегрузки и костылей, тысячи их.
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
15.03.2017, 18:03 39
oopguru, видимо всё это не настолько критично и важно, раз "недоязыки" живут и развиваются, а такие экзотические вещи как Ё дальше форумов не выбираются. И давайте не будем использовать "быдло" в виде аргументов. Речь о голом факте - шарпы, явы, плюсы (и прочее) прекрасно справляются с возлагаемыми на них задачами.
1
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
15.03.2017, 18:03 40
Цитата Сообщение от oopguru Посмотреть сообщение
Вы не можете манипулировать типами в рантайме, не можете иметь MOP, не можете создавать управляющие конструкции, не можете интроспектировать и менять код...
Каким образом из наличия какой-то фичи в Ё Вы делаете вывод, что этого нельзя сделать в C#?
А ещё в Ё есть оператор сложения... значит, в C# нельзя два числа сложить?
0
15.03.2017, 18:03
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
15.03.2017, 18:03
Помогаю со студенческими работами здесь

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

Зачем он нужен?
Зачем нужен git bush если есть Github Desktop? Т.е. в декстопе можно делать все тоже самое только...

Зачем нужен using?
Пожалуйста подскажите зачем использовать слово using?например пот здесь: using (var reader = new...

Зачем нужен Qt
Привет всем. Такой собственно вопрос. Зачем нужен Qt и есть ли смысл его изучать? C++ знаю на...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru