Re[5]: Вопрос по кодонаписанию
От: Тычеблин Китай  
Дата: 10.01.06 13:27
Оценка:
Здравствуйте, Airat Burganov, Вы писали:

AB>В вашей способности объяснять и понимать я уже не сомневаюсь. Ее просто нет.


ну так мы не волшебники, мы только учимся....
Re[4]: Вопрос по кодонаписанию
От: dshe  
Дата: 10.01.06 13:29
Оценка: 5 (1)
Здравствуйте, Airat Burganov, Вы писали:

D>>То они в равной степени предоставляют "структурную" информацию. Оба эти варианта говорят о том, что comp позволяет подписаться на определенное событие.

AB>(Не касаясь того, как это будет реализованно)
AB>Да.. структурно. Но вас не смущает то, что onComponentEvent — public переменная?

Немного смущает. Впрочем, можно заменить прямой доступ к переменной вызовом метода. Также, поскольку в той моей оригинальной реализации метод fire() будет "светиться" подписчикам, думаю, что имело бы смысл выделить интерфейс для подписки
public interface Subscription<T> {
    public void add(T o);
    public void remove(T o);
}

public final class Multicast<T> implements Subscription<T> {
    // . . .
}

И вот уже после этого сделать метод, который возвращает Subscription<T>, а не Multicast<T>.
    protected final Multicast<ComponentListener> onComponentEventMulticast = Multicast.create(ComponentListener.class);
    public Subscription<ComponentListener> onComponentEvent() {
        return onComponentEventMulticast;
    }


D>>Однако, если реализовать подписку классическим вариантом, то можно заметить, что много кода буквально дублируется. Код подписки для различных listener'ов похож до безобразия. Поэтому было бы неплохо его написать один раз и потом использовать (а не переписывать для каждого типа listener'а заново).

AB>Вот это действительно очень надоедливая штука. Правда есть EventListenerList, который во-многом позволяет смириться с этим.

К сожалению, EventListenerList не освобождает от необходимости переписывать каждый раз
 protected void fireFooXXX() {
     // Guaranteed to return a non-null array
     Object[] listeners = listenerList.getListenerList();
     // Process the listeners last to first, notifying
     // those that are interested in this event
     for (int i = listeners.length-2; i>=0; i-=2) {
         if (listeners[i]==FooListener.class) {
             // Lazily create the event:
             if (fooEvent == null)
                 fooEvent = new FooEvent(this);
             ((FooListener)listeners[i+1]).fooXXX(fooEvent);
         }
     }
 }
--
Дмитро
Re[5]: Вопрос по кодонаписанию
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 10.01.06 13:51
Оценка:
Здравствуйте, dshe, Вы писали:

D>К сожалению, EventListenerList не освобождает от необходимости переписывать каждый раз

D>
D> protected void fireFooXXX() {
D>     // Guaranteed to return a non-null array
D>     Object[] listeners = listenerList.getListenerList();
D>     // Process the listeners last to first, notifying
D>     // those that are interested in this event
D>     for (int i = listeners.length-2; i>=0; i-=2) {
D>         if (listeners[i]==FooListener.class) {
D>             // Lazily create the event:
D>             if (fooEvent == null)
D>                 fooEvent = new FooEvent(this);
D>             ((FooListener)listeners[i+1]).fooXXX(fooEvent);
D>         }
D>     }
D> }
D>


Ну так это необходимо для внесения оптимизаций в цикл малтикаста события. Не уверен что эта оптимизация очень сильно влияет на производительность, но небольшой выйгрыш давать должна, иначе ее бы тут не было. В твоем случае необходимо предусматривать каллбак интерфейс для взаимодействия мальтикастера с контекстом его вызова. К сожалению в java нет гибких и простых способов передачи контекста в вызываемый метод.
#333355130
Re[6]: Вопрос по кодонаписанию
От: C0s Россия  
Дата: 10.01.06 14:23
Оценка:
Здравствуйте, Lucker, Вы писали:

L>К сожалению в java нет гибких и простых способов передачи контекста в вызываемый метод.


может я и вырываю из контекста фразу, но мне кажется, что гибкие способы передать контекст в вызываемый метод существуют, а простота/сложность тех трех-четырех известных мне — понятие уже исключительно субъективное, зависящее от привычки, знания языка и непосредственно решаемой задачи

D>>К сожалению, EventListenerList не освобождает от необходимости переписывать каждый раз
protected void fireFooXXX()


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


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

ps. а если уж полной придираться, то я бы назвал метод getListeners(), т.к. предпочитаю избегать тавтологий в названиях, а в данном случае видим еще и то, что метод с суффиксом List на самом деле возвращает Array, но это уже все offtopic
Re[7]: Вопрос по кодонаписанию
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 10.01.06 14:42
Оценка:
Здравствуйте, C0s, Вы писали:

L>>К сожалению в java нет гибких и простых способов передачи контекста в вызываемый метод.


C0s>может я и вырываю из контекста фразу, но мне кажется, что гибкие способы передать контекст в вызываемый метод существуют, а простота/сложность тех трех-четырех известных мне — понятие уже исключительно субъективное, зависящее от привычки, знания языка и непосредственно решаемой задачи


Да ладно . Нету в java одновременно гибкие и в то же время простого способа передачи контекста (в данном случае нужно иметь возможность этот контекст модифицировать).

C0s>что касается кода, то субъективно мне он не нравится, прежде всего, сама идея по-разному организовывать циклический перебор

C0s>в том смысле, что массив, как мне кажется, из вызова getListenerList() уже должен приходить отфильтрованный массив
C0s>ps. а если уж полной придираться, то я бы назвал метод getListeners(), т.к. предпочитаю избегать тавтологий в названиях, а в данном случае видим еще и то, что метод с суффиксом List на самом деле возвращает Array, но это уже все offtopic

есть еще public EventListener[] getListeners(Class t), но его вероятно не используют все с той же целью оптимизации, дабы не создавать новый массив при каждом чихе.
#333355130
Re[2]: Вопрос по кодонаписанию
От: Тычеблин Китай  
Дата: 10.01.06 14:43
Оценка:
Здравствуйте, dshe, Вы писали:

вот тут Андрей Вишневкий построил фрэймворк там ваще очень интересные идеи


Lightweight events concept

This is a very important chapter. The LwVCL library uses listener concept like Java AWT or SWING libraries. It means that if you want to handle any event you should register an appropriate event listener. The events and listeners are much like in AWT library (see package org.zaval.lw.event.*) and hope, you'll get it easily. But there are several key differences:

First of all, lightweight components don't provide listener support. The lightweight component doesn't implement event distribution functionality and this is really good, because event distribution is concentrated in one place — event manager. This way has one more advantage: it decreases memory usage because lightweight components should not contain the list of listeners (listeners support). It's very simple: if you want to catch events inside your lightweight component, it is necessary just to implement an appropriate listener interface and the library event manager will immediately start sending the events to the component. For example, to catch mouse events inside your component, you should implement LwMouseListener listener interface. As it was described above, a lightweight component doesn't provide listeners support for mouse, key, component, container, focus and other events unlike a Java AWT component. But it is possible to handle all these events using LwEventManager event manager, by registering an appropriate listener. In this case the registered listener will get the events for all components, so if you want to listen the events for the certain lightweight component you should test a source of the events.

The lightweight library provides the mechanism to control input child events. The input event is an event that is initiated by mouse, keyboard or any other input device. This is very important to have this feature for creating composite components. Composite component is a container that consists of several components (child components) that have to work together. For example the LwButton component is a composite component. The button component can have other components (including composite components) as its child. The problem, in this case, is following: if a mouse button has been clicked over any child component, the button mouse listener will not get the mouse event and so cannot handle it. There are several ways to resolve the problem:

Register a mouse listener in by the event manager and test if the source object is the button component or its child component. This solution is like Java AWT (but in this case it is necessary to test if the event source of the event is the child of the composite component), but this way doesn't solve the problem if you want to use other composite component as the button container child component (you cannot control a composite child component).

Control child components' events. The Java AWT hasn't anything like that. The main idea is the parent component can control input events distributing process for its child components. In this case the parent should implement the LwComposite interface and starting from the moment the event manager will "ask" the composite component if the child component input event should be re-directed to the parent. If the composite component says to redirect the input event, the lightweight event manager distributes the event as if the child component doesn't exist. The child becomes "transparent" for the input event. The image below illustrates the composite components concept:


те отлавливать все основные события можно на любом объекте

прикольно то, что это все действительно работает. даже при весьма ограниченных рессурсах и никаких тебе addXXXEvent и проч на самом объекте.
все сосредоточенно в LwEventManager который присутствует в одном экземпляре !!!

круто знай наших
Re[8]: Вопрос по кодонаписанию
От: Airat Burganov Россия http://www.burganov.com
Дата: 10.01.06 14:56
Оценка:
L>есть еще public EventListener[] getListeners(Class t), но его вероятно не используют все с той же целью оптимизации, дабы не создавать новый массив при каждом чихе.
я его использую. Все-таки мои компоненты будут использовать не миллионы программистов по всему миру.
Re[9]: Вопрос по кодонаписанию
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 10.01.06 15:02
Оценка:
Здравствуйте, Airat Burganov, Вы писали:

L>>есть еще public EventListener[] getListeners(Class t), но его вероятно не используют все с той же целью оптимизации, дабы не создавать новый массив при каждом чихе.

AB>я его использую. Все-таки мои компоненты будут использовать не миллионы программистов по всему миру.

я имел ввиду компоненты Swing.
#333355130
Re[3]: Вопрос по кодонаписанию
От: dshe  
Дата: 10.01.06 15:27
Оценка:
Здравствуйте, Тычеблин, Вы писали:

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


Т> вот тут Андрей Вишневкий построил фрэймворк там ваще очень интересные идеи


Т>прикольно то, что это все действительно работает. даже при весьма ограниченных рессурсах и никаких тебе addXXXEvent и проч на самом объекте.

Т>все сосредоточенно в LwEventManager который присутствует в одном экземпляре !!!

Т>круто знай наших


Вообще-то, что касается работы Андрея Вишневского, то я к нему отношусь пока скептически. Мне показалось, что это Yet Another (GUI) Framework (который к тому же дублирует функциональность Swing/AWT). Многие framework'и обладают одним существенным недостатком -- они intrusive, т.е. как только на какой-то подсядешь, слезть с него будет очень болезненно. Поэтому для того, чтобы какой-то framework использовать, гениальной идеи и великолепной реализации мало, необходима еще уверенность, что завтра этот проект не станет заброшенным и будет все еще конкурентноспособным.
--
Дмитро
Re[10]: Вопрос по кодонаписанию
От: Airat Burganov Россия http://www.burganov.com
Дата: 10.01.06 15:27
Оценка:
AB>>я его использую. Все-таки мои компоненты будут использовать не миллионы программистов по всему миру.
L>я имел ввиду компоненты Swing.
в смысле разработчиков swing'а? Им-то как раз производительность важна, потому что неизвестно где и в каких условиях будут использоваться компоненты миллионами разработчиков
Re[11]: Вопрос по кодонаписанию
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 10.01.06 15:41
Оценка:
Здравствуйте, Airat Burganov, Вы писали:

AB>>>я его использую. Все-таки мои компоненты будут использовать не миллионы программистов по всему миру.

L>>я имел ввиду компоненты Swing.
AB>в смысле разработчиков swing'а? Им-то как раз производительность важна, потому что неизвестно где и в каких условиях будут использоваться компоненты миллионами разработчиков

без обид, но сдается мне Тычеблин прав, насчет недопонимания. Я же и имел ввиду что в компонентах Swing-а getListegers() не используется в контексте мултикаст-цикла по причинам оптимизации, дабы не создавать лишние массивы при каждом чихе.
#333355130
Re[4]: Вопрос по кодонаписанию
От: Тычеблин Китай  
Дата: 10.01.06 15:44
Оценка:
Здравствуйте, dshe, Вы писали:

D>Здравствуйте, Тычеблин, Вы писали:


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


Т>> вот тут Андрей Вишневкий построил фрэймворк там ваще очень интересные идеи


Т>>прикольно то, что это все действительно работает. даже при весьма ограниченных рессурсах и никаких тебе addXXXEvent и проч на самом объекте.

Т>>все сосредоточенно в LwEventManager который присутствует в одном экземпляре !!!

Т>>круто знай наших


D>Вообще-то, что касается работы Андрея Вишневского, то я к нему отношусь пока скептически. Мне показалось, что это Yet Another (GUI) Framework (который к тому же дублирует функциональность Swing/AWT). Многие framework'и обладают одним существенным недостатком -- они intrusive, т.е. как только на какой-то подсядешь, слезть с него будет очень болезненно. Поэтому для того, чтобы какой-то framework использовать, гениальной идеи и великолепной реализации мало, необходима еще уверенность, что завтра этот проект не станет заброшенным и будет все еще конкурентноспособным.


было бы интереснее все же про упомянутую идею услышать.


<откровенный оффтоп>

да и навязчивости (интрузивности) особой откровенно я не увидел.
есть возможность совместного (смешанного) использования , немного swing чуть awt и VCL.
конечно многие решения откровенно сомнительны, но на меня произвело впечатление факт того как легко созданное
перекладывается на другие платформы со свингом так не прокатит, точнее прокатит но проще переписать заново.

</откровенный оффтоп>
Re[12]: Вопрос по кодонаписанию
От: Airat Burganov Россия http://www.burganov.com
Дата: 10.01.06 15:52
Оценка:
L>без обид, но сдается мне Тычеблин прав, насчет недопонимания. Я же и имел ввиду что в компонентах Swing-а getListegers() не используется в контексте мултикаст-цикла по причинам оптимизации, дабы не создавать лишние массивы при каждом чихе.
Если кто не использует, сам себе злобный буратино. Создание объектов в java довольно дешевое.
Когда я работал со свингом — использовал, вместо того, чтобы писать ту неудобную процедуру.

конечно, это не относится к непосредственно коду swing'а, там соображения оптимизиации имеют смысл.
Re[8]: Вопрос по кодонаписанию
От: C0s Россия  
Дата: 10.01.06 15:55
Оценка:
Здравствуйте, Lucker, Вы писали:

L>Да ладно . Нету в java одновременно гибкие и в то же время простого способа передачи контекста (в данном случае нужно иметь возможность этот контекст модифицировать).


наверное, мне надо бы спросить, что значит "надо модифицировать"? если контекст суть объект, то этот объект вполне может быть mutable
да и вообще, это вопрос в большей степени философский, ибо когда есть N гибких способов решить какую-то проблему, и ты сумел для себя их них выбрать M и научиться применять, то эти M уже для тебя — простые

L>есть еще public EventListener[] getListeners(Class t), но его вероятно не используют все с той же целью оптимизации, дабы не создавать новый массив при каждом чихе.


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

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

последний раз я программировал gui N-большое лет назад и на delphi, но все равно помню, что для типичной формы или набора форм граф источников-подписчиков в большинстве случаев статичен. если даже требуется замысловатое поведение в динамике а-ля показать текстовое поле ввода, если двумя строками выше выбран радио-баттон такой-то, то предпочтительнее в реализациях листенеров проверять состояние формы (при необходимости можно даже в своей модели завести доп. флаги, нежели проверять видно-не видно), чем на лету перестраивать набор листенеров.
как следствие, можно задачу построения этого графа явно вынести из Component (суть создание объекта посредника) и все нюансы типа выбор между unicast/multicast отдать программисту, вплоть до написания собственных посредников между генераторами событий (Component) и подписчиками — для оптимизаций/наворотов. набор классов наиболее общеупотребимых посредников можно было бы предоставить в подпакете...

или я заблуждаюсь, а создатели Component сэкономили своим копи-пастом программистам много времени?

что касается "so-called оптимизаций", то в глаза бросилось огромное количество приведений типов в AWTEventMulticaster, это, конечно, не массивы создавать по чиху, но все равно не впечатляет
Re[9]: Вопрос по кодонаписанию
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 10.01.06 16:16
Оценка:
Здравствуйте, C0s, Вы писали:

C0s>наверное, мне надо бы спросить, что значит "надо модифицировать"? если контекст суть объект, то этот объект вполне может быть mutable

на примере того же цикла: объект Event создается во время работы цикла, если есть хоть один подписчик на собьытие, причем как его создать известно только в контексте fireXXX метода, и переложить эту обязанность на предполагаемую реализацию мультикастера, без создания дополнительных абстракций, невозможно. Иначе проще создать объект Event и передать его в гипотетический мультикастер. Конечно можно проверить, если ли кто из подписчиков на нужное событи в этом самом мультикастере, что опять приведет к повторному кодированию проверки в каждом месте вызова (немного меньше — но все же). Итого, как всегда, или copy-paste, или потери в производительности на дополнительное создание объектов. Я бы выбрал второе, но сантехники должны быбрать первое, так как производительноть свинга — еще та мазоль. Есть третий вариант — правильный — Аспекты, но в силу многих причин современной реализации АОП в java его пока на уровне SDK не применяют. Вероятно со временем все изменится.

Так вот, единственный гибкий и простой способ передачи модифицируемого контекста в вызов — Map или его адаптер, иначе для каждого конктретного случая придется определять свой класс, что вырисовывается в сомнительного преимущества альтернативу. В случае с мапом — проблема с обобщенностью интерфейса и потерей информации о типах на этапе компиляции.

C0s>да и вообще, это вопрос в большей степени философский, ибо когда есть N гибких способов решить какую-то проблему, и ты сумел для себя их них выбрать M и научиться применять, то эти M уже для тебя — простые


Вообще я клоню к тому, что не плохо было бы поиметь closures в java.

C0s>что касается "so-called оптимизаций", то в глаза бросилось огромное количество приведений типов в AWTEventMulticaster, это, конечно, не массивы создавать по чиху, но все равно не впечатляет


не мне тебе рассказыать об истории развития платформы и к чему эта история порой приводит.
#333355130
Re: Вопрос по кодонаписанию
От: tavr  
Дата: 10.01.06 16:51
Оценка:
Здравствуйте, Тычеблин, Вы писали:

Т>Сначала думал оформить в контексте Вопрос по правильному кодонаписанию
Автор: leska
Дата: 06.01.06
потом передумал. У меня вопрос тоже по стилю но о другом.


Т>Предлагаю обсудить то, как можно было бы более правильно и красиво реализовать подписку на собылия объекта и отказ от них.

Т>то как это сделано в AWT/SWING например у Component
Т>лично я нахожу откровенно корявым и загаживающим API. (нет? )

Т>более элегантным решением могло бы стать что-то вроди

Т>таким образом использование будет выглядить так
Т>Но (!) как это может быть устроено внутри? что думаете?

мне в этом смысле нравится идея из SWT:
   addListener(int type, IListener l);
   removeListener(int type, IListener l);
   getListeners(int type);
   fireEvent(int type, Event event);


можно навесить один и тот же listener на несколько типов событий
   addListener(type1 | type2 | type3, IListener l)


легко добавить свои типы событий, определив дополнительную константу
Re[2]: Вопрос по кодонаписанию
От: dshe  
Дата: 10.01.06 17:26
Оценка:
Здравствуйте, tavr, Вы писали:

T>Здравствуйте, Тычеблин, Вы писали:


T>мне в этом смысле нравится идея из SWT:

T>
T>   addListener(int type, IListener l);
T>   removeListener(int type, IListener l);
T>   getListeners(int type);
T>   fireEvent(int type, Event event);
T>


T>можно навесить один и тот же listener на несколько типов событий

T>
T>   addListener(type1 | type2 | type3, IListener l)
T>


T>легко добавить свои типы событий, определив дополнительную константу


А что делать, когда констант не хватит? И как контролировать то, что одна и те же константа не используется для разных целей?
--
Дмитро
Re[13]: Вопрос по кодонаписанию
От: Тычеблин Китай  
Дата: 11.01.06 08:51
Оценка:
Здравствуйте, Airat Burganov, Вы писали:

AB>... Создание объектов в java довольно дешевое.


это утверждение ложно и по памяти и по рессурсам CPU даже для такого банального класса как Object, не говоря про создание экземпляров более сложных классов.
это написано не только в продвинутых трудах по оптимизации, но и в букварях по JAVA.
Re[14]: Вопрос по кодонаписанию
От: Airat Burganov Россия http://www.burganov.com
Дата: 11.01.06 09:42
Оценка:
AB>>... Создание объектов в java довольно дешевое.

Т>это утверждение ложно и по памяти и по рессурсам CPU даже для такого банального класса как Object, не говоря про создание экземпляров более сложных классов.

Т>это написано не только в продвинутых трудах по оптимизации, но и в букварях по JAVA.
ссылки плиз.
Re[14]: Вопрос по кодонаписанию
От: Денис Цыплаков Россия  
Дата: 11.01.06 11:04
Оценка:
Тычеблин пишет:

> это утверждение ложно и по памяти и по рессурсам CPU даже для такого

> банального класса как Object, не говоря про создание экземпляров более
> сложных классов.
> это написано не только в продвинутых трудах по оптимизации, но и в
> букварях по JAVA.

Значит тестируем

IObjectFactory.java
-------------------

package ru.rtec.test.co;

/**
  * Интерфейс фабрики объектов.
  *
  * <p><b>Author</b> : Denis Tsyplakov <b> Date</b>: 11.01.2006 13:46:50</p>
  */
public interface IObjectFactory
{
     Object getObject();
}

----------------------
BeanFactory.java
----------------------

package ru.rtec.test.co;

/**
  * Фабрика бинов
  *
  * <p><b>Author</b> : Denis Tsyplakov <b> Date</b>: 11.01.2006 13:58:18</p>
  */
public class BeanFactory implements IObjectFactory
{

     public Object getObject()
     {
         return new CustomBean();
     }

     class CustomBean
     {
         int i;

         long j;

         boolean b;
     }

}

-------------------------
StringFactory.java
-------------------------

package ru.rtec.test.co;

/**
  * Фабрика строк 0,1,2,3,...
  *
  * <p><b>Author</b> : Denis Tsyplakov <b> Date</b>: 11.01.2006 13:52:09</p>
  */
public class StringFactory implements IObjectFactory
{
     long counter = 0;

     public synchronized Object getObject()
     {
         return new String (""+counter++);
     }
}

------------------------
Tester.java
------------------------

package ru.rtec.test.co;

public class Tester
{

     private static final int TEST_LEHGTH = 100000;

     static Object[] objs = new Object[TEST_LEHGTH];

     public static void main(String[] args)
     {
         System.out.println("кол-во создаваемых объектов: " +
            TEST_LEHGTH);
         test("String Factory",(IObjectFactory)new StringFactory());
         test("Custom bean Factory",(IObjectFactory)new BeanFactory());
     }

     private static void test(final String name,
                              final IObjectFactory factory)
     {
         long start = System.currentTimeMillis();
         for ( int i = 0;i<TEST_LEHGTH;i++)
         {
             objs[i] = factory.getObject();
         }
         long len = System.currentTimeMillis() - start;
         System.out.println(name + " : " + len + " ms.");
     }
}

------------------------
Результаты на CPU 2 ГГц RAM 1Гб
------------------------
кол-во создаваемых объектов: 100000
String Factory : 219 ms.
Custom bean Factory : 63 ms.

Меня такая скорость устраивает.

--
WBR Денис Цыплаков /* jabber UID: denis.tsyplakov@jabber.ru */
Знающий не говорит, говорящий не знает
Posted via RSDN NNTP Server 2.0

Автору поста в подарок от модератора подсветка синтаксиса. Blazkowicz.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.