LINUX.ORG.RU

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

ООП ради ООП?

ООП ради ради удобства. Хотя я предпочел бы протитипное ООП. Но и классовое в Руби сделано действительно хорошо.

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

всего лишь тупая обёртка

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

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

len() — всего лишь тупая обёртка, чтобы дергать метод объекта. Что и требовалось доказать.

Кому требовалось, почему «доказать»? Это общеизвестная вещь.

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

питон позиционирует себя как дак-тайпед язык(если я не ошибаюсь), в таком случае этот ваш «абстрактный» len непонятно откуда взялся и по всему видимо не нужен.

Если белочка, то шкаф?

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

интересная трактовка дак-тайпинга...

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

Соглашения никогда не работают.

__len__

Капитан подсказывает, что что-то тут не так.

И кстати в рубях, AFAIK, тоже зоопарк с count, size и length.

count — считает объекты по условию. size возвращает количество элементов в контейнере. length — синоним для size. Кончай придуриваться.

Или ты предлагаешь прописать его в базовый класс?

Ты smalltalk-like ООП попутал с C++-like.

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

Кому требовалось, почему «доказать»? Это общеизвестная вещь.

Баверману. Но он нихрена не понял всё равно.

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

Соглашения никогда не работают.
__len__

Капитан подсказывает, что что-то тут не так.

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

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

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

Ты жжошь напалмом.

class Object
    def len(v)
         v.size
    end
end

p len([1, 2, 3, 4])
p len("qwerty")

:-D

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

Кому требовалось, почему «доказать»? Это общеизвестная вещь.

Баверману

О, ему это точно не требовалось.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner
object.__len__(self)

    Called to implement the built-in function len(). Should return the length of the object, an integer >= 0. Also, an object that doesn’t define a __nonzero__() method and whose __len__() method returns zero is considered to be false in a Boolean context.

И что мешает переопределить __len__ так, чтобы он возвращал херню вместо количества элементов контейнера?

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

И что мешает переопределить __len__ так, чтобы он возвращал херню вместо количества элементов контейнера?

Ничего не мешает. Но интерпретатор бросит исключение, если ты не вернешь int.

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

Но интерпретатор бросит исключение, если ты не вернешь int.

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

Но интерпретатор бросит исключение, если ты не вернешь int.

А как же дактайпинг, бро?!

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

Внезапно, в Ruby интерпретатор тоже бросит исключение

(пожимая плечами) Ну и славно.

А как же дактайпинг, бро?!

Выражайся яснее.

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

«Если нечто ведёт себя как X, то это X.» Подставляя Int вместо X, получаем, получаем...

интерпретатор бросит исключение, если ты не вернешь int

Упс. Херню получаем.

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

«Если нечто ведёт себя как X, то это X.» Подставляя Int вместо X, получаем, получаем...

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

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

А если тебе нужно совершенно левый класс, ну что ж... ты хочешь странного.

А мужики-то не знают.

В спецификации языка написано int, значит - int. А для чего мужикам понадобилось, чтобы len() возвращал объект левого класса (не производный от int)?

tailgunner ★★★★★
()

Руби-фанбои такие забавные.

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

Декораторы являются стандартным средством расширения функциональности

Декоратор - это не «стандартное средство расширение функциональности», а *сахар* для «стандартного средства расширения функциональности». Без этого сахарка реализация мультиметодов с помощью функций-оберток вообще была бы неюзабельная.

а доказательство по аналогии является мошенничеством.

С помощью аналогии я назвал предоставляемые решения костылем

А выпилили их потому, что больше не нужны.

Потому что они стали избыточны и смотрелись бы костылем для поддержки обратной совместимости. То есть вопросы костыльности (в какой-то мере) волнуют даже Гвидо

Каппризы.

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

Не нравится - сделай свое (на функцию можно навесить атрибуты, если тебе не нравятся классы).

Красивых реализаций мультиметодов для питона я не встречал. И не уверен, что смогу сделать что-либо приемлемое самостоятельно.

private - это далеко не свое ООП.

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

На практике, это одно и то же (а в теории, рефлексия - надмножество интроспекции).

Не совсем точно, но пусть будет

Так что тебе мешает реализовать и то, и другое?

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

Это да. Хотя try-except-finally уже добавили, да и его отсуствие в основном раздражало теоретически, эти претензии уже ближе к реальности.

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

От себя добавлю жалобу на отсуствие pattern matching

А мне вот кажется, что паттерн матчинг - весьма опасная техника: вместо того, чтобы продумать более менее строгий алгоритм мы начинаем играть в какие-то детский игры полные императива и частных случаев - «если это, то се, если то - то это, ой забыл еще вон то, и вон там если чо, на всякий случай».

Но пойнт в том, что полного набора желаемых фич нет вообще нигде

Естественно, хотя бы потому что «полный набор желаемых фич» у всех разный.

, а по балансу Питон на первом месте.

А что имеешь против nemerle? Не учитывая наличие реализации исключительно для clr...

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

«Если нечто ведёт себя как X, то это X.» Подставляя Int вместо X, получаем, получаем...

...что к X можно обращаться, как к Int. Даже если X интом не является, но умеет его имитировать.

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

Декоратор - это не «стандартное средство расширение функциональности», а *сахар* для «стандартного средства расширения функциональности»

Да никакой разницы. Средство есть? Да. Оно решает задачу? Да. Всё, вопрос закрыт.

Для меня всегда было дикостью в ооп, что ручка имеет набор методов рисовать_на_бумаге, рисовать_на_гофрокартоне, писать_на_пипирусе

Претензии к Кею.

ооп питона + приват - это именно что «свое ооп».

От «свое ООП» я таки ожидал большего.

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

Какие-то методы интроспекции в питоне-таки есть.

«Какие-то». Бгг.

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

То же самое можно сказать о switch и даже if (собственно, pattern matching - это и есть обобщение if; даже обобщенные функции CLOS - pattern matching).

А что имеешь против nemerle

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

Не учитывая наличие реализации исключительно для clr...

Если убрать из рассмотрения CLR, стремно ставить на язык, за которым нет значительного сообщества и/или мощной корпорации.

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

Да никакой разницы. Средство есть? Да. Оно решает задачу? Да. Всё, вопрос закрыт.

Если тебя устраивает такое решение - то закрыт. Меня нет.

Претензии к Кею.

В том-то и дело, что есть более человеческое ооп. Да, в CL.

От «свое ООП» я таки ожидал большего.

Если бы не вырывал одно предложение из абзаца, возможно, не только бы ожидал, но и прочитал о большем.

Вообще удивляет, насколько неглубоки претензии к Питону.

Это претензии к ооп питона, а не к питону.

Даже я мог бы придраться весомее.

Попробуй.

То же самое можно сказать о switch и даже if (собственно, pattern matching - это и есть обобщение if;

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

даже обобщенные функции CLOS - pattern matching).

Объекты - императивны по своей сути, в отличии от функций. В случае с generic functions мы *специализируем* их по объекту, то есть всего лишь говорим с объектами какого рода она работает. Сама же реализация функции может быть вполне декларативна. Ты бы еще полиморфизм назвал паттерн-матчингом. А объекты CLOS - конс ячейками %)

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

Не учитывая clr, отсутствие большого сообщества и поддержки корпорацией - в чем проблемы?

// примечательно, что ты проигнорировал замечание об идентификации конца блока в python

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

А мне вот кажется, что паттерн матчинг - весьма опасная техника: вместо того, чтобы продумать более менее строгий алгоритм мы начинаем играть в какие-то детский игры полные императива и частных случаев - «если это, то се, если то - то это, ой забыл еще вон то, и вон там если чо, на всякий случай».

Если реализация нормальная, то такого не может быть - она скажет, если какие-то clauses забыли. Ну и PM это if/cond/switch на стероидах, а если он ещё и к месту (к ADT), то вовсе оказывается одним из самых органичных выразительных средств языка.

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

а паттерн матчинг - отличный стимул делать это и на уровне определения функций - отрубили еще одну руку декларативности.

Посмотри как он сделан в ML / Haskell / Coq - он как раз добавляет новое измерение декларатвности.

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

Даже я мог бы придраться весомее.

Попробуй.

Выражения. Руби expression-oriented, IIRC. Вот этого в Питоне реально иногда реально не хватает. По сравнению с этим, многострочные лямбды - ерунда.

даже обобщенные функции CLOS - pattern matching).

Объекты - императивны по своей сути, в отличии от функций.

В огороде бузина.

В случае с generic functions мы *специализируем* их по объекту, то есть всего лишь говорим с объектами какого рода она работает

И если это не pattern matching, то что это?

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

Не учитывая clr, отсутствие большого сообщества и поддержки корпорацией - в чем проблемы?

Ты уже поместил язык в вакуум. Скоро ты придашь ему шарообразную форму?

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

примечательно, что ты проигнорировал замечание об идентификации конца блока в python

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

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

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

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

Бред ушибленного хаскелем.

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

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

Бред ушибленного хаскелем.

Я согласен на ML, но даже в этом случае ты мне льстишь %)

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

Выражения. Руби expression-oriented, IIRC. Вот этого в Питоне реально иногда реально не хватает. По сравнению с этим, многострочные лямбды - ерунда.

В руби считается нормой писать в таком стиле: line = inf.readline while line != «what I'm looking for». Тебе expression-oriented python нужен для этого? Или влом return/yield писать?

В огороде бузина.

«pattern matching» (который на самом деле полиморфизм) в CLOS - оправдан.

Ты уже поместил язык в вакуум. Скоро ты придашь ему шарообразную форму?

Меня интересуют в первую очередь лингвистические проблемы и выразительные средства самого *языка*. А не сложившаяся во круг него ситуация, не связанная с предлагаемыми им средствами.

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

Об идентации я не сказал не слова, меня интересует идентификация *конца* блока. С отступами в питоне как раз-таки все норм.

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

В руби считается нормой писать в таком стиле: line = inf.readline while line != «what I'm looking for». Тебе expression-oriented python нужен для этого? Или влом return/yield писать?

Для всего (хотя yield всё равно придется писать).

Меня интересуют в первую очередь лингвистические проблемы и выразительные средства самого *языка*

Я уже несколько раз сказал - с ними всё прекрасно (насколько я могу судить).

Об идентации я не сказал не слова, меня интересует идентификация *конца* блока

Похоже, ты не понял, зачем нужна идентация. Ты вообще на Питоне работаешь?

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

Используя pattern matching, что мы всегда перечисляем частные случаи.

Мы скорее делаем так - даём себе понятие о типе исходных данных A, типе целевых данных B, затем о контракте необходимой функции, например, f : A -> B, после этого мы покрываем все casы этой f:

data A ...
data B ...

f : A -> B
f ...

т.е. идём, всё-таки, от общей спецификации данных к контрактам функций и к частному - к тому как конкретные функции работают с данными. Структуры данных + алгоритмы. Если первые это просто ADT (некоторые индуктивные конструкции, пусть, множества), а вторые - чистые функции (математически), то всё несколько упрощается, появляется возможность использовать нормальный PM. Если даже не только ADT и ещё и грязные функции - какой-то PM всё равно можно организовать.

Если при этом мы потеряем case в определении, например:

tail (_:xs) = xs

foo 0 = 0
foo 1 = 1
foo 2 = 2

то получим:

    Warning: Pattern match(es) are non-exhaustive
             In an equation for `tail': Patterns not matched: []

    Warning: Pattern match(es) are non-exhaustive
             In an equation for `foo':
                 Patterns not matched: #x with #x `notElem` [0#, 1#, 2#]

(в каком-то языке это могут быть и ошибки) и допишем:

tail [] = []
tail (_:xs) = xs

foo 0 = 0
foo 1 = 1
foo 2 = 2
foo _ = ...

это же касается любого возможного вложенного паттерн-матчинга (NPM = nested pattern matching).

Почему это так - PM в данном языке это как такого рода функции в математике:

      /
      | x if x >= 0
|x| = <
      | -x if x < 0
      \

т.е. конечный набор термов с предикатами на аргументах - при истинности предиката при данных значениях аргументов за определение функции принимается ассоциированный с предикатом терм. В ЯП PM+guards это точно то же самое, с той лишь разницей, что термы и предикаты это нечто ограниченное (restricted, впрочем, с точки зрения формальной логики и теории типов ЯП может быть настолько мощным, что это будет просто одно и то же, с точностью до изоморфизма [CH]). В математике существует понятие тотальности функций, точно также в ЯП может существовать понятие тотальности определения PM по своим casам (хотя это не гарантирует тотальности функции вообще).

Так или иначе, PM это нечто, что компилируется:

not True = False
not False = True

после устранения top-level PM превращается в case expression:

not x = case x of
  True -> False
  False -> True

потом NPM в case (в этом примере этого нет) компилируется (и тут есть свои тонкости и возможные оптимизации) в обычный PM и далее в примитивы let / case_i / get_k (i-ый тип, k-ый аккессор - это, фактически, и есть низкоуровневые switch по type tagу и аккессоры структур).

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

В руби считается нормой писать в таком стиле: line = inf.readline while line != «what I'm looking for». Тебе expression-oriented python нужен для этого?

Не понятно только, при чем тут expression-oriented.

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

а паттерн матчинг - отличный стимул делать это и на уровне определения функций - отрубили еще одну руку декларативности.

Посмотри как он сделан в ML / Haskell / Coq - он как раз добавляет новое измерение декларатвности.

Херня это а не декларативность. Сравни:

factorial 0 = 1
factorial n | n > 0 = n * factorial (n-1)

factorial n = foldr (*) 1 [1..n]

Не лиспе декларативный алгоритм выглядит, естественно, еще лучше ввиду префиксной нотации.

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

Похоже, ты не понял, зачем нужна идентация.

