Вывернутый (?) INotifyPropertyChanged
От: Fortnum  
Дата: 27.10.10 11:13
Оценка: 6 (1)
Во всех WPF фреймворках для контроллеров есть базовый класс, реализующий INotifyPropertyChanged. Например, в Caliburn — это класс PropertyChangedBase. Основная идея таких классов следующая:
  Скрытый текст
public class PropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

После чего становится несколько легче реализовать свойства наследников такого базого класса. Например:

  Скрытый текст
public class MyViewModel : PropertyChangedBase
{
   double _myValue;

    public double MyValue
    {
        get
        {
            return _myValue;
        }
        set
        {
            if (_myValue != value)
            {
                _myValue = value;

                OnPropertyChanged("MyValue");
            }
        }
    }
}


Но я нигде не встречал идею... вывернуть эту идею еще дальше. Поясню. Необходимо сделать такой базовый класс:

  Скрытый текст
public class ValueViewModel<T> : ViewModel
{
    T _value;

    public T Value
    {
        get
        {
            return _value;
        }
        set
        {
            if (!object.Equals(_value, value))
            {
                _value = value;

                OnPropertyChanged("Value");
            }
        }
    }
}


И реализация свойств контроллеров сведется к следующему:

public class MyViewModel : ViewModel
{
    public ValueViewModel<double> MyValueViewModel { get; set; }
}


Правда:
<!-- Вместо вот такого -->
<control MyValue="{Binding MyValue}"/>

<!-- Придется писать вот такое -->
<control MyValue="{Binding MyValueViewModel.Value}"/>


Но выгода же очевидна — не надо писать каждый раз get {}; set {}; и загромождать логику ViewModel'и.

Реализовать event'ы ValueChanging и ValueChanged также можно в этом MyValueViewModel.

Чем это плохо?
Re: Вывернутый (?) INotifyPropertyChanged
От: _FRED_ Черногория
Дата: 27.10.10 12:00
Оценка: 6 (1)
Здравствуйте, Fortnum, Вы писали:

F>Во всех WPF фреймворках для контроллеров есть базовый класс, реализующий INotifyPropertyChanged.


Ой как грусно. Устанавливать базу ради реализации одного единственного события — это

F>Но я нигде не встречал идею... вывернуть эту идею еще дальше. Поясню. Необходимо сделать такой базовый класс:

  Скрытый текст
F>public class ValueViewModel<T> : ViewModel
F>{
F>    T _value;

F>    public T Value
F>    {
F>        get
F>        {
F>            return _value;
F>        }
F>        set
F>        {
F>            if (!object.Equals(_value, value))
F>            {
F>                _value = value;

F>                OnPropertyChanged("Value");
F>            }
F>        }
F>    }
F>}

F>И реализация свойств контроллеров сведется к следующему:

F>Но выгода же очевидна — не надо писать каждый раз get {}; set {}; и загромождать логику ViewModel'и.

F>Реализовать event'ы ValueChanging и ValueChanged также можно в этом MyValueViewModel.

F>Чем это плохо?


Ну вот вы и "придумали" свои собственные свойства зависимостей

Мне больше понравилась такая вот
Автор: Visor2004
Дата: 01.09.10
идея реализации.
Help will always be given at Hogwarts to those who ask for it.
Re: Вывернутый (?) INotifyPropertyChanged
От: GlebZ Россия  
Дата: 27.10.10 12:17
Оценка:
Здравствуйте, Fortnum, Вы писали:

F> if (!object.Equals(_value, value))

Вот эта строчка может создавать проблемы
Re[2]: Вывернутый (?) INotifyPropertyChanged
От: Fortnum  
Дата: 27.10.10 14:29
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Ой как грусно. Устанавливать базу ради реализации одного единственного события — это


Ну там в конструкторе еще Dispatcher захватывается. А как иначе? Хотя бы то, что класс реализует интерфейс, надо где-то прописывать. А главное, это хоть как-то решает проблему — лучше, чем copy&paste, хотя не так давно я только так и делал — не умер

_FR>Ну вот вы и "придумали" свои собственные свойства зависимостей

_FR>Мне больше понравилась такая вот
Автор: Visor2004
Дата: 01.09.10
идея реализации.


Ну да Получается, что экземпляр DependencyProperty на стороне View мы моделируем отдельным объектом на стороне ViewModel. Почему нет? Как мне кажется, с точки зрения архитектуры вполне логично "объект-объект" , сокращение синтаксиса идет лишь как следствие, а не как цель. А в приведенном вами примере скоращение синтаксиса все-таки цель. К тому же, если я правильно понял, он применим лишь для проецирования свойств модели на свойства модели вида, что сразу кастрирует саму суть существования промежуточного слоя ViewModel — если перенос пропертей модели во ViewModel в проекте представляет такую трудоемкую задачу, почему бы для некоторых юзкейзов сразу не использовать MVC? По мне, гораздо эффектнее и полезнее выглядит вот этот метод из той же ветки
Автор: Пельмешко
Дата: 15.09.10
.

Кстати, отношение логических слоев ModelView<->View подобно отношению слоев Control<->ControlTemplate Но это не значит, что стоит отказываться от MVVM, а?

здесь

If you look at the WPF/SL control architecture, you’ll notice something quite interesting: A Control’s behavior and its View are separated. The platform splits controls into two parts, the Control class (ViewModel) and the ControlTemplate (View). Yes, one reason why MVVM makes sense is because the platform itself is architected in that way. Recalling the previous point: How do you describe the interaction between the Control Class and the ControlTemplate? TemplateBinding. Of coarse, you could venture to build your own MVVM architecture by creating your VMs as descendants of Control and then defining Views as ControlTemplates (please don’t do this). But, there is a better way. DataTemplates extend the same concept by allowing Views over any type of object.

Re[3]: Вывернутый (?) INotifyPropertyChanged
От: _FRED_ Черногория
Дата: 27.10.10 14:52
Оценка:
Здравствуйте, Fortnum, Вы писали:

_FR>>Ой как грусно. Устанавливать базу ради реализации одного единственного события — это


F>Ну там в конструкторе еще Dispatcher захватывается. А как иначе?


А сразу от DispatcherObjecta чего бы не унаследоваться тогда

F>Хотя бы то, что класс реализует интерфейс, надо где-то прописывать. А главное, это хоть как-то решает проблему — лучше, чем copy&paste, хотя не так давно я только так и делал — не умер


Да какой там копипаст — несколько простейших строк? Ерунда. Избегать [в разумных пределах] следует дублирования логики, а не строк. А логику можно вынести отдельно, но дв не об этом.

_FR>>Ну вот вы и "придумали" свои собственные свойства зависимостей

_FR>>Мне больше понравилась такая вот
Автор: Visor2004
Дата: 01.09.10
идея реализации.

F>Ну да Получается, что экземпляр DependencyProperty на стороне View мы моделируем отдельным объектом на стороне ViewModel. Почему нет? Как мне кажется, с точки зрения архитектуры вполне логично "объект-объект" , сокращение синтаксиса идет лишь как следствие, а не как цель. А в приведенном вами примере скоращение синтаксиса все-таки цель.

Синтаксиса чего? Объявления? Вовсе нет. Сокращение синтаксиса — это бенефит. Цель же — устранение того, что не нужно и метаподход к управлению свойствами, командами, коллекциями представления модели.

F>К тому же, если я правильно понял, он применим лишь для проецирования свойств модели на свойства модели вида, что сразу кастрирует саму суть существования промежуточного слоя ViewModel — если перенос пропертей модели во ViewModel в проекте представляет такую трудоемкую задачу, почему бы для некоторых юзкейзов сразу не использовать MVC? По мне, гораздо эффектнее и полезнее выглядит вот этот метод из той же ветки
Автор: Пельмешко
Дата: 15.09.10
.


Если речь о лямбдах — то это всё как раз костыли к сокращению копипаста. А преддложенный метод не позволяет сократить копипаст — он позволяет в корне избавиться от него.
Help will always be given at Hogwarts to those who ask for it.
Re: Вывернутый (?) INotifyPropertyChanged
От: cvetkov  
Дата: 27.10.10 15:16
Оценка:
я использую аналогичнвй велосипед. Есть только одно опасение, такое свойство можно передать куда нибуть в качестве параметра метода и она потеряет связь с родителем.
... << RSDN@Home 1.2.0 alpha 4 rev. 1227>>
Re: Вывернутый (?) INotifyPropertyChanged
От: Visor2004  
Дата: 28.10.10 08:41
Оценка:
Здравствуйте, Fortnum, Вы писали:

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

public class MyViewModel : ViewModel
{
    public ValueViewModel<double?> MyValueViewModel { get; set; }
}

...

var a = new MyViewModel();
if (a.Value.HasValue)
   Console.Write(a.MyValueViewModel.Value.Value);


Выглядит не очень хорошо. Я бился над проблемой ухода от постоянной копипасты всяких OnPropertyChanged более полугода, и пришел к выводу, что единственное решение проблемы — это расширение синтаксический сахар, все остальное имеет побочные эффекты — вы уменьшаете сложность описания свойства, но увеличиваете сложность его использования... Моя реализация с использованием PropertyDescriptor
Автор: Visor2004
Дата: 01.09.10
, особенно наглядно демонстрирует это. Потому берите какой-нить язык, позволяющий расширять свой синтаксис, тот же Nemerle я думаю отлично подойдет, пишите там необходимые расширения и реализуйте слой ViewModel на нем. Что-то типа такого:

public notificable decimal? Cost 
{ 
   get; 
   set; 
}


И будет вообще красота
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re[2]: Вывернутый (?) INotifyPropertyChanged
От: Fortnum  
Дата: 28.10.10 09:20
Оценка:
Здравствуйте, Visor2004, Вы писали:

V>Ваше решение обладает теми же недостатками, что и все, сделанные людьми решающими подобные задачи. В ряде кейсов, например:


Согласен Value.Value некрасиво. Надо что-нибудь другое придумать будет, .ValueOfProperty.Value, например

V>единственное решение проблемы — это расширение синтаксический сахар, все остальное имеет побочные эффекты — вы уменьшаете сложность описания свойства, но увеличиваете сложность его использования... [skip] Потому берите какой-нить язык, позволяющий расширять свой синтаксис


Да, наверное, это выход. Как в С++ в разных фреймворках, где повсеместно используют маросы #define, для радикального изменения логики класса.

Есть еще один вариант. Не могу, к сожалению, сейчас квалифицированно что-нибудь сказать по нему, но подкоркой чувствую, что должно работать. Это всяческие композитные классы типа прокси. Если не ошибаюсь Unity Application Block от Microsoft позволяет это делать, а еще может быть в новом С# есть подходящий функционал, да и самому реализовать можно. Ведь основная проблема — скомпоновать большой класс из отдельно отлаженных маленьких протомоделек (причем не просто перечень пропертей, но и перенос логики работы этих протомоделек), не переписывая эти модельки заново копипастой в этот большой класс. Если копипастить, можно partial воспользоваться Те же макросы это, по сути, та же композиция, только статическая. Т.е. в рантайме идентичность скомпонованных классов теряется. С прокси мне кажется вариант поинтереснее — например, можно включить один и тот же экземпляр протомодельки в два разных экземпляра ViewModel. Сейчас все то же самое можно сделать, только дерево ViewModel слишком ветвистое получается, что не способствует пониманию читаемого кода, плюс возможные накладки с именами ссылающихся друг на друга моделек.
Re[2]: Вывернутый (?) INotifyPropertyChanged
От: MxMsk Португалия  
Дата: 28.10.10 10:52
Оценка: +1 :)
Здравствуйте, Visor2004, Вы писали:

V>Выглядит не очень хорошо. Я бился над проблемой ухода от постоянной копипасты всяких OnPropertyChanged более полугода, и пришел к выводу, что единственное решение проблемы — это расширение синтаксический сахар, все остальное имеет побочные эффекты — вы уменьшаете сложность описания свойства, но увеличиваете сложность его использования... Моя реализация с использованием PropertyDescriptor
Автор: Visor2004
Дата: 01.09.10
, особенно наглядно демонстрирует это. Потому берите какой-нить язык, позволяющий расширять свой синтаксис, тот же Nemerle я думаю отлично подойдет, пишите там необходимые расширения и реализуйте слой ViewModel на нем. Что-то типа такого:

Оффтоп, конечно, но, господа, я поражаюсь советам в стиле "берите какой-нить язык". Вот прям взяли так всё бросили, крикнули заказчикам, что уходим на полгода в монастырь, откопали за приемлемый уровень зарплаты программеров, владеющих экзотическим языком, и ради чего? Ради одного несчастного события PropertyChanged? Нет уж.
Re[3]: Вывернутый (?) INotifyPropertyChanged
От: Visor2004  
Дата: 28.10.10 11:25
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>Здравствуйте, Visor2004, Вы писали:


V>>Выглядит не очень хорошо. Я бился над проблемой ухода от постоянной копипасты всяких OnPropertyChanged более полугода, и пришел к выводу, что единственное решение проблемы — это расширение синтаксический сахар, все остальное имеет побочные эффекты — вы уменьшаете сложность описания свойства, но увеличиваете сложность его использования... Моя реализация с использованием PropertyDescriptor
Автор: Visor2004
Дата: 01.09.10
, особенно наглядно демонстрирует это. Потому берите какой-нить язык, позволяющий расширять свой синтаксис, тот же Nemerle я думаю отлично подойдет, пишите там необходимые расширения и реализуйте слой ViewModel на нем. Что-то типа такого:

MM>Оффтоп, конечно, но, господа, я поражаюсь советам в стиле "берите какой-нить язык". Вот прям взяли так всё бросили, крикнули заказчикам, что уходим на полгода в монастырь, откопали за приемлемый уровень зарплаты программеров, владеющих экзотическим языком, и ради чего? Ради одного несчастного события PropertyChanged? Нет уж.

А почему поражаетесь? есть люди для которых этот вариант работает, например, я в конце концов так и поступил. Не хотите/не можете использовать, не используйте, никто не заставляет. Я в своем ответе указал на то, что за полгода разных проб так и не удалось найти вариант для C#, который бы удовлетворял критериям простоты использования и простоты декларации свойств, отсюда и рекомендация сменить язык. Более того, я привел ссылку на альтернативный C# подход. Что возмутительного вы находите?
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re[3]: Вывернутый (?) INotifyPropertyChanged
От: Visor2004  
Дата: 28.10.10 11:30
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>Есть еще один вариант. Не могу, к сожалению, сейчас квалифицированно что-нибудь сказать по нему, но подкоркой чувствую, что должно работать. Это всяческие композитные классы типа прокси. Если не ошибаюсь Unity Application Block от Microsoft позволяет это делать, а еще может быть в новом С# есть подходящий функционал, да и самому реализовать можно. Ведь основная проблема — скомпоновать большой класс из отдельно отлаженных маленьких протомоделек (причем не просто перечень пропертей, но и перенос логики работы этих протомоделек), не переписывая эти модельки заново копипастой в этот большой класс. Если копипастить, можно partial воспользоваться Те же макросы это, по сути, та же композиция, только статическая. Т.е. в рантайме идентичность скомпонованных классов теряется. С прокси мне кажется вариант поинтереснее — например, можно включить один и тот же экземпляр протомодельки в два разных экземпляра ViewModel. Сейчас все то же самое можно сделать, только дерево ViewModel слишком ветвистое получается, что не способствует пониманию читаемого кода, плюс возможные накладки с именами ссылающихся друг на друга моделек.


Инфраструктура для таких протомоделек присутствует во фреймворке начиная с первых его версий, по сути вы только что описали взаимосвязь между TypeDescriptor и PropertyDescriptor. Этот подход не облегчает жизни в большинстве кейсов.
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re[4]: Вывернутый (?) INotifyPropertyChanged
От: MxMsk Португалия  
Дата: 28.10.10 11:31
Оценка:
Здравствуйте, Visor2004, Вы писали:

V>А почему поражаетесь? есть люди для которых этот вариант работает, например, я в конце концов так и поступил. Не хотите/не можете использовать, не используйте, никто не заставляет. Я в своем ответе указал на то, что за полгода разных проб так и не удалось найти вариант для C#, который бы удовлетворял критериям простоты использования и простоты декларации свойств, отсюда и рекомендация сменить язык. Более того, я привел ссылку на альтернативный C# подход. Что возмутительного вы находите?

Да что-то уж больно много почестей уделяется PropertyChanged
Re[5]: Вывернутый (?) INotifyPropertyChanged
От: Visor2004  
Дата: 28.10.10 11:44
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>Здравствуйте, Visor2004, Вы писали:


V>>А почему поражаетесь? есть люди для которых этот вариант работает, например, я в конце концов так и поступил. Не хотите/не можете использовать, не используйте, никто не заставляет. Я в своем ответе указал на то, что за полгода разных проб так и не удалось найти вариант для C#, который бы удовлетворял критериям простоты использования и простоты декларации свойств, отсюда и рекомендация сменить язык. Более того, я привел ссылку на альтернативный C# подход. Что возмутительного вы находите?

MM>Да что-то уж больно много почестей уделяется PropertyChanged

Ну, наверное, потому что не нравится людям все время писать одинаковый код. А нормального решения сходу придумать нельзя, вот и изголяется кто как может... Но вообще, я заметил, что в сложном софте, при изменении свойства его надо сразу валидировать, обновлять undo стек и еще кучу всякой дряни делать, потому где-то в 60% своих ViewModel я продолжаю использовать кастомный PropertyDescriptor, в котором вся эта логика реализована.
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re[5]: Вывернутый (?) INotifyPropertyChanged
От: Visor2004  
Дата: 28.10.10 11:46
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>Здравствуйте, Visor2004, Вы писали:


V>>А почему поражаетесь? есть люди для которых этот вариант работает, например, я в конце концов так и поступил. Не хотите/не можете использовать, не используйте, никто не заставляет. Я в своем ответе указал на то, что за полгода разных проб так и не удалось найти вариант для C#, который бы удовлетворял критериям простоты использования и простоты декларации свойств, отсюда и рекомендация сменить язык. Более того, я привел ссылку на альтернативный C# подход. Что возмутительного вы находите?

MM>Да что-то уж больно много почестей уделяется PropertyChanged

Классическая задача о предоставлении сквозного функционала, в С# нет нормальных средств для реализации сквозной функциональности, только пара тяжеловесных фреймворков и PostSharp, на который у меня лично аллергия просто, хз почему, наверное, хочется средство из коробки.
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re[4]: Вывернутый (?) INotifyPropertyChanged
От: Fortnum  
Дата: 28.10.10 11:49
Оценка:
Здравствуйте, Visor2004, Вы писали:

V>Инфраструктура для таких протомоделек присутствует во фреймворке начиная с первых его версий, по сути вы только что описали взаимосвязь между TypeDescriptor и PropertyDescriptor. Этот подход не облегчает жизни в большинстве кейсов.


Инфраструктура присутствует, но общепринятое законченное решение отсутствует, либо еще не широко распространено или я до него не дорос Хотя оно сюда так и напрашивается. Если не ошибаюсь, должно быть что-то похожее на Remoting, и поддержка решения на том же уровне.
Re[5]: Вывернутый (?) INotifyPropertyChanged
От: Visor2004  
Дата: 28.10.10 11:52
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>Инфраструктура присутствует, но общепринятое законченное решение отсутствует, либо еще не широко распространено или я до него не дорос Хотя оно сюда так и напрашивается. Если не ошибаюсь, должно быть что-то похожее на Remoting, и поддержка решения на том же уровне.


Она очень широко распространения при написании WinForms компонент.
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re[6]: Вывернутый (?) INotifyPropertyChanged
От: Fortnum  
Дата: 28.10.10 11:54
Оценка:
Здравствуйте, Visor2004, Вы писали:

V>Она очень широко распространения при написании WinForms компонент.


Не понял, в стандартном .NET есть готовое решение по динамическому сливанию двух классов в один?
Re[7]: Вывернутый (?) INotifyPropertyChanged
От: Visor2004  
Дата: 28.10.10 12:04
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>Здравствуйте, Visor2004, Вы писали:


V>>Она очень широко распространения при написании WinForms компонент.


F>Не понял, в стандартном .NET есть готовое решение по динамическому сливанию двух классов в один?


Почитайте здесь. С помощью этого можно реализовывать и более сложные сценарии, чем просто слияние классов.
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re[3]: Вывернутый (?) INotifyPropertyChanged
От: _FRED_ Черногория
Дата: 28.10.10 12:21
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>Оффтоп, конечно, но, господа, я поражаюсь советам в стиле "берите какой-нить язык". Вот прям взяли так всё бросили, крикнули заказчикам, что уходим на полгода в монастырь, откопали за приемлемый уровень зарплаты программеров, владеющих экзотическим языком, и ради чего? Ради одного несчастного события PropertyChanged? Нет уж.


Ну многие так же думают о переходе с C#2 на C#3 (не говоря уже о более позднем) Категорически не воспринимают (не знают ) var, автосвойства и прочие _мелочи_ (о более концептуальных вещах я не говорю). И это тоже можно объяснить, если захотеть

При этом, если раньше всё делалось на раби, то перейти на пайтон или люа проблем почему-то обычно не составляет (ещё один необъяснимый преимущество/недостаток динамических языков?)

Так что "взять какой-нить язык" совсем не сложно — проблему представляет не "язык", ни даже "взять", а то, что "есть". Но есть оно (то что "есть") подходяще, то и "взять" не сложно.
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Вывернутый (?) INotifyPropertyChanged
От: MxMsk Португалия  
Дата: 28.10.10 12:36
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, MxMsk, Вы писали:


MM>>Оффтоп, конечно, но, господа, я поражаюсь советам в стиле "берите какой-нить язык". Вот прям взяли так всё бросили, крикнули заказчикам, что уходим на полгода в монастырь, откопали за приемлемый уровень зарплаты программеров, владеющих экзотическим языком, и ради чего? Ради одного несчастного события PropertyChanged? Нет уж.


_FR>Ну многие так же думают о переходе с C#2 на C#3 (не говоря уже о более позднем) Категорически не воспринимают (не знают ) var, автосвойства и прочие _мелочи_ (о более концептуальных вещах я не говорю). И это тоже можно объяснить, если захотеть

Ну ты сравнил: смена версии языка и смена не только языка, но и парадигмы. Понятно, что можно, если захотеть. Но нужны еще скажем так и экономические обоснования. Я бы с удовольствием сейчас всё бросил и плюхнулся в какой-нибудь другой Nemerle или F#. Вот только деньги я не сам себе плачу и код не для себя пишу

_FR>При этом, если раньше всё делалось на раби, то перейти на пайтон или люа проблем почему-то обычно не составляет (ещё один необъяснимый преимущество/недостаток динамических языков?)

_FR>Так что "взять какой-нить язык" совсем не сложно — проблему представляет не "язык", ни даже "взять", а то, что "есть". Но есть оно (то что "есть") подходяще, то и "взять" не сложно.
В моем случае взять и перейти сложно потому, что это не представляет выгоды. Мы на написание свойств моделей тратим в разы меньше времени, чем на весь остальной функционал. Прихожу я значит к начальству и говорю: "Вы знаете, задолбался я писать PropertyChanged. Давайте перепишем проект на другой язык" Да ладно бы язык был более менее снабжен адекватными средствами, так ведь нет, даже долбанный F# и тот плоховато ложиться на WPF. Так что
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.