LINUX.ORG.RU

Ответ на: комментарий от anonymous

>Из того, с чем я работал, понравились доки по Symfony и Django.

Интересны конкретные ссылки на конкретные материалы. А то часто даже официальных примеров более одного.

Хочется примеров не продуктов с хорошими обучалками, а самих хороших обучалок. Можно даже не официальных.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от VirRaa

>http://www.symfony-project.org/doc/1_4/

Прикольно. Сразу же на входе висит чей-то комментарий в Diigo: «The documentation on 1.4 as of 1/2010 still is hell (at least for doctrine). The only decent document is the tutorial on Jobeet and still it has some errors.» :)

KRoN73 ★★★★★
() автор топика

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

И ещё напиши что же такого прекрасно в сем фреймворке по сравнению с тем же стандартом де-факто, за который платят работодатели - Zend.

После года-двух реальной работы все становятся алчными. Знаете как я выбирал фреймворк для написание новой системы? По hh.ru. Всякую вкусняшку по типу Yii приходиться отодвигать на второй план.

Ещё для меня важна производительность. Для PHP это простая сборка всего проекта в один файл. В идеале вместе с шаблонами и конфигами. Как в старину делали - без единого инклюда!

PavelR
()
Ответ на: комментарий от PavelR

>Начни с HowTo. Блог за десять минут, дарвей за пять

Это само собой. Но и для этого хорошо бы ориентироваться на доступную и проверенную стилистику других решений. Проблема в том, что когда пишешь документацию по своей системе, то пишешь её обычно непонятно для других. Слишком разный уровень расстановки акцентов. Я двух человек в онлайне натаскивал на свою систему, и страшно удивлялся, насколько они не понимают элементарные, казалось бы, вещи, и, наоборот, как легко схватывают то, на что ты делаешь излишнюю детализацию.

А учебники рановато.


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

Ибо, предвижу, до сих пор плохо документированное АПИ.


Да, в том-то и проблема, что документации по API нет вообще. И хотя принципы/названия/т.п. унифицированные и предельно простые, но надо ж садиться и писать... А времени на это мало. Так что и хочу начать с малого, со всяких How-to.

И ещё напиши что же такого прекрасно в сем фреймворке по сравнению с тем же стандартом де-факто, за который платят работодатели - Zend.


Zend - это немного другой уровень. Это, скорее, не фреймворк (как бы он официально не звался), а набор библиотек. Собственно, мой фреймворк при желании, как раз, хоть под Zend'ом будет работать. Это именно фреймворк - каркас для связи приложений и библиотек. Как своих, так и сторонних. Так что сравнение у меня обязательно в планах, но не с Zend'ом, а с Django/Yii/Symphony и т.п.

После года-двух реальной работы все становятся алчными.


Ну, тут мне сложно судить. Я «в отрасли» работаю лет 12, закладки фреймворка начал делать лет 10 назад, в нынешнем виде он начал формироваться лет 6 назад :)

По hh.ru.


Мне проще, немного другой уровень. Заказывают обычно проекты под ключ, так что фреймворк я выбираю сам :)

Ещё для меня важна производительность.


Для меня - тоже. И тут всё вполне хорошо :) Во многом - отлично. А для совсем критических участков - у меня хорошо проработана система статического кеширования.

Для PHP это простая сборка всего проекта в один файл.


Далеко-далеко не всегда. У меня типовая работа фреймворка - это загрузка десятка-другого мелких файлов. Вряд ли больше. Конечно, 10 файлов грузятся и компилируются в PHP дольше, чем один суммарного размера, но в том-то и дело, что в случае объединения в один файл, грузить придётся не 10 файлов, а 500 файлов на 1Мб размером только в ядре. И ещё 700 файлов на 8Мб в сторонних библиотеках (Smarty, PEAR всякие и т.п.) Да ещё сотня-другая файлов на пол-мега для среднего проекта.. Собирать всё это в один файл - чудовищно :D

...

А вот для каких-то типовых решений, вызывающих реально большую нагрузку (т.е. после профилирования и не страдая «преждевременной оптимизацией») - да, можно основные компоненты собрать в один файл. Но пока не было надобности, профилирование показывает, что загрузка PHP-файлов никогда не занимает много ресурсов.

Как в старину делали - без единого инклюда!


Я однажды прикола ради написал довольно продвинутую гостевую книгу на самомодифицирующемся коде. Сообщения вписывались в сам PHP-файл книги. Ни одного другого внешнего файла. Но было это уже лет 8-9 назад :D

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

> Я «в отрасли» работаю лет 12, закладки фреймворка начал делать лет 10 назад, в нынешнем виде он начал...

А года четыре. Думаю пара на пенсию.

Конечно, 10 файлов грузятся и компилируются в PHP дольше, чем один суммарного размера...

Компилировать не нужно. Есть eaccelerator.

Вы читали разгромную статью Котерова про FastCGI?

Собирать всё это в один файл - чудовищно :D

Но об этом нужно помнить. И не делать конфигов в каком-нибудь yml. Symfony, кстати, собирается по стандартной инструкции. Именно за счет этого им удается ещё и в тестах выигрывать. Но сам не пробовал, честно говоря.

PavelR
()
Ответ на: комментарий от PavelR

> Вы читали разгромную статью Котерова про FastCGI?

Эту? http://dklab.ru/chicken/nablas/49.html

Если автор (сиречь, Котеров) не понимает, как реализован FastCGI в PHP и для чего он нужен, то о чем говорить? И измеряет он в статье несколько не те вещи, так как скорость *выполнения* скрипта от SAPI не зависит.

sjinks ★★★
()
Ответ на: комментарий от sjinks

> Если автор (сиречь, Котеров) не понимает, как реализован FastCGI в PHP и для чего он нужен, то о чем говорить?

Все верно он говорит. FastCGI в PHP нет. Только наколенные поделки, кои текут и падают.

И потом, Котеров гений средь PHP-кодерков. Раскрутился, несмотря на откровенную блевотину в книгах.

PavelR
()
Ответ на: комментарий от PavelR

>FastCGI в PHP нет. Только наколенные поделки, кои текут и падают.

Удивительно. Но после emerge lighttpd, раскомментирования соответствующей строчки конфига и запуска демона сервер получаем PHP FastCGI, который не падает, не течёт, да и сделан явно не на коленке.

...

FastCGI в Nginx с его знаменитой ошибкой - это проблема Nginx'а, а не PHP :)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от PavelR

> Только наколенные поделки, кои текут и падают.

Это такой тонкий троллинг?

И потом, Котеров гений средь PHP-кодерков.

О да. Сколько раз он на PHPConf облажался?

sjinks ★★★
()
Ответ на: комментарий от KRoN73

> FastCGI в Nginx с его знаменитой ошибкой - это проблема Nginx'а, а не PHP :)

Там две проблемы: криво настроенный php и жестко заданный listen backlog для сокета FastCGI (впрочем, очень легко патчится).

sjinks ★★★
()

> Какие обучалки по фреймворкам вам больше всего понравились?

Где за 10 строк пишут, почему надо использовать именно целевую систему, желательно без маркетинговых слов «быстрее-выше-колосссальней», а в последующих 100-1000 строках поливают говном конкурирующие решения (симфони, джанго, каталист и т.д.), приводя аналогии «вот в таком раскрученном это делается долго и уныло, вот здесь вообще течет и валится, тут вообще ДЫРА, а вот У НАС ТО это можно сделать за секунду, работать будет быстрее и никаких дыр!»

Грубо говоря, сначала надо убедить, почему я должен использовать конкретное поделие, а не быдлокодить самостоятельно.

simple_best_world_web_master
()

http://docs.turbogears.org/1.0/Wiki20
http://pylonsbook.com/en/1.1/

