ОбновитьПрогрессВФоне (БСП)

Автор: 1С
ОбщийМодуль.УправлениеДоступомСлужебный
БСП

Обновить прогресс фоне.

Процедура ОбновитьПрогрессВФоне(Контекст, АдресРезультата) Экспорт
	
	ДатаНачалаОбновленияПрогресса = ТекущаяДатаСеанса();
	ДлительныеОперации.СообщитьПрогресс(0); // Обновление прогресса выполняется.
	
	СтрокиСписков   = Контекст.ХранимыеДанные.СтрокиСписков;
	СвойстваСписков = Контекст.ХранимыеДанные.СвойстваСписков;
	Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда
		Контекст.ХранимыеДанные.ДатаПоследнегоОбновления = '00010101';
	КонецЕсли;
	
	ДействующиеПараметры = Неопределено;
	ИдентификаторыТаблиц = ИдентификаторыСписковСОграничением(ДействующиеПараметры);
	
	Для Каждого КлючИЗначение Из ИдентификаторыТаблиц Цикл
		Если Не Контекст.ПоказыватьОбработанныеСписки Тогда
			Продолжить;
		КонецЕсли;
		Если СтрокиСписков.Получить(КлючИЗначение.Значение) <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		ДобавитьНовуюСтрокуСписка(Контекст, КлючИЗначение.Значение, КлючИЗначение.Ключ);
	КонецЦикла;
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("МаксимальнаяДата", МаксимальнаяДатаПриПродолжении());
	Запрос.УстановитьПараметр("ДатаПоследнегоОбновления", Контекст.ХранимыеДанные.ДатаПоследнегоОбновления);
	Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор",
		ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор());
	
	Контекст.ХранимыеДанные.ДатаПоследнегоОбновления = ДатаНачалаОбновленияПрогресса;
	
	ТекстыЗапросов = Новый Массив;
	ТекстыЗапросов.Добавить(
	"ВЫБРАТЬ
	|	ВсеСпискиОбновления.Список КАК Список,
	|	МАКСИМУМ(ВсеСпискиОбновления.ОбновлениеЭлементов) КАК ОбновлениеЭлементов,
	|	МАКСИМУМ(ВсеСпискиОбновления.ОбновлениеКлючейДоступа) КАК ОбновлениеКлючейДоступа
	|ИЗ
	|	(ВЫБРАТЬ РАЗЛИЧНЫЕ
	|		ОбновлениеКлючейДоступаКДанным.Список КАК Список,
	|		ИСТИНА КАК ОбновлениеЭлементов,
	|		ЛОЖЬ КАК ОбновлениеКлючейДоступа
	|	ИЗ
	|		РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ РАЗЛИЧНЫЕ
	|		ОбновлениеКлючейДоступаПользователей.Список,
	|		ЛОЖЬ,
	|		ИСТИНА
	|	ИЗ
	|		РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей) КАК ВсеСпискиОбновления
	|
	|СГРУППИРОВАТЬ ПО
	|	ВсеСпискиОбновления.Список");
	
	ТекстыЗапросов.Добавить(
	"ВЫБРАТЬ
	|	ОбновлениеКлючей.Список КАК Список,
	|	ОбновлениеКлючей.ДляВнешнихПользователей КАК ДляВнешнихПользователей,
	|	ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор КАК ЭтоОсновнаяЗапись,
	|	МАКСИМУМ(ОбновлениеКлючей.РазмерЗадания) КАК РазмерЗадания,
	|	МАКСИМУМ(ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра) КАК МаксимальнаяДатаИзменения,
	|	МИНИМУМ(ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра) КАК МинимальнаяДатаИзменения
	|ИЗ
	|	РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючей
	|ГДЕ
	|	ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра >= &ДатаПоследнегоОбновления
	|
	|СГРУППИРОВАТЬ ПО
	|	ОбновлениеКлючей.Список,
	|	ОбновлениеКлючей.ДляВнешнихПользователей,
	|	ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор
	|ИТОГИ ПО
	|	Список,
	|	ДляВнешнихПользователей");
	
	ТекстыЗапросов.Добавить(СтрЗаменить(ТекстыЗапросов[1],
		"РегистрСведений.ОбновлениеКлючейДоступаКДанным",
		"РегистрСведений.ОбновлениеКлючейДоступаПользователей"));
	
	Если Контекст.РассчитыватьПоКоличествуДанных Тогда
		ТекстыЗапросов.Добавить(
		"ВЫБРАТЬ
		|	ОбновлениеКлючей.Список КАК Список,
		|	ОбновлениеКлючей.ДляВнешнихПользователей КАК ДляВнешнихПользователей,
		|	ОбновлениеКлючей.ПараметрыЗадания КАК ПараметрыЗадания
		|ИЗ
		|	РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючей
		|ГДЕ
		|	ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра >= &ДатаПоследнегоОбновления
		|	И ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор
		|	И ОбновлениеКлючей.Список <> НЕОПРЕДЕЛЕНО
		|ИТОГИ ПО
		|	Список");
		
		ТекстыЗапросов.Добавить(СтрЗаменить(ТекстыЗапросов[3],
			"РегистрСведений.ОбновлениеКлючейДоступаКДанным",
			"РегистрСведений.ОбновлениеКлючейДоступаПользователей"));
		
		ТекстыЗапросов.Добавить(
		"ВЫБРАТЬ
		|	КОЛИЧЕСТВО(*) КАК Количество
		|ИЗ
		|	Справочник.КлючиДоступа КАК КлючиДоступа");
	КонецЕсли;
	
	Запрос.Текст = СтрСоединить(ТекстыЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов());
	РезультатыЗапроса = Запрос.ВыполнитьПакет();
	
	ВсеСпискиОбновления = РезультатыЗапроса[0].Выгрузить();
	СтрокиОбновленияКоличестваЭлементов = Новый Массив;
	СтрокиОбновленияКоличестваКлючейДоступа = Новый Массив;
	
	Для Каждого СписокОбновления Из ВсеСпискиОбновления Цикл
		Если Не ЗначениеЗаполнено(СписокОбновления.Список) Тогда
			Продолжить;
		КонецЕсли;
		Строка = СтрокиСписков.Получить(СписокОбновления.Список);
		Если Строка = Неопределено Тогда
			ДобавитьНовуюСтрокуСписка(Контекст, СписокОбновления.Список, "");
		КонецЕсли;
	КонецЦикла;
	
	УдаляемыеСтроки = Новый Массив;
	Для Каждого КлючИЗначение Из СтрокиСписков Цикл
		Строка = КлючИЗначение.Значение;
		СписокОбновления = ВсеСпискиОбновления.Найти(Строка.Список, "Список");
		Если СписокОбновления = Неопределено И Не Контекст.ПоказыватьОбработанныеСписки Тогда
			УдаляемыеСтроки.Добавить(Строка);
			Продолжить;
		КонецЕсли;
		СвойстваСписка = СвойстваСписков.Получить(Строка.Список);
		Если СписокОбновления = Неопределено Или Не СписокОбновления.ОбновлениеЭлементов Тогда
			СвойстваСписка.РазмерЗаданияОбновленияЭлементов = 0;
			СвойстваСписка.ПоследнийОбновленныйЭлемент = Null;
			СвойстваСписка.РазмерЗаданияОбновленияЭлементовДляВнешнихПользователей = 0;
			СвойстваСписка.ПоследнийОбновленныйЭлементДляВнешнихПользователей = Null;
			Строка.ДоляОбработанныхЭлементовДляПользователей = 1;
			Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей = 1;
			Если Контекст.РассчитыватьПоКоличествуДанных Тогда
				Если Строка.ОбработаноЭлементов <> 100 Тогда
					СтрокиОбновленияКоличестваЭлементов.Добавить(Строка);
				КонецЕсли;
			Иначе
				ОбнулитьКоличествоЭлементов(Строка, Контекст);
			КонецЕсли;
			ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, 100, Строка, Контекст);
		КонецЕсли;
		Если СписокОбновления = Неопределено Или Не СписокОбновления.ОбновлениеКлючейДоступа Тогда
			СвойстваСписка.РазмерЗаданияОбновленияКлючейДоступа = 0;
			СвойстваСписка.ПоследнийОбновленныйКлючДоступа = Null;
			СвойстваСписка.РазмерЗаданияОбновленияКлючейДоступаДляВнешнихПользователей = 0;
			СвойстваСписка.ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей = Null;
			Строка.ДоляОбработанныхКлючейДоступаДляПользователей = 1;
			Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей = 1;
			Если Контекст.РассчитыватьПоКоличествуДанных Тогда
				Если Строка.ОбработаноКлючейДоступа <> 100 Тогда
					СтрокиОбновленияКоличестваКлючейДоступа.Добавить(Строка);
				КонецЕсли;
			Иначе
				ОбнулитьКоличествоКлючейДоступа(Строка, Контекст);
			КонецЕсли;
			ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, 100, Строка, Контекст);
		КонецЕсли;
		Если СписокОбновления = Неопределено Тогда
			ОбновитьЗначениеВСтроке(Строка.ПоследнееОбновление, '00010101', Строка, Контекст);
			ОбновитьЗначениеВСтроке(Строка.ПервоеПланированиеОбновления, МаксимальнаяДата(), Строка, Контекст);
		КонецЕсли;
	КонецЦикла;
	
	Если Контекст.РассчитыватьПоКоличествуДанных Тогда
		ВыборкаПоСпискам = РезультатыЗапроса[3].Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
		Пока ВыборкаПоСпискам.Следующий() Цикл
			СвойстваСписка = СвойстваСписков.Получить(ВыборкаПоСпискам.Список);
			Если СвойстваСписка = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			ВыборкаПоВидамПользователей = ВыборкаПоСпискам.Выбрать();
			Пока ВыборкаПоВидамПользователей.Следующий() Цикл
				Если ВыборкаПоВидамПользователей.ДляВнешнихПользователей Тогда
					СвойстваСписка.ПоследнийОбновленныйЭлементДляВнешнихПользователей
						= ВыборкаПоВидамПользователей.ПараметрыЗадания;
				Иначе
					СвойстваСписка.ПоследнийОбновленныйЭлемент
						= ВыборкаПоВидамПользователей.ПараметрыЗадания;
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
		ВыборкаПоСпискам = РезультатыЗапроса[4].Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
		Пока ВыборкаПоСпискам.Следующий() Цикл
			СвойстваСписка = СвойстваСписков.Получить(ВыборкаПоСпискам.Список);
			Если СвойстваСписка = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			ВыборкаПоВидамПользователей = ВыборкаПоСпискам.Выбрать();
			Пока ВыборкаПоВидамПользователей.Следующий() Цикл
				Если ВыборкаПоВидамПользователей.ДляВнешнихПользователей Тогда
					СвойстваСписка.ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей
						= ВыборкаПоВидамПользователей.ПараметрыЗадания;
				Иначе
					СвойстваСписка.ПоследнийОбновленныйКлючДоступа
						= ВыборкаПоВидамПользователей.ПараметрыЗадания;
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
	КонецЕсли;
	
	СпискиОбновленияЭлементов = РезультатыЗапроса[1].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
	ОбъектыМетаданныхПоИдентификаторам = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(
		СпискиОбновленияЭлементов.Строки.ВыгрузитьКолонку("Список"), Ложь);
	
	Для Каждого ОписаниеОбновления Из СпискиОбновленияЭлементов.Строки Цикл
		Строка = СтрокиСписков.Получить(ОписаниеОбновления.Список);
		Если Строка = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		ОбъектМетаданных = ОбъектыМетаданныхПоИдентификаторам.Получить(ОписаниеОбновления.Список);
		Если ОбъектМетаданных = Неопределено Или Не ЗначениеЗаполнено(Строка.Список) Тогда
			Если УдаляемыеСтроки.Найти(Строка) = Неопределено Тогда
				УдаляемыеСтроки.Добавить(Строка);
			КонецЕсли;
			Продолжить;
		ИначеЕсли ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных")
		        И Не ЗначениеЗаполнено(Строка.ИмяТаблицы) Тогда
			Строка.ИмяТаблицы = ОбъектМетаданных.ПолноеИмя();
		КонецЕсли;
		СвойстваСписка = СвойстваСписков.Получить(Строка.Список);
		ЗаполнитьДолиОбработанных(Строка, ОписаниеОбновления, СвойстваСписка, Истина, Контекст);
		Если Не Контекст.РассчитыватьПоКоличествуДанных Тогда
			Обработано = ОбработаноПоДолям(Строка.ДоляОбработанныхЭлементовДляПользователей,
				Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей, Строка.ИмяТаблицы, ДействующиеПараметры);
			ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, Обработано, Строка, Контекст);
			ОбнулитьКоличествоЭлементов(Строка, Контекст);
		Иначе
			Если Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда
				СтрокиОбновленияКоличестваЭлементов.Добавить(Строка);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	СпискиОбновленияКлючейДоступа = РезультатыЗапроса[2].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
	ОбъектыМетаданныхПоИдентификаторам = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(
		СпискиОбновленияКлючейДоступа.Строки.ВыгрузитьКолонку("Список"), Ложь);
	
	Для Каждого ОписаниеОбновления Из СпискиОбновленияКлючейДоступа.Строки Цикл
		ОбъектМетаданных = ОбъектыМетаданныхПоИдентификаторам.Получить(ОписаниеОбновления.Список);
		Строка = СтрокиСписков.Получить(ОписаниеОбновления.Список);
		Если Строка = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Если ОбъектМетаданных = Неопределено Или Не ЗначениеЗаполнено(Строка.Список) Тогда
			Если УдаляемыеСтроки.Найти(Строка) = Неопределено Тогда
				УдаляемыеСтроки.Добавить(Строка);
			КонецЕсли;
			Продолжить;
		ИначеЕсли ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных")
		        И Не ЗначениеЗаполнено(Строка.ИмяТаблицы) Тогда
			Строка.ИмяТаблицы = ОбъектМетаданных.ПолноеИмя();
		КонецЕсли;
		СвойстваСписка = СвойстваСписков.Получить(Строка.Список);
		ЗаполнитьДолиОбработанных(Строка, ОписаниеОбновления, СвойстваСписка, Ложь, Контекст);
		Если Не Контекст.РассчитыватьПоКоличествуДанных Тогда
			Обработано = ОбработаноПоДолям(Строка.ДоляОбработанныхКлючейДоступаДляПользователей,
				Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей, Строка.ИмяТаблицы, ДействующиеПараметры);
			ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, Обработано, Строка, Контекст);
			ОбнулитьКоличествоКлючейДоступа(Строка, Контекст);
		Иначе
			Если Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда
				СтрокиОбновленияКоличестваКлючейДоступа.Добавить(Строка);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Для Каждого УдаляемаяСтрока Из УдаляемыеСтроки Цикл
		СтрокиСписков.Удалить(УдаляемаяСтрока.Список);
		СвойстваСписков.Удалить(УдаляемаяСтрока.Список);
		Индекс = Контекст.ДобавленныеСтроки.Найти(УдаляемаяСтрока);
		Если Индекс <> Неопределено Тогда
			Контекст.ДобавленныеСтроки.Удалить(Индекс);
			Продолжить;
		КонецЕсли;
		Контекст.УдаленныеСтроки.Вставить(УдаляемаяСтрока.Список, Истина);
	КонецЦикла;
	
	Индекс = Контекст.ДобавленныеСтроки.Количество() - 1;
	Пока Индекс >= 0 Цикл
		Если Не ЗначениеЗаполнено(Контекст.ДобавленныеСтроки[Индекс].ИмяТаблицы) Тогда
			Контекст.ДобавленныеСтроки.Удалить(Индекс);
		КонецЕсли;
		Индекс = Индекс - 1;
	КонецЦикла;
	
	Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда
		Для Каждого ОписаниеСтроки Из СтрокиСписков Цикл
			СтрокиОбновленияКоличестваЭлементов.Добавить(ОписаниеСтроки.Значение);
			СтрокиОбновленияКоличестваКлючейДоступа.Добавить(ОписаниеСтроки.Значение);
		КонецЦикла;
	КонецЕсли;
	
	Если Контекст.РассчитыватьПоКоличествуДанных Тогда
		КоличествоКлючей = РезультатыЗапроса[5].Выгрузить()[0].Количество;
		Если Контекст.ЭтоПовторноеОбновлениеПрогресса
		   И Контекст.ХранимыеДанные.КоличествоКлючей <> КоличествоКлючей Тогда
			
			Для Каждого ОписаниеСтроки Из СтрокиСписков Цикл
				Если СтрокиОбновленияКоличестваКлючейДоступа.Найти(ОписаниеСтроки.Значение) = Неопределено Тогда
					СтрокиОбновленияКоличестваКлючейДоступа.Добавить(ОписаниеСтроки.Значение);
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
		Контекст.ХранимыеДанные.КоличествоКлючей = КоличествоКлючей;
	Иначе
		Контекст.ХранимыеДанные.КоличествоКлючей = 0;
	КонецЕсли;
	
	Если Контекст.РассчитыватьПоКоличествуДанных Тогда
		ТекущийКонтекст = Новый Структура;
		ТекущийКонтекст.Вставить("ДобавленныеСтроки",                       Контекст.ДобавленныеСтроки);
		ТекущийКонтекст.Вставить("ИзмененныеСтроки",                        Контекст.ИзмененныеСтроки);
		ТекущийКонтекст.Вставить("СвойстваСписков",                         СвойстваСписков);
		ТекущийКонтекст.Вставить("СтрокиСписков",                           СтрокиСписков);
		ТекущийКонтекст.Вставить("ДействующиеПараметры",                    ДействующиеПараметры);
		ТекущийКонтекст.Вставить("СтрокиОбновленияКоличестваЭлементов",     СтрокиОбновленияКоличестваЭлементов);
		ТекущийКонтекст.Вставить("СтрокиОбновленияКоличестваКлючейДоступа", СтрокиОбновленияКоличестваКлючейДоступа);
		ТекущийКонтекст.Вставить("ИдентификаторыТаблиц",                    ИдентификаторыТаблиц);
		ТекущийКонтекст.Вставить("ХранимыеДанные",                          Контекст.ХранимыеДанные);
		ВсегоОбновлено = 100;
		РассчитатьВсегоОбновленоПоКоличествуДанных(ТекущийКонтекст, ВсегоОбновлено);
	Иначе
		Если Контекст.ХранимыеДанные.Свойство("КоличествоЭлементовПоСпискам") Тогда
			Контекст.ХранимыеДанные.Удалить("КоличествоЭлементовПоСпискам");
			Контекст.ХранимыеДанные.Удалить("КоличествоКлючейДоступаПоСпискам");
		КонецЕсли;
		ВсегоКоличество = ИдентификаторыТаблиц.Количество();
		Если СтрокиСписков.Количество() > ВсегоКоличество Тогда
			ВсегоКоличество = СтрокиСписков.Количество();
		КонецЕсли;
		ВсегоОбновлено = (100 + 100) * (ВсегоКоличество - СтрокиСписков.Количество());
		Для Каждого КлючИЗначение Из СтрокиСписков Цикл
			Строка = КлючИЗначение.Значение;
			ВсегоОбновлено = ВсегоОбновлено + Строка.ОбработаноЭлементов + Строка.ОбработаноКлючейДоступа;
		КонецЦикла;
		ВсегоОбновлено = ВсегоОбновлено / 2 / ВсегоКоличество;
	КонецЕсли;
	Если ВсегоОбновлено > 100 Тогда
		ВсегоОбновлено = 100;
	КонецЕсли;
	Контекст.ВсегоОбновлено = Цел(ВсегоОбновлено);
	
	ВремяОбновления = ТекущаяДатаСеанса() - ДатаНачалаОбновленияПрогресса;
	
	Если Контекст.ЭтоПовторноеОбновлениеПрогресса
	   И ВремяОбновления > Контекст.ПериодОбновленияПрогресса Тогда
		
		Контекст.ПериодОбновленияПрогресса = ВремяОбновления;
	Иначе
		Контекст.Удалить("ПериодОбновленияПрогресса");
	КонецЕсли;
	
	Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса И ВремяОбновления > 60 Тогда
		Контекст.АвтообновлениеПрогресса = Ложь;
	Иначе
		Контекст.Удалить("АвтообновлениеПрогресса");
	КонецЕсли;
	
	Отбор = Новый Структура("Метаданные", Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей);
	Задания = РегламентныеЗаданияСервер.НайтиЗадания(Отбор);
	Включено = Ложь;
	Для Каждого Задание Из Задания Цикл
		Если Задание.Использование Тогда
			Включено = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если Не Включено И Контекст.ВсегоОбновлено < 100 Тогда
		Контекст.Вставить("РегламентноеЗаданиеОтключено");
	КонецЕсли;
	
	ПоместитьВоВременноеХранилище(Контекст, АдресРезультата);
	
КонецПроцедуры

///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2019, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

Рекомендации

Похожие публикации

ОбновитьИнформационнуюБазуВФоне (БСП)

СообщениеПрогресса (БСП)

ИдентификаторПрогресса (БСП)

ВыполнитьВФоне (БСП)

Прогресс с помощью СКД на обычных формах

ВыполнитьКомандуВФоне (БСП)

СформироватьСообщениеВФоне (БСП)

СообщитьПрогресс (БСП)

TurboConf ИР адаптер 1.82