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

#Область СлужебныйПрограммныйИнтерфейс

#Область БлокировкаСеансовИЗаданий

// Возвращает текущее состояние блокировки сеансов и регламентных заданий для информационной базы.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//
// Возвращаемое значение: 
//   см. АдминистрированиеКластера.СвойстваБлокировкиСеансовИРегламентныхЗаданий
//
Функция БлокировкаСеансовИЗаданийИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ) Экспорт
	
	Результат = СвойстваИнформационнойБазы(ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ, СловарьСвойствБлокировкиСеансовИРегламентныхЗаданий());
	
	Если Результат.ДатаС = АдминистрированиеКластера.ПустаяДата() Тогда
		Результат.ДатаС = Неопределено;
	КонецЕсли;
	
	Если Результат.ДатаПо = АдминистрированиеКластера.ПустаяДата() Тогда
		Результат.ДатаПо = Неопределено;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Результат.КодРазрешения) Тогда
		Результат.КодРазрешения = "";
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Результат.Сообщение) Тогда
		Результат.Сообщение = "";
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Результат.ПараметрБлокировки) Тогда
		Результат.ПараметрБлокировки = "";
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Устанавливает новое состояние блокировки сеансов и регламентных заданий для информационной базы.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//   СвойстваБлокировкиСеансовИЗаданий - см. АдминистрированиеКластера.СвойстваБлокировкиСеансовИРегламентныхЗаданий
//
Процедура УстановитьБлокировкуСеансовИЗаданийИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ, Знач СвойстваБлокировкиСеансовИЗаданий) Экспорт
	
	УстановитьСвойстваИнформационнойБазы(
		ПараметрыАдминистрированияКластера,
		ПараметрыАдминистрированияИБ,
		СловарьСвойствБлокировкиСеансовИРегламентныхЗаданий(),
		СвойстваБлокировкиСеансовИЗаданий);
	
КонецПроцедуры

// Проверяет корректность параметров администрирования.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//   ПроверятьПараметрыАдминистрированияИнформационнойБазы - Булево - флаг необходимости проверки параметров
//                  администрирования кластера.
//   ПроверятьПараметрыАдминистрированияКластера - Булево - флаг необходимости проверки параметров администрирования кластера
//
Процедура ПроверитьПараметрыАдминистрирования(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ = Неопределено,
	ПроверятьПараметрыАдминистрированияИнформационнойБазы = Истина,
	ПроверятьПараметрыАдминистрированияКластера = Истина) Экспорт
	
	Если ПроверятьПараметрыАдминистрированияКластера Или ПроверятьПараметрыАдминистрированияИнформационнойБазы Тогда
		
		Попытка
			ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
			СвойстваРабочихПроцессов(ИдентификаторКластера, ПараметрыАдминистрированияКластера);
		Исключение
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось подключиться с компьютера %1 к кластеру серверов по причине:
					|%2
				    |
					|Если на компьютере %1 не запущен сервер администрирования (ras), следует его запустить.
					|Например:
					|""%3"" cluster --port=%4 %5:%6
					|
					|Также рекомендуется проверить параметры подключения и сетевого экрана.'"),
				ИмяКомпьютера(), ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()),
				КаталогПрограммы() + ?(ОбщегоНазначения.ЭтоWindowsСервер(), "ras.exe", "ras"),
				XMLСтрока(ПараметрыАдминистрированияКластера.ПортСервераАдминистрирования),
				ПараметрыАдминистрированияКластера.АдресАгентаСервера,
				XMLСтрока(ПараметрыАдминистрированияКластера.ПортАгентаСервера));
		КонецПопытки;
		
	КонецЕсли;
	
	Если ПроверятьПараметрыАдминистрированияИнформационнойБазы Тогда
		
		Словарь = Новый Структура();
		Словарь.Вставить("БлокировкаСеансов", "sessions-deny");
		
		СвойстваИнформационнойБазы(ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ, Словарь);
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область БлокировкаРегламентныхЗаданий

// Возвращает текущее состояние блокировки регламентных заданий для информационной базы.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//
// Возвращаемое значение:
//   Булево
//
Функция БлокировкаРегламентныхЗаданийИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ) Экспорт
	
	Словарь = Новый Структура("БлокировкаРегламентныхЗаданий", "scheduled-jobs-deny");
	
	СвойстваИБ = СвойстваИнформационнойБазы(ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ, Словарь);
	Возврат СвойстваИБ.БлокировкаРегламентныхЗаданий;
	
КонецФункции

// Устанавливает новое состояние блокировки регламентных заданий для информационной базы.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//   БлокировкаРегламентныхЗаданий - Булево - флаг установки блокировки регламентных заданий информационной базы.
//
Процедура УстановитьБлокировкуРегламентныхЗаданийИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ, Знач БлокировкаРегламентныхЗаданий) Экспорт
	
	Словарь = Новый Структура("БлокировкаРегламентныхЗаданий", "scheduled-jobs-deny");
	Свойства = Новый Структура("БлокировкаРегламентныхЗаданий", БлокировкаРегламентныхЗаданий);
	
	УстановитьСвойстваИнформационнойБазы(
		ПараметрыАдминистрированияКластера,
		ПараметрыАдминистрированияИБ,
		Словарь,
		Свойства);
	
КонецПроцедуры

#КонецОбласти

#Область СеансыИнформационнойБазы

// Возвращает описания сеансов информационной базы.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//   Фильтр - см. АдминистрированиеКластера.ФильтрСеансов, Массив из см. АдминистрированиеКластера.ФильтрСеансов
//
// Возвращаемое значение: 
//   Массив из см. АдминистрированиеКластера.СвойстваСеанса
//
Функция СеансыИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ, Знач Фильтр = Неопределено) Экспорт
	
	ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	ИдентификаторИнформационнойБазы = ИдентификаторИнформационнойБазы(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ);
		
	ПараметрыКластера = ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	
	// Лицензии для процессов.
	Команда = "process list --licenses " + ПараметрыКластера;
	ЛицензииПроцессов = Новый Соответствие;
	Для Каждого Лицензия Из ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, , , ТипыСвойствЛицензии()) Цикл
		Лицензия.Вставить("license-type", ?(Лицензия["license-type"] = "soft", 0, 1));
		ЛицензииПроцессов.Вставить(Лицензия["process"], Лицензия); 
	КонецЦикла;
	
	// Процессы.
	Команда = "process list " + ПараметрыКластера;
	Процессы = Новый Соответствие;
	Для Каждого Процесс Из ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, , , ТипыСвойствРабочегоПроцесса()) Цикл
		Процесс.Вставить("license", ЛицензииПроцессов[Процесс["process"]]);
		Процесс.Вставить("running", ?(Процесс["running"], 1, 0));
		Процесс.Вставить("use", ?(Процесс["use"] = "used", 1, ?(Процесс["use"] = "not-used", 0, 2)));  // "not-used" - это неточное значение.
		Процессы.Вставить(Процесс["process"], Процесс);
	КонецЦикла;
	
	// Описания соединений.
	Команда = "connection list " + ПараметрыКластера;
	ОписанияСоединений = Новый Соответствие;
	Для Каждого Соединение Из ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, , , ТипыСвойствОписанияСоединения()) Цикл
		Соединение.Вставить("process", Процессы[Соединение["process"]]);
		ОписанияСоединений.Вставить(Соединение["connection"], Соединение);
	КонецЦикла;
	
	// Лицензии для сеансов.
	Команда = "session list --licenses " + ПараметрыКластера;
	ЛицензииСеансов = Новый Соответствие;
	Для Каждого ЛицензияСеанса Из ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, , , ТипыСвойствЛицензии()) Цикл
		ЛицензияСеанса.Вставить("license-type", ?(ЛицензияСеанса["license-type"] = "soft", 0, 1));
		ЛицензииСеансов.Вставить(ЛицензияСеанса["session"], ЛицензияСеанса);
	КонецЦикла;
	
	// Блокировки сеансов.
	Команда = "lock list --infobase=%1 " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИдентификаторИнформационнойБазы);
	БлокировкиСеансов = Новый Соответствие();
	Для Каждого БлокировкаСеанса Из ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, , , ТипыСвойствБлокировки()) Цикл
		АдминистрированиеКластера.ДанныеСеансаИзБлокировки(БлокировкиСеансов,
		                                                               БлокировкаСеанса["descr"],
		                                                               БлокировкаСеанса["session"],
		                                                               ПараметрыАдминистрированияИБ.ИмяВКластере); 

	КонецЦикла;
	
	// Сеансы.
	Команда = "session list --infobase=%1 " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИдентификаторИнформационнойБазы);
	Фильтр = ФильтрВНотациюRac(Фильтр, СловарьСвойствСеансов());
	Результат = Новый Массив;
	Для Каждого Сеанс Из ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, , Фильтр, ТипыСвойствСеансов()) Цикл
		Сеанс.Вставить("process", Процессы[Сеанс["process"]]);
		Сеанс.Вставить("license", ЛицензииСеансов[Сеанс["session"]]);
		Сеанс.Вставить("connection", ОписанияСоединений[Сеанс["connection"]]);
		РазобранныйСеанс = РазобратьЭлементВывода(Сеанс, СловарьСвойствСеансов());
		
		РазобранныйСеанс.Вставить("РежимБлокировкиБД", ?(БлокировкиСеансов[Сеанс["session"]] <> Неопределено, БлокировкиСеансов[Сеанс["session"]].РежимБлокировкиБД, ""));
		РазобранныйСеанс.Вставить("Разделитель", ?(БлокировкиСеансов[Сеанс["session"]] <> Неопределено, БлокировкиСеансов[Сеанс["session"]].Разделитель, ""));
		
		Результат.Добавить(РазобранныйСеанс);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Удаляет сеансы с информационной базой по фильтру.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//   Фильтр - см. АдминистрированиеКластера.ФильтрСеансов, Массив из см. АдминистрированиеКластера.ФильтрСеансов
//
Процедура УдалитьСеансыИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ, Знач Фильтр = Неопределено) Экспорт
	
	ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	ИдентификаторИнформационнойБазы = ИдентификаторИнформационнойБазы(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ);
	
	ПараметрыКластера = ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	
	КоличествоПопыток = 3;
	ВсеСеансыУдалены = Ложь;
	
	Для ТекущаяПопытка = 0 По КоличествоПопыток Цикл
		
		Сеансы = СвойстваСеансов(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИдентификаторИнформационнойБазы, Фильтр, Ложь);
		
		Если Сеансы.Количество() = 0 Тогда
			
			ВсеСеансыУдалены = Истина;
			Прервать;
			
		ИначеЕсли ТекущаяПопытка = КоличествоПопыток Тогда
			
			Прервать;
			
		КонецЕсли;
		
		Для Каждого Сеанс Из Сеансы Цикл
			
			Попытка
				
				Команда = "session terminate --session=%1 " + ПараметрыКластера;
				ПодставитьПараметрыВКоманду(Команда,  Сеанс.Получить("session"));
				ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
				
			Исключение
				
				// Сеанс мог завершиться к моменту вызова rac session terminate.
				Продолжить;
				
			КонецПопытки;
			
		КонецЦикла;
		
	КонецЦикла;
	
	Если Не ВсеСеансыУдалены Тогда
	
		ВызватьИсключение НСтр("ru = 'Не удалось удалить сеансы.'");
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область СоединенияСИнформационнойБазой

// Возвращает описания соединений с информационной базой.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//   Фильтр - см. АдминистрированиеКластера.ФильтрСоединений, Массив из см. АдминистрированиеКластера.ФильтрСоединений
//
// Возвращаемое значение:
//   Массив из см. АдминистрированиеКластера.СвойстваСоединения
//
Функция СоединенияСИнформационнойБазой(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ, Знач Фильтр = Неопределено) Экспорт
	
	ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	ИдентификаторИнформационнойБазы = ИдентификаторИнформационнойБазы(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ);
	Возврат СвойстваСоединений(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИдентификаторИнформационнойБазы, ПараметрыАдминистрированияИБ, Фильтр, Истина);
	
КонецФункции

// Разрывает соединения с информационной базой по фильтру.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//   Фильтр - см. АдминистрированиеКластера.ФильтрСоединений, Массив из см. АдминистрированиеКластера.ФильтрСоединений
//
Процедура РазорватьСоединенияСИнформационнойБазой(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ, Знач Фильтр = Неопределено) Экспорт
	
	ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	ИдентификаторИнформационнойБазы = ИдентификаторИнформационнойБазы(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ);
	
	ПараметрыКластера = ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	
	Значение = Новый Массив;
	Значение.Добавить("1CV8");               // идентификатор приложения 1С:Предприятие в режиме запуска "Толстый клиент".
	Значение.Добавить("1CV8C");              // идентификатор приложения 1С:Предприятие в режиме запуска "Тонкий клиент".
	Значение.Добавить("WebClient");          // идентификатор приложения 1С:Предприятие в режиме запуска "Веб-клиент".
	Значение.Добавить("Designer");           // идентификатор приложения Конфигуратор.
	Значение.Добавить("COMConnection");      // идентификатор сессии внешнего соединения 1С:Предприятия через COM.
	Значение.Добавить("WSConnection");       // идентификатор сессии Web-сервиса.
	Значение.Добавить("BackgroundJob");      // идентификатор сессии обработки заданий.
	Значение.Добавить("WebServerExtension"); // идентификатор расширения Web-сервера.

	АдминистрированиеКластера.ДобавитьУсловиеФильтра(Фильтр, "ИдентификаторКлиентскогоПриложения", ВидСравнения.ВСписке, Значение);
	
	КоличествоПопыток = 3;
	ВсеСоединенияРазорваны = Ложь;
	
	Для ТекущаяПопытка = 0 По КоличествоПопыток Цикл
	
		Соединения = СвойстваСоединений(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИдентификаторИнформационнойБазы, ПараметрыАдминистрированияИБ, Фильтр, Ложь);
		
		Если Соединения.Количество() = 0 Тогда
			
			ВсеСоединенияРазорваны = Истина;
			Прервать;
			
		ИначеЕсли ТекущаяПопытка = КоличествоПопыток Тогда
			
			Прервать;
			
		КонецЕсли;
	
		Для Каждого Соединение Из Соединения Цикл
			
			Попытка
				
				Команда = "connection disconnect --process=%1 --connection=%2 --infobase-user=%3 --infobase-pwd=%4 " + ПараметрыКластера;
				ПодставитьПараметрыВКоманду(Команда,
					Соединение.Получить("process"),
					Соединение.Получить("connection"),
					ПараметрыАдминистрированияИБ.ИмяАдминистратораИнформационнойБазы,
					ПараметрыАдминистрированияИБ.ПарольАдминистратораИнформационнойБазы);
				ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
				
			Исключение
				
				// Соединение могло уже завершиться к моменту вызова rac connection disconnect.
				Продолжить;
				
			КонецПопытки;
			
		КонецЦикла;
		
	КонецЦикла;
	
	Если Не ВсеСоединенияРазорваны Тогда
	
		ВызватьИсключение НСтр("ru = 'Не удалось разорвать соединения.'");
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ПрофилиБезопасности

// Возвращает имя профиля безопасности, назначенного для информационной базы.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//
// Возвращаемое значение: 
//   Строка - имя профиля безопасности, назначенного для информационной базы. Если для информационной базы не назначен
//            профиль безопасности - возвращается пустая строка.
//
Функция ПрофильБезопасностиИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ) Экспорт
	
	Словарь = Новый Структура();
	Словарь.Вставить("ИмяПрофиля", "security-profile-name");
	
	Результат = СвойстваИнформационнойБазы(ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ, Словарь).ИмяПрофиля;
	Если ЗначениеЗаполнено(Результат) Тогда
		Возврат Результат;
	Иначе
		Возврат "";
	КонецЕсли;
	
КонецФункции

// Возвращает имя профиля безопасности, назначенного для информационной базы в качестве профиля безопасности
//  безопасного режима.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//
// Возвращаемое значение: 
//   Строка - имя профиля безопасности, назначенного для информационной базы в качестве профиля безопасности безопасного
//            режима. Если для информационной базы не назначен профиль безопасности - возвращается пустая строка.
//
Функция ПрофильБезопасностиБезопасногоРежимаИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ) Экспорт
	
	Словарь = Новый Структура();
	Словарь.Вставить("ИмяПрофиля", "safe-mode-security-profile-name");
	
	Результат = СвойстваИнформационнойБазы(ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ, Словарь).ИмяПрофиля;
	Если ЗначениеЗаполнено(Результат) Тогда
		Возврат Результат;
	Иначе
		Возврат "";
	КонецЕсли;
	
КонецФункции

// Назначает для информационной базы использование профиля безопасности.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//   ИмяПрофиля - Строка - имя профиля безопасности. Если передана пустая строка - для информационной базы будет 
//                         отключено использование профиля безопасности.
//
Процедура УстановитьПрофильБезопасностиИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ, Знач ИмяПрофиля = "") Экспорт
	
	Словарь = Новый Структура();
	Словарь.Вставить("ИмяПрофиля", "security-profile-name");
	
	Значения = Новый Структура();
	Значения.Вставить("ИмяПрофиля", ИмяПрофиля);
	
	УстановитьСвойстваИнформационнойБазы(
		ПараметрыАдминистрированияКластера,
		ПараметрыАдминистрированияИБ,
		Словарь,
		Значения);
	
КонецПроцедуры

// Назначает для информационной базы использование профиля безопасности безопасного режима.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//   ИмяПрофиля - Строка - имя профиля безопасности. Если передана пустая строка - для информационной базы будет
//                         отключено использование профиля безопасности безопасного режима.
//
Процедура УстановитьПрофильБезопасностиБезопасногоРежимаИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ, Знач ИмяПрофиля = "") Экспорт
	
	Словарь = Новый Структура();
	Словарь.Вставить("ИмяПрофиля", "safe-mode-security-profile-name");
	
	Значения = Новый Структура();
	Значения.Вставить("ИмяПрофиля", ИмяПрофиля);
	
	УстановитьСвойстваИнформационнойБазы(
		ПараметрыАдминистрированияКластера,
		ПараметрыАдминистрированияИБ,
		Словарь,
		Значения);
	
КонецПроцедуры

// Проверяет существование в кластере серверов профиля безопасности.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ИмяПрофиля - Строка - имя профиля безопасности, существование которого проверяется.
//
// Возвращаемое значение:
//   Булево
//
Функция ПрофильБезопасностиСуществует(Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля) Экспорт
	
	Фильтр = Новый Структура("Имя", ИмяПрофиля);
	
	ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	
	ПрофилиБезопасности = ПолучитьПрофилиБезопасности(ИдентификаторКластера, ПараметрыАдминистрированияКластера, Фильтр);
	
	Возврат (ПрофилиБезопасности.Количество() = 1);
	
КонецФункции

// Возвращает свойства профиля безопасности.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ИмяПрофиля - Строка - имя профиля безопасности.
//   ИдентификаторКластера - Строка - внутренний идентификатор кластера серверов.
//
// Возвращаемое значение: 
//   см. АдминистрированиеКластера.СвойстваПрофиляБезопасности
//
Функция ПрофильБезопасности(Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач ИдентификаторКластера = Неопределено) Экспорт
	
	Фильтр = Новый Структура("Имя", ИмяПрофиля);
	
	Если ИдентификаторКластера = Неопределено Тогда
		ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	КонецЕсли;
	
	ПрофилиБезопасности = ПолучитьПрофилиБезопасности(ИдентификаторКластера, ПараметрыАдминистрированияКластера, Фильтр);
	
	Если ПрофилиБезопасности.Количество() <> 1 Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'В кластере серверов %1 не зарегистрирован профиль безопасности %2'"), ИдентификаторКластера, ИмяПрофиля);
	КонецЕсли;
	
	Результат = ПрофилиБезопасности[0];
	Результат = ПреобразоватьЗначенияСвойствИспользованияСписковДоступа(Результат);
	
	// Виртуальный каталоги
	Результат.Вставить("ВиртуальныеКаталоги",
		ПолучитьВиртуальныеКаталоги(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИмяПрофиля));
	
	// Разрешенные COM-классы
	Результат.Вставить("COMКлассы",
		ПолучитьРазрешенныеCOMКлассы(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИмяПрофиля));
	
	// Внешние компоненты
	Результат.Вставить("ВнешниеКомпоненты",
		ПолучитьРазрешенныеВнешниеКомпоненты(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИмяПрофиля));
	
	// Внешние модули
	Результат.Вставить("ВнешниеМодули",
		ПолучитьРазрешенныеВнешниеМодули(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИмяПрофиля));
	
	// Приложения ОС
	Результат.Вставить("ПриложенияОС",
		ПолучитьРазрешенныеПриложенияОС(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИмяПрофиля));
	
	// Интернет-ресурсы
	Результат.Вставить("ИнтернетРесурсы",
		ПолучитьРазрешенныеИнтернетРесурсы(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИмяПрофиля));
	
	Возврат Результат;
	
КонецФункции

// Создает профиль безопасности по переданному описанию.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   СвойстваПрофиляБезопасности - см. АдминистрированиеКластера.СвойстваПрофиляБезопасности
//
Процедура СоздатьПрофильБезопасности(Знач ПараметрыАдминистрированияКластера, Знач СвойстваПрофиляБезопасности) Экспорт
	
	ИмяПрофиля = СвойстваПрофиляБезопасности.Имя;
	
	Фильтр = Новый Структура("Имя", ИмяПрофиля);
	
	ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	
	ПрофилиБезопасности = ПолучитьПрофилиБезопасности(ИдентификаторКластера, ПараметрыАдминистрированияКластера, Фильтр);
	
	Если ПрофилиБезопасности.Количество() = 1 Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'В кластере серверов %1 уже зарегистрирован профиль безопасности %2'"), ИдентификаторКластера, ИмяПрофиля);
	КонецЕсли;
	
	ОбновитьСвойстваПрофиляБезопасности(ПараметрыАдминистрированияКластера, СвойстваПрофиляБезопасности);
	
КонецПроцедуры

// Устанавливает свойства для существующего профиля безопасности по переданному описанию.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   СвойстваПрофиляБезопасности - см. АдминистрированиеКластера.СвойстваПрофиляБезопасности
//
Процедура УстановитьСвойстваПрофиляБезопасности(Знач ПараметрыАдминистрированияКластера, Знач СвойстваПрофиляБезопасности)  Экспорт
	
	ИмяПрофиля = СвойстваПрофиляБезопасности.Имя;
	
	Фильтр = Новый Структура("Имя", ИмяПрофиля);
	
	ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	
	ПрофилиБезопасности = ПолучитьПрофилиБезопасности(ИдентификаторКластера, ПараметрыАдминистрированияКластера, Фильтр);
	
	Если ПрофилиБезопасности.Количество() <> 1 Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'В кластере серверов %1 не зарегистрирован профиль безопасности %2'"), ИдентификаторКластера, ИмяПрофиля);
	КонецЕсли;
	
	СтарыеСвойства = ПрофильБезопасности(ПараметрыАдминистрированияКластера, ИмяПрофиля, ИдентификаторКластера);
	
	ОбновитьСвойстваПрофиляБезопасности(ПараметрыАдминистрированияКластера, СвойстваПрофиляБезопасности, СтарыеСвойства);
	
КонецПроцедуры

// Удаляет профиль безопасности.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ИмяПрофиля - Строка - имя профиля безопасности.
//
Процедура УдалитьПрофильБезопасности(Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля) Экспорт
	
	Команда = "profile remove --name=%1 " + ПараметрыКластера(ПараметрыАдминистрированияКластера);
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля);
	ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
	
КонецПроцедуры

#КонецОбласти

#Область ИнформационныеБазы

// Возвращает внутренний идентификатор информационной базы.
//
// Параметры:
//   ИдентификаторКластера - Строка - внутренний идентификатор кластера серверов.
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//
// Возвращаемое значение: 
//   Строка
//
Функция ИдентификаторИнформационнойБазы(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИнформационнойБазы) Экспорт
	
	Фильтр = Новый Структура("name", ПараметрыАдминистрированияИнформационнойБазы.ИмяВКластере);
	
	ИнформационныеБазы = СвойстваИнформационныхБаз(ИдентификаторКластера, ПараметрыАдминистрированияКластера, Фильтр);
	
	Если ИнформационныеБазы.Количество() = 1 Тогда
		Возврат ИнформационныеБазы[0].Получить("infobase");
	Иначе
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'В кластере серверов %1 не зарегистрирована информационная база %2'"), ИдентификаторКластера, ПараметрыАдминистрированияИнформационнойБазы.ИмяВКластере);
	КонецЕсли;
	
КонецФункции

// Возвращает описания информационных баз.
//
// Параметры:
//   ИдентификаторКластера - Строка - внутренний идентификатор кластера серверов.
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   Фильтр - Структура - параметры фильтрации информационных баз.
//
// Возвращаемое значение:
//   Массив из Структура
//
Функция СвойстваИнформационныхБаз(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач Фильтр = Неопределено) Экспорт
	
	Команда = "infobase summary list " + ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	Свойства = ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, , Фильтр, ТипыСвойствОписанияБазы());
	
	Возврат Свойства;
	
КонецФункции

#КонецОбласти

#Область Кластер

// Возвращает внутренний идентификатор кластера серверов.
//
// Параметры:
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//
// Возвращаемое значение:
//   Строка
//
Функция ИдентификаторКластера(Знач ПараметрыАдминистрированияКластера) Экспорт
	
	Фильтр = Новый Структура("port", ПараметрыАдминистрированияКластера.ПортКластера);
	
	Кластеры = СвойстваКластеров(ПараметрыАдминистрированияКластера, Фильтр);
	
	Если Кластеры.Количество() = 1 Тогда
		Возврат Кластеры[0].Получить("cluster");
	Иначе
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не обнаружен кластер серверов с портом %1'"), ПараметрыАдминистрированияКластера.ПортКластера);
	КонецЕсли;
	
КонецФункции

// Возвращает описания кластеров серверов.
//
// Параметры:  
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   Фильтр - Структура - параметры фильтрации кластеров серверов.
//
// Возвращаемое значение: 
//   Массив - массив соответствий, описаний кластеров в нотации rac.
//
Функция СвойстваКластеров(Знач ПараметрыАдминистрированияКластера, Знач Фильтр = Неопределено) Экспорт
	
	Если ЗначениеЗаполнено(ПараметрыАдминистрированияКластера.АдресСервераАдминистрирования) Тогда
		Сервер = СокрЛП(ПараметрыАдминистрированияКластера.АдресСервераАдминистрирования);
		Если ЗначениеЗаполнено(ПараметрыАдминистрированияКластера.ПортСервераАдминистрирования) Тогда
			Сервер = Сервер + ":" + ПривестиЗначение(ПараметрыАдминистрированияКластера.ПортСервераАдминистрирования);
		КонецЕсли;
	Иначе
		Сервер = "";
	КонецЕсли;
	
	Возврат ЗапуститьКоманду("cluster list " + Сервер, ПараметрыАдминистрированияКластера, , Фильтр, ТипыСвойствКластера());
	
КонецФункции

#КонецОбласти

#Область РабочиеПроцессыСерверы

// Возвращает описания рабочих процессов.
//
// Параметры:
//   ИдентификаторКластера - Строка - внутренний идентификатор кластера серверов,
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   Фильтр - Структура - параметры фильтрации рабочих процессов.
//
// Возвращаемое значение: 
//   Массив - массив соответствий, описаний рабочих процессов в нотации rac.
//
Функция СвойстваРабочихПроцессов(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач Фильтр = Неопределено) Экспорт
	
	Возврат ЗапуститьКоманду("process list " + ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера), ПараметрыАдминистрированияКластера, , Фильтр);
	
КонецФункции

// Возвращает описания рабочих серверов.
//
// Параметры:
//  ИдентификаторКластера - Строка - внутренний идентификатор кластера серверов,
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   Фильтр - Структура - параметры фильтрации рабочих серверов.
//
// Возвращаемое значение: 
//   Массив - массив соответствий, описаний рабочих серверов в нотации rac.
//
Функция СвойстваРабочихСерверов(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач Фильтр = Неопределено) Экспорт
	
	ПараметрыКластера = ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	
	Возврат ЗапуститьКоманду("server list " + ПараметрыКластера, ПараметрыАдминистрированияКластера, , Фильтр, ТипыСвойствРабочихСерверов());
	
КонецФункции

#КонецОбласти

// Возвращает описания сеансов информационной базы.
//
// Параметры:
//   ИдентификаторКластера - Строка - внутренний идентификатор кластера серверов.
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ИдентификаторИнформационнойБазы - Строка - внутренний идентификатор информационной базы.
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//   Фильтр - см. АдминистрированиеКластера.ФильтрСеансов, Массив из см. АдминистрированиеКластера.ФильтрСеансов
//   ИспользоватьСловарь - Булево - если Истина, возвращаемый результат будет заполнен с использованием словаря.
//
// Возвращаемое значение: 
//   - Массив из см. АдминистрированиеКластера.СвойстваСеанса
//   - Массив из Соответствие
//
Функция СвойстваСеансов(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИдентификаторИнформационнойБазы, Знач Фильтр = Неопределено, Знач ИспользоватьСловарь = Истина) Экспорт
	
	Команда = "session list --infobase=%1 " + ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);	
	ПодставитьПараметрыВКоманду(Команда, ИдентификаторИнформационнойБазы);	
	
	Если ИспользоватьСловарь Тогда
		Словарь = СловарьСвойствСеансов();
	Иначе
		Словарь = Неопределено;
		Фильтр = ФильтрВНотациюRac(Фильтр, СловарьСвойствСеансов());
	КонецЕсли;
	
	Результат = ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, Словарь, Фильтр, ТипыСвойствСеансов());
	
	Возврат Результат;                                       
	
КонецФункции

// Возвращает описания соединений с информационной базой.
//
// Параметры:
//   ИдентификаторКластера - Строка - внутренний идентификатор кластера серверов.
//   ПараметрыАдминистрированияКластера - см. АдминистрированиеКластера.ПараметрыАдминистрированияКластера
//   ИдентификаторИнформационнойБазы - Строка - внутренний идентификатор информационной базы.
//   ПараметрыАдминистрированияИБ - см. АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера
//   Фильтр - см. АдминистрированиеКластера.ФильтрСеансов, Массив из см. АдминистрированиеКластера.ФильтрСеансов
//   ИспользоватьСловарь - Булево - если Истина, возвращаемый результат будет заполнен с использованием словаря.
//
// Возвращаемое значение: 
//   - Массив из см. АдминистрированиеКластера.СвойстваСоединения
//   - Массив из Соответствие
//
Функция СвойстваСоединений(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИдентификаторИнформационнойБазы, Знач ПараметрыАдминистрированияИБ, Знач Фильтр = Неопределено, Знач ИспользоватьСловарь = Ложь) Экспорт
	
	ПараметрыКластера = ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	
	Если ИспользоватьСловарь Тогда
		Словарь = СловарьСвойствСоединений();
	Иначе
		Словарь = Неопределено;
		Фильтр = ФильтрВНотациюRac(Фильтр, СловарьСвойствСоединений());
	КонецЕсли;
	
	Результат = Новый Массив();
	РабочиеПроцессы = СвойстваРабочихПроцессов(ИдентификаторКластера, ПараметрыАдминистрированияКластера);
	
	Для Каждого РабочийПроцесс Из РабочиеПроцессы Цикл
		
		Команда = "connection list --process=%1 --infobase=%2 --infobase-user=%3 --infobase-pwd=%4 " + ПараметрыКластера;
		ПодставитьПараметрыВКоманду(Команда,
			РабочийПроцесс.Получить("process"),
			ИдентификаторИнформационнойБазы,
			ПараметрыАдминистрированияИБ.ИмяАдминистратораИнформационнойБазы,
			ПараметрыАдминистрированияИБ.ПарольАдминистратораИнформационнойБазы);
			
		СоединенияРабочегоПроцесса = ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, Словарь, Фильтр, ТипыСвойствСоединений());
		Для Каждого Соединение Из СоединенияРабочегоПроцесса Цикл
			Если ИспользоватьСловарь Тогда
				Если Соединение.РежимСоединенияСБазойДанных = "none" Тогда
					Соединение.Вставить("РежимСоединенияСБазойДанных", 0);
				ИначеЕсли Соединение.РежимСоединенияСБазойДанных = "shared" Тогда
					Соединение.Вставить("РежимСоединенияСБазойДанных", 1);
				Иначе // exclusive
					Соединение.Вставить("РежимСоединенияСБазойДанных", 2);
				КонецЕсли;
				Соединение.Вставить("РежимСоединенияСИнформационнойБазой", ?(Соединение.РежимСоединенияСИнформационнойБазой = "shared", 0, 1));
				Соединение.Вставить("УправлениеНаходитсяНаСервере", ?(Соединение.УправлениеНаходитсяНаСервере = "client", 0, 1));
			Иначе
				Соединение.Вставить("process", РабочийПроцесс.Получить("process"));
			КонецЕсли;
			Результат.Добавить(Соединение);
		КонецЦикла;
		
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Возвращает путь к консольному клиенту сервера администрирования.
//
// Возвращаемое значение:
//   Строка
//
Функция ПутьККлиентуСервераАдминистрирования() Экспорт
	
	КаталогЗапуска = КаталогИсполняемыхФайловПлатформы();
	Клиент = КаталогЗапуска + "rac";
	
	Если ОбщегоНазначения.ЭтоWindowsСервер() Тогда
		Клиент = Клиент + ".exe";
	КонецЕсли;
	
	Возврат Клиент;
	
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция КаталогИсполняемыхФайловПлатформы()
	
	Результат = КаталогПрограммы();
	СимволРазделителя = ПолучитьРазделительПути();
	
	Если Прав(Результат, 1) <> СимволРазделителя Тогда
		Результат = Результат + СимволРазделителя;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция СвойстваИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ, Знач Словарь)
	
	ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	ИдентификаторИнформационнойБазы = ИдентификаторИнформационнойБазы(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ);
	
	ПараметрыКластера = ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	
	Команда = "infobase info --infobase=%1 --infobase-user=%2 --infobase-pwd=%3";
	ПодставитьПараметрыВКоманду(Команда, 
		ИдентификаторИнформационнойБазы, 
		ПараметрыАдминистрированияИБ.ИмяАдминистратораИнформационнойБазы, 
		ПараметрыАдминистрированияИБ.ПарольАдминистратораИнформационнойБазы);
		
	Результат = ЗапуститьКоманду(Команда + " " + ПараметрыКластера, ПараметрыАдминистрированияКластера, Словарь, , ТипыСвойствИнформационнойБазы());
	
	Возврат Результат[0];
	
КонецФункции

Процедура УстановитьСвойстваИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ, Знач Словарь, Знач ЗначенияСвойств)
	
	ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	ИдентификаторИнформационнойБазы = ИдентификаторИнформационнойБазы(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ);
	
	ПараметрыКластера = ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	
	ПараметрыПолучения = Новый Структура;
	ПараметрыПолучения.Вставить("ПараметрыАдминистрированияКластера", ПараметрыАдминистрированияКластера);
	ПараметрыПолучения.Вставить("ПараметрыАдминистрированияИБ", ПараметрыАдминистрированияИБ);
	ПараметрыПолучения.Вставить("ТипОбъекта", "infobase");
	ПоддерживаемыеСвойства = ПоддерживаемыеСвойстваОбъектов(ПараметрыПолучения);
	
	Команда = "infobase update --infobase=%1 --infobase-user=%2 --infobase-pwd=%3";
	ПодставитьПараметрыВКоманду(Команда, 
		ИдентификаторИнформационнойБазы, 
		ПараметрыАдминистрированияИБ.ИмяАдминистратораИнформационнойБазы, 
		ПараметрыАдминистрированияИБ.ПарольАдминистратораИнформационнойБазы);
		
	// Для этих двух булевых свойств отличается представление.
	НовыеЗначенияСвойств = ОбщегоНазначения.СкопироватьРекурсивно(ЗначенияСвойств);
	Для Каждого КлючИЗначение Из Словарь Цикл
		Если КлючИЗначение.Значение = "scheduled-jobs-deny" Или КлючИЗначение.Значение = "sessions-deny" Тогда
			НовыеЗначенияСвойств.Вставить(КлючИЗначение.Ключ, Формат(НовыеЗначенияСвойств[КлючИЗначение.Ключ], "БЛ=off; БИ=on"));
		КонецЕсли;
	КонецЦикла;
	
	ДобавитьПараметрыКомандыПоСловарю(Команда, Словарь, НовыеЗначенияСвойств, ПоддерживаемыеСвойства);
	
	ЗапуститьКоманду(Команда + " " + ПараметрыКластера, ПараметрыАдминистрированияКластера);
	
КонецПроцедуры

Функция ПолучитьПрофилиБезопасности(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач Фильтр = Неопределено)
	
	Команда = "profile list " + ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	Результат = ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, СловарьСвойствПрофиляБезопасности(), Фильтр, ТипыСвойствПрофиля()); 
	
	Возврат Результат;
	
КонецФункции

Функция ПолучитьВиртуальныеКаталоги(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач Фильтр = Неопределено)
	
	Возврат СпискиКонтроляДоступа(
		ИдентификаторКластера,
		ПараметрыАдминистрированияКластера,
		ИмяПрофиля,
		"directory", // Не локализуется
		СловарьСвойствВиртуальногоКаталога(),
		,
		ТипыСвойствВиртуальногоКаталога());
	
КонецФункции

Функция ПолучитьРазрешенныеCOMКлассы(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач Фильтр = Неопределено)
	
	Возврат СпискиКонтроляДоступа(
		ИдентификаторКластера,
		ПараметрыАдминистрированияКластера,
		ИмяПрофиля,
		"com", // Не локализуется
		СловарьСвойствCOMКласса(),
		,
		ТипыСвойствCOMКласса());
	
КонецФункции

Функция ПолучитьРазрешенныеВнешниеКомпоненты(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач Фильтр = Неопределено)
	
	Возврат СпискиКонтроляДоступа(
		ИдентификаторКластера,
		ПараметрыАдминистрированияКластера,
		ИмяПрофиля,
		"addin", // Не локализуется
		СловарьСвойствВнешнейКомпоненты(),
		,
		ТипыСвойствВнешнейКомпоненты());
	
КонецФункции

Функция ПолучитьРазрешенныеВнешниеМодули(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач Фильтр = Неопределено)
	
	Возврат СпискиКонтроляДоступа(
		ИдентификаторКластера,
		ПараметрыАдминистрированияКластера,
		ИмяПрофиля,
		"module", // Не локализуется
		СловарьСвойствВнешнегоМодуля(),
		,
		ТипыСвойствВнешнегоМодуля());
	
КонецФункции

Функция ПолучитьРазрешенныеПриложенияОС(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач Фильтр = Неопределено)
	
	Возврат СпискиКонтроляДоступа(
		ИдентификаторКластера,
		ПараметрыАдминистрированияКластера,
		ИмяПрофиля,
		"app", // Не локализуется
		СловарьСвойствПриложенияОС(),
		,
		ТипыСвойствПриложенияОС());
	
КонецФункции

Функция ПолучитьРазрешенныеИнтернетРесурсы(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач Фильтр = Неопределено)
	
	Возврат СпискиКонтроляДоступа(
		ИдентификаторКластера,
		ПараметрыАдминистрированияКластера,
		ИмяПрофиля,
		"inet", // Не локализуется
		СловарьСвойствИнтернетРесурса(),
		,
		ТипыСвойствИнтернетРесурса());
	
КонецФункции

Функция СпискиКонтроляДоступа(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач ИмяСписка, Знач Словарь, Знач Фильтр = Неопределено, Знач ТипыСвойств = Неопределено)
	
	Команда = "profile acl --name=%1 %2 list " + ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля, ИмяСписка);
	
	Результат = ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, Словарь, Фильтр, ТипыСвойств);
	
	Возврат Результат;
	
КонецФункции

Процедура ОбновитьСвойстваПрофиляБезопасности(Знач ПараметрыАдминистрированияКластера, Знач НовыеСвойства, Знач СтарыеСвойства = Неопределено)
	
	Если СтарыеСвойства = Неопределено Тогда
		СтарыеСвойства = АдминистрированиеКластера.СвойстваПрофиляБезопасности();
	КонецЕсли;
	
	ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	ПараметрыКластера = ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	
	ИмяПрофиля = НовыеСвойства.Имя;
	
	ПараметрыПолучения = Новый Структура;
	ПараметрыПолучения.Вставить("ПараметрыАдминистрированияКластера", ПараметрыАдминистрированияКластера);
	ПараметрыПолучения.Вставить("ТипОбъекта", "profile");
	ПоддерживаемыеСвойства = ПоддерживаемыеСвойстваОбъектов(ПараметрыПолучения);
	
	СловарьСвойствПрофиля = СловарьСвойствПрофиляБезопасности(Ложь);
	Для Каждого ФрагментСловаря Из СловарьСвойствПрофиля Цикл
		Если НовыеСвойства.Свойство(ФрагментСловаря.Ключ) Тогда
			Если НовыеСвойства[ФрагментСловаря.Ключ] <> СтарыеСвойства[ФрагментСловаря.Ключ] Тогда
				Команда = "profile update";
				ДобавитьПараметрыКомандыПоСловарю(Команда, СловарьСвойствПрофиля, НовыеСвойства, ПоддерживаемыеСвойства.profile); 
				ЗапуститьКоманду(Команда + " " + ПараметрыКластера, ПараметрыАдминистрированияКластера);
				Прервать;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Для Каждого ФрагментСловаря Из СловарьСвойствИспользованияСписокКонтроляДоступа() Цикл
		Если НовыеСвойства[ФрагментСловаря.Ключ] = СтарыеСвойства[ФрагментСловаря.Ключ] Тогда
			Продолжить;
		КонецЕсли;
		УстановитьИспользованиеСпискаКонтроляДоступа(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИмяПрофиля, ФрагментСловаря.Значение, Не НовыеСвойства[ФрагментСловаря.Ключ]);
	КонецЦикла;
	
	// Виртуальные каталоги
	ОбновитьЭлементыСпискаКонтроляДоступа(ИдентификаторКластера, 
		ПараметрыАдминистрированияКластера, 
		ИмяПрофиля, 
		"directory", 
		СловарьСвойствВиртуальногоКаталога(), 
		НовыеСвойства.ВиртуальныеКаталоги,
		СтарыеСвойства.ВиртуальныеКаталоги);
	
	// Разрешенные COM-классы
	ОбновитьЭлементыСпискаКонтроляДоступа(ИдентификаторКластера, 
		ПараметрыАдминистрированияКластера, 
		ИмяПрофиля, 
		"com", 
		СловарьСвойствCOMКласса(), 
		НовыеСвойства.COMКлассы,
		СтарыеСвойства.COMКлассы);
	
	// Внешние компоненты
	ОбновитьЭлементыСпискаКонтроляДоступа(ИдентификаторКластера, 
		ПараметрыАдминистрированияКластера, 
		ИмяПрофиля, 
		"addin", 
		СловарьСвойствВнешнейКомпоненты(), 
		НовыеСвойства.ВнешниеКомпоненты,
		СтарыеСвойства.ВнешниеКомпоненты);
	
	// Внешние модули
	ОбновитьЭлементыСпискаКонтроляДоступа(ИдентификаторКластера, 
		ПараметрыАдминистрированияКластера, 
		ИмяПрофиля, 
		"module", 
		СловарьСвойствВнешнегоМодуля(),
		НовыеСвойства.ВнешниеМодули,
		СтарыеСвойства.ВнешниеМодули);
		
	// Приложения ОС
	ОбновитьЭлементыСпискаКонтроляДоступа(ИдентификаторКластера, 
		ПараметрыАдминистрированияКластера, 
		ИмяПрофиля, 
		"app", 
		СловарьСвойствПриложенияОС(), 
		НовыеСвойства.ПриложенияОС,
		СтарыеСвойства.ПриложенияОС);
	
	// Интернет-ресурсы
	ОбновитьЭлементыСпискаКонтроляДоступа(ИдентификаторКластера, 
		ПараметрыАдминистрированияКластера,
		ИмяПрофиля, 
		"inet", 
		СловарьСвойствИнтернетРесурса(), 
		НовыеСвойства.ИнтернетРесурсы,
		СтарыеСвойства.ИнтернетРесурсы);
	
КонецПроцедуры

Процедура УстановитьИспользованиеСпискаКонтроляДоступа(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач ИмяСписка, Знач Использование)
	
	Команда = "profile acl --name=%1 %2 --access=%3 " + ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля, ИмяСписка, ?(Использование, "list", "full"));
	ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
	
КонецПроцедуры

Процедура УдалитьЭлементСпискаКонтроляДоступа(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, 
	Знач ИмяПрофиля, Знач ИмяСписка, Знач КлючЭлемента)
	
	КлючСписка = КлючиСписковКонтроляДоступа()[ИмяСписка];
	
	Команда = "profile acl --name=%1 %2 remove --%3=%4 " + ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля, ИмяСписка, КлючСписка, КлючЭлемента); 
	
	ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
	
КонецПроцедуры

Процедура ОбновитьЭлементСпискаКонтроляДоступа(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, 
	Знач ИмяПрофиля, Знач ИмяСписка, Знач Словарь, Знач СвойстваЭлемента)
	
	ПараметрыКластера = ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера);
	
	ПараметрыПолучения = Новый Структура;
	ПараметрыПолучения.Вставить("ПараметрыАдминистрированияКластера", ПараметрыАдминистрированияКластера);
	ПараметрыПолучения.Вставить("ТипОбъекта", "profile");
	ПоддерживаемыеСвойства = ПоддерживаемыеСвойстваОбъектов(ПараметрыПолучения);
	
	Команда = "profile acl --name=%1 %2 update";
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля, ИмяСписка);
	ДобавитьПараметрыКомандыПоСловарю(Команда, Словарь, СвойстваЭлемента, ПоддерживаемыеСвойства["profile_" + ИмяСписка]);
	
	ЗапуститьКоманду(Команда + " " + ПараметрыКластера, ПараметрыАдминистрированияКластера);
	
КонецПроцедуры

Процедура ОбновитьЭлементыСпискаКонтроляДоступа(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, 
	Знач ИмяПрофиля, Знач ИмяСписка, Знач Словарь, Знач НовыеЭлементы, Знач СтарыеЭлементы = Неопределено)
	
	Если СтарыеЭлементы = Неопределено Или СтарыеЭлементы.Количество() = 0 Тогда
		Для Каждого НовыйЭлемент Из НовыеЭлементы Цикл
			ОбновитьЭлементСпискаКонтроляДоступа(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИмяПрофиля, ИмяСписка, Словарь, НовыйЭлемент);
		КонецЦикла;
		Возврат;
	КонецЕсли;
	
	КлючСписка = КлючиСписковКонтроляДоступа()[ИмяСписка];
	ИмяКлючевогоПараметра = "";
	Для Каждого КлючИЗначение Из Словарь Цикл
		Если КлючИЗначение.Значение = КлючСписка Тогда
			ИмяКлючевогоПараметра = КлючИЗначение.Ключ;
			КонецЕсли;
	КонецЦикла;
	
	ЭлементыДляУдаления = Новый Соответствие;
	Для Каждого СтарыйЭлемент Из СтарыеЭлементы Цикл
		ЭлементыДляУдаления.Вставить(СтарыйЭлемент[ИмяКлючевогоПараметра], СтарыйЭлемент);
	КонецЦикла;
	
	// Создание или обновление (если свойства различаются).
	Для Каждого НовыйЭлемент Из НовыеЭлементы Цикл
		Ключ = НовыйЭлемент[ИмяКлючевогоПараметра];
		СтарыйЭлемент = ЭлементыДляУдаления.Получить(Ключ);
		Если СтарыйЭлемент = Неопределено Тогда
			ОбновитьЭлементСпискаКонтроляДоступа(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИмяПрофиля, ИмяСписка, Словарь, НовыйЭлемент);
		Иначе
			ЭлементыДляУдаления.Удалить(Ключ);
			// Обновление только если различаются свойства.
			Для Каждого КлючИЗначение Из НовыйЭлемент Цикл
				Если КлючИЗначение.Значение <> СтарыйЭлемент[КлючИЗначение.Ключ] Тогда
					ОбновитьЭлементСпискаКонтроляДоступа(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИмяПрофиля, ИмяСписка, Словарь, НовыйЭлемент);
					Прервать;
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
	КонецЦикла;
	
	// Удаление ненужных элементов.
	Для Каждого КлючИЗначение Из ЭлементыДляУдаления Цикл
		УдалитьЭлементСпискаКонтроляДоступа(ИдентификаторКластера, ПараметрыАдминистрированияКластера, ИмяПрофиля, ИмяСписка, КлючИЗначение.Ключ);
	КонецЦикла;
	
КонецПроцедуры

Функция ПреобразоватьЗначенияСвойствИспользованияСписковДоступа(Знач Описание)
	
	Словарь = СловарьСвойствИспользованияСписокКонтроляДоступа();
	
	Результат = Новый Структура;
	
	Для Каждого КлючИЗначение Из Описание Цикл
		
		Если Словарь.Свойство(КлючИЗначение.Ключ) Тогда
			
			Если КлючИЗначение.Значение = "list" Тогда
				
				Значение = Ложь;
				
			ИначеЕсли КлючИЗначение.Значение = "full" Тогда
				
				Значение = Истина;
				
			КонецЕсли;
			
			Результат.Вставить(КлючИЗначение.Ключ, Значение);
			
		Иначе
			
			Результат.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ПривестиЗначение(Знач Значение)
	
	Если ТипЗнч(Значение) = Тип("Дата") Тогда
		
		Возврат XMLСтрока(Значение);
		
	ИначеЕсли ТипЗнч(Значение) = Тип("Булево") Тогда
		
		Возврат Формат(Значение, "БЛ=no; БИ=yes");
		
	ИначеЕсли ТипЗнч(Значение) = Тип("Число") Тогда
		
		Возврат Формат(Значение, "ЧРД=,; ЧН=0; ЧГ=0; ЧО=1");
		
	ИначеЕсли ТипЗнч(Значение) = Тип("Строка") Тогда
		
		// В документации написано:
		// Строки, допускающие произвольные символы, выводятся в двойных кавычках, при этом двойные кавычки в самих строках дублируются.
		Цифры = "0123456789";
		Латиница = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
		Кириллица = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЪЬЭЮЯабвгдежзийклмнопрстуфхцчшщыъьэюя"; // АПК:1036 проверка орфографии не требуется.
		ДопустимыеСимволы = Цифры + Латиница + Кириллица + "-";
		Если СтрокаСодержитТолькоДопустимыеСимволы(Значение, ДопустимыеСимволы) Тогда
			Возврат Значение;
		Иначе
			Возврат """" + СтрЗаменить(Значение, """", """""") + """";
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Строка(Значение);
	
КонецФункции

Функция СтрокаСодержитТолькоДопустимыеСимволы(Строка, ДопустимыеСимволы)
	
	ВсеДопустимыеСимволы = Новый Соответствие;
	Для Позиция = 1 По СтрДлина(ДопустимыеСимволы) Цикл
		ВсеДопустимыеСимволы[Сред(ДопустимыеСимволы, Позиция, 1)] = Истина;
	КонецЦикла;
	
	Для Позиция = 1 По СтрДлина(Строка) Цикл
		Если ВсеДопустимыеСимволы[Сред(Строка, Позиция, 1)] = Неопределено Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Истина;
	
КонецФункции

Функция ПривестиЭлементВывода(ЭлементВывода, ТипЭлемента)
	
	Если ТипЭлемента = Тип("Строка") Тогда
		
		Возврат ЭлементВывода;
		
	ИначеЕсли ТипЭлемента = Тип("Число") Тогда
		
		Если ПустаяСтрока(ЭлементВывода) Тогда
			Возврат 0;
		КонецЕсли;
		
		Попытка
			Возврат Число(ЭлементВывода);
		Исключение
			ВызватьИсключение НСтр("ru = 'Неправильный формат.'");
		КонецПопытки;
		
	ИначеЕсли ТипЭлемента = Тип("Дата") Тогда
		
		Если ПустаяСтрока(ЭлементВывода) Тогда
			Возврат Дата(1, 1, 1);
		КонецЕсли;
		
		Попытка
			Возврат XMLЗначение(Тип("Дата"), ЭлементВывода);
		Исключение
			ВызватьИсключение НСтр("ru = 'Неправильный формат.'");
		КонецПопытки;
		
	ИначеЕсли ТипЭлемента = Тип("Булево") Тогда
		
		Если ЭлементВывода = "on" Или ЭлементВывода = "yes" Тогда
			Возврат Истина;
		ИначеЕсли ЭлементВывода = "off" Или ЭлементВывода = "no" Тогда
			Возврат Ложь;
		Иначе
			ВызватьИсключение НСтр("ru = 'Неправильный формат.'");
		КонецЕсли;
		
	ИначеЕсли ТипЭлемента = Неопределено Тогда
		
		// Попытка понять какой тип в строке не производится, 
		// т.к., например, пустая строка может быть пустой датой, 
		// а в строке могут быть только числа (например PID рабочего процесса).
		
		Если ПустаяСтрока(ЭлементВывода) Тогда
			Возврат Неопределено;
		КонецЕсли;
		
		Возврат ЭлементВывода;
		
	Иначе
		
		ВызватьИсключение НСтр("ru = 'Неверный тип элемента.'");
		
	КонецЕсли;
	
	Возврат ЭлементВывода;
	
КонецФункции