Отделяет начало блока, его продолжение и окончание. Вот с первыми двумя задачами идентация справляется хорошо, с последней - плохо. Что неясно?

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

Не понятно только, при чем тут expression-oriented.

Неудачный пример. Имелось ввиду что-то типа if(obj=xz.get_value())... где в if мы можем вставить сколько угодно длинное выражение, которое вернет значение и одновременно выполнит операцию присваивания (так можно делать в С, perl). И это значение сравнить с чем-нибудь или использовать как условие для дальнейшего выполнения блока.

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

Ахренеть.

Я рассматриваю только визуальный аспект (синтаксис) с т.з. программиста. И удобство с таким синтаксисом работать. Понятно, что идентация (для компилятора) нужна как замена begin-end.

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

Я рассматриваю только визуальный аспект (синтаксис) с т.з. программиста

Ты первый, кто считает, что идентация «отделяет начало, тело и окончание». Обычно люди считают что-то вроде «отражает логическую вложенность операторов».

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

Блин, вы задолбали о питоне флеймить! Тема же о руби. Мне, вот, лично интересно было бы прочитать, какие фичи своего любимого языка рубисты считают удачными. А они, хитрым образом, перевели стрелки на недостатки питона, а питонисты купились на такой примитивный троллинг.

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

Имелось ввиду что-то типа if(obj=xz.get_value())... где в if мы можем вставить сколько угодно длинное выражение, которое вернет значение и одновременно выполнит операцию присваивания (так можно делать в С, perl).

Снова неудачный пример. Вкури вот это в качестве удачного примера:

def bar
	"Hello"
end

def baz
	1/0
end


puts (begin
	bar
rescue
	"error"
end)

puts (begin
	baz
rescue
	"error"
end)
geekless ★★
()
Ответ на: комментарий от quasimoto

«pattern matching» (который на самом деле полиморфизм) в CLOS - оправдан.

Какой полиморфизм?

В чем вопрос? Специализация (в обычных языках) метода по одному классу - полиморфизм, который реализуется через перегрузку. Специализация метода по нескольким классам (типам объектов) в CLOS - суть тот же механизм, перегрузка. Если множественную диспетчеризацию в CLOS можно назвать паттерн матчингом, то ее же можно назвать и вермешелью из if-ов (потому что паттерн матчинг это switch, а switch это if). И прийти вообще к каким-то ацким терминологическим бредням. Призываю с этим завязывать.

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

Сравни

Не пиши факториала. Или по крайней мере пиши как product [1 .. n].

Не лиспе декларативный алгоритм выглядит, естественно, еще лучше ввиду префиксной нотации.

Давай немножко в сторону от «декларативного факториала»?

Что-нибудь вроде бинарной сериализации. Или интерпретатора / компилятора. Есть такая книжка «Modern Compiler Implementation in ML» (потом появились версии для си и джавы). ML был выбран не случайно, как пишет автор.

Но это бессмысленно обсуждать - разработка в типах / функциях ML-ей похожа на разработку в классах / мультиметодах CLOS. А «декларативность» тут - какое-то слово-паразит (особенно после того как оказывается, что паттерн-матчинг это императивщена и портит «декларативность» языка), вот language agnostic design concepts полезнее.

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

Ты первый, кто считает, что идентация «отделяет начало, тело и окончание».

Обычно люди считают что-то вроде «отражает логическую вложенность операторов».

Жесть. Еще раз, как синтаксически (для программиста - визуально) мы идентифицируем средства для «отражения логической вложенности операторов»?

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

Блин, вы задолбали о питоне флеймить! Тема же о руби.

(сурово) Мы занимкаемся любимым делом везде, где это возможно.

А они, хитрым образом, перевели стрелки на недостатки питона, а питонисты купились

Мы не могли молчать!!111

Но вообще-то перечислено достаточно черт Руби, которые считают удачными. Собственно, их две: Ъ-ООП и метапрограммирование. <fat>Но, понятное дело, чувствуя слабость своей позиции, рубисты спрятались за троллингом</fat>

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

Еще раз, как синтаксически (для программиста - визуально) мы идентифицируем средства для «отражения логической вложенности операторов»?

Вложенность отражается отступами. Начало блока - первая строка блока, конец блока - последняя строка. Что непонятно?

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

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

Дык любому рубисту фичи очевидны.

1. Всё есть выражение. (За редким исключением.)

2. Блоки + соответствующая поддержка в стандартной библиотеке, позволяющая удобно писать в функциональном стиле.

3. catch-throw для выхода из глубоко вложенных конструкций. (Не путать с begin-raise-rescue-ensure-end.)

4. Модули. Примеси.

5. Разные мелкие удобства типа %w и т.п.

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