Форум Кладовочки АЛьФ`а

Общие вопросы => 7.7 => Тема начата: SnakePlisskin от 29 августа 2025, 16:43

Название: COM соединение с базой
Отправлено: SnakePlisskin от 29 августа 2025, 16:43
Доброго дня, господа!
Сложилась такая ситуация, что нужно в базу 8, перегрузить справочник номенклатура, из базы на 7.7, причем делать это в регламентном задании на стороне 8 (клиент-серверная), после первоначальной загрузки в последующих "синхронизациях" нужно проверять на изменение наименования / полного наименования. Честно говоря раньше с такими задачами не сталкивался.

накидал вот такой код

    V77 = Новый COMОбъект("V77.Application");
    Запрос = V77.CreateObject("Запрос");
    ТекстЗапроса=

    "//{{ЗАПРОС(Сформировать)
    |Обрабатывать НеПомеченныеНаУдаление;
    |Номенклатура = Справочник.Номенклатура.ТекущийЭлемент;
    |Код = Справочник.Номенклатура.Код;
    |Наименование = Справочник.Номенклатура.Наименование;
    |Родитель = Справочник.Номенклатура.Родитель.Наименование;
    |РодительКод = Справочник.Номенклатура.Родитель.Код;
    |Группировка Номенклатура;
    |";//}}ЗАПРОС
   
    Если Запрос.Выполнить(ТекстЗапроса)=0 Тогда
        ОбщегоНазначения.СообщитьОбОшибке("Ошибка выпонения запроса номенклатуры в базе-источнике");
        Возврат;
    КонецЕсли;
   
    Таблица = Новый ТаблицаЗначений;
    Таблица.Колонки.Добавить("Код",,,15);
    Таблица.Колонки.Добавить("Наименование",,,50);
    Таблица.Колонки.Добавить("Родитель",,,50);   
    Таблица.Колонки.Добавить("РодительКод",,,15);
    Таблица.Колонки.Добавить("ЭтоГруппа",,,1);
   
    Пока Запрос.Группировка() Цикл
        Строка = Таблица.Добавить();
        Строка.ЭтоГруппа    = Запрос.Номенклатура.ЭтоГруппа();
        Строка.Код          = Запрос.Код;
        Строка.Наименование = Запрос.Наименование;
        Строка.Родитель     = Запрос.Родитель;
        Строка.РодительКод  = Запрос.РодительКод;
    КонецЦикла;   
    V77 = "";

Но это только заполнение таблицы для последующей ее обработки, 36 тысяч элементов, заполняется почти 4 минуты, можно ли как то ускорить, хотя как, я особо не понимаю, но все же. Плюс может есть-какой то другой путь решения задачи ?
Название: Re: COM соединение с базой
Отправлено: Злоп от 29 августа 2025, 20:29
Группировка номенклатура без групп без упорядочивания
.
Тз = создатьобьект("таблицазначений")
Запрос.выгрузить(таблицазначений,....)
Название: Re: COM соединение с базой
Отправлено: Злоп от 29 августа 2025, 20:41
Н хрена непонятно про изменение наименования. Где может происходить - только на стороне 77? Если номенклатура в 77 изменяется !!! Только интерактивно!!! Заведи в спр. Номенклатура флаг с сортировка=1, при изменении взводи его, в запросе фильтруй по условию флаг=взведен, после отработки регзадания в конце его сбрасывай в 77 флаг. Первый регламент отработает медленно, остальные будут быстро.
При сбросе флага делай в транзакции по например 10 элементов, чтобы если какой дятел держит номенклатуру открытой - чтобы не сломалось. Сброс флага делай в попытке. Если очередная порция не прошла в транзакции - да и хрен с ней, при следующем регламенте пройдёт.
.
Или контроль изменений номенклатуры регистрируй штатно с использованием УРБД. Регламент будет подчищать таблицу изменений. Можно без урбд, служебный справочник изменений куда писать ссылку на номенклатуру которая изменилась и запрос только по этому списку.
.
Ну или проще всего прямым запросом
Название: Re: COM соединение с базой
Отправлено: Злоп от 29 августа 2025, 20:44
Если база файловая - с использованием 1sqlite прямой запрос. Ну и скульную базу тоже можно прямым запросом.
Ускорение на 1-2 порядка будет.
Название: Re: COM соединение с базой
Отправлено: Злоп от 29 августа 2025, 20:47
А если еще между регламентами закешировать verstamp элементов справочника и в прямом запросе фильтровать к отбору по несовпадающим верстамп (он у элемента меняется при каждой модификации) то вообще время мизер будет
Название: Re: COM соединение с базой
Отправлено: Злоп от 29 августа 2025, 20:50
В 77 поставить по умолчанию режим открытия "для просмотра" ибо нехер открыть, посмотреть и жать ОК.
Название: Re: COM соединение с базой
Отправлено: Злоп от 29 августа 2025, 20:59
Это я так, в порядке дежурного бреда накидал, топая пешком домой.
Гуры и сенсейбабаи поправят.
Название: Re: COM соединение с базой
Отправлено: Злоп от 29 августа 2025, 21:02
Изменения наименования/полного наименования я бы вообще контролировать забил. Чек только на изменение элемента как факт.
Название: Re: COM соединение с базой
Отправлено: Злоп от 29 августа 2025, 21:03
Если номенклатура (наименования) может меняться на двух сторонах - ССЗБ.
Схемы примерно те же самые с добавкой контроля изменений на снеговике
Название: Re: COM соединение с базой
Отправлено: vladmenleo от 30 августа 2025, 05:40
ВЫбросить нафиг ком соединение, делать через файл, самое простое dbf. На стороне 7.7 выгружаешь роботом по расписанию каждую ночь к примеру, а на стороне 8-ки загружаешь из файла. Работает такое  фиг знает сколько лет и хлеба не просит. Чтобы уменьшить объем, у нас в номенклатуре 7.7 есть спецполе дата последнего редактирования, и в выгрузку выгружаем только измененные за последние несколько дней
Название: Re: COM соединение с базой
Отправлено: SnakePlisskin от 30 августа 2025, 08:39
ЗЛОП - спасибо за ответы.
Базы обе SQL правда лежат на разных серверах, прямые запросы в клюшках умею, а как из снеговика добраться до базы SQL 7.7 не умею...буду благодарен за пример.

А почему Группировка номенклатура без групп без упорядочивания - как тогда структуру справочника повторить если групп не будет ?


vladmenleo - чета dbf - совсем как то по олдскульному, но тоже как вариант.
Название: Re: COM соединение с базой
Отправлено: vladmenleo от 31 августа 2025, 05:58
Ну не хочешь по олдскульному, юзай xml к примеру. Хозяин барин  ;D
Название: Re: COM соединение с базой
Отправлено: Злоп от 31 августа 2025, 10:41
Цитата: SnakePlisskin от 30 августа 2025, 08:39ЗЛОП - спасибо за ответы.
чета dbf - совсем как то по олдскульному, но тоже как вариант.
Дбф читается очень быстро
Название: Re: COM соединение с базой
Отправлено: ADirks от 01 сентября 2025, 07:33
Например (ADODB):
(ТекстЗапроса - нормальный SQL-запрос)

Функция СоединениеСКЛ(ИмяСервера, ИмяПользователя, ПарольПользователя, ИмяБазы = "") Экспорт
Если НЕ ЗначениеЗаполнено(ИмяСервера) Тогда
Возврат Неопределено;
ИначеЕсли НЕ ЗначениеЗаполнено(ИмяПользователя) Тогда
Возврат Неопределено;
КонецЕсли;


ConnectionString = "Driver={SQL Server Native Client 11.0};Server="+ИмяСервера+";uid="+ИмяПользователя;
Если НЕ ПустаяСтрока(ПарольПользователя) Тогда
ConnectionString = ConnectionString + ";pwd="+ПарольПользователя;
КонецЕсли;
Если ИмяБазы <> "" Тогда
ConnectionString = ConnectionString + ";Database="+ИмяБазы;
КонецЕсли;

СоединениеСКЛ = Новый  COMОбъект("ADODB.Connection");
СоединениеСКЛ.ConnectionTimeout = 5;
СоединениеСКЛ.CommandTimeout = 0;
СоединениеСКЛ.CursorLocation = 3;
СоединениеСКЛ.Provider = "MSDASQL";
СоединениеСКЛ.ConnectionString = ConnectionString;
Попытка
СоединениеСКЛ.Open();
Исключение
Сообщить(ОписаниеОшибки());
СоединениеСКЛ = Неопределено;
КонецПопытки;


Возврат СоединениеСКЛ;
КонецФункции


Функция ВыполнитьИнструкцию(Соединение, ТекстЗапроса)  Экспорт
ТЗ = Новый ТаблицаЗначений;

Если Соединение = Неопределено Тогда
Сообщить("Соединение не установлено", СтатусСообщения.Внимание);
Возврат Неопределено;
КонецЕсли;

cmd = Новый COMОбъект("ADODB.Command");
cmd.CommandTimeout = 0;
cmd.ActiveConnection = Соединение;   
cmd.CommandText = ТекстЗапроса;

rs = cmd.Execute();

Fields = Rs.Fields;
nFields = Fields.Count;

Колонки = ТЗ.Колонки;
мКолонки = новый массив(nFields);
Для нПоле = 0 По nFields-1 Цикл
ИмяКолонки = Fields.Item(нПоле).Name;
мКолонки[нПоле] = ИмяКолонки;
Колонки.Добавить(ИмяКолонки);
КонецЦикла;

Если Не Rs.eof Тогда
rs.MoveFirst();
КонецЕсли;
Пока Не Rs.eof Цикл   
стрТЗ = ТЗ.Добавить();

Для каждого ИмяКол из мКолонки Цикл
Значение = Fields.Item(ИмяКол).Value;
Если Значение <> Null Тогда
стрТЗ[ИмяКол] = Значение;
КонецЕсли;       
КонецЦикла;

rs.MoveNext();
КонецЦикла;

Возврат ТЗ;
КонецФункции

Функция ВыполнитьСкалярный(Соединение, ТекстЗапроса) Экспорт
стРез = Неопределено;

cmd = Новый COMОбъект("ADODB.Command");
cmd.CommandTimeout = 0;
cmd.ActiveConnection = Соединение;   
cmd.CommandText = ТекстЗапроса;
rs = cmd.Execute();

Fields = Rs.Fields;

//Ничего не получилось в результате
Если Rs.EOF И Rs.BOF Тогда
Возврат НЕопределено;
КонецЕсли;

rs.MoveFirst();
Пока Не Rs.EOF Цикл   
стРез = Новый Структура;

Для каждого Поле из Fields Цикл
ИмяКол = Поле.Name;
Значение = Поле.Value;
стРез.Вставить(ИмяКол, Значение);
КонецЦикла;

Прервать;
КонецЦикла;

Возврат стРез;
КонецФункции
Название: Re: COM соединение с базой
Отправлено: Харлампий Дымба от 01 сентября 2025, 11:15
Стоит упомянуть, что это реализованный функционал в типовой бухгалтерии 7.70.671 (начиная с 7.70.564 - 12 лет в обед) - обработка ПомощникПереходаНа1С8 умеет делать синхронизацию справочников и документов. Вот это вот все: "Справочник.ПараметрыСинхронногоУчета", "Справочник.МенеджерВыгрузок", "Справочник.МодифицированныеОбъекты", глУчестьЭлементПриИзменении, глУчестьДокументПриИзменении, ACC_ACC8.ert etc. При желании можно и с этими поразбираться и стащить себе схему работы. Я бы, если честно, не стал.

+Вопрос: в исходном коде Строка.Родитель и Строка.РодительКод разве заполнены после выполнения запроса?
 
Название: Re: COM соединение с базой
Отправлено: SnakePlisskin от 01 сентября 2025, 12:36
Цитата: Харлампий Дымба от 01 сентября 2025, 11:15Стоит упомянуть, что это реализованный функционал в типовой бухгалтерии 7.70.671 (начиная с 7.70.564 - 12 лет в обед) - обработка ПомощникПереходаНа1С8 умеет делать синхронизацию справочников и документов. Вот это вот все: "Справочник.ПараметрыСинхронногоУчета", "Справочник.МенеджерВыгрузок", "Справочник.МодифицированныеОбъекты", глУчестьЭлементПриИзменении, глУчестьДокументПриИзменении, ACC_ACC8.ert etc. При желании можно и с этими поразбираться и стащить себе схему работы. Я бы, если честно, не стал.

+Вопрос: в исходном коде Строка.Родитель и Строка.РодительКод разве заполнены после выполнения запроса?
 

А вот кстати, да я сейчас посмотрел...родитель и родитель код - для элементов заполнены вообще не правильно, а для самих групп - просто пусто все.
Название: Re: COM соединение с базой
Отправлено: SnakePlisskin от 02 сентября 2025, 15:24
Пошел немного по другому пути, сделал обработку того что мне нужно на стороне 7.7, в 8 сделал вызов функции из 7.7, функция возвращает нужную мне тз , вот только уперся в то что, 8-ка определяет ее просто как COM объект, как побороть ?

   Таблица = Новый ТаблицаЗначений;
   Таблица = V77.глПолучитьРезультатЗапросаДля83();

Название: Re: COM соединение с базой
Отправлено: SnakePlisskin от 02 сентября 2025, 15:52
Попробовал так :

    СтрокаРезультат = V77.ValueToStringInternal(V77.глПолучитьРезультатЗапросаДля83());
    Таблица = ЗначениеИзСтрокиВнутр(СтрокаРезультат);

Ошибка формата потока.
Название: Re: COM соединение с базой
Отправлено: Злоп от 02 сентября 2025, 16:20
Ну так структура внутренняя у ТЗ в клюшках и снеговике - разная, чего ж ты хотел...
.
Пусть тебе клюшечная функция возвращает не ТЗ, а, например, XML или джсон и разбирай их в снеговике штатными средствами.
.
Опять же ничто не мешает в снеговике работать с объектами клюшек
Пишешь в снеговике типа
V77.тз.Выбратьстроки() - и это выполняется в контексте клюшек
Название: Re: COM соединение с базой
Отправлено: SnakePlisskin от 02 сентября 2025, 16:32
Цитата: Злоп от 02 сентября 2025, 16:20Ну так структура внутренняя у ТЗ в клюшках и снеговике - разная, чего ж ты хотел...
.
Пусть тебе клюшечная функция возвращает не ТЗ, а, например, XML или джсон и разбирай их в снеговике штатными средствами.
.
Опять же ничто не мешает в снеговике работать с объектами клюшек
Пишешь в снеговике типа
V77.тз.Выбратьстроки() - и это выполняется в контексте клюшек

Не совсем понял, а как работать вот с этим "V77.тз.Выбратьстроки()" - если на стороне снеговика клюшечная функция возвращает ТЗ а снеговик ее воспринимает как COM объект ?

Все эти мытарства, получились из за того что ссылочные реквизиты в номенклатуре, видятся в снеговике как COMобъекты, банально не понятно как определить ВидНоменклатуры - Товар или Услуги, реквизит которой имеет ссылочный тип...как до него добраться в снеговике ?
Название: Re: COM соединение с базой
Отправлено: Djelf от 02 сентября 2025, 16:52
Ну а как ты в 8ке передашь тз на форму, без массива массивов?
Вроде везде, тз, тз, и тз... Но они все разные тз, просто называются одинаково.
Смирись. Либо сереиализация, через что угодно, либо через файл.
Название: Re: COM соединение с базой
Отправлено: SnakePlisskin от 02 сентября 2025, 17:14
Цитата: Djelf от 02 сентября 2025, 16:52Ну а как ты в 8ке передашь тз на форму, без массива массивов?
Вроде везде, тз, тз, и тз... Но они все разные тз, просто называются одинаково.
Смирись. Либо сереиализация, через что угодно, либо через файл.

А мне не нужна тз на форме - я хотел таблицу значений сформировать в глобальнике - в 7.7, заодно убрав все не примитивные типы, а в снеговике просто получить эту таблицу значений и сделать уже с ней все что нужно
Название: Re: COM соединение с базой
Отправлено: Злоп от 02 сентября 2025, 18:52

Не совсем понял, а как работать вот с этим "V77.тз.Выбратьстроки()" - если на стороне снеговика клюшечная функция возвращает ТЗ?
-
1. Могу тупить/путать
2. Вариант ТИПА v77.тз. Выбратьстроки()
Выполняется не в контексте снеговика, а в контексте клюшек.
Тз при этом д. Б. Доступна в контексте клюшек, т.е. быть глобальной переменной экспортной. Для этой цели в типовых достаточно глобальных переменных таких, типа глРасшифровка, глУсловие и прочих
Название: Re: COM соединение с базой
Отправлено: SnakePlisskin от 02 сентября 2025, 20:29
Цитата: Злоп от 02 сентября 2025, 18:52Не совсем понял, а как работать вот с этим "V77.тз.Выбратьстроки()" - если на стороне снеговика клюшечная функция возвращает ТЗ?
-
1. Могу тупить/путать
2. Вариант ТИПА v77.тз. Выбратьстроки()
Выполняется не в контексте снеговика, а в контексте клюшек.
Тз при этом д. Б. Доступна в контексте клюшек, т.е. быть глобальной переменной экспортной. Для этой цели в типовых достаточно глобальных переменных таких, типа глРасшифровка, глУсловие и прочих

Короче вот так работает.

   тзИзКлюшек = V77.глПолучитьРезультатЗапросаДля83();
   тзИзКлюшек.ВыбратьСтроки();
   Пока тзИзКлюшек.ПолучитьСтроку() = 1 Цикл
      Строка = Таблица.Добавить();
   КонецЦикла;

V77 - это COM соединение.
глПолучитьРезультатЗапросаДля83() - функция в глобальнике в клюшках которая формирует таблицу.
Название: Re: COM соединение с базой
Отправлено: Злоп от 03 сентября 2025, 00:12
типа так.
если углубится, то сможешь воперировать агрегатными объектами 77 прямо из снеговика.
у меня была мега сверочная обработка по Оле (тот же ком?) между двумя базами 77. выборки, сверки ииже бубмли хуяси сесренький козлик. Правда это работало только потому что я не контролировал работу обработки а бил ломом по лицу бухам (условно). Ну не могут они мыслить синтетически/аналитически (по крайне мере рядовые бухи коих тьма), пока не пнешь с пенделя - так и будут сопли жевать или тупить глядя в экран - судя по всему наличие компа окончательно разорвало понимание связей и взаимодействий. Пора возвращаться к бумажным журналам-ордерам и ведомостям. Полная деградация. НУ или я просто злоп. У них 4 - это 2+2. а то что это вообще-то 1+3, 1+1+1+1, 2+1+1 - это где-то в другой вселенной.. некромонгеров...
Название: Re: COM соединение с базой
Отправлено: Злоп от 03 сентября 2025, 00:15
Встречал весьма адекватных бухов, с которыми работать - как журнал "Лиза" - одно удовольствие (мужской вариант журнала - "Лизун"), но в большинстве - просто нажиматели кнопок, карго-культ... я один такой?
Название: Re: COM соединение с базой
Отправлено: SnakePlisskin от 03 сентября 2025, 12:38
Написал на стороне клюшек, функцию через прямой запрос со всеми данными, которые нужны, попутно переведя все что нужно в примитивные типы, на стороне 8-ке только построчно получаю таблицу и уже загружаю в тз снеговика, далее дисконект от базы 7.7, осталось разобраться с зоопарком единиц измерения...
Название: Re: COM соединение с базой
Отправлено: Ветер в поле от 04 сентября 2025, 11:54
Я использую два варианта для совместной работы 1С77 и 1С83. Если нет какой-то суперсложной логики со стороны 77, то 83 прямым запросом лезет в SQL-базу 77. Если на 77 нужно обработать данные по сложным алгоритмам, то используется web-сервер. Есть компонента AddIn.HTTPSrv7 на Инфостарте, которая позволяет 77 выступать web-сервером. Очень прилично и быстро работает. Я обмениваюсь данными в JSON, но не критично. Веб-сервер часто месяцами работает. Нагрузка средняя - в районе 1600 запросов в сутки. Главный плюс использования веб-запросов - ураганная скорость, т.к. можно использовать всякие кэши. Типичный запрос выполняется 10-40 мс + накладные расходы на формирование и передачу запроса, которые очень небольшие. Поэтому синхронизация может выполняться почти непрерывно. У меня такая логика реализована - при создании/изменения в 83, например, пациента, в очередь отправляются данные, что этот элемент надо выгрузить в 77. Раз в 30 секунд происходит выгрузка всех накопившихся данных. Если выгрузить не удалось (веб-сервер подвис, ошибка приключилась), то данные будут накапливаться. Со стороны 77 можно было реализовать так же, но исторически сложилось так, что 83 все изменившиеся данные забирает периодически напрямую из SQL 77. Там в элементах есть реквизит со временем последнего изменения. 83 помнит последнее загруженное изменение и выбирает элементы, которые имеют реквизит с бОльшим временем. Для установки такого реквизита можно использовать триггеры, тогда не приходится вручную следить за его обновлением.
Название: Re: COM соединение с базой
Отправлено: SnakePlisskin от 04 сентября 2025, 14:36
Цитата: Ветер в поле от 04 сентября 2025, 11:54Я использую два варианта для совместной работы 1С77 и 1С83. Если нет какой-то суперсложной логики со стороны 77, то 83 прямым запросом лезет в SQL-базу 77. Если на 77 нужно обработать данные по сложным алгоритмам, то используется web-сервер. Есть компонента AddIn.HTTPSrv7 на Инфостарте, которая позволяет 77 выступать web-сервером. Очень прилично и быстро работает. Я обмениваюсь данными в JSON, но не критично. Веб-сервер часто месяцами работает. Нагрузка средняя - в районе 1600 запросов в сутки. Главный плюс использования веб-запросов - ураганная скорость, т.к. можно использовать всякие кэши. Типичный запрос выполняется 10-40 мс + накладные расходы на формирование и передачу запроса, которые очень небольшие. Поэтому синхронизация может выполняться почти непрерывно. У меня такая логика реализована - при создании/изменения в 83, например, пациента, в очередь отправляются данные, что этот элемент надо выгрузить в 77. Раз в 30 секунд происходит выгрузка всех накопившихся данных. Если выгрузить не удалось (веб-сервер подвис, ошибка приключилась), то данные будут накапливаться. Со стороны 77 можно было реализовать так же, но исторически сложилось так, что 83 все изменившиеся данные забирает периодически напрямую из SQL 77. Там в элементах есть реквизит со временем последнего изменения. 83 помнит последнее загруженное изменение и выбирает элементы, которые имеют реквизит с бОльшим временем. Для установки такого реквизита можно использовать триггеры, тогда не приходится вручную следить за его обновлением.

А есть пример работы с данными SQL базы 7.7 напрямую из 8 ? Ибо уже сутки бьюсь с COM объектом в клиент серверном варианте...пока толку 0.
Название: Re: COM соединение с базой
Отправлено: Ветер в поле от 05 сентября 2025, 09:43
Цитата: SnakePlisskin от 04 сентября 2025, 14:36А есть пример работы с данными SQL базы 7.7 напрямую из 8 ? Ибо уже сутки бьюсь с COM объектом в клиент серверном варианте...пока толку 0.

К сожалению, я не имею доступа к кодам 83. Я отвечаю только за 77.
Знаю, что таблицы 77 в конфигурации 83 подключены через Внешние источники. Тогда в запросах можно использовать русские наименования таблиц и их реквизитов, а не всякие SC1017.SP1020
Название: Re: COM соединение с базой
Отправлено: Ветер в поле от 05 сентября 2025, 09:55
Хотя вот нашел пример вызова хранимой процедуры, возвращающая набор строк. Но писал это "специалист" ПервогоБита, которые те еще студенты, но некоторое представление о коде дает.
Попытка
ADOСоединение  = Новый COMОбъект("ADODB.Connection");
ADOСоединение.ConnectionString = "Driver={SQL Server};Server=192.168.1.163;Database=EC;Uid=v8;Pwd=123456;";
ADOСоединение.Open();
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;

Command = Новый COMObject("ADODB.Command");
Command.ActiveConnection = ADOСоединение;
ТекстЗапроса = "v8_getAnalysisListByPatient";
Command.CommandText = ТекстЗапроса;
Command.CommandType = 4;

Command.Parameters(1).value = Структура.ИД;

Результат = Command.Execute();
Массив = Новый массив;
Если НЕ Результат.EOF() Тогда
МассивСтруктур = Новый Массив;
Пока Результат.EOF() = 0 Цикл
КолКолонок = Результат.Fields.Count();
Строка  = Новый Структура;
Для Инд = 0 По КолКолонок-1 Цикл
Строка.Вставить(Строка(Результат.Fields(Инд).Name),Строка(Результат.Fields(Инд).Value));
КонецЦикла;
Массив.Добавить(Строка);
Результат.MoveNext();

КонецЦикла;
КонецЕсли;