Функция ПарсерВывода(Знач ПотокВывода, Знач Словарь, Знач Фильтр = Неопределено, ТипыСвойств = Неопределено)
	
	Результат = Новый Массив;
	ЭлементРезультата = Новый Соответствие;
	
	Позиция = 1;
	КонецВывода = СтрДлина(ПотокВывода);
	
	Пока Позиция <= КонецВывода Цикл
		
		ИмяСвойства = ПрочитатьДоРазделителя(ПотокВывода, Позиция, ":");
		СтрокаСвойства = ПрочитатьДоРазделителя(ПотокВывода, Позиция, Символы.ПС);
		ТипСвойства = ?(ТипыСвойств = Неопределено, Неопределено, ТипыСвойств.Получить(ИмяСвойства));
		ЗначениеСвойства = ПривестиЭлементВывода(СтрокаСвойства, ТипСвойства);
		ЭлементРезультата.Вставить(ИмяСвойства, ЗначениеСвойства);
		
		Если Сред(ПотокВывода, Позиция, 1) = Символы.ПС Тогда
			Позиция = Позиция + 1;
			ПарсерЭлементаВывода(ЭлементРезультата, Результат, Словарь, Фильтр);
			ЭлементРезультата = Новый Соответствие;
		КонецЕсли;
		
	КонецЦикла;
	
	Если ЭлементРезультата.Количество() > 0 Тогда
		ПарсерЭлементаВывода(ЭлементРезультата, Результат, Словарь, Фильтр);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ПрочитатьДоРазделителя(Поток, Позиция, Разделитель)
	
	ТекущийСимвол = Сред(Поток, Позиция, 1);
	
	// Сдвинуть позицию на значащий символ.
	Пока ПустаяСтрока(ТекущийСимвол) И Не ТекущийСимвол = Разделитель И Позиция < СтрДлина(Поток) Цикл
		Позиция = Позиция + 1;
		ТекущийСимвол = Сред(Поток, Позиция, 1);
	КонецЦикла;
	
	Если ТекущийСимвол = Разделитель Тогда
		Позиция = Позиция + 1;
		Возврат "";
	КонецЕсли;
	
	Кавычка = """";
	Если ТекущийСимвол = Кавычка Тогда
		Позиция = Позиция + 1;
		НачальнаяПозиция = Позиция;
		// Нужно идти до следующей одиночной кавычки
		Пока Позиция <= СтрДлина(Поток) Цикл
			НайденнаяКавычка = СтрНайти(Поток, Кавычка, НаправлениеПоиска.СНачала, Позиция); 
			Если НайденнаяКавычка = 0 Тогда
				ВызватьИсключение НСтр("ru = 'Неправильный формат.'");
			ИначеЕсли Сред(Поток, НайденнаяКавычка + 1, 1) = Кавычка Тогда
				Позиция = НайденнаяКавычка + 2;
			Иначе
				Позиция = НайденнаяКавычка + 1;
				// За кавычкой может быть разделитель.
				Если Сред(Поток, Позиция, 1) = Разделитель Тогда
					Позиция = Позиция + 1;
				КонецЕсли;
				Прервать;
			КонецЕсли;
		КонецЦикла;
		Если Позиция > СтрДлина(Поток) Тогда
			ВызватьИсключение НСтр("ru = 'Неправильный формат.'");
		КонецЕсли;
		Значение = СокрЛП(Сред(Поток, НачальнаяПозиция, НайденнаяКавычка - НачальнаяПозиция));
		Значение = СтрЗаменить(Значение, Кавычка + Кавычка, Кавычка);
		Возврат Значение;
	Иначе
		// Простой случай, прочитать нужно до следующего разделителя
		ПозицияРазделителя = СтрНайти(Поток, Разделитель, НаправлениеПоиска.СНачала, Позиция);
		Значение = СокрЛП(Сред(Поток, Позиция, ПозицияРазделителя - Позиция));
		Позиция = ПозицияРазделителя + 1;
		Возврат Значение;
	КонецЕсли;
	
КонецФункции

Процедура ПарсерЭлементаВывода(ЭлементРезультата, Результат, Словарь, Фильтр)
	
	Если Словарь <> Неопределено Тогда
		Объект = РазобратьЭлементВывода(ЭлементРезультата, Словарь);
	Иначе
		Объект = ЭлементРезультата;
	КонецЕсли;
	
	Если Фильтр <> Неопределено И Не АдминистрированиеКластера.ПроверитьУсловияФильтра(Объект, Фильтр) Тогда
		Возврат;
	КонецЕсли;
	
	Результат.Добавить(Объект);
	
КонецПроцедуры

Функция РазобратьЭлементВывода(Знач ЭлементВывода, Знач Словарь)
	
	Результат = Новый Структура();
	
	Для Каждого ФрагментСловаря Из Словарь Цикл
		Если ТипЗнч(ФрагментСловаря.Значение) = Тип("ФиксированнаяСтруктура") Тогда
			ПодчиненныйОбъект = ЭлементВывода[ФрагментСловаря.Значение.Ключ];
			Если ПодчиненныйОбъект = Неопределено Тогда
				Результат.Вставить(ФрагментСловаря.Ключ, Неопределено);
			Иначе
				Свойство = РазобратьЭлементВывода(ЭлементВывода[ФрагментСловаря.Значение.Ключ], ФрагментСловаря.Значение.Словарь);
				Результат.Вставить(ФрагментСловаря.Ключ, Свойство);
			КонецЕсли;
		Иначе
			Результат.Вставить(ФрагментСловаря.Ключ, ЭлементВывода[ФрагментСловаря.Значение]);
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ФильтрВНотациюRac(Знач Фильтр, Знач Словарь)
	
	Если Фильтр = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Если Словарь = Неопределено Тогда
		Возврат Фильтр;
	КонецЕсли;
	
	Результат = Новый Массив();
	
	Для Каждого Условие Из Фильтр Цикл
		
		Если ТипЗнч(Условие) = Тип("КлючИЗначение") Тогда
			
			Результат.Добавить(Новый Структура("Свойство, ВидСравнения, Значение", Словарь[Условие.Ключ], ВидСравнения.Равно, Условие.Значение));
			
		ИначеЕсли ТипЗнч(Условие) = Тип("Структура") Тогда
			
			Результат.Добавить(Новый Структура("Свойство, ВидСравнения, Значение", Словарь[Условие.Свойство], Условие.ВидСравнения, Условие.Значение));
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция СловарьСвойствБлокировкиСеансовИРегламентныхЗаданий()
	
	Результат = АдминистрированиеКластера.СвойстваБлокировкиСеансовИРегламентныхЗаданий();
	
	Результат.БлокировкаСеансов = "sessions-deny";
	Результат.ДатаС = "denied-from";
	Результат.ДатаПо = "denied-to";
	Результат.Сообщение = "denied-message";
	Результат.КодРазрешения = "permission-code";
	Результат.ПараметрБлокировки = "denied-parameter";
	Результат.БлокировкаРегламентныхЗаданий = "scheduled-jobs-deny";
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствСеансов()
	
	Лицензия = Новый Структура;
	Лицензия.Вставить("Ключ", "license");
	Лицензия.Вставить("Словарь", СловарьСвойствЛицензии());
	
	ОписаниеСоединения = Новый Структура;
	ОписаниеСоединения.Вставить("Ключ", "connection");
	ОписаниеСоединения.Вставить("Словарь", СловарьСвойствОписанияСоединения());
	
	РабочийПроцесс = Новый Структура;
	РабочийПроцесс.Вставить("Ключ", "process");
	РабочийПроцесс.Вставить("Словарь", СловарьСвойствРабочегоПроцесса());
	
	Результат = АдминистрированиеКластера.СвойстваСеанса();
	
	Результат.Номер = "session-id";
	Результат.ИмяПользователя = "user-name";
	Результат.ИмяКлиентскогоКомпьютера = "host";
	Результат.ИдентификаторКлиентскогоПриложения = "app-id";
	Результат.ИдентификаторЯзыка = "locale";
	Результат.МоментСозданияСеанса = "started-at";
	Результат.МоментПоследнейАктивностиСеанса = "last-active-at";
	Результат.БлокировкаСУБД = "blocked-by-dbms";
	Результат.Блокировка = "blocked-by-ls";
	Результат.Передано = "bytes-all";
	Результат.ПереданоЗа5Минут = "bytes-last-5min";
	Результат.СерверныхВызовов = "calls-all";
	Результат.СерверныхВызововЗа5Минут = "calls-last-5min";
	Результат.ДлительностьСерверныхВызовов = "duration-all";
	Результат.ДлительностьТекущегоСерверногоВызова = "duration-current";
	Результат.ДлительностьСерверныхВызововЗа5Минут = "duration-last-5min";
	Результат.ПереданоСУБД = "dbms-bytes-all";
	Результат.ПереданоСУБДЗа5Минут = "dbms-bytes-last-5min";
	Результат.ДлительностьВызововСУБД = "duration-all-dbms";
	Результат.ДлительностьТекущегоВызоваСУБД = "duration-current-dbms";
	Результат.ДлительностьВызововСУБДЗа5Минут = "duration-last-5min-dbms";
	Результат.СоединениеСУБД = "db-proc-info";
	Результат.ВремяСоединенияСУБД = "db-proc-took";
	Результат.МоментЗахватаСоединенияСУБД = "db-proc-took-at";
	Результат.Спящий = "hibernate";
	Результат.ЗавершитьЧерез = "hibernate-session-terminate-time";
	Результат.ЗаснутьЧерез = "passive-session-hibernate-time";
	Результат.ПрочитаноСДиска = "read-total";
	Результат.ПрочитаноСДискаВТекущемВызове = "read-current";
	Результат.ПрочитаноСДискаЗа5Минут = "read-last-5min";
	Результат.ЗанятоПамяти = "memory-total";
	Результат.ЗанятоПамятиВТекущемВызове = "memory-current";
	Результат.ЗанятоПамятиЗа5Минут = "memory-last-5min";
	Результат.ЗаписаноНаДиск = "write-total";
	Результат.ЗаписаноНаДискВТекущемВызове = "write-current";
	Результат.ЗаписаноНаДискЗа5Минут = "write-last-5min";
	Результат.Лицензия = Новый ФиксированнаяСтруктура(Лицензия);
	Результат.ОписаниеСоединения = Новый ФиксированнаяСтруктура(ОписаниеСоединения);
	Результат.РабочийПроцесс = Новый ФиксированнаяСтруктура(РабочийПроцесс);
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствСоединений()
	
	Результат = АдминистрированиеКластера.СвойстваСоединения();
	
	Результат.Номер = "conn-id";
	Результат.ИмяПользователя = "user-name";
	Результат.ИмяКлиентскогоКомпьютера = "host";
	Результат.ИдентификаторКлиентскогоПриложения = "app-id";
	Результат.МоментУстановкиСоединения = "connected-at";
	Результат.РежимСоединенияСИнформационнойБазой = "ib-conn-mode";
	Результат.РежимСоединенияСБазойДанных = "db-conn-mode";
	Результат.БлокировкаСУБД = "blocked-by-dbms";
	Результат.Передано = "bytes-all";
	Результат.ПереданоЗа5Минут = "bytes-last-5min";
	Результат.СерверныхВызовов = "calls-all";
	Результат.СерверныхВызововЗа5Минут = "calls-last-5min";
	Результат.ПереданоСУБД = "dbms-bytes-all";
	Результат.ПереданоСУБДЗа5Минут = "dbms-bytes-last-5min";
	Результат.СоединениеСУБД = "db-proc-info";
	Результат.ВремяСУБД = "db-proc-took";
	Результат.МоментЗахватаСоединенияСУБД = "db-proc-took-at";
	Результат.ДлительностьСерверныхВызовов = "duration-all";
	Результат.ДлительностьВызововСУБД = "duration-all-dbms";
	Результат.ДлительностьТекущегоСерверногоВызова = "duration-current";
	Результат.ДлительностьТекущегоВызоваСУБД = "duration-current-dbms";
	Результат.ДлительностьСерверныхВызововЗа5Минут = "duration-last-5min";
	Результат.ДлительностьВызововСУБДЗа5Минут = "duration-last-5min-dbms";
	Результат.ПрочитаноСДиска = "read-total";
	Результат.ПрочитаноСДискаВТекущемВызове = "read-current";
	Результат.ПрочитаноСДискаЗа5Минут = "read-last-5min";
	Результат.ЗанятоПамяти = "memory-total";
	Результат.ЗанятоПамятиВТекущемВызове = "memory-current";
	Результат.ЗанятоПамятиЗа5Минут = "memory-last-5min";
	Результат.ЗаписаноНаДиск = "write-total";
	Результат.ЗаписаноНаДискВТекущемВызове = "write-current";
	Результат.ЗаписаноНаДискЗа5Минут = "write-last-5min";
	Результат.УправлениеНаходитсяНаСервере = "thread-mode";
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствПрофиляБезопасности(Знач ВключаяСвойстваИспользованияСписковКонтроляДоступа = Истина)
	
	Результат = АдминистрированиеКластера.СвойстваПрофиляБезопасности();
	
	Результат.Удалить("COMКлассы");
	Результат.Удалить("ВиртуальныеКаталоги");
	Результат.Удалить("ВнешниеКомпоненты");
	Результат.Удалить("ВнешниеМодули");
	Результат.Удалить("ИнтернетРесурсы");
	Результат.Удалить("ПриложенияОС");
	
	Результат.Имя = "name";
	Результат.Описание = "descr";
	Результат.ПрофильБезопасногоРежима = "config";
	Результат.ПолныйДоступКПривилегированномуРежиму =  "priv";
	Результат.ПолныйДоступКФункциямКриптографии = "crypto";
	Результат.ПолныйДоступКРасширениюВсехМодулей = "all-modules-extension";
	Результат.ДоступныеДляРасширенияМодули = "modules-available-for-extension";
	Результат.НедоступныеДляРасширенияМодули = "modules-not-available-for-extension";
	Результат.ПолныйДоступКРасширениюПравДоступа = "right-extension";
	Результат.РолиОграничивающиеРасширениеПравДоступа = "right-extension-definition-roles";
	
	СловарьСвойствИспользованияСписковКонтроляДоступа = СловарьСвойствИспользованияСписокКонтроляДоступа();
	Для Каждого ФрагментСловаря Из СловарьСвойствИспользованияСписковКонтроляДоступа Цикл
		Если ВключаяСвойстваИспользованияСписковКонтроляДоступа Тогда
			Результат[ФрагментСловаря.Ключ] = ФрагментСловаря.Значение;
		Иначе
			Результат.Удалить(ФрагментСловаря.Ключ);
		КонецЕсли;
	КонецЦикла;
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствИспользованияСписокКонтроляДоступа()
	
	Результат = Новый Структура();
	
	Результат.Вставить("ПолныйДоступКФайловойСистеме", "directory");
	Результат.Вставить("ПолныйДоступКCOMОбъектам", "com");
	Результат.Вставить("ПолныйДоступКВнешнимКомпонентам", "addin");
	Результат.Вставить("ПолныйДоступКВнешнимМодулям", "module");
	Результат.Вставить("ПолныйДоступКПриложениямОперационнойСистемы", "app");
	Результат.Вставить("ПолныйДоступКИнтернетРесурсам", "inet");
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствВиртуальногоКаталога()
	
	Результат = АдминистрированиеКластера.СвойстваВиртуальногоКаталога();
	
	Результат.ЛогическийURL = "alias";
	Результат.ФизическийURL = "physicalPath";
	
	Результат.Описание = "descr";
	
	Результат.ЧтениеДанных = "allowedRead";
	Результат.ЗаписьДанных = "allowedWrite";
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствCOMКласса()
	
	Результат = АдминистрированиеКластера.СвойстваCOMКласса();
	
	Результат.Имя = "name";
	Результат.Описание = "descr";
	
	Результат.ФайлМоникер = "fileName";
	Результат.CLSID = "id";
	Результат.Компьютер = "host";
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствВнешнейКомпоненты()
	
	Результат = АдминистрированиеКластера.СвойстваВнешнейКомпоненты();
	Результат.Имя = "name";
	Результат.Описание = "descr";
	Результат.ХешСумма = "hash";
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствВнешнегоМодуля()
	
	Результат = АдминистрированиеКластера.СвойстваВнешнегоМодуля();
	Результат.Имя = "name";
	Результат.Описание = "descr";
	Результат.ХешСумма = "hash";
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствПриложенияОС()
	
	Результат = АдминистрированиеКластера.СвойстваПриложенияОС();
	
	Результат.Имя = "name";
	Результат.Описание = "descr";
	
	Результат.ШаблонСтрокиЗапуска = "wild";
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствИнтернетРесурса()
	
	Результат = АдминистрированиеКластера.СвойстваИнтернетРесурса();
	
	Результат.Имя = "name";
	Результат.Описание = "descr";
	
	Результат.Протокол = "protocol";
	Результат.Адрес = "url";
	Результат.Порт = "port";
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствОписанияСоединения()
	
	РабочийПроцесс = Новый Структура;
	РабочийПроцесс.Вставить("Ключ", "process");
	РабочийПроцесс.Вставить("Словарь", СловарьСвойствРабочегоПроцесса());
	
	Результат = АдминистрированиеКластера.СвойстваОписанияСоединения();
	
	Результат.ИмяПриложения = "application";
	Результат.Блокировка = "blocked-by-ls";
	Результат.МоментУстановкиСоединения = "connected-at";
	Результат.Номер = "conn-id";
	Результат.ИмяКлиентскогоКомпьютера = "host";
	Результат.НомерСеанса = "session-number";
	Результат.РабочийПроцесс = Новый ФиксированнаяСтруктура(РабочийПроцесс);
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствЛицензии()
	
	Результат = АдминистрированиеКластера.СвойстваЛицензии();
	
	Результат.ИмяФайла = "full-name";
	Результат.ПолноеПредставление = "full-presentation";
	Результат.КраткоеПредставление = "short-presentation";
	Результат.ВыданаСервером = "issued-by-server";
	Результат.ТипЛицензии = "license-type";
	Результат.МаксимальноеКоличествоПользователейДляКомплекта = "max-users-all";
	Результат.МаксимальноеКоличествоПользователейВКлюче = "max-users-cur";
	Результат.ЛицензияПолученаЧерезAladdinLicenseManager = "net";
	Результат.АдресПроцесса = "rmngr-address";
	Результат.ИдентификаторПроцесса = "rmngr-pid";
	Результат.ПортПроцесса = "rmngr-port";
	Результат.СерияКлюча = "series";
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция СловарьСвойствРабочегоПроцесса()
	
	Лицензия = Новый Структура;
	Лицензия.Вставить("Ключ", "license");
	Лицензия.Вставить("Словарь", СловарьСвойствЛицензии());
	
	Результат = АдминистрированиеКластера.СвойстваРабочегоПроцесса();
	
	Результат.ДоступнаяПроизводительность = "available-perfomance";
	Результат.ЗатраченоКлиентом = "avg-back-call-time";
	Результат.РеакцияСервера = "avg-call-time";
	Результат.ЗатраченоСУБД = "avg-db-call-time";
	Результат.ЗатраченоМенеджеромБлокировок = "avg-lock-call-time";
	Результат.ЗатраченоСервером = "avg-server-call-time";
	Результат.КлиентскихПотоков = "avg-threads";
	Результат.ОтносительнаяПроизводительность = "capacity";
	Результат.Соединений = "connections";
	Результат.ИмяКомпьютера = "host";
	Результат.Включен = "is-enable";
	Результат.Порт = "port";
	Результат.ПревышениеНадКритическимЗначением = "memory-excess-time";
	Результат.ЗанятоПамяти = "memory-size";
	Результат.Идентификатор = "pid";
	Результат.Запущен = "running";
	Результат.КоличествоВызововПоКоторымПосчитанаСтатистика = "selection-size";
	Результат.МоментЗапуска = "started-at";
	Результат.Использование = "use";
	Результат.Лицензия = Новый ФиксированнаяСтруктура(Лицензия);
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция КлючиСписковКонтроляДоступа()
	
	Результат = Новый Структура();
	
	Результат.Вставить("directory", "alias");
	Результат.Вставить("com", "name");
	Результат.Вставить("addin", "name");
	Результат.Вставить("module", "name");
	Результат.Вставить("app", "name");
	Результат.Вставить("inet", "name");
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
	
КонецФункции

Функция ТипыСвойствКластера()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("cluster", Тип("Строка"));
	Типы.Вставить("host", Тип("Строка"));
	Типы.Вставить("port", Тип("Число"));
	Типы.Вставить("name", Тип("Строка"));
	Типы.Вставить("expiration-timeout", Тип("Число"));
	Типы.Вставить("lifetime-limit", Тип("Число"));
	Типы.Вставить("max-memory-size", Тип("Число"));
	Типы.Вставить("max-memory-time-limit", Тип("Число"));
	Типы.Вставить("security-level", Тип("Число"));
	Типы.Вставить("session-fault-tolerance-level", Тип("Число"));
	Типы.Вставить("load-balancing-mode", Тип("Строка"));
	Типы.Вставить("errors-count-threshold", Тип("Число"));
	Типы.Вставить("kill-problem-processes", Тип("Число"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);

КонецФункции

Функция ТипыСвойствРабочихСерверов()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("server", Тип("Строка"));
	Типы.Вставить("agent-host", Тип("Строка"));
	Типы.Вставить("agent-port", Тип("Число"));
	Типы.Вставить("port-range", Тип("Строка"));
	Типы.Вставить("name", Тип("Строка"));
	Типы.Вставить("using", Тип("Строка"));
	Типы.Вставить("dedicate-managers", Тип("Строка"));
	Типы.Вставить("infobases-limit", Тип("Число"));
	Типы.Вставить("memory-limit", Тип("Число"));
	Типы.Вставить("connections-limit", Тип("Число"));
	Типы.Вставить("safe-working-processes-memory-limit", Тип("Число"));
	Типы.Вставить("safe-call-memory-limit", Тип("Число"));
	Типы.Вставить("cluster-port", Тип("Число"));

	Возврат Новый ФиксированноеСоответствие(Типы);
	
КонецФункции

Функция ТипыСвойствОписанияБазы()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("infobase", Тип("Строка"));
	Типы.Вставить("name", Тип("Строка"));
	Типы.Вставить("descr", Тип("Строка"));

	Возврат Новый ФиксированноеСоответствие(Типы);
	
КонецФункции

Функция ТипыСвойствИнформационнойБазы()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("infobase", Тип("Строка"));
	Типы.Вставить("name", Тип("Строка"));
	Типы.Вставить("dbms", Тип("Строка"));
	Типы.Вставить("db-server", Тип("Строка"));
	Типы.Вставить("db-name", Тип("Строка"));
	Типы.Вставить("db-user", Тип("Строка"));
	Типы.Вставить("security-level", Тип("Число"));
	Типы.Вставить("license-distribution", Тип("Строка"));
	Типы.Вставить("scheduled-jobs-deny", Тип("Булево"));
	Типы.Вставить("sessions-deny", Тип("Булево"));
	Типы.Вставить("denied-from", Тип("Дата"));
	Типы.Вставить("denied-message", Тип("Строка"));
	Типы.Вставить("denied-parameter", Тип("Строка"));
	Типы.Вставить("denied-to", Тип("Дата"));
	Типы.Вставить("permission-code", Тип("Строка"));
	Типы.Вставить("external-session-manager-connection-string", Тип("Строка"));
	Типы.Вставить("external-session-manager-required", Тип("Булево"));
	Типы.Вставить("security-profile-name", Тип("Строка"));
	Типы.Вставить("safe-mode-security-profile-name", Тип("Строка"));
	Типы.Вставить("descr", Тип("Строка"));

	Возврат Новый ФиксированноеСоответствие(Типы);
	
КонецФункции

Функция ТипыСвойствСеансов()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("session", Тип("Строка"));
	Типы.Вставить("session-id", Тип("Число"));
	Типы.Вставить("infobase", Тип("Строка"));
	Типы.Вставить("connection", Тип("Строка"));
	Типы.Вставить("process", Тип("Строка"));
	Типы.Вставить("user-name", Тип("Строка"));
	Типы.Вставить("host", Тип("Строка"));
	Типы.Вставить("app-id", Тип("Строка"));
	Типы.Вставить("locale", Тип("Строка"));
	Типы.Вставить("started-at", Тип("Дата"));
	Типы.Вставить("last-active-at", Тип("Дата"));
	Типы.Вставить("hibernate", Тип("Булево"));
	Типы.Вставить("passive-session-hibernate-time", Тип("Число"));
	Типы.Вставить("hibernate-session-terminate-time", Тип("Число"));
	Типы.Вставить("blocked-by-dbms", Тип("Число"));
	Типы.Вставить("blocked-by-ls", Тип("Число"));
	Типы.Вставить("bytes-all", Тип("Число"));
	Типы.Вставить("bytes-last-5min", Тип("Число"));
	Типы.Вставить("calls-all", Тип("Число"));
	Типы.Вставить("calls-last-5min", Тип("Число"));
	Типы.Вставить("dbms-bytes-all", Тип("Число"));
	Типы.Вставить("dbms-bytes-last-5min", Тип("Число"));
	Типы.Вставить("db-proc-info", Тип("Строка"));
	Типы.Вставить("db-proc-took", Тип("Число"));
	Типы.Вставить("db-proc-took-at", Тип("Дата"));
	Типы.Вставить("duration-all", Тип("Число"));
	Типы.Вставить("duration-all-dbms", Тип("Число"));
	Типы.Вставить("duration-current", Тип("Число"));
	Типы.Вставить("duration-current-dbms", Тип("Число"));
	Типы.Вставить("duration-last-5min", Тип("Число"));
	Типы.Вставить("duration-last-5min-dbms", Тип("Число"));
	Типы.Вставить("memory-current", Тип("Число"));
	Типы.Вставить("memory-last-5min", Тип("Число"));
	Типы.Вставить("memory-total", Тип("Число"));
	Типы.Вставить("read-current", Тип("Число"));
	Типы.Вставить("read-last-5min", Тип("Число"));
	Типы.Вставить("read-total", Тип("Число"));
	Типы.Вставить("write-current", Тип("Число"));
	Типы.Вставить("write-last-5min", Тип("Число"));
	Типы.Вставить("write-total", Тип("Число"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);
	
КонецФункции

Функция ТипыСвойствСоединений()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("connection", Тип("Строка"));
	Типы.Вставить("conn-id", Тип("Число"));
	Типы.Вставить("user-name", Тип("Строка"));
	Типы.Вставить("host", Тип("Строка"));
	Типы.Вставить("app-id", Тип("Строка"));
	Типы.Вставить("connected-at", Тип("Дата"));
	Типы.Вставить("thread-mode", Тип("Строка"));
	Типы.Вставить("ib-conn-mode", Тип("Строка"));
	Типы.Вставить("db-conn-mode", Тип("Строка"));
	Типы.Вставить("blocked-by-dbms", Тип("Число"));
	Типы.Вставить("bytes-all", Тип("Число"));
	Типы.Вставить("bytes-last-5min", Тип("Число"));
	Типы.Вставить("calls-all", Тип("Число"));
	Типы.Вставить("calls-last-5min", Тип("Число"));
	Типы.Вставить("dbms-bytes-all", Тип("Число"));
	Типы.Вставить("dbms-bytes-last-5min", Тип("Число"));
	Типы.Вставить("db-proc-info", Тип("Строка"));
	Типы.Вставить("db-proc-took", Тип("Число"));
	Типы.Вставить("db-proc-took-at", Тип("Дата"));
	Типы.Вставить("duration-all", Тип("Число"));
	Типы.Вставить("duration-all-dbms", Тип("Число"));
	Типы.Вставить("duration-current", Тип("Число"));
	Типы.Вставить("duration-current-dbms", Тип("Число"));
	Типы.Вставить("duration-last-5min", Тип("Число"));
	Типы.Вставить("duration-last-5min-dbms", Тип("Число"));
	Типы.Вставить("memory-current", Тип("Число"));
	Типы.Вставить("memory-last-5min", Тип("Число"));
	Типы.Вставить("memory-total", Тип("Число"));
	Типы.Вставить("read-current", Тип("Число"));
	Типы.Вставить("read-last-5min", Тип("Число"));
	Типы.Вставить("read-total", Тип("Число"));
	Типы.Вставить("write-current", Тип("Число"));
	Типы.Вставить("write-last-5min", Тип("Число"));
	Типы.Вставить("write-total", Тип("Число"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);
	
КонецФункции

Функция ТипыСвойствПрофиля()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("name", Тип("Строка"));
	Типы.Вставить("descr", Тип("Строка"));
	Типы.Вставить("config", Тип("Булево"));
	Типы.Вставить("priv", Тип("Булево"));
	Типы.Вставить("directory", Тип("Строка"));
	Типы.Вставить("com", Тип("Строка"));
	Типы.Вставить("addin", Тип("Строка"));
	Типы.Вставить("module", Тип("Строка"));
	Типы.Вставить("app", Тип("Строка"));
	Типы.Вставить("inet", Тип("Строка"));
	Типы.Вставить("crypto", Тип("Булево"));
	Типы.Вставить("right-extension", Тип("Булево"));
	Типы.Вставить("right-extension-definition-roles", Тип("Строка"));
	Типы.Вставить("all-modules-extension", Тип("Булево"));
	Типы.Вставить("modules-available-for-extension", Тип("Строка"));
	Типы.Вставить("modules-not-available-for-extension", Тип("Строка"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);
		
КонецФункции

Функция ТипыСвойствОписанияСоединения()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("connection", Тип("Строка"));
	Типы.Вставить("conn-id", Тип("Число"));
	Типы.Вставить("host", Тип("Строка"));
	Типы.Вставить("process", Тип("Строка"));
	Типы.Вставить("infobase", Тип("Строка"));
	Типы.Вставить("application", Тип("Строка"));
	Типы.Вставить("connected-at", Тип("Дата"));
	Типы.Вставить("session-number", Тип("Число"));
	Типы.Вставить("blocked-by-ls", Тип("Число"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);
		
КонецФункции

Функция ТипыСвойствЛицензии()
	
	Типы = Новый Соответствие;
	
	// Возвращается только для лицензии рабочего процесса.
	Типы.Вставить("process", Тип("Строка"));
	Типы.Вставить("port", Тип("Число"));
	Типы.Вставить("pid", Тип("Строка"));
	Типы.Вставить("host", Тип("Строка"));
	
	// Возвращается только для лицензии сеанса.
	Типы.Вставить("session", Тип("Строка"));
	Типы.Вставить("user-name", Тип("Строка"));
	Типы.Вставить("app-id", Тип("Строка"));	
	Типы.Вставить("host", Тип("Строка"));
	
	// Общее для всех лицензий.
	Типы.Вставить("full-name", Тип("Строка"));
	Типы.Вставить("series", Тип("Строка"));
	Типы.Вставить("issued-by-server", Тип("Булево"));
	Типы.Вставить("license-type", Тип("Строка"));
	Типы.Вставить("net", Тип("Булево"));
	Типы.Вставить("max-users-all", Тип("Число"));
	Типы.Вставить("max-users-cur", Тип("Число"));
	Типы.Вставить("rmngr-address", Тип("Строка"));
	Типы.Вставить("rmngr-port", Тип("Число"));
	Типы.Вставить("rmngr-pid", Тип("Строка"));
	Типы.Вставить("short-presentation", Тип("Строка"));
	Типы.Вставить("full-presentation", Тип("Строка"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);
		
КонецФункции

Функция ТипыСвойствБлокировки()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("connection", Тип("Строка"));
	Типы.Вставить("session", Тип("Строка"));
	Типы.Вставить("object", Тип("Строка"));
	Типы.Вставить("locked", Тип("Дата"));
	Типы.Вставить("descr", Тип("Строка"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);
		
КонецФункции

Функция ТипыСвойствРабочегоПроцесса()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("process", Тип("Строка"));
	Типы.Вставить("host", Тип("Строка"));
	Типы.Вставить("port", Тип("Число"));
	Типы.Вставить("pid", Тип("Строка"));
	Типы.Вставить("is-enable", Тип("Булево"));
	Типы.Вставить("running", Тип("Булево"));
	Типы.Вставить("started-at", Тип("Дата"));
	Типы.Вставить("use", Тип("Строка"));
	Типы.Вставить("available-perfomance", Тип("Число"));
	Типы.Вставить("capacity", Тип("Число"));
	Типы.Вставить("connections", Тип("Число"));
	Типы.Вставить("memory-size", Тип("Число"));
	Типы.Вставить("memory-excess-time", Тип("Число"));
	Типы.Вставить("selection-size", Тип("Число"));
	Типы.Вставить("avg-back-call-time", Тип("Число"));
	Типы.Вставить("avg-call-time", Тип("Число"));
	Типы.Вставить("avg-db-call-time", Тип("Число"));
	Типы.Вставить("avg-lock-call-time", Тип("Число"));
	Типы.Вставить("avg-server-call-time", Тип("Число"));
	Типы.Вставить("avg-threads", Тип("Число"));

	Возврат Новый ФиксированноеСоответствие(Типы);
		
КонецФункции

Функция ТипыСвойствВиртуальногоКаталога()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("alias", Тип("Строка"));
	Типы.Вставить("physicalPath", Тип("Строка"));
	Типы.Вставить("descr", Тип("Строка"));
	Типы.Вставить("allowedRead", Тип("Булево"));
	Типы.Вставить("allowedWrite", Тип("Булево"));

	Возврат Новый ФиксированноеСоответствие(Типы);
	
КонецФункции

Функция ТипыСвойствCOMКласса()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("name", Тип("Строка"));
	Типы.Вставить("descr", Тип("Строка"));
	Типы.Вставить("fileName", Тип("Строка"));
	Типы.Вставить("id", Тип("Строка"));
	Типы.Вставить("host", Тип("Строка"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);
	
КонецФункции

Функция ТипыСвойствВнешнейКомпоненты()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("name", Тип("Строка"));
	Типы.Вставить("descr", Тип("Строка"));
	Типы.Вставить("hash", Тип("Строка"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);
	
КонецФункции

Функция ТипыСвойствВнешнегоМодуля()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("name", Тип("Строка"));
	Типы.Вставить("descr", Тип("Строка"));
	Типы.Вставить("hash", Тип("Строка"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);
	
КонецФункции

Функция ТипыСвойствПриложенияОС()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("name", Тип("Строка"));
	Типы.Вставить("descr", Тип("Строка"));
	Типы.Вставить("wild", Тип("Строка"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);
	
КонецФункции

Функция ТипыСвойствИнтернетРесурса()
	
	Типы = Новый Соответствие;
	
	Типы.Вставить("name", Тип("Строка"));
	Типы.Вставить("descr", Тип("Строка"));
	Типы.Вставить("protocol", Тип("Строка"));
	Типы.Вставить("url", Тип("Строка"));
	Типы.Вставить("port", Тип("Число"));
	
	Возврат Новый ФиксированноеСоответствие(Типы);
	
КонецФункции

Функция ПоддерживаемыеСвойства(Команда, ПараметрыАдминистрированияКластера, ТипыСвойств)
	
	Результат = ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, , , ТипыСвойств);
	
	Свойства = Новый Соответствие;
	Для Каждого КлючИЗначение Из Результат[0] Цикл
		Свойства.Вставить(КлючИЗначение.Ключ, Истина);
	КонецЦикла;
	
	Возврат Свойства;
	
КонецФункции

Функция ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера, Словарь = Неопределено, Фильтр = Неопределено, ТипыСвойств = Неопределено)
	
	Если БезопасныйРежим() <> Ложь Тогда
		ВызватьИсключение НСтр("ru = 'Администрирование кластера невозможно в безопасном режиме'");
	КонецЕсли;
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		ВызватьИсключение НСтр("ru = 'В модели сервиса недопустимо выполнение прикладной информационной базой функций администрирования кластера'");
	КонецЕсли;
	
	// Подставим в командную строку путь до утилиты rac и адрес сервера ras.
	Клиент = ПутьККлиентуСервераАдминистрирования();
	ФайлКлиента = Новый Файл(Клиент);
	Если Не ФайлКлиента.Существует() Тогда
		
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Невозможно выполнить операцию администрирования кластера серверов по причине: не существует файл %1
			           |
			           |Для администрирования кластера через сервер администрирования (ras) установите на данном
			           |компьютере клиент сервера администрирования (rac).
			           |Для его установки:
			           |- Для компьютеров с ОС Windows переустановите платформу, установив компонент ""Сервер 1С:Предприятия"";
			           |- Для компьютеров с ОС Linux установите пакет 1c-enterprise83-server*.'"),
			ФайлКлиента.ПолноеИмя);
		
	КонецЕсли;
	
	КоманднаяСтрока = """" + Клиент + """ " + Команда;
	
	ПараметрыЗапускаПрограммы = ФайловаяСистема.ПараметрыЗапускаПрограммы();
	ПараметрыЗапускаПрограммы.ТекущийКаталог = КаталогИсполняемыхФайловПлатформы();
	ПараметрыЗапускаПрограммы.ДождатьсяЗавершения = Истина;
	ПараметрыЗапускаПрограммы.ПолучитьПотокВывода = Истина;
	ПараметрыЗапускаПрограммы.ПолучитьПотокОшибок = Истина;
	
	Результат = ФайловаяСистема.ЗапуститьПрограмму(ПреобразоватьКоманднуюСтрокуВМассив(КоманднаяСтрока),
		ПараметрыЗапускаПрограммы);
	
	ПотокВывода = Результат.ПотокВывода;
	ПотокОшибок = Результат.ПотокОшибок;
	
	Если ЗначениеЗаполнено(ПотокОшибок) Тогда
		ВызватьИсключение ПотокОшибок;
	КонецЕсли;
	
	Если ПустаяСтрока(ПотокВывода) Тогда
		Возврат Новый Массив;
	КонецЕсли;
	
	Результат = ПарсерВывода(ПотокВывода, Словарь, Фильтр, ТипыСвойств);
	Возврат Результат;
	