И я не верю в статьи «почему мой * лучше чужих *».
Нужен краткий фич-лист, чтобы понять нужно оно человеку или нет.
Кому-то нравится джанга, ибо «джанга эта крута и проста».
Кому-то нравится пайлонс, ибо можно делать что хочешь.
Кому-то нравится турбогирс, ибо оно более гибкое чем джанга.

Важно просто определиться для чего фреймворк. Для каких людей. Для какого бюджета, целей и с какими планами.

tia
()
Ответ на: комментарий от KRoN73

> Удивительно. Но после emerge lighttpd, раскомментирования соответствующей строчки конфига и запуска демона сервер получаем PHP FastCGI, который не падает, не течёт, да и сделан явно не на коленке.

Стоп! И больше ничего делать не придется? Ведь в других языках программирования нужно писать приложение для FastCGI с явной точкой входа, по сути собственный сервер.

Тот же самый сраный mod_php получиться, разве нет? Заранее подготовленный php, определенная частота ребутов - не более. Или я что-то проспал?!

PavelR
()
Ответ на: комментарий от sjinks

> О да. Сколько раз он на PHPConf облажался?

Деточка, когда ты подрастешь, ты станешь понимать смысл слова «гений» в современных товарно-денежных отношениях.

PavelR
()
Ответ на: комментарий от tia

> Важно просто определиться для чего фреймворк. Для каких людей. Для какого бюджета, целей и с какими планами.

Для построения масштабируемого сайта, создания новых разделов минут за 15, причем со своими шаблонами и своей логикой, своим контролем доступа и быть может обработчиками. Для людей, которые пишут код не первый день, но не переносят похапе и педон. Бюджет в 0$. Цель: завоевание мира конечно же, а для чего еще сайт нужен?

simple_best_world_web_master
()
Ответ на: комментарий от PavelR

>Тот же самый сраный mod_php получиться, разве нет?

По сути - да. И чем же он «сраный»? :)

Заранее подготовленный php, определенная частота ребутов - не более.


Какой «заранее подготовленный»? Откуда «частота ребутов»?

Или я что-то проспал?!


Вполне может быть. Но у меня Лайти на www.aviaport.ru по паре мессяцев без рестарта легко крутится, пока в настройках что-то не поменяешь. Да и тогда рестартует по graceful. Полный растарт только при обновлениях версии самого Лайти.

Повторюсь - не стоит судить о php-fastcgi по nginx'у. Это не лучший пример.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от PavelR

> Деточка, когда ты подрастешь,

Ребенок, не смеши мои седые пятки.

sjinks ★★★
()
Ответ на: комментарий от PavelR

> Тот же самый сраный mod_php получиться, разве нет?

Нет. mod_php с Apache prefork плох тем, что на каждый запрос (не важно, статика это или динамика) апач форкает процесс, что (при неграмотной конфигурации) может приводить к бесполезному забиванию памяти и своппингу. В случае php-fcgi количество процессов, как правило, фиксировано — запросы распределяются по свободным процессам, при отсутствии таковых ставятся в очередь (размер которой ограничен listen backlog, значение которого зачем-то жестко задано в коде php).

В результате с php-fcgi не происходит лишних форков, потребление памяти (при условии отсутствия текущих расширений) константное (плюс/минус на persistent resources, если приложение их использует), плюс fcgi может физически находиться на другом сервере/серверах. Ну и при высокой нагрузке и фиксированном количестве процессов не будет жестокого переключения контекста по iowait.

sjinks ★★★
()
Ответ на: комментарий от KRoN73

> Откуда «частота ребутов»?

Очевидно, PHP_FCGI_MAX_REQUESTS.

Повторюсь - не стоит судить о php-fastcgi по nginx'у. Это не лучший пример.

Почему? FastCGI один и тот же. Просто лайти, если бэкэнд не отвечает, делает паузу (до секунды, точное значение не вспомню, а сорцы смотреть лень) и повторяет запрос. nginx по дефолту этого не делает (в том плане, что если очередь запросов бэкэнда полна, нет смысла грузить его еще больше), но это легко обходится. Спорить о том, какой подход лучше, смысла нет, так как у обоих подходов есть свои плюсы и минусы.

Либо, как я уже говорил, патчится значение listen backlog в исходнике php, после чего про 502 ошибку можно забыть.

sjinks ★★★
()
Ответ на: комментарий от KRoN73

> Повторюсь - не стоит судить о php-fastcgi по nginx'у. Это не лучший пример.

Я наверное тоже долго спал в анабиозе, так как пользы от fastcgi относительно похапе тоже не понимаю (независимо от сервера). Если говорить о прекомпиляции самого кода и запуске интерпретатора - да, охотно верю в рост производительности. А вот разделение кода на инициализацию / обслуживание / очистку я видимо проспал. И если где-то в начале скрипта будет подключение к СУБД, то оно так ведь и будет долбить лишними коннектами на каждый запрос, не? Т.е. с точки зрения инициализации выигрыша никакого не будет. Или будет?

simple_best_world_web_master
()
Ответ на: комментарий от simple_best_world_web_master

В nginx это принесено в жертву ради поддержки пулов бэкэндов. В этом случае если один бэкэнд умер, nginx переадресует запрос следующему в цепочке.

sjinks ★★★
()
Ответ на: комментарий от simple_best_world_web_master

> А вот разделение кода на инициализацию / обслуживание / очистку я видимо проспал.

В случае с php этого не будет. Если написать standalone fastcgi server (видел реализацию на пхп, но не щупал), то тогда можно произвести инициализацию до обслуживания запросов

то оно так ведь и будет долбить лишними коннектами на каждый запрос

Можно использовать persistent connections. Но опять же, осторожно и с умом.

так как пользы от fastcgi относительно похапе тоже не понимаю

mod_php + Apache prefork - форк на каждый запрос + нерациональный расход памяти. Использование FstCGI (с любым сервером), во-первых, позволяет отделить сервер от php (упадет один - останется другой) плюс можно организовывать независимые пулы серверов (отказоустойчивость, распределение нагрузки), во-вторых, позволяет контролировать расход памяти.

Т.е. с точки зрения инициализации выигрыша никакого не будет.

С точки зрения скрипта и по сравнению с mod_php — нет.

sjinks ★★★
()
Ответ на: комментарий от simple_best_world_web_master

> А если сдохло все и не запускаются?

В любом случае, перезапуск упавшего бэкэнда — *на мой взгляд*, не является задачей web-сервера. Тем более, если бэкэнд находится на другом хосте.

Я понимаю подход разработчиков лайти, но для таких случаем на сервере стоит monit или что-то аналогичное — помимо перезапуска, уведомляет администратора (кстати, может контролировать объем памяти процесса, потребление процессора и т.п.) и при желании можно заставить отправлять всякую полезную диагностическую информацию, которая может быть полезна для установления причин падения.

sjinks ★★★
()
Ответ на: комментарий от sjinks

Вот написал ты простыню текста, прикладываешь 20 картинок, нажимаешь отправить... На выбор: 500/502, сообщение браузера «can't connect» или «извините, у нас тут бекэнд отвалился, но ваш запрос сохранен, мы его обязательно рассмотрим!»? В этом плане подход лайти мне кажется наилучшим.

simple_best_world_web_master
()
Ответ на: комментарий от simple_best_world_web_master

> «извините, у нас тут бекэнд отвалился, но ваш запрос сохранен, мы его обязательно рассмотрим!»

Он на диск пишет?

На выбор: 500/502, сообщение браузера «can't connect»

Не буду говорить, что при желании можно нажать F5. Я бы решал эту проблему пулом бэкэндов — мне в любом случае не нравится single point of failure.

Я не спорю, у Лайти подход хороший, но просто не в моем вкусе.

sjinks ★★★
()
Ответ на: комментарий от simple_best_world_web_master

> ваш запрос сохранен, мы его обязательно рассмотрим!

Сразу в голову не пришло: отправится запрос минут через 10 (например), но пользователь уже результат не увидит? Или как оно работает?

sjinks ★★★
()
Ответ на: комментарий от sjinks

>Очевидно, PHP_FCGI_MAX_REQUESTS.

А это, как бы, вполне скрыто и от пользователя и в достаточной степени от админа.

Спорить о том, какой подход лучше, смысла нет, так как у обоих подходов есть свои плюсы и минусы.


Воистину, спорить смысла нет. Ибо в результате у Лайти нулевой процент отказов (если верить статистике Гугля и Яндекса), а соответствующие ошибки Энжиникса мы видели все.

Либо, как я уже говорил, патчится значение listen backlog в исходнике php, после чего про 502 ошибку можно забыть.


Я ничего не патчил у себя, ничего ручками в этом ключе не настраивал, но никаких проблем с FastCGI не вижу.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от simple_best_world_web_master

>Я наверное тоже долго спал в анабиозе, так как пользы от fastcgi относительно похапе тоже не понимаю

Польза прямая. Это единственный способ запускать PHP на не-апачевских серверах и с производительностью mod_php

А вот разделение кода на инициализацию / обслуживание / очистку я видимо проспал.


Да, этого в PHP нет. Но и с каждым перезапуском получается неплохо. Все уже позабыли известные тесты производительности по сравнению с Django?

И если где-то в начале скрипта будет подключение к СУБД, то оно так ведь и будет долбить лишними коннектами на каждый запрос, не?


Как сделаешь, так и будет. Никто не запрещает держать пул соединений и юзать pconnect.

Т.е. с точки зрения инициализации выигрыша никакого не будет.


По сравнению с mod_php приницпиального выигрыша не будет.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от sjinks

>В любом случае, перезапуск упавшего бэкэнда — *на мой взгляд*, не является задачей web-сервера. Тем более, если бэкэнд находится на другом хосте.

Об этом можно много спорить. Но результат очевиден всем :)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от sjinks

> Он на диск пишет?

К сожалению, пока только в астрал, ибо ждем 1.5, которого еще нет. Упомянул просто как пример.

Не буду говорить, что при желании можно нажать F5

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

Я бы решал эту проблему пулом бэкэндов — мне в любом случае не нравится single point of failure.

1. пул может сдохнуть целиком (например, вместе с СУБД)

2. как быть с stateful сервером? Пришел клиент, авторизовался, породил сессию, а мы его потом на другой сервак кидаем, который про него ничего не знает (я конечно в курсе про репликацию у мемкешда через патч, но это не слишком красиво). А если мы завязыываемся в конечном итоге на 1 сервер, то см. пункт 1. Всякие IP-hash-балансировщики тут тоже не помогут.

Я не спорю, у Лайти подход хороший, но просто не в моем вкусе.

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

simple_best_world_web_master
()
Ответ на: комментарий от KRoN73

>Под «учебниками» я, как раз, и имею в виду примеры конкретных простых решений, раскрывающие основные принципы.

В буржуйской литературе такoй учебник называется cookbook. При изучении чего-то нового в первую очередь пытаюсь найти эти самые cookbook'и.

Пример:

http://cdn.oreilly.com/oreilly/booksamplers/4_jQuery_Sampler.pdf

ZeMvlad
()
Ответ на: комментарий от KRoN73

>>А вот разделение кода на инициализацию / обслуживание / очистку я видимо проспал.

Да, этого в PHP нет

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

roller ★★★
()
Ответ на: комментарий от roller

>Представте только все используемые классы уже в памяти, ничего парсить и подымать не надо

Ну, вот, в 5.3 поставили нормальный сборщик мусора. Так что, глядишь, скоро «настоящий» FastCGI можно будет сделать. Но пока и того, что есть хватает.

