powered by simpleCommunicator - 2.0.52     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Нейминг базовых классов
25 сообщений из 65, страница 2 из 3
Нейминг базовых классов
    #39491926
mikron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttЕвгенийВЧто тут то не так? Чем плох старина Stream?

Тем, что требуется вынужденно наследоваться от класса, ты не можешь просто взять и реализовать интерфейс IStream, тебе придётся как минимум реализовать лишний адаптер.

Чаще всего потоки используются только на чтение или только на запись, а клиентам теперь приходится лишний раз проверять Stream, умеет ли он то, что от него требуется (CanRead, CanWrite, CanSeek), вместо того, чтобы выяснить это ещё на стадии компиляции (IReadStream / IWriteStream / ISeekStream).

Зелено ещё. Так делать точно не надо.
Почитай "Entity interface anti-pattern".

Во первых - возвращаясь к теме топика "ИЧитатПоток" странное имя. Логичнее уж IInputStream/IOutputStream

Во вторых, продолжу "Архитектуру".
Добавим для примера "способность" асинхронного чтения: IAsyncReadStream, IAsyncWriteStream.
Теперь добавим для примера "способность" прерывать асинхронное чтение: IInterruptableStream.

Вот насоздавали кучу интерфайсов. Попробуем их использоват.
Пусть у нас метод, который получает как параметр поток, который одновременно IAsyncReadStream, IInterruptableStream, ISeekStream.
Описать его одним интерфейсом не получится. Значит создадим комбинации:
I[Random | Sequential][Async | Interruptable | Blocking] [Read | Write] Stream.

Теперь можно описать параметр метода одним интерфейсом IRandomInterruptableAsyncReadStream. Вспотел?

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

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

Но заметь, реализация у нас будет только одна FileStream.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492013
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mikronПочитай "Entity interface anti-pattern".

Не к месту.

mikronВо первых - возвращаясь к теме топика "ИЧитатПоток" странное имя. Логичнее уж IInputStream/IOutputStream

Логичнее, согласен, мне просто лень было набирать IReadableStream, так что придирка мимо.

mikronЗначит создадим комбинации:
I[Random | Sequential][Async | Interruptable | Blocking] [Read | Write] Stream.

И в чём проблема оставить базовый класс Stream, наследующий все интерфейсы? И нашим и вашим. Такой подход активно практикуется Microsoft, посмотри на фильтры ASP.NET MVC.

mikronТеперь можно описать параметр метода одним интерфейсом IRandomInterruptableAsyncReadStream. Вспотел?

Нет, не вспотел. Серебряной пули не существует, но это не значит, что невозможно найти разумный компромисс.

mikronПроблема дизайна очевидна: создавая для каждого "свойства" свой интерфейс мы будем каждый раз умножать кол-во интерфейсов

Это не проблема, это расширяемость. Видеть в расширяемости проблему, это гениально.


mikronи при этом писать кучу "невыполняемого" бесполезного кода в угоду "архитектуре", при этом полностью теряя из вида что архитектура является не самоцелью а только методом.

Как раз таки наоборот. Если мне нужен поток только для чтения, я реализую такой поток, за каким хреном мне надо реализовывать +100500 доп. методов бросая NotImplementedException? Нахрена мне этот мусорный балласт?

mikronИрония так же в том, что в итоге мы всё это просто выкинем, просто потому что некоторые свойства которые мы описали интерфейсами динамические и зависят от времени выполнения. К примеру тот-же поток. Под одним и тем же путём может быть и файл и канал.

Если я принимаю поток только для чтения, мне всё равно что там, файл или канал, или ещё что-то. Главное чтобы он мог читать. Что мне даст во времени выполнения возможность файла ещё и писать, а канала только читать, если мне нужно только чтение изначально? Тут ты за уши притянул лишнего :)

Пока что не убедительно.
Рано говорить «зелено».
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492031
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttХотя касательно Stream это величайшей фейл Microsoft. Нужен был интерфейс IStream, а не базовый класс. Это просто мега-отвратительное решение. А ещё лучше IReadStream и IWriteStrem, но уже поздно.
hVosttИ в чём проблема оставить базовый класс Stream, наследующий все интерфейсы? И нашим и вашим.
Вспомнился детский анекдот советских времен. Бабушка дает свидетельские показания в суде:
- Ну, иду значит по лесу, грибочки собираю, смотрю, в кустах - эти двое еб*тся...
- (судья перебивает) Свидетель, не "еб*тся" а "сношаются"
- А, ладно, иду значит по лесу, грибочки собираю, смотрю, в кустах - эти двое сношаются, пригляделась - еб*тся!
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492038
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LRВспомнился детский анекдот советских времен. Бабушка дает свидетельские показания в суде:
- Ну, иду значит по лесу, грибочки собираю, смотрю, в кустах - эти двое еб*тся...
- (судья перебивает) Свидетель, не "еб*тся" а "сношаются"
- А, ладно, иду значит по лесу, грибочки собираю, смотрю, в кустах - эти двое сношаются, пригляделась - еб*тся!

Я говорил про замену контракта со Stream на I***Stream, а не убрать класс Stream вовсе. Так что анекдот из разряда, услышал звон, да не знаю где он.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492045
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttЯ говорил про замену контракта со Stream на I***Stream, а не убрать класс Stream вовсе. Так что анекдот из разряда, услышал звон, да не знаю где он.
mikronПусть у нас метод, который получает как параметр поток, который одновременно IAsyncReadStream, IInterruptableStream, ISeekStream.
Описать его одним интерфейсом не получится.
Что дальше?
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492061
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LRЧто дальше?

Элементарно, Ватсон

Код: c#
1.
2.
3.
4.
    public interface ISomeClient
    {
        void GetMeStream<TStream>(TStream stream) where TStream : IAsyncReadStream, IInterruptableStream, ISeekStream;
    }



Дайте уже разумные аргументы
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492073
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttЭлементарно, Ватсон
Что ж, замечательно, согласен.))
Однако, касательно "Stream это величайшей фейл Microsoft. Нужен был интерфейс IStream, а не базовый класс" нужно заметить, что в те далекие времена дженериков еще не было - ничего другого Microsoft-у не оставалось.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492103
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttLRЧто дальше?

Элементарно, Ватсон

Код: c#
1.
2.
3.
4.
    public interface ISomeClient
    {
        void GetMeStream<TStream>(TStream stream) where TStream : IAsyncReadStream, IInterruptableStream, ISeekStream;
    }



Дайте уже разумные аргументы
Ограничение отписать легко, а вот кто и когда реализует TStream?
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492113
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttИменно это и означает :)
А если не сможем, то это очевидно ошибка.
Если Барак Обама перегрыз провод и не льются байты - это не ошибка, это авария.

hVostt
А если твой стрим тупо не поддерживает асинхронный режим?
Тупо синхронно выполниться метод имеющий асинхронную сигнатуру.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492116
mikron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttmikronВо первых - возвращаясь к теме топика "ИЧитатПоток" странное имя. Логичнее уж IInputStream/IOutputStream

Логичнее, согласен, мне просто лень было набирать IReadableStream, так что придирка мимо.

vHost, скажи, как можно вести с тобой разумную полемику если ты просто из упёртости отрицаеш даже те аргументы с кототрыми сам соглашаешся?

Судя по твоим ответам ты не понял.


hVosttmikronЗначит создадим комбинации:
I[Random | Sequential][Async | Interruptable | Blocking] [Read | Write] Stream.

И в чём проблема оставить базовый класс Stream, наследующий все интерфейсы? И нашим и вашим. Такой подход активно практикуется Microsoft, посмотри на фильтры ASP.NET MVC.

Вот именно это и проблема "Entity interface anti-pattern". Куча интерфеийсов и только одна реализация.
Твой аргумент - ссылка на авторитеты говорит так-же против - МС не сделала ненужные интерфейсы.

hVosttНет, не вспотел. Серебряной пули не существует, но это не значит, что невозможно найти разумный компромисс.
mikronПроблема дизайна очевидна: создавая для каждого "свойства" свой интерфейс мы будем каждый раз умножать кол-во интерфейсов
Это не проблема, это расширяемость. Видеть в расширяемости проблему, это гениально.

Это не расширяемость а пустая трата ресурсов человеческих (на написание) и машинных (при выполнении).
Что даст специално для под кокнретный набор своиств заточенный интерфеис? Ведь всегда можно использовать надмножество.


hVosttmikronи при этом писать кучу "невыполняемого" бесполезного кода в угоду "архитектуре", при этом полностью теряя из вида что архитектура является не самоцелью а только методом.
Как раз таки наоборот. Если мне нужен поток только для чтения, я реализую такой поток, за каким хреном мне надо реализовывать +100500 доп. методов бросая NotImplementedException? Нахрена мне этот мусорный балласт?

Это экономически обоснованно:
В 99.99 % случаев потоки не преопределяются. И значит болшинство не тянет ненужный баласт в виде интерфейсов.
А в 0.01% случаев если потребуется реализовывать свой "поток" эти расходы приемлемы и оправданы.

hVosttmikronИрония так же в том, что в итоге мы всё это просто выкинем, просто потому что некоторые свойства которые мы описали интерфейсами динамические и зависят от времени выполнения. К примеру тот-же поток. Под одним и тем же путём может быть и файл и канал.
Если я принимаю поток только для чтения, мне всё равно что там, файл или канал, или ещё что-то. Главное чтобы он мог читать. Что мне даст во времени выполнения возможность файла ещё и писать, а канала только читать, если мне нужно только чтение изначально? Тут ты за уши притянул лишнего :)

Или ты недопонял.
Если тебе нужен поток для чтения и с позиционированием ты не сможеш этого гарантировать ни какими контрактами на этапе компиляции,
так-как доступные интерфейсы определяются только во время выполнения.
Но это доступно в других ОО подчодах, например в COM.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492158
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mikronЕсли тебе нужен поток для чтения и с позиционированием ты не сможеш этого гарантировать ни какими контрактами на этапе компиляции,
так-как доступные интерфейсы определяются только во время выполнения.
Решение было приведено выше .
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492213
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LRЧто ж, замечательно, согласен.))
Однако, касательно "Stream это величайшей фейл Microsoft. Нужен был интерфейс IStream, а не базовый класс" нужно заметить, что в те далекие времена дженериков еще не было - ничего другого Microsoft-у не оставалось

Ну с коллекциями-то они порешали. Хоть и не идеально, но хорошо. Почему то, что верно для коллекций, коллекций с количеством, коллекций с индексацией, коллекцией с возможностью добавления/удаления и т.д. это верно, а для стримов вдруг неверно?
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492216
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЕвгенийВОграничение отписать легко, а вот кто и когда реализует TStream?

Реализует поставщик стримов. Реализует именно те интерфейсы, которые имеют смысл. Остальные нет.
Для чтения потока данных из сети, очевидно не будет Seek и Write.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492218
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЕвгенийВТупо синхронно выполниться метод имеющий асинхронную сигнатуру.

В то время, когда ты ожидаешь именно асинхронного поведения и не хочешь блокировать поток? Ну-ну :)
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492224
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mikronvHost, скажи, как можно вести с тобой разумную полемику если ты просто из упёртости отрицаеш даже те аргументы с кототрыми сам соглашаешся?

Давай без демагогии?

mikronВот именно это и проблема "Entity interface anti-pattern". Куча интерфеийсов и только одна реализация.
Твой аргумент - ссылка на авторитеты говорит так-же против - МС не сделала ненужные интерфейсы.

Куча интерфейсов далеко не одна реализация. В этом и смысл. Так что мимо опять.


mikronЭто не расширяемость а пустая трата ресурсов человеческих (на написание) и машинных (при выполнении).

Не вижу пояснений. Небо зелёное.


mikronТвой аргумент - ссылка на авторитеты говорит так-же против - МС не сделала ненужные интерфейсы.

Ничего подобного не наблюдаю, что бы подтверждало твой тезис.


mikronВ 99.99 % случаев потоки не преопределяются. И значит болшинство не тянет ненужный баласт в виде интерфейсов.

Откуда статистика? Мой опыт показывает обратное. Недавно реализовывал сервер WebDAV, жутко плевался на необходимость реализации нужного Stream отдельным классом и кучи NotImplementedException. Так что не надо выдумывать какую-то фигню.


mikronА в 0.01% случаев если потребуется реализовывать свой "поток" эти расходы приемлемы и оправданы.

Не выдумывай. Взял какие-то глупые проценты и потолка и пытаешься пихнуть их мне в виде аргументов. Совсем что ли за дураков людей держишь??


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

Чё ты несёшь? Если мне нужен IReadableStream, а компонент его не реализует, то будет ошибка компиляции. Если ошибки компиляции не будет, значит я ожидаю, что компонент реализует нужный мне интерфейс и ничего в рантайме чекать мне не придётся.


mikronНо это доступно в других ОО подчодах, например в COM.

Не знаю к чему ты упомянул COM. Ну ладно, он воплощает идеи ООП. И что?
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492226
Addx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Когда мы обсуждаем базовые классы то в целом понятно, название должно отражать функционал.
А если мы наследуемся от базового класса, и создаем класс с прикладной логикой?
Что-то вроде FileSearchStream?
По сути смысл указания в названии, что он CanRead и CanSeek теряет всякий смысл - не тащить же в название весь список методов и поддерживаемых интерфейсов?
По сути стайлгайд в наименовании классов не может быть универсальным (не привязанным к конкретной системе)

hVosttЯ говорил про замену контракта со Stream на I***Stream, а не убрать класс Stream вовсе.

Почему бы не убрать вообще из всех классов параметры-классы и не оставить только интерфейсы?
А к каждому классу в базовых библиотеках создать одноименный интерфейс?
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492229
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AddxА если мы наследуемся от базового класса, и создаем класс с прикладной логикой?
Что-то вроде FileSearchStream?

Твой пример мне говорит о том этот стрим только для чтения. Значит он должен реализовывать соответствующие интерфейсы. При чём тут наименование. Если он не умеет писать, у тебя даже не получится скомпилировать попытку записи. Это вин. Фейл, это забыть проверить CanWrite, и попытаться записать. Или проверить CanWrite и выбросить NotSupportedException, когда ты мог бы вообще этой фигнёй не заниматься изначально.


AddxПо сути смысл указания в названии, что он CanRead и CanSeek теряет всякий смысл - не тащить же в название весь список методов и поддерживаемых интерфейсов?

Это никак не кореллирует с названием классов. Мы говорим о контрактах. Ты либо хочешь читать из потока, либо писать в поток, либо то и другое. Плевать как называется класс, ты ведь получаешь ссылку на объект.


AddxПочему бы не убрать вообще из всех классов параметры-классы и не оставить только интерфейсы?
А к каждому классу в базовых библиотеках создать одноименный интерфейс?

Не утрируй :) Говорим о конкретном фейле Microsoft. Интерфейсы головного мозга это тоже антипаттерн.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492234
mikron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttЕвгенийВОграничение отписать легко, а вот кто и когда реализует TStream?

Реализует поставщик стримов. Реализует именно те интерфейсы, которые имеют смысл. Остальные нет.
Для чтения потока данных из сети, очевидно не будет Seek и Write.

Попробуй реализовать обычный фаил ма диске.
Какие интерфесы он будет реализовывать? И каие будут всегда работать?

Ещё раз: контрактами на этапе компиляции невозможно гарантировать доступность интерфейса время выполнения.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492243
mikron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttmikronТвой аргумент - ссылка на авторитеты говорит так-же против - МС не сделала ненужные интерфейсы.

Ничего подобного не наблюдаю, что бы подтверждало твой тезис.

Так посмотри же на класс Stream и FileStream.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492247
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mikronПопробуй реализовать обычный фаил ма диске.
Какие интерфесы он будет реализовывать? И каие будут всегда работать?

При чём тут твой файл на диске?

стандартный класс Stream реализует хоть что-то?
читает файл с диска?

Считаешь, что твой поток, реализующий доступ к файлу может как читать, так и писать, реализуй все интерфейсы. В чём твоя проблема?

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

Я хочу ТОЛЬКО читать из потока. В методе ты видишь, что он принимает Stream. А я хочу, чтобы ты вообще не мог сунуть объект потока, который не умеет читать. Чтобы потом не ловить ошибки в рантайме. Нафига?
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492254
mikron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttmikronЕсли тебе нужен поток для чтения и с позиционированием ты не сможеш этого гарантировать ни какими контрактами на этапе компиляции,
так-как доступные интерфейсы определяются только во время выполнения.

Чё ты несёшь? Если мне нужен IReadableStream, а компонент его не реализует, то будет ошибка компиляции. Если ошибки компиляции не будет, значит я ожидаю, что компонент реализует нужный мне интерфейс и ничего в рантайме чекать мне не придётся.


Вот ты исползуеш FileStream как реализуюший класс. Никаких проверок в коде. Компилируется.
Но во время работы программы создаётс FileStream для пути по которому находится файл/пайп в кототрый можно только писать. Очевидно что весь код болле не рабочий и твой "архитектурные" испражнения ни к чему не видут. Нужна всё та же проверка в коде IsReadable.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492258
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mikronВот ты исползуеш FileStream как реализуюший класс. Никаких проверок в коде. Компилируется.
Но во время работы программы создаётс FileStream для пути по которому находится файл/пайп в кототрый можно только писать. Очевидно что весь код болле не рабочий и твой "архитектурные" испражнения ни к чему не видут. Нужна всё та же проверка в коде IsReadable.

И что твой код, который собрался писать в файл, будет делать в таком случае? В моём он получит эксепшен, не хватает каких-то прав доступа. Нельзя дальше работать, исключительная ситуация. Я просил объект потока, в который я собираюсь писать. Мне пофигу по каким причинам, это сделать не получилось.

В общем, пример никак не аргументирует и не защищает твою позицию.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492261
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mikron,

Возьмём вот этот метод WebClient.OpenRead . Возвращает поток для чтения. Будешь проверять CanRead? Или сразу будешь читать? А если CanRead вернул false? А писать в поток будешь?
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492272
mikron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttmikronВот ты исползуеш FileStream как реализуюший класс. Никаких проверок в коде. Компилируется.
Но во время работы программы создаётс FileStream для пути по которому находится файл/пайп в кототрый можно только писать. Очевидно что весь код болле не рабочий и твой "архитектурные" испражнения ни к чему не видут. Нужна всё та же проверка в коде IsReadable.

И что твой код, который собрался писать в файл, будет делать в таком случае? В моём он получит эксепшен, не хватает каких-то прав доступа. Нельзя дальше работать, исключительная ситуация. Я просил объект потока, в который я собираюсь писать. Мне пофигу по каким причинам, это сделать не получилось.

В общем, пример никак не аргументирует и не защищает твою позицию.

откудого у тебя возникнет эксепшен? Может кто то всё-же будет делать проверки?

hVosttзначит я ожидаю, что компонент реализует нужный мне интерфейс и ничего в рантайме чекать мне не придётся.

Значит всё-таки твой интерфейс ничего не гарантирует. Значит нет в нём ползы. Исползуй базовый класс Stream.
...
Рейтинг: 0 / 0
Нейминг базовых классов
    #39492283
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttНу с коллекциями-то они порешали. Хоть и не идеально, но хорошо. Почему то, что верно для коллекций, коллекций с количеством, коллекций с индексацией, коллекцией с возможностью добавления/удаления и т.д. это верно, а для стримов вдруг неверно?
Может быть поэтому?
[Serializable]
public abstract class CollectionBase : IList, ICollection,IEnumerable
[SerializableAttribute]
[ ComVisibleAttribute(true) ]
public abstract class Stream : MarshalByRefObject , IDisposable
...
Рейтинг: 0 / 0
25 сообщений из 65, страница 2 из 3
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Нейминг базовых классов
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]