КонецФункции

Функция ПараметрыКластера(ПараметрыАдминистрированияКластера, ИдентификаторКластера = Неопределено)
	
	Если ИдентификаторКластера = Неопределено Тогда
		ИдентификаторКластера = ИдентификаторКластера(ПараметрыАдминистрированияКластера);
	КонецЕсли;
	
	ПараметрыКластера = "--cluster=" + ИдентификаторКластера;
	Если ЗначениеЗаполнено(ПараметрыАдминистрированияКластера.ИмяАдминистратораКластера) Тогда
		ПараметрыКластера = ПараметрыКластера + " --cluster-user=""" + ПараметрыАдминистрированияКластера.ИмяАдминистратораКластера + """";
		Если ЗначениеЗаполнено(ПараметрыАдминистрированияКластера.ПарольАдминистратораКластера) Тогда
			ПараметрыКластера = ПараметрыКластера + " --cluster-pwd=""" + ПараметрыАдминистрированияКластера.ПарольАдминистратораКластера + """";
		КонецЕсли;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ПараметрыАдминистрированияКластера.АдресСервераАдминистрирования) Тогда
		Сервер = СокрЛП(ПараметрыАдминистрированияКластера.АдресСервераАдминистрирования);
		Если ЗначениеЗаполнено(ПараметрыАдминистрированияКластера.ПортСервераАдминистрирования) Тогда
			Сервер = Сервер + ":" + ПривестиЗначение(ПараметрыАдминистрированияКластера.ПортСервераАдминистрирования);
		КонецЕсли;
		ПараметрыКластера = ПараметрыКластера + " " + Сервер;
	КонецЕсли;
	
	Возврат ПараметрыКластера;
	
КонецФункции

Процедура ПодставитьПараметрыВКоманду(Команда, Знач Параметр1, 
	Знач Параметр2 = Неопределено, 
	Знач Параметр3 = Неопределено, 
	Знач Параметр4 = Неопределено)
	
	Команда = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Команда, 
		ПривестиЗначение(Параметр1),
		ПривестиЗначение(Параметр2),
		ПривестиЗначение(Параметр3),
		ПривестиЗначение(Параметр4));
	
КонецПроцедуры

Процедура ДобавитьПараметрыКомандыПоСловарю(Команда, Словарь, ЗначенияСвойств, ПоддерживаемыеСвойства = Неопределено)
	
	Для Каждого ФрагментСловаря Из Словарь Цикл
		ИмяПараметра = ФрагментСловаря.Значение;	
		Если ПоддерживаемыеСвойства <> Неопределено И ПоддерживаемыеСвойства.Получить(ИмяПараметра) = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Если ЗначенияСвойств.Свойство(ФрагментСловаря.Ключ) Тогда
			
			ЗначениеПараметра = ПривестиЗначение(ЗначенияСвойств[ФрагментСловаря.Ключ]);
			Команда = Команда + " --" + ИмяПараметра + "=" + ЗначениеПараметра;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Функция ПоддерживаемыеСвойстваОбъектов(ПараметрыПолучения)
	
	Если ПараметрыПолучения.ТипОбъекта = "profile" Тогда
		Возврат ПоддерживаемыеСвойстваПрофиля(ПараметрыПолучения.ПараметрыАдминистрированияКластера);
	ИначеЕсли ПараметрыПолучения.ТипОбъекта = "infobase" Тогда
		Возврат ПоддерживаемыеСвойстваИнформационнойБазы(ПараметрыПолучения.ПараметрыАдминистрированияКластера, 
			ПараметрыПолучения.ПараметрыАдминистрированияИБ);
	КонецЕсли;
	
КонецФункции

Функция ПоддерживаемыеСвойстваПрофиля(ПараметрыАдминистрированияКластера)
	
	ИмяПрофиля = "ServiceProfile-81e39185-997c-4ae3-81f7-e7582cfdfa03";
	ОписаниеПрофиля = НСтр("ru = 'Служебный профиль для проверки поддерживаемых свойств.'");
	
	ПараметрыКластера = ПараметрыКластера(ПараметрыАдминистрированияКластера);
	
	Команда = "profile update --name=%1 --descr=%2 " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля, ОписаниеПрофиля);
	ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
	
	Команда = "profile acl --name=%1 directory update --alias=%2 " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля, "Каталог");
	ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
	
	Команда = "profile acl --name=%1 com update --name=%2 " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля, "ComОбъект");
	ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
	
	Команда = "profile acl --name=%1 addin update --name=%2 " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля, "ВнешняяКомпонента");
	ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
	
	Команда = "profile acl --name=%1 module update --name=%2 " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля, "ВнешнийМодуль");
	ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
	
	Команда = "profile acl --name=%1 app update --name=%2 " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля, "Приложение");
	ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
	
	Команда = "profile acl --name=%1 inet update --name=%2 " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля, "ИнтернетРесурсы");
	ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);
	
	Свойства = Новый Структура;
	
	Команда = "profile list " + ПараметрыКластера;
	Свойства.Вставить("profile", ПоддерживаемыеСвойства(Команда, ПараметрыАдминистрированияКластера, ТипыСвойствПрофиля()));
	
	Команда = "profile acl --name=%1 directory list " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля);
	Свойства.Вставить("profile_directory", ПоддерживаемыеСвойства(Команда, ПараметрыАдминистрированияКластера, ТипыСвойствВиртуальногоКаталога()));
	
	Команда = "profile acl --name=%1 com list " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля);
	Свойства.Вставить("profile_com", ПоддерживаемыеСвойства(Команда, ПараметрыАдминистрированияКластера, ТипыСвойствCOMКласса()));
		
	Команда = "profile acl --name=%1 addin list " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля);
	Свойства.Вставить("profile_addin", ПоддерживаемыеСвойства(Команда, ПараметрыАдминистрированияКластера, ТипыСвойствВнешнейКомпоненты()));
	
	Команда = "profile acl --name=%1 module list " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля);
	Свойства.Вставить("profile_module", ПоддерживаемыеСвойства(Команда, ПараметрыАдминистрированияКластера, ТипыСвойствВнешнегоМодуля()));
	
	Команда = "profile acl --name=%1 app list " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля);
	Свойства.Вставить("profile_app", ПоддерживаемыеСвойства(Команда, ПараметрыАдминистрированияКластера, ТипыСвойствПриложенияОС()));
		
	Команда = "profile acl --name=%1 inet list " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля);
	Свойства.Вставить("profile_inet", ПоддерживаемыеСвойства(Команда, ПараметрыАдминистрированияКластера, ТипыСвойствИнтернетРесурса()));
		
	Команда = "profile remove --name=%1 " + ПараметрыКластера;
	ПодставитьПараметрыВКоманду(Команда, ИмяПрофиля);
	ЗапуститьКоманду(Команда, ПараметрыАдминистрированияКластера);

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

Функция ПоддерживаемыеСвойстваИнформационнойБазы(ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ)
	
	СвойстваБазы = СвойстваИнформационнойБазы(ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ, Неопределено);
	
	Свойства = Новый Соответствие;
	
	Для Каждого КлючИЗначение Из СвойстваБазы Цикл
		Свойства.Вставить(КлючИЗначение.Ключ, Истина);
	КонецЦикла;
	
	Возврат Свойства;
	
КонецФункции

Функция ПреобразоватьКоманднуюСтрокуВМассив(Знач КоманднаяСтрока)
	
	Результат = Новый Массив;
	
	КавычкиОткрыты = Ложь;
	ДлинаСтроки = СтрДлина(КоманднаяСтрока);
	ПредыдущийСимвол = "";
	НовыйЭлемент = "";
	
	Для Индекс = 1 По ДлинаСтроки Цикл
		
		Символ = Сред(КоманднаяСтрока, Индекс, 1);
		Если Символ = """" Тогда
			КавычкиОткрыты = Не КавычкиОткрыты;
		КонецЕсли;
		
		Если Не Символ = """" Тогда
			НовыйЭлемент = НовыйЭлемент + Символ;
		КонецЕсли;
		
		Если ПредыдущийСимвол = """" И Символ = """"
			 И КавычкиОткрыты Тогда
			НовыйЭлемент = НовыйЭлемент + ПредыдущийСимвол;
		КонецЕсли;
		
		Если (Символ = " " И Не КавычкиОткрыты) Или Индекс = ДлинаСтроки Тогда
			Если Не ПустаяСтрока(НовыйЭлемент) Тогда
				Результат.Добавить(СокрЛП(НовыйЭлемент));
			КонецЕсли;
			
			НовыйЭлемент = "";
			Продолжить;
		КонецЕсли;
		
		ПредыдущийСимвол = Символ;
		
	КонецЦикла;
		
	Возврат Результат;
	
КонецФункции

#КонецОбласти