...

А классы мы в memcached храним :)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от roller

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

Чего ждать то? В Java, Python, Ruby это давно есть уже.

PavelR
()
Ответ на: комментарий от KRoN73

>А классы мы в memcached храним :)

А десериализация нонче бесплатна?)

Чего ждать то? В Java, Python, Ruby это давно есть уже.

Это вы к чему сказали?

roller ★★★
()
Ответ на: комментарий от simple_best_world_web_master

> 1. пул может сдохнуть целиком (например, вместе с СУБД)

Это как? Наборы FastCGI-серверов не зависят от наборов web-серверов и СУБД. Сдохнет один пул — останется другой, не вижу проблемы.

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

Почему не знает? Идентификатор сессии живет в куках, они передаются заголовках запроса от web-сервера FastCGI-серверу, сама сессия может храниться в месте, доступном всем FastCGI-серверам. Ну или самый простой вариант — сессию можно хранить в БД.

то лучше сложить данные и переждать

Тогда такой вариант: DDoS может длиться часами, сессия пользователя за это время истечет. Когда ддос закончится, сервер повторит запрос, получит ответ «авторизуйтесь заново», и в результате получим те же яйца, но только в профиль.

Ну вот зааплодил ты 100 метров, а тебе говорят 500

Согласитесь, сервер, оперирующий такими объемами данных, вряд ли будет иметь Single Point of Failure.

К сожалению, пока только в астрал, ибо ждем 1.5, которого еще нет. Упомянул просто как пример.

Реализовать такую штуку и как отдельный бэкэнд не сложно. Например, складывать только POST/PUT/DELETE-запросы (в GET/HEAD смысла нет, так как пользователь не увидит результат. Хотя, если кто-то использует GET для изменения состояния…), периодически пинать сервер, и если тот жив, отсылать ему запросы.

Но: мне не совсем понятно, как это делать без взаимодействия с пользователем. Например, если сессия истекла, и пользователь должен авторизоваться. Как сообщить об этом пользователю, если такая досылка запросов осуществляется где-то в фоне?

sjinks ★★★
()
Ответ на: комментарий от roller

> Представте только все используемые классы уже в памяти, ничего парсить и подымать не надо. Все что не зависит от реквеста уже проинициализированно (коннект к базе, кеш,...).

Из этого все, кроме «все используемые классы уже в памяти» может быть реализовано путем использования persistent resources. Иногда с затратами на сериализацию/десериализацию.

В принципе, первое тоже возможно, только придется писать свое расширение PHP для начальной подгрузки всех требуемых классов на стадии MODULE INIT. Либо Zend-расширение, которое сохраняет классы после первой их компиляции.

sjinks ★★★
()
Ответ на: комментарий от KRoN73

> Ибо в результате у Лайти нулевой процент отказов (если верить статистике Гугля и Яндекса)

Это по Вашим сайтам или глобальная статистика? Если глобальная, то где ее можно посмотреть? Просто я у Лайти неоднократно видел Server Error с 502 кодом ответа.

sjinks ★★★
()
Ответ на: комментарий от KRoN73

> никаких проблем с FastCGI не вижу.

Если не секрет, какая пиковая дневная посещаемость? Я реально упирался в то, что при 1500+ одновременных посетителях с *одним* пулом FastCGI-серверов на не самом быстром сервере затык был именно в listen backlog (который 512). Покупать более дорогой сервер с большим количеством памяти/быстрым процессором было лень, я решил проблему путем патча пхп. В результате получилось практически то же поведение, что и у лайти, только с той разницей, что не нужно было проверять, свободен ли fcgi и повторять запрос, так как соединение автоматом помещалось в бэклог.

sjinks ★★★
()
Ответ на: комментарий от roller

>А десериализация нонче бесплатна?)

Копеечна :)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от sjinks

>Классы? Или объекты?

Конечно, объекты.

KRoN73 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.