Dennis_Chikin 3 658 Опубликовано 4 Января 2015 Поделиться Опубликовано 4 Января 2015 (изменено) С чего начинать и где взять. Установка Lua:http://www.amk-team.ru/forum/index.php?showtopic=11584&p=629106 Руководство «Программирование на языке Lua», третье издание:http://www.amk-team.ru/forum/index.php?showtopic=11584&p=905308 Изменено 2 Марта 2015 пользователем Kirgudu Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Malandrinus 615 Опубликовано 14 Января 2012 Автор Поделиться Опубликовано 14 Января 2012 Багфикс к таймерам. http://rghost.net/35897685 Monnoroch, почему ASSERT, зачем такая жестокость? Обычно в такой ситуации бросают исключение, потому на мой взгляд логичнее было бы просто ничего не сделать и как-то сообщить пользователю, что он не совсем прав. А то сразу assert делать слишком сурово. В добавок мне видится ситуация, когда я хочу подписаться на эвент, если еще не подписан, и ничего не делать если подписан. Понимаешь, убрать эту проверку можно. В принципе можно даже не ограничивать попытки подписать один и тот же слот два раза. По большому счёту системе всё равно, что в очереди два одинаковых вызова. Вызовет оба, а при отписывании отпишет первый найденный, а при втором отписывании - второй. Но на мой взгляд это лишено всяческого смысла и практического применения я этому не вижу. Предположим, с этим решили. Два раза не подписываем. Теперь вопрос, что делать, вылетать/предупреждать/тихо ничего не делать? Вот ты говоришь, что представляешь себе ситуацию, когда можно захотеть подписаться на сигнал и при этом неизвестно, подписаны мы уже или нет. Но дело в том, что я то как раз такой ситуации из моего собственного опыта не вижу. Вот два примера подписывания. Первый, для глобальной функции при подписывании модуля. Но каждый модуль подписывается только один раз и никогда не будет подписан второй раз. Или скажем в таймерах, где подписывание методов происходит в конструкторе класса. Конструктор не может быть вызван более одного раза для объекта, так что даже теоретически подписывание не произойдёт дважды. Если пытаться себе представить некую необычайно динамическую ситуацию с частым подписыванием/отписыванием некой функции, то как быть с парностью этих действий? Я имею в виду, что вот мы подписали, затем подписали ещё раз, затем ещё и сделали это неопределённое число раз (ведь именно это хочется, не так ли). Теперь надо отписать. Можно конечно принять ту же идеологию и для отписывания: есть слот - отписали, нет - ну и фиг с ним. Но ведь как бы подразумевается, что между подписыванием и отписыванием идут вызовы, ради которых мы это делали. А выходит, что мы даже не знаем, шли они или уже давно закончились, поскольку парность вызовов порушена. Вот я полагаю, что так строить систему нельзя. Если я подписал на вызов, то предполагается, что вплоть до действия отписывания эти вызовы идут, и я могу быть в этом уверен. До сих пор мне как-то удавалось строить систему таким образом, что этот принцип не нарушался. На мой взгляд, если эта очерёдность нарушится, то только если я что-то сделаю неправильно. В этом случае ассерт сработает, я об этом узнаю (что я сделал что-то неправильно) и смогу это исправить. Я надеюсь, что смог объяснить, почему у меня там стоит ассерт. Это вообще то не столь уж значительно дело. Честно. Если ты действительно найдёшь практическую ситуацию (не придуманную "на всякий случай"), когда этот ассерт будет мешать, ну так и убери его. Делов то на пару секунд. Это ведь не мой персональный способ усложнить себе и другим жизнь. Я пытался сказать, что эта техника помогает избегать ошибок. Она на самом деле экономит мне время. Замена ассерта на более мягкую обработку ошибки позволит тут избавиться от ветвлений типа if not obj:is_already_subscribed(slot) then obj:subscribe(slot) end Исходя из всего сказанного ранее, я на самом деле предпочёл бы, чтобы такой фрагмент стоял в моём коде именно в таком виде. В этом случае я бы явно видел, что вот здесь я преодолеваю ограничение безопасности. Повторюсь только, что если этот код вдруг стал появляться в большом количестве, то это повод задуматься о проблемах дизайна. насчёт этого Либо добавить signals_mgr:subscribe_silently() Надеюсь, что смог донести мысль, что "на всякий случай" такие возможности добавлять не надо. Они вредны. Однако, если реально надо, то ничто не мешает добавить это самостоятельно. Я и сам добавлю что-то в этом роде, но для этого мне нужно увидеть реальный случай, где это могло бы иметь смысл. До тех пор у меня такой функции не будет. Но ведь исходники доступны, так что у себя никто не мешает сделать что угодно. К тому же с ветвлением obj:is_already_subscribed вызывается дважды. Это разовое действие. Кроме того, эта проверка стоит в ассерте. Подразумевается, что в релизной версии мы большую часть ассертов убираем (или комментируем). xStream, Опять разговор о фломастерах начинается. Только вот твои фломастеры у тебя никто не отбирает Ох, Аня, ну где я что-то у тебя отнимаю? Если ты опасаешься, что я полезу в твой код всё там менять, то не переживай, не полезу =) Andrey07071977, - выкладывай . Перепробовал уже с пяток разных методов, ни один не нравится, последнее на чем остановился это то с чего начал (1/uninitialized). один из методов - использование функции fail, добавленной в рамках проекта x-ray extensions. Это собственно движковый вылет. Второй метод, использование консольной команды "quit", которая незатейливо закрывает игру. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
xStream 86 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 malandrinus, Ох, Аня, ну где я что-то у тебя отнимаю? Если ты опасаешься, что я полезу в твой код всё там менять, то не переживай, не полезу =) Глупости говоришь. Мне все равно, кто что будет делать, я свой сделала. Ты просто постоянно высказываешь мысли так, как будто это непреложная истина в конечной инстанции. Или как будто тебя лишают возможности использовать тот стиль программирования, к которому ты привык. Я не понимаю, как такое можно вообще в принципе сделать (запретить). Ты всегда можешь делать так, как хочешь, перед тем как использовать какой-то компонент: сделать 100 проверок и впихнуть 40 ассертов - дело то твое. Мягче надо быть, мягче. Все, кто стоит на моем пути: идите нахрен и там погибните! © Ссылка на комментарий
Monnoroch 6 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 (изменено) malandrinus, Я имею в виду, что вот мы подписали, затем подписали ещё раз, затем ещё и сделали это неопределённое число раз Хранить счетчик подписываний, а не подписывать каждый раз. А пример я приводил: вот у меня класс хелпер какой-то. Мне присылают обьект и список эвентов на которые подписать. Задача - подписать на все. Ну понятно же, что не хочется каждый раз проверять - подписан ли уже, и если нет, то подписывать, хочется же сделать код прозрачней. Ну вот метод: function subscribe_all(mgr, slots) for _,v in pairs(slots) mgr:subscribe(v) end end Допустим код одной схемы вызывает: helper.subscribe_all(mgr, {s1,s2,s3}) А второй: helper.subscribe_all(mgr, {s2,s3,s4}) Вон как все красиво. Да, можно всунуть if, но как-то уже не то. Хотя вот я тут подумал - если просто в сам класс подписывателя инкапсулировать этот subscribe_all с if-ом, то будет все хорошо в плане использования. По поводу этого: когда этот ассерт будет мешать, ну так и убери его...До тех пор у меня такой функции не будет. Я думал обо всей системе, как о библиотеке, у которой есть интерфейс а реализация меня волновать не должна. И конечно пользователь сам может определить subscribe_silent с помощью того же if-а и снаружи библиотеки, но это потенциальное дублирование кода - каждый будет свою версию определять. И потом, тут проблема именно в том, что два разных человека подписывают один и тот же обьект на один и тот же эвент. Ну вот выпал мне этот ассерт - что мне делать? Ставить ту самую явную проверку, вариантов особо других нет. Я же не знаю, всегда ли так получается, что он уже подписан. Это же не мой код. И не ошибка в логике. Ты не пойми неправильно, я не пытаюсь учить ученого, просто мне показался странным подобный дизайн модуля, который потенциально может использоваться кучей народу в куче модификаций Во, кстати, я еще досмотрел и такой вопрос: почему сигнал встраивается в слот? Можно же было бы сделать как-то так: obj:subscribe(signal,slot), тогда один слот мог бы быть подпинан на множество сигналов в разное время разным кодом. Изменено 14 Января 2012 пользователем Monnoroch Ссылка на комментарий
xStream 86 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 http://dl.dropbox.com/u/46539648/xs_scripts.rar Все скрипты в куче. ----------------------- Допилена работа с нетпакетами: - Вариант, когда собрались менять абстрактную часть, а объекта уже нет. - Скелет, скелет - надо проверить, грустняша... - Ну и описание, вроде тянет на мануал. (можно использовать as is, а вот для абстрактной части пакетов придется попотеть) Изменена слегка песочница: - проверка на зависание делается иначе, спасибо malandrinus - как следствие, за ненадобностью удален метод :hangCheck() у ивентов. Все, кто стоит на моем пути: идите нахрен и там погибните! © Ссылка на комментарий
KD87 718 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 xStream, часть пакета, свазанная со skeleton_flags - именно в STATE части. Вот кусок псевдокода из CSE_PHSkeleton::STATE_Read: NET_Packet::r_stringZ(tNetPacket, &v4->startup_animation); NET_Packet::r(tNetPacket, &v3->_flags, 1u); NET_Packet::r(tNetPacket, &v3->source_id, 2u); if ( v3->_flags.flags & 4 ) v3->vfptr->data_load(v3, tNetPacket); Идет вызов виртуальной функции, в конечном счете вызывается SPHBonesData::net_Load(). Что читается в ней, я уже в этой теме "типа" писал. Ссылка на комментарий
xStream 86 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 Окей, только при попытке это сымитировать именно так, как ты написал, приводит к жопе под названием CTD Все, кто стоит на моем пути: идите нахрен и там погибните! © Ссылка на комментарий
KD87 718 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 (изменено) xStream, приведи код, которым пытаешься читать. Изменено 14 Января 2012 пользователем KD87 Ссылка на комментарий
xStream 86 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 Он в либе - _r_skeleton Все, кто стоит на моем пути: идите нахрен и там погибните! © Ссылка на комментарий
KD87 718 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 (изменено) xStream, но чтение-то заблокировано. Вот тут, например: if prop.name~="skeleton" or not (bit_and(ret.skeleton_flags, 4)==0) then Как это выглядело при включенном чтении? Изменено 14 Января 2012 пользователем KD87 Ссылка на комментарий
xStream 86 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 Если бит включен, то читается скелет, той самой функцией - _r_skeleton Если выключен, то скипается. То есть - выглядело точно так же. Выключено простым комментированием --{ name = 'skeleton', type = 'skeleton' } Все, кто стоит на моем пути: идите нахрен и там погибните! © Ссылка на комментарий
Artos 99 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 xStream, в писалке '_w_skeleton' все же не добавила: pk:w_u16(#val.bones) --/< bones_count function _w_skeleton(pk, val) for i=1,4 do --/ u16x4 == u64 pk:w_u16(val.bones_mask[i]) end pk:w_u16(val.root_bone) pk:w_vec3(val.ph_angular_velosity) pk:w_vec3(val.ph_linear_velosity) pk:w_u16(#val.bones) --/< bones_count for _,bone in ipairs(val.bones) do _w_q8v(pk,bone.ph_position) _w_q8v(pk,bone.ph_rotation) pk:w_u8(bone.enabled) end end или я ошибаюсь? (сам пока пытаюсь методом тыка ...) Также в классах:"net_alife_mounted_weapon" и "net_alife_object" ошибка с 'self.object', т.к. он нигде не определяется. "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Andrey07071977 18 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 (изменено) Monnoroch, Не надо никаких сообщений в лог. Это сажает производительность 1. Для современных систем однострочные выводы в лог, как слону дробинка, тем более что ты не в update, надеюсь, ставишь подписки 2. Предполагается что двойные подписки будут отловленны на стадии разработки/тестирования. В релизе нет необходимости вывода в лог и уж тем более крэшить игру (в разработке, кстати тоже нет смысла крэшить) П.С. malandrinus, прошу понять правильно, не критикую и не навязываю точку зрения, просто "разбор полетов" (feedback) П.П.С. Про quit знаю, за fail спасибо, попробую Изменено 14 Января 2012 пользователем Andrey07071977 Ссылка на комментарий
Monnoroch 6 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 Andrey07071977, Так ведь нет же, я как раз и пытаюсь протолкнуть идею, что двойные подписки - совершенно нормальное явление. Потому и отлавливать их сомнительный профит, разве только если в конкретных случаях. Ссылка на комментарий
xStream 86 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 (изменено) xStream, в писалке '_w_skeleton' все же не добавила: pk:w_u16(#val.bones) --/< bones_count Блииииииин, точно. Надо снова проверять. Также в классах:"net_alife_mounted_weapon" и "net_alife_object" ошибка с 'self.object', т.к. он нигде не определяется. Прошу обратить на super(obj) во всех конструкторах! Это вызов родительского конструктора, то есть net_base:__init(obj), туда передаается и там и присваивается. Так что ошибки нет: self.object - есть ВСЕГДА. Мы же должны помнить объект, из которого читаем / в который пишем. ЗЫ Там же и self.skip задается, не смутило, что тоже не "определен"? Добавлено через 10 мин.: Гыгы, а про передачу skip я и забыла совсем... http://dl.dropbox.com/u/46539648/xs_netpk.script вот здесь подправленный по идее скелет и везде добавлена передача скипа Update. Скелет заработал, вылетов не обнаружилось... Изменено 14 Января 2012 пользователем xStream Все, кто стоит на моем пути: идите нахрен и там погибните! © Ссылка на комментарий
Andrey07071977 18 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 Monnoroch, двойные подписки - совершенно нормальное явление На мой взгляд, при правильной организации кода, таких случаев не должно возникать вообще. Приведенный тобой пример, может произойти при неаккуратном совмещении модов с одноименными глобальными (_G) функциями подписчиками, но это опять-же проблема девелопера, на этапе совмещения Ссылка на комментарий
Artos 99 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 xStream, в "net_base" запоминается под self.obj, а не self.object ... А по self.skip не стал ничего писать, т.к. в своем варианте (в моде) использую управляемое получение пакета, т.е. если НЕ потребно читать весь (c update) - то и читается только state. Это и чуть ускоряет и экономит ресурсы и снижает вероятность ошибок при полной перезаписи пакетов, тогда, когда нужно порою всего-то задать типа story_id. Т.о. флаг 'skip' передаю (если требуется) уже в вызов при получении пакета (полного или частичного) и соответственно протрассировал его по классам. "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Malandrinus 615 Опубликовано 14 Января 2012 Автор Поделиться Опубликовано 14 Января 2012 (изменено) Monnoroch, Хранить счетчик подписываний, а не подписывать каждый раз. Ну ок. Вот у меня слот. Слот это функция, которая что-то делает, к примеру увеличивает некий счётчик или удаляет переданный ей объект, или создаёт объект, или выводит сообщение, или проигрывает звук... Я подписал эту функцию два раза. Она вызовется два раза, два раза увеличится счётчик, попытаемся второй раз удалить объект, или создадим лишний, или на экран два раза выведется одно и тоже сообщение... На мой взгляд реальный косяк. О счётчиках. Счётчики - это типичный элемент сервера, того, кого используют. Здесь же слот - пользователь, а сервер - это сигнал. Как раз у сигнала есть счётчики (даже больше, очередь), а слоту это не надо. Подумай об этом с такой стороны. Что-то в твоей задумке неправильно, если вот так меняются роли сторон. А пример я приводил: вот у меня класс хелпер какой-то. Мне присылают обьект и список эвентов на которые подписать. Извини, так в общем нельзя. Что за хелпер, что за объект и кто может так присылать, что вы не в состоянии договориться, кто и что подписывает? Для объектов я выше приводил стратегию работы с ними. Помести подписывание в их конструктор, он с гарантией отработает один раз за всё время жизни объекта. Допустим код одной схемы вызывает: helper.subscribe_all(mgr, {s1,s2,s3}) А второй: helper.subscribe_all(mgr, {s2,s3,s4}) Вон как все красиво. Да, можно всунуть if, но как-то уже не то. Хотя вот я тут подумал - если просто в сам класс подписывателя инкапсулировать этот subscribe_all с if-ом, то будет все хорошо в плане использования. Я признаюсь, не понял ничего. Можешь привести упрощённую, но конкретную ситуацию. В терминах реальной задачи, пожалуйста. Я думал обо всей системе, как о библиотеке, у которой есть интерфейс а реализация меня волновать не должна. Тогда мирись с дизайном автора =) И потом, тут проблема именно в том, что два разных человека подписывают один и тот же обьект на один и тот же эвент. Ну вот выпал мне этот ассерт - что мне делать? Ставить ту самую явную проверку, вариантов особо других нет. Я же не знаю, всегда ли так получается, что он уже подписан. Это же не мой код. И не ошибка в логике. Очень даже ошибка в логике. Как совершенно верно сказал Andrey07071977, кривое совмещение модов. В начале этого поста я привёл несколько ситуаций, которые это иллюстрируют. мне показался странным подобный дизайн модуля, который потенциально может использоваться кучей народу в куче модификаций Я почему-то считаю ровно наоборот. Это дизайн, который призван помочь в совмещении, позволяя раннее обнаружение конфликтов. Чтобы не быть голословным: совмещаю два мода, так уж получилось, что в обоих вдруг идёт подписка на некую функцию. Я совместил, запустил, получил вылет с предупреждением и указанием, какой слот пытается подписаться повторно. Пошёл и исправил. Всё, конфликтной ситуации нет, исправлена на ранней стадии вместо отложенного выискивания багов к примеру из-за в два раза быстрее тикающего счётчика или невесть откуда появляющихся лишних объектов. Ещё в туже степь. Из моего собственного опыта эта гипотетическая ситуация с повторным подписыванием вообще маловероятна. Обычно я пишу свою функцию, класс, я же его и подписываю. Ещё раз, я не отвергаю на корню возможность иного, но очень хотелось бы конкретный пример, в терминах предметной области. Во, кстати, я еще досмотрел и такой вопрос: почему сигнал встраивается в слот? Можно же было бы сделать как-то так: obj:subscribe(signal,slot), тогда один слот мог бы быть подпинан на множество сигналов в разное время разным кодом. Так ведь наоборот, в сигнале хранятся ссылки на слоты, точнее на их дескрипторы. И вообще-то никто не мешает подписать одну функцию/метод класса на другой сигнал. Нельзя на один сигнал. Вообще-то, можно даже на один сигнал, но по одному в разноприоритетные очереди. Andrey07071977, В релизе нет необходимости вывода в лог и уж тем более крэшить игру Это не совсем так. Логи игры при вылетах - результат работы именно таких ассертов. Без них было бы совсем кисло =) (в разработке, кстати тоже нет смысла крэшить) Именно крэшить, в этом вся суть! Ассерт проверяет условие, нарушение которого приводит систему в неопределённое состояние. После того, как это условие нарушено, продолжать работу нельзя, надо остановиться и разбираться. И кстати, ассерты удаляют из релиза не потому, что бы они не крэшили релиз, а просто чтобы не занимали ресурсы на проверки. Подразумевается, что в релизе эти ассерты уже никогда-никогда не сработают =) Если по-серьёзному, то в нормально отлаженной программе именно так и происходит. Изменено 14 Января 2012 пользователем malandrinus Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Andrey07071977 18 Опубликовано 14 Января 2012 Поделиться Опубликовано 14 Января 2012 (изменено) malandrinus, Логи игры при вылетах - результат работы именно таких ассертов. Без них было бы совсем кисло =)Про ассерты писал исключительно в контексте проверки двойной подписки, т.е. если даже каким то образом это проникло в релиз, то просто return, без ассерта, без лога, и без приведения системы в поломанный стэйт. Именно крэшить, в этом вся суть!Дело в том что у меня на втором мониторе всегда открыта дополнительная консоль из luacap от alpet - очень рекомендую при отладке, сразу видно что и где происходит. Т.О. в моем случае крэшить смысла нет, и так сразу видно что произошла ошибка. В штатных же ситуациях, наверное ты прав, лучше сразу дать знать что произошла ошибка. Подразумевается, что в релизе эти ассерты уже никогда-никогда не сработают =)Ну и шуточки у вас, гражданин прокурор Добавлено через 20 мин.: П.С. Ладно, из'ездили уже тему про ассерты, пора завязывать . Итог, кому мешают - не сложно изменить. Изменено 14 Января 2012 пользователем Andrey07071977 Ссылка на комментарий
Viнt@rь 50 Опубликовано 15 Января 2012 Поделиться Опубликовано 15 Января 2012 Возможно не по теме топика пишу, но все же... 1. К примеру, уважаемая xStream, вот почему ты ограничиваешь себя стандартным обьемом для сохраняемых данных, в смысле почему бы не написать что-то на подобии лаунчера от Алпета: написать функции, которые бы сохраняли/загружали/удаляли данные в отдельный файл, в итоге не пришлось бы себя ограничивать тем мизерным обьемом для сохранения данных... ЗЫ это касается не только xStream :ny_smile: 2. malandrinus, по поводу x-ray extensions, не знаю говорили ли тебе про это или нет, но если врезать: "0x1022398D 5 global_space_ext" в xrGame.dll, то оно приводит к битым сейвам... GUI для конвертера от бардака(всего и вся в форматы сдк) Полезный утиль-"Utilits pack(mod)" Ссылка на комментарий
Monnoroch 6 Опубликовано 15 Января 2012 Поделиться Опубликовано 15 Января 2012 malandrinus, Ситуация простая: некий мододел захотел на непися повесить поведение при неком скриптовом событии - например при выбросе. А выброс, так как наша система работает вокруг слот-сигнальной модели, генерирует сигнал. Ну что делает мододел - подписывает слот на сигнал. А теперь другой мододел расщедрился и хочет подписать всех сталкеров на это поведение но не знает что один уже подписан. Вот пожалуйста, двойное подписываени. Слот при этом бутет выглядеть как-то, например, так: slt = {signal = "blowout", self = obj, fun = obj.hit} и так для всех сталкеров. Ну и что, вот человек отлаживает эти моды вместе и видит: в цикле по всем сталкерам оказывается один уже подписан! Ну хорошо, и что ему делать-то? Искать где подписан и отписывать? Это копошение во внутренней реализации мода - не есть хорошо при любом раскладе. Код должен иметь как можно меньшую связность. А если разрешить двойное подписание, то все разруливается: второе подписывание элементарно игнорируется, вернее увеличивается счетчик подписываний до двух. А когда кто-то отписывает его, счетчик уменьшается до одного. А потом до нуля - и тут физически происходит отписывание. А сигнал, сколько бы раз на него слот не подписался, вызывает его, естественно только один раз, зачем ему больше? Хотя тут можно даже параметр сделать, это дело настраивающий: один или несколько. Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти