[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции(Знач Стр, Парам1 = Неопределено,
                                             Парам2 = Неопределено,
                                             Парам3 = Неопределено,
                                             Парам4 = Неопределено,
                                             Парам5 = Неопределено,
                                             Парам6 = Неопределено,
                                             Парам7 = Неопределено,
											 Парам8 = Неопределено,
											 Парам9 = Неопределено) Экспорт

	Если Парам1 <> Неопределено Тогда
		Стр = СтрЗаменить(Стр,"%1",Парам1);
	КонецЕсли;
	Если Парам2 <> Неопределено Тогда
		Стр = СтрЗаменить(Стр,"%2",Парам2);
	КонецЕсли;
	Если Парам3 <> Неопределено Тогда
		Стр = СтрЗаменить(Стр,"%3",Парам3);
	КонецЕсли;
	Если Парам4 <> Неопределено Тогда
		Стр = СтрЗаменить(Стр,"%4",Парам4);
	КонецЕсли;
	Если Парам5 <> Неопределено Тогда
		Стр = СтрЗаменить(Стр,"%5",Парам5);
	КонецЕсли;
	Если Парам6 <> Неопределено Тогда
		Стр = СтрЗаменить(Стр,"%6",Парам6);
	КонецЕсли;
	Если Парам7 <> Неопределено Тогда
		Стр = СтрЗаменить(Стр,"%7",Парам7);
	КонецЕсли;
	Если Парам8 <> Неопределено Тогда
		Стр = СтрЗаменить(Стр,"%8",Парам8);
	КонецЕсли;
	Если Парам9 <> Неопределено Тогда
		Стр = СтрЗаменить(Стр,"%9",Парам9);
	КонецЕсли;

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

//Записывает произвольное событие в журнал регистрации с типом "Информация"
&НаКлиенте

Процедура ЗаписатьЛогВЖРИнформация(Знач ИмяСобытия, Знач Стр) Экспорт
	ЗаписатьЛогВЖРИнформацияСервер(ИмяСобытия, Стр);
КонецПроцедуры

//Записывает произвольное событие в журнал регистрации с типом "Ошибка"
&НаКлиенте

Процедура ЗаписатьЛогВЖРОшибка(Знач ИмяСобытия, Знач Стр) Экспорт
	ЗаписатьЛогВЖРОшибкаСервер(ИмяСобытия, Стр);
КонецПроцедуры

// Возвращает значение флага ВозможнаОптимизацияРаботыСФайлами
&НаКлиенте

Функция ВозможнаОптимизацияРаботыСФайлами() Экспорт
	Возврат ВозможнаОптимизацияРаботыСФайлами;
КонецФункции

// Убирает символы их строки, которые нельзя использовать в ключе структуры
&НаКлиенте

Функция УбратьЗапрещенныеСимволыИзКлючаСтруктуры(Знач Стр) Экспорт
	Стр = СтрЗаменить(Стр, """", "");
	Стр = СтрЗаменить(Стр, Символы.ПС, "");
	Стр = СтрЗаменить(Стр, Символы.ВК, "");
	ЗапрещенныеСимволы = " <>.,\/|':;!№%?*()@#$%^&*+-`~↓↑–";

	Для НомерСимвола = 1 По СтрДлина(ЗапрещенныеСимволы) Цикл
		ЗапрещенныйСимвол = Сред(ЗапрещенныеСимволы, НомерСимвола, 1);
		Стр = СтрЗаменить(Стр, ЗапрещенныйСимвол, "");
	КонецЦикла;

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

// Возвращает многострочную строку по переданному массиву. Для замены СтрСоединить.
&НаКлиенте

Функция МассивВСтроку(Массив, Символ = Неопределено) Экспорт

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

	Результат = МассивВСтрокуНаСервереБезКонтекста(Массив, Символ, ЕстьПоддержкаФункцияРазложитьСтрокуВМассивПодстрок);
	Возврат Результат;

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

// Возвращает многострочную строку по переданному массиву. Для замены СтрСоединить.
&НаКлиентеНаСервереБезКонтекста

Функция МассивВСтрокуНаСервереБезКонтекста(Знач Массив, Знач Символ = Неопределено,
	Знач ЕстьПоддержкаФункцияРазложитьСтрокуВМассивПодстрок = Ложь) Экспорт

	Если Символ = Неопределено Тогда
		Символ = Символы.ПС;
	КонецЕсли;

	Если ЕстьПоддержкаФункцияРазложитьСтрокуВМассивПодстрок Тогда
		Возврат Вычислить("СтрСоединить(Массив, Символ)");
	КонецЕсли;

	Стр = "";
	Для Ккк = 0 По Массив.Количество() - 1 Цикл
		Стр = Стр + Массив[Ккк];
		Если Ккк < Массив.Количество() - 1 Тогда
			Стр = Стр + Символ;
		КонецЕсли;
	КонецЦикла;

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

// Возвращает строку, дополненную нулями слева.
&НаКлиенте

Функция ПолучитьФорматированныйНомер(НомШага, КолСимволов) Экспорт
	Стр = Формат(НомШага, "ЧГ=; ЧН=0");
	Стр = СтрЗаменить(Стр, Символы.НПП, "");

	Пока СтрДлина(Стр) < КолСимволов Цикл
		Стр = "0" + Стр;
	КонецЦикла;

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

// Возвращает ИД под которым будут сохранятся и читаться настройки.
&НаКлиентеНаСервереБезКонтекста

Функция ПолучитьИДСохраненияОбщихНастроек(РежимСамотестирования, ВерсияПоставки, РежимОбучения)

	Ид = "VanessaAutomationUF";

	Если РежимСамотестирования Тогда
		Ид = "VanessaAutomationUF_autotest";
	КонецЕсли;

	Если ВерсияПоставки = "single" Тогда
		Ид = Ид + "_" + ВерсияПоставки;
	КонецЕсли;

	Если РежимОбучения Тогда
		Ид = Ид + "_Обучение";
	КонецЕсли;

	Возврат Ид;

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

// Возвращает префикс, который используется при сохранении настроек
&НаКлиентеНаСервереБезКонтекста

Функция ПолучитьПрефиксИнструмента(РежимСамотестирования, ВерсияПоставки, РежимОбучения)
	ПрефиксИнструмента = "vanessabehavior_";
	Если РежимСамотестирования Тогда
		ПрефиксИнструмента = ПрефиксИнструмента + "autotest_";
	КонецЕсли;

	Если ВерсияПоставки <> "standart" Тогда
		ПрефиксИнструмента = ПрефиксИнструмента + "_" + СокрЛП(ВерсияПоставки);
	КонецЕсли;

	Если РежимОбучения Тогда
		ПрефиксИнструмента = ПрефиксИнструмента + "_Обучение";
	КонецЕсли;

	Возврат ПрефиксИнструмента;
КонецФункции

// Выполняет команду системы без показа черного окна и возвращает результат потока вывода
&НаКлиенте

Функция ВыполнитьКомандуСПотокомВывода(Команда, Кодировка = Неопределено) Экспорт
	#Если НЕ ВебКлиент Тогда
	Если Кодировка = Неопределено Тогда
		Кодировка = КодировкаТекста.OEM;
	КонецЕсли;

	ИмяФайлаПотокаВывода = ПолучитьИмяВременногоФайла("stdout.tmp");
	Команда = Команда + " > ""%1""";
	Команда = СтрЗаменить(Команда, "%1", ИмяФайлаПотокаВывода);

	ВыполнитьКомандуОСБезПоказаЧерногоОкна(Команда);

	ЧтениеПотокаОшибок = Новый ЧтениеТекста(ИмяФайлаПотокаВывода, Кодировка);
	ПотокВывода = ЧтениеПотокаОшибок.Прочитать();
	ЧтениеПотокаОшибок.Закрыть();

	Попытка
		УдалитьФайлыКомандаСистемы(ИмяФайлаПотокаВывода);
	Исключение
		ТекстСообщения = Локализовать("Не получилось удалить файл %1");
		ТекстСообщения = СтрЗаменить(ТекстСообщения, "%1", ИмяФайлаПотокаВывода);
		ЗаписатьЛогВЖРОшибка("VanessaAutomation.УдалениеВременногоФайла", ТекстСообщения);
	КонецПопытки;

	Возврат ПотокВывода;
	#КонецЕсли
КонецФункции

// Устарела. Использовать Локализовать(Сообщение)
//
&НаКлиенте

Функция ПолучитьТекстСообщенияПользователю(Текст) Экспорт
	Возврат Локализовать(Текст);
КонецФункции

// Возвращает текст сообщения пользователю с учетом языка, на котором запущен Менеджер тестирования
//
// Параметры:
// 	Сообщение - Строка
// Возвращаемое значение:
// 	Строка
//
&НаКлиенте

Функция Локализовать(Сообщение) Экспорт

	Если ЗначениеЗаполнено(Объект.ТекстСообщенийПользователю) Тогда
		Значение = Объект.ТекстСообщенийПользователю[СокрЛП(Сообщение)];
		Если ЗначениеЗаполнено(Значение) Тогда
			Возврат Значение;
		КонецЕсли;
	КонецЕсли;

	Возврат Сообщение;

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

&НаСервере

Функция ЛокализоватьСервер(Знач Сообщение) Экспорт

	Возврат ТекстСообщенияПользователюВызовСервера(Сообщение, Объект.ТекстСообщенийПользователю);

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

// Служебная
//
&НаСервереБезКонтекста

Функция ТекстСообщенияПользователюВызовСервера(Знач Сообщение, Знач ТекстыСообщенийПользователю)

	Если ЗначениеЗаполнено(ТекстыСообщенийПользователю) Тогда
		Значение = ТекстыСообщенийПользователю[Сообщение];
		Если ЗначениеЗаполнено(Значение) Тогда
			Возврат Значение;
		КонецЕсли;
	КонецЕсли;

	Возврат Сообщение;

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

// Делает паузу во время исполнения кода на указанное число секунд
// Для реализации используется команда ping либо поиск окна клиента тестирования с заданным таймаутом.
// Кроссплатформено
&НаКлиенте

[Assistant]
Функция ПодставитьПараметрыВСтроку(Знач Стр, Парам1 = Неопределено,
                                             Парам2 = Неопределено,
                                             Парам3 = Неопределено,
                                             Парам4 = Неопределено,
                                             Парам5 = Неопределено,
                                             Парам6 = Неопределено,
                                             Парам7 = Неопределено,
											 Парам8 = Неопределено,
											 Парам9 = Неопределено)


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

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

&НаКлиенте

Функция ФайлСуществуетКомандаСистемы(Знач ИмяФайла, ДопПараметры = Неопределено) Экспорт

	#Если НЕ ВебКлиент Тогда

	Если ПустаяСтрока(ИмяФайла) Тогда
		Возврат Ложь;
	ИначеЕсли НЕ ЗапрещеныСинхронныеВызовы Тогда
		ФайлПроверкаСуществования = Новый Файл(ИмяФайла);
		Возврат ФайлПроверкаСуществования.Существует();
	ИначеЕсли ЗапрещеныСинхронныеВызовы И ВозможнаОптимизацияРаботыСФайлами Тогда
		Возврат ФайлСуществуетСервер(ИмяФайла);
	Иначе
		ИмяВременногоЛог = ПолучитьИмяВременногоФайла("log");

		Если НЕ ЭтоLinux Тогда
			ИмяФайла = СтрЗаменить(ИмяФайла, "/", "\");
			ВыполнитьКомандуОСБезПоказаЧерногоОкна("(If Exist """ + ИмяФайла + """ (Echo yes) Else (Echo no)) > """ + ИмяВременногоЛог + """");
		Иначе
			ИмяВременнгоФайла = ПолучитьИмяВременногоФайла("sh");
			ЗТ = Новый ЗаписьТекста(ИмяВременнгоФайла, "UTF-8", Символы.ПС, Истина, Символы.ПС);

			ЗТ.ЗаписатьСтроку("#!/bin/sh");

			Если Найти(ИмяФайла, " ") > 0 Тогда
				ИмяФайла = СтрЗаменить(ИмяФайла, " ", "\ ");
			КонецЕсли;

			СтрокаКоманды = "sh -c 'test -f " + ИмяФайла + " && echo yes || echo no' > " + ИмяВременногоЛог + "";
			ЗТ.ЗаписатьСтроку(СтрокаКоманды);
			СтрокаКоманды = "sh -c 'test -d " + ИмяФайла + " && echo yes || echo no' >> " + ИмяВременногоЛог + "";
			ЗТ.ЗаписатьСтроку(СтрокаКоманды);
			ЗТ.Закрыть();

			КомандаСистемы("sh " + ИмяВременнгоФайла);
		КонецЕсли;

		ФайлСуществует = Ложь;

		Текст = Новый ЧтениеТекста;
		Текст.Открыть(ИмяВременногоЛог, "UTF-8");

		Пока Истина Цикл
			Стр = Текст.ПрочитатьСтроку();
			Если Стр = Неопределено Тогда
				Прервать;
			КонецЕсли;

			Если Стр = "yes" Тогда
				ФайлСуществует = Истина;
			КонецЕсли;
		КонецЦикла;
		Текст.Закрыть();

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

	#КонецЕсли
КонецФункции

&НаКлиенте

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

	Если СтрДлина(ИмяКаталога) <= 3 Тогда
		Возврат;
	КонецЕсли;

	Если Найти(Прав(ИмяКаталога, 1), "\/") > 0 Тогда
		ИмяКаталога = Лев(ИмяКаталога, СтрДлина(ИмяКаталога) - 1);
	КонецЕсли;

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

КонецПроцедуры

// Возвращает файл с картинкой.
// Поиск картинки сначала происходит в каталоге проекта, затем в каталоге фичи.
// ИмяФайла  - Строка - путь к файлу
//
&НаКлиенте

Функция ПолучитьФайлКартинки(Знач ИмяФайла, КаталогФичи = Неопределено) Экспорт
	Путь = Объект.КаталогПроекта;
	Если НЕ ЗначениеЗаполнено(Путь) Тогда
		ВызватьИсключение Локализовать("Не указано значение настройки Vanessa-automation: <КаталогПроекта>.");
	КонецЕсли;

	Если ФайлСуществуетКомандаСистемы(ИмяФайла) Тогда
		Возврат Новый Файл(ИмяФайла);
	КонецЕсли;

	Если Найти(ИмяФайла, ".") = 0 Тогда
		ИмяФайла = ИмяФайла + ".png";
	КонецЕсли;

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

			Если ЗначениеЗаполнено(КаталогФичи) Тогда
				Путь = КаталогФичи;
			Иначе
				Состояние = ПолучитьСостояниеVanessaAutomation();
				Если Состояние <> Неопределено И Состояние.ТекущаяФича.Свойство("Каталог") Тогда
					Путь = Состояние.ТекущаяФича.Каталог;
				КонецЕсли;
			КонецЕсли;

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

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

	Если СписокФайлов.Количество() > 1 Тогда
		ВызватьИсключение ПодставитьПараметрыВСтроку(
			Локализовать("В каталоге <%1> найдено больше одного файла <%2>: %3."),
			Путь,
			ИмяФайла,
			СписокФайлов.Количество()
		);
	КонецЕсли;

	Возврат СписокФайлов[0].Значение;
КонецФункции

// Возвращает файл с картинкой
// ИмяФайла  - Строка - путь к файлу
//
&НаКлиенте

Функция ПолучитьФайлКартинкиДляРаботыVA(ИмяФайла) Экспорт
	Путь = Объект.КаталогИнструментов;
	Если НЕ ЗначениеЗаполнено(Путь) Тогда
		ВызватьИсключение Локализовать("Не указано значение настройки Vanessa-automation: <КаталогИнструментов>.");
	КонецЕсли;

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

	Если СписокФайлов.Количество() > 1 Тогда
		ВызватьИсключение ПодставитьПараметрыВСтроку(
			Локализовать("В каталоге <%1> найдено больше одного файла <%2>: %3."),
			Путь,
			ИмяФайла,
			СписокФайлов.Количество()
		);
	КонецЕсли;

	Возврат СписокФайлов[0].Значение;
КонецФункции

// Возвращает файл с картинкой
// ИмяФайла  - Строка - путь к файлу
//
&НаКлиенте

[Assistant] Функция ВерсияФайлаКомандаСистемы(ИмяФайла)


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции(Текст, ДанныеПрофиля = Неопределено) Экспорт
	Путь = Объект.КаталогДляГенерацииКартинок;
	Если НЕ ЗначениеЗаполнено(Путь) Тогда
		ВызватьИсключение Локализовать("Не указано значение настройки Vanessa-automation: <КаталогДляГенерацииКартинок>.");
	КонецЕсли;

	Шрифт = "arial";
	ЦветФона = "white";
	ЦветШрифта = "black";
	Размер = 13;

	Если ТипЗнч(ДанныеПрофиля) = Тип("Структура") Тогда
		Шрифт = ДанныеПрофиля.Шрифт;
		ЦветФона = ДанныеПрофиля.ЦветФона;
		ЦветШрифта = ДанныеПрофиля.ЦветШрифта;
		Размер = ДанныеПрофиля.Размер;
	ИначеЕсли ТипЗнч(ОбъектКонтекстСохраняемый) = Тип("Структура") Тогда
		Если ОбъектКонтекстСохраняемый.Свойство("ОсновнойПрофильПоискаКартинкиСТекстом") Тогда
			ОсновнойПрофильПоискаКартинкиСТекстом = ОбъектКонтекстСохраняемый.ОсновнойПрофильПоискаКартинкиСТекстом;
			Шрифт      = ОсновнойПрофильПоискаКартинкиСТекстом.Шрифт;
			ЦветФона   = ОсновнойПрофильПоискаКартинкиСТекстом.ЦветФона;
			ЦветШрифта = ОсновнойПрофильПоискаКартинкиСТекстом.ЦветШрифта;
			Размер     = ОсновнойПрофильПоискаКартинкиСТекстом.Размер;
		КонецЕсли;
	КонецЕсли;

	ИмяКартинки = Текст + "_" + Шрифт + "_" + ЦветФона + "_" + ЦветШрифта + "_" + Размер + ".png";
	ИмяКартинки = СтрЗаменить(ИмяКартинки, ":", КодСимвола(":"));
	ИмяКартинки = УбратьВсеЗапрещенныеСимволыИзИмениФайла(ИмяКартинки);
	ИмяКартинки = СтрЗаменить(ИмяКартинки, "#", "");
	ИмяКартинки = ДополнитьСлешВПуть(Путь) + ИмяКартинки;

	Если ФайлСуществуетКомандаСистемы(ИмяКартинки) Тогда
		Возврат Новый Файл(ИмяКартинки);
	КонецЕсли;

	Если ПустаяСтрока(Объект.ЗаписьВидеоКомандаConvert) Тогда
		ВызватьИсключение Локализовать("Не заполнена команда ""Convert"" из пакета ImageMagic.");
	КонецЕсли;

	Если НужноОбернутьВКавычкиКомандуКоверт(Объект.ЗаписьВидеоКомандаConvert) Тогда
		Команда = """" + Объект.ЗаписьВидеоКомандаConvert + """";
	Иначе
		Команда = Объект.ЗаписьВидеоКомандаConvert;
	КонецЕсли;

	Команда = Команда + " -background ""%1"" -fill ""%2"" -font ""%3"" -pointsize %4 label:""%5""  ""%6""";
	Команда = СтрЗаменить(Команда, "%1", ЦветФона);
	Команда = СтрЗаменить(Команда, "%2", ЦветШрифта);
	Команда = СтрЗаменить(Команда, "%3", Шрифт);
	Команда = СтрЗаменить(Команда, "%4", Размер);
	Команда = СтрЗаменить(Команда, "%5", Текст);
	Команда = СтрЗаменить(Команда, "%6", ИмяКартинки);

	ВыполнитьКомандуОСБезПоказаЧерногоОкна(Команда);

	Если НЕ ФайлСуществуетКомандаСистемы(ИмяКартинки) Тогда
		ВызватьИсключение ПодставитьПараметрыВСтроку(
			Локализовать("Не получилось создать картинку по тексту <%1>."),
			Текст
		);
	КонецЕсли;

	Возврат Новый Файл(ИмяКартинки);
КонецФункции

&НаСервереБезКонтекста

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

	Возврат Файл.ЭтоКаталог();
КонецФункции

&НаКлиенте

Функция ЭтоКаталогКомандаСистемы(Путь) Экспорт

	#Если НЕ ВебКлиент Тогда

	Если ПустаяСтрока(Путь) Тогда
		Возврат Ложь;
	КонецЕсли;

	Если НЕ ЗапрещеныСинхронныеВызовы Тогда
		Файл = Новый Файл(Путь);
		Возврат Файл.ЭтоКаталог();
	ИначеЕсли ЗапрещеныСинхронныеВызовы И ВозможнаОптимизацияРаботыСФайлами Тогда
		Возврат ЭтоКаталогКомандаСистемыСервер(Путь);
	Иначе

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

				ИмяВременногоФайлаКоманды = ПолучитьИмяВременногоФайла("bat");

				// эти две строки нужны для записи файла без BOM - начало
				ЗТ = Новый ЗаписьТекста(ИмяВременногоФайлаКоманды, КодировкаТекста.ANSI, , Ложь);
				ЗТ.Закрыть();
				// эти две строки нужны для записи файла без BOM - окончание

				ЗТ = Новый ЗаписьТекста(ИмяВременногоФайлаКоманды, КодировкаТекста.UTF8, , Истина);
				Если НЕ ЭтоWindowsXP Тогда
					ЗТ.ЗаписатьСтроку("chcp 65001");
				КонецЕсли;
				ТекстКоманды = "echo ""%~a1""|findstr ""d"" && echo Folder || echo File";
				ЗТ.ЗаписатьСтроку(ТекстКоманды);
				ЗТ.Закрыть();

				ЭтоКаталогКомандаСистемыСлужебныйФайл = ИмяВременногоФайлаКоманды;
			КонецЕсли;

			ИмяФайлаЛога = ПолучитьИмяВременногоФайла("txt");
			КомандаКаталоги = """" + ЭтоКаталогКомандаСистемыСлужебныйФайл + """ """ + Путь + """ > """ + ИмяФайлаЛога + """";
			ВыполнитьКомандуОСБезПоказаЧерногоОкна(КомандаКаталоги);

			Текст = Новый ЧтениеТекста;
			Текст.Открыть(ИмяФайлаЛога, "UTF-8");

			ЭтоКаталог = Ложь;
			Пока Истина Цикл
				Стр = Текст.ПрочитатьСтроку();
				Если Стр = Неопределено Тогда
					Прервать;
				КонецЕсли;

				Если НРег(СокрЛП(Стр)) = "folder" Тогда
					ЭтоКаталог = Истина;
					Прервать;
				КонецЕсли;

			КонецЦикла;

			Текст.Закрыть();
			УдалитьФайлыКомандаСистемы(ИмяФайлаЛога);

			Возврат ЭтоКаталог;

		КонецЕсли;
	КонецЕсли;

	#КонецЕсли

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

&НаКлиенте

Функция ПолучитьДопОписаниеСкриншота()
	Если ТипЗнч(ЗначениеПараметровДляСнятияСкриншотов) = Тип("Структура") Тогда
		Если ЗначениеПараметровДляСнятияСкриншотов.Свойство("ДобавлятьКИменамСкриншотовОписаниеОшибки")
			И ЗначениеПараметровДляСнятияСкриншотов.ДобавлятьКИменамСкриншотовОписаниеОшибки Тогда

			Если НЕ ЗначениеЗаполнено(ЗначениеПараметровДляСнятияСкриншотов.ОписаниеОшибкиВнутриСценария) Тогда
				Возврат "_" + Формат(ЗначениеПараметровДляСнятияСкриншотов.ТекШаг.ИдСтроки, "ЧГ=; ЧН=0");
			КонецЕсли;

			Возврат "_" + ЗначениеПараметровДляСнятияСкриншотов.ОписаниеОшибкиВнутриСценария;
		КонецЕсли;
	КонецЕсли;

	Возврат Неопределено;
КонецФункции

&НаКлиенте

Функция ОпределитьПрикреплятьСкриншотКШагу()
	Если ТипЗнч(ЗначениеПараметровДляСнятияСкриншотов) = Тип("Структура") Тогда
		Если ЗначениеПараметровДляСнятияСкриншотов.Свойство("ПрикреплятьСкриншотКШагу")
			И ЗначениеПараметровДляСнятияСкриншотов.ПрикреплятьСкриншотКШагу Тогда

			Возврат Истина;
		КонецЕсли;
	КонецЕсли;

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

&НаКлиенте

Процедура СнимокЭкранаБраузера(ИмяФайлаСкриншота, КоординатыОбласти)

	#Если НЕ ВебКлиент Тогда

	ПараметрыМетода = Новый Структура("format,quality,fromSurface", "png", 85, Ложь);
	ДанныеJSON = Новый Структура("id,method,params", 1, "Page.captureScreenshot", ПараметрыМетода);

	ЗаписьJSON = Новый ЗаписьJSON;
	ЗаписьJSON.УстановитьСтроку();
	ЗаписатьJSON(ЗаписьJSON, ДанныеJSON);
	КомандаJSON = ЗаписьJSON.Закрыть();

	ОписаниеОповещения = Новый ОписаниеОповещения("ПолученСнимокБраузера", ЭтаФорма,
		Новый Структура("ИмяФайлаСкриншота,КоординатыОбласти", ИмяФайлаСкриншота,КоординатыОбласти) );
	ВнешняяКомпонентаДляСкриншотов.НачатьВызовВебСокет(ОписаниеОповещения, АдресВебСокет, КомандаJSON);

	#КонецЕсли

КонецПроцедуры

&НаКлиенте

[Assistant] Функция ПолучитьФайлКартинкиИзТекста(Текст, ДанныеПрофиля = Неопределено)


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции(Поле, ТипКнопки, ДопПараметры)
	ТекущиеДанныеКлиентаТестирования = ТекущиеДанныеКлиентаТестирования();

	Если ТекущиеДанныеКлиентаТестирования.PIDКлиентаТестирования = 0 Тогда
		ВызватьИсключение ПодставитьПараметрыВСтроку(
			Локализовать("Не определен PID клиента тестирования с именем <%1>."),
				ТекущиеДанныеКлиентаТестирования.Имя);
	КонецЕсли;

	ДанныеПолей = НайтиЭлементыПроцессаUIAutomation(ТекущиеДанныеКлиентаТестирования.PIDКлиентаТестирования, Поле.ТекстЗаголовка);
	ДанныеПолей = ИсключитьТекстовыеПоляИзНайденыхЭлементовUIAutomation(ДанныеПолей);
	НужныйЭлемент = Неопределено;
	Если ДанныеПолей <> Неопределено И ДанныеПолей.Количество() = 1 Тогда
		НужныйЭлемент = ДанныеПолей[0];
	КонецЕсли;

	Если НужныйЭлемент = Неопределено Тогда
		Попытка
			Поле.Активизировать();
			ВнешняяКомпонентаДляСкриншотов.sleep(50);
			НужныйЭлемент = ПрочитатьОбъектJSON(ВнешняяКомпонентаДляСкриншотов.АктивныйЭлемент);
		Исключение
		КонецПопытки;
	КонецЕсли;

	МасштабЭкрана = ПолучитьМасштабЭкрана();

	ЭлементыРодитель = ПрочитатьОбъектJSON(ВнешняяКомпонентаДляСкриншотов.ПолучитьРодителяЭлемента(НужныйЭлемент.Id));
	Если ЭлементыРодитель.Type = "Pane"
		И ЭлементыРодитель.Size.Left >= НужныйЭлемент.Size.Left - МасштабЭкрана / 100 - 1
		И ЭлементыРодитель.Size.Top >= НужныйЭлемент.Size.Top - МасштабЭкрана / 100 - 1
		И ЭлементыРодитель.Size.Bottom <= НужныйЭлемент.Size.Bottom + МасштабЭкрана / 100 + 1
	Тогда
		НужныйЭлемент = ЭлементыРодитель;
	КонецЕсли;

	Если ТипЗнч(ДопПараметры) = Тип("Структура") Тогда
		ДопПараметры.Вставить("ИДЭлемента", НужныйЭлемент.Id);
	КонецЕсли;

	СнимокОкна = ВнешняяКомпонентаДляСкриншотов.ПолучитьСнимокОкна(НужныйЭлемент.Handle);
	ТекстJSON = ВнешняяКомпонентаДляСкриншотов.ПолучитьРазмерОкна(НужныйЭлемент.Handle);
	РазмерыОкна = ПрочитатьСтрокуJSON(ТекстJSON);
	СнимокОбласти = ВнешняяКомпонентаДляСкриншотов.ОбрезатьИзображение(СнимокОкна
		, НужныйЭлемент.Size.Left - РазмерыОкна.Left
		, НужныйЭлемент.Size.Top - РазмерыОкна.Top
		, НужныйЭлемент.Size.Width
		, НужныйЭлемент.Size.Height);

	ОписаниеКартинки = ПолучитьКартинкуНаСервере(УникальныйИдентификатор, МасштабЭкрана, ТипКнопки, Версия851ИлиВыше);
	Если ОписаниеКартинки.Свойство("ТекстОшибки") Тогда
		ТекстОшибки = Локализовать(ОписаниеКартинки.ТекстОшибки);
		ТекстОшибки = СтрЗаменить(ТекстОшибки, "%1", ОписаниеКартинки.Параметр1);
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;

	Если ОписаниеКартинки = Неопределено Тогда
		Возврат Ложь;
	КонецЕсли;

	НомерКартинки = 0;
	Если ТипКнопки = "ВыпадающийСписок" Тогда
		НомерКартинки = 5;
	ИначеЕсли ТипКнопки = "ОткрытиеЭлемента" Тогда
		НомерКартинки = 4;
	ИначеЕсли ТипКнопки = "ОчисткаЭлемента" Тогда
		НомерКартинки = 6;
	ИначеЕсли ТипКнопки = "ВыборИзСписка" Тогда
		НомерКартинки = 7;
	КонецЕсли;

	Если Версия851ИлиВыше Тогда
		НомерКартинки = 0;
	КонецЕсли;

	X = ОписаниеКартинки.ВысотаКартинки * НомерКартинки;
	Y = 0;
	W = ОписаниеКартинки.ВысотаКартинки;
	H = ОписаниеКартинки.ВысотаКартинки;

	Если (НомерКартинки = 2) ИЛИ (НомерКартинки = 3) Тогда
		Y = ОписаниеКартинки.ВысотаКартинки / 4;
		H = ОписаниеКартинки.ВысотаКартинки / 2;
	КонецЕсли;

	КартинкаКнопки = ПолучитьИзВременногоХранилища(ОписаниеКартинки.АдресКартинки);
	УдалитьИзВременногоХранилища(ОписаниеКартинки.АдресКартинки);

	КартинкаКнопки  = ВнешняяКомпонентаДляСкриншотов.ОбрезатьИзображение(КартинкаКнопки, X, Y, W, H);

	КартинкаЭлемента = СнимокОбласти;
	ФрагментЭлемента = ВнешняяКомпонентаДляСкриншотов.НайтиФрагмент(КартинкаЭлемента, КартинкаКнопки);

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

	Если Координаты.match < 0.99 Тогда
		Возврат Ложь;

	КонецЕсли;

	Если НомерКартинки = 7 Тогда
		//три точки
		Если Координаты.match < 1 Тогда
			ОткрытьВыпадающийСписок(Поле);
			ДанныеКнопок = НайтиЭлементыПроцессаUIAutomation(ТекущиеДанныеКлиентаТестирования.PIDКлиентаТестирования, "Показать все", "Text");
			Если ДанныеКнопок <> Неопределено И ДанныеКнопок.Количество() = 1 Тогда
				ПереместитьМышкуПоКоординатамUIAutomation(ДанныеКнопок[0].Size);
				МодульРаботаСБраузером().АнимацияКлика(Поле);
				Возврат Истина;
			КонецЕсли;
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;

	Координаты.Left = Координаты.Left + НужныйЭлемент.Size.Left;
	Координаты.Right = Координаты.Left + Координаты.Width;
	Координаты.Top = Координаты.Top + НужныйЭлемент.Size.Top;
	Координаты.Bottom = Координаты.Top + Координаты.Height;

	Если НомерКартинки = 5 Тогда
		//ВыпадающийСписок
		Попытка
			Если Поле.ВыпадающийСписокОткрыт() Тогда
				Возврат Истина;
			КонецЕсли;
		Исключение
		КонецПопытки;
	КонецЕсли;

	ПереместитьМышкуПоКоординатамUIAutomation(Координаты);
	МодульРаботаСБраузером().АнимацияКлика(Поле);
	ВнешняяКомпонентаДляСкриншотов.sleep(200);

	Возврат Истина;

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

&НаКлиенте

Процедура КликПоЗначениюВыпадающегоСпискаUIAutomation(ПолеРеквизит, ВыбираемоеЗначение, ДопПараметры)
	ТекущиеДанныеКлиентаТестирования = ТекущиеДанныеКлиентаТестирования();

	Если ТекущиеДанныеКлиентаТестирования.PIDКлиентаТестирования = 0 Тогда
		ВызватьИсключение ПодставитьПараметрыВСтроку(
			Локализовать("Не определен PID клиента тестирования с именем <%1>."),
				ТекущиеДанныеКлиентаТестирования.Имя);
	КонецЕсли;

	Если Версия8323ИлиВыше Тогда
		ДанныеЭлементов = НайтиЭлементыПроцессаUIAutomation(ТекущиеДанныеКлиентаТестирования.PIDКлиентаТестирования, ВыбираемоеЗначение, "Custom");
	Иначе
		ДанныеЭлементов = НайтиЭлементыПроцессаUIAutomation(ТекущиеДанныеКлиентаТестирования.PIDКлиентаТестирования, ВыбираемоеЗначение, "ListItem");
	КонецЕсли;
	Если ТипЗнч(ДанныеЭлементов) = Тип("Массив") И ДанныеЭлементов.Количество() > 0 Тогда
		ПереместитьМышкуПоКоординатамUIAutomation(ДанныеЭлементов[0].Size);
		МодульРаботаСБраузером().АнимацияКлика(ПолеРеквизит);
	КонецЕсли;

	ПолеРеквизит.ВыполнитьВыборИзВыпадающегоСписка(ВыбираемоеЗначение);

КонецПроцедуры

&НаСервереБезКонтекста

[Assistant] Функция КликПоКнопкеПоляUIAutomation(Поле, ТипКнопки, ДопПараметры)


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции(Знач УникальныйИдентификатор, Знач Масштаб, ТипКнопки, Версия851ИлиВыше)

	ВременныйФайл = ПолучитьИмяВременногоФайла("zip");

	Если Версия851ИлиВыше Тогда

		//Что бывает:
		//_editCalc.zip _editCalendar.zip _editCalendarAndClock.zip _editClear.zip
		//_editClock.zip _editDropDown.zip _editDropDownOpen.zip _editDropUp.zip
		//_editLeft.zip _editLocked.zip _editMinus.zip _editOpen.zip _editPlus.zip
		//_editRegDown.zip _editRegUp.zip _editRight.zip _editSelect.zip _editType.zip _editUnlocked.zip

		Если ТипКнопки = "ОчисткаЭлемента" Тогда
			ФайлРесурса = "v8res://core85/_editClear.zip";
		ИначеЕсли ТипКнопки = "ВыпадающийСписок" Тогда
			ФайлРесурса = "v8res://core85/_editDropDown.zip";
		ИначеЕсли ТипКнопки = "ВыборИзСписка" Тогда
			ФайлРесурса = "v8res://core85/_editSelect.zip";
		ИначеЕсли ТипКнопки = "ОткрытиеЭлемента" Тогда
			ФайлРесурса = "v8res://core85/_editOpen.zip";
		Иначе
			Результат = Новый Структура;
			Результат.Вставить("ТекстОшибки", "Неизвестный тип картинки: <%1>");
			Результат.Вставить("Параметр1", ТипКнопки);

			Возврат Результат;
		КонецЕсли;
	Иначе
		ФайлРесурса = "v8res://core83/edtButtons.zip";
	КонецЕсли;

	КопироватьФайл(ФайлРесурса, ВременныйФайл);

	ОтборКартинки = Новый Соответствие;
	ОтборРазмеров = Новый Соответствие;
	ОтборРазмеров.Вставить(100, "ldpi");
	ОтборРазмеров.Вставить(125, "aldpi");
	ОтборРазмеров.Вставить(150, "mdpi");
	ОтборРазмеров.Вставить(175, "amdpi");
	ОтборРазмеров.Вставить(200, "hdpi");
	ОтборРазмеров.Вставить(300, "xdpi");
	ОтборРазмеров.Вставить(400, "udpi");
	ЗначениеОтбора = ОтборРазмеров.Получить(Масштаб);
	ОтборКартинки.Вставить("screenDensity", ЗначениеОтбора);

	Картинка = Новый Картинка(ВременныйФайл);
	Если Версия851ИлиВыше Тогда
		ОтборКартинки.Вставить("interfaceVariant", "taxi");
		ДвоичныеДанныеКартинки = Картинка.ПолучитьДвоичныеДанные(Ложь, ОтборКартинки);
	Иначе
		ДвоичныеДанныеКартинки = Картинка.ПолучитьДвоичныеДанные(Ложь, ОтборКартинки);
	КонецЕсли;
	УдалитьФайлы(ВременныйФайл);
	АдресКартинки = ПоместитьВоВременноеХранилище(ДвоичныеДанныеКартинки, УникальныйИдентификатор);
	ЭкземелярКартинки = Новый Картинка(ДвоичныеДанныеКартинки);
	ВысотаКартинки = ЭкземелярКартинки.Высота();
	Результат = Новый Структура("АдресКартинки,ВысотаКартинки", АдресКартинки, ВысотаКартинки);
	Возврат Результат;

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

&НаКлиенте

Процедура ПереместитьМышкуПоКоординатамUIAutomation(Данные)

	Если Данные = Неопределено Тогда
		Возврат;
	КонецЕсли;

	X =  Окр((Данные.Right + Данные.Left) / 2, 0);
	Y = Окр((Данные.Top + Данные.Bottom) / 2, 0);

	Если X <> 0 И Y <> 0 Тогда
		ВыполнитьПеремещениеМышкиВнешнейКомпонентой(X, Y);
	КонецЕсли;

КонецПроцедуры

&НаКлиенте

Процедура ЭмуляцияНажатияМышиUIAutomation(Данные)

	Если Данные = Неопределено Тогда
		Возврат;
	КонецЕсли;

	X =  Окр((Данные.Size.Right + Данные.Size.Left) / 2, 0);
	Y = Окр((Данные.Size.Top + Данные.Size.Bottom) / 2, 0);

	Если X = 0 И Y = 0 Тогда
		Возврат;
	КонецЕсли;

	ТекстJSON = ВнешняяКомпонентаДляСкриншотов.ПолучитьРазмерОкна(Данные.Handle);
	КоординатыОкна = ПрочитатьСтрокуJSON(ТекстJSON);
	КоординатыТочки = (X - КоординатыОкна.Left) + 65536 * (Y - КоординатыОкна.Top);

	WM_LBUTTONDOWN = 513;
	WM_LBUTTONUP = 514;
	MK_LBUTTON = 1;

	ВнешняяКомпонентаДляСкриншотов.PostMessage(Данные.Handle, WM_LBUTTONDOWN, MK_LBUTTON, КоординатыТочки);
	ВнешняяКомпонентаДляСкриншотов.Пауза(100);
	ВнешняяКомпонентаДляСкриншотов.PostMessage(Данные.Handle, WM_LBUTTONUP, 0, КоординатыТочки);

КонецПроцедуры

&НаКлиенте

Процедура КликПоЭлементуUIAutomation(ДанныеUIAutomation, Элемент)

	ПереместитьМышкуПоКоординатамUIAutomation(ДанныеUIAutomation.Size);
	КликПоЭлементу_Автоинструкции(Элемент);

КонецПроцедуры

&НаКлиенте

Функция КликПоКнопкеКИВОкнеБраузер(Кнопка)

	КликПоЭлементуФормыБраузерСлужебный(Кнопка, "navigationItem");

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

&НаКлиенте

Процедура КликПоКнопкеПанельОткрытыхБраузер(Кнопка)

	КликПоЭлементуФормыБраузерСлужебный(Кнопка, "openedFormCaption");

КонецПроцедуры

&НаКлиенте

Процедура ПересчитатьДанныеКоординатСУчетомМасштабирования(ДанныеКоординат, X, Y) Экспорт
	КоэффициентМасштабированияЭкрана = Объект.КоэффициентМасштабированияЭкрана;
	Если КоэффициентМасштабированияЭкрана = 0 Тогда
		КоэффициентМасштабированияЭкрана = 1;
	КонецЕсли;

	X = Окр(ДанныеКоординат.X * КоэффициентМасштабированияЭкрана);
	Y = Окр(ДанныеКоординат.Y * КоэффициентМасштабированияЭкрана);
КонецПроцедуры

&НаКлиенте

Процедура КликПоЗначениюВыпадающегоСпискаБраузер(Элемент, Значение)

	#Если НЕ ВебКлиент Тогда

	Попытка
		ПредставлениеСпискаВыбора = ДополнитьПредставлениеСпискаВыбора(Элемент.ПолучитьПредставлениеСпискаВыбора());
	Исключение
		ПредставлениеСпискаВыбора = Новый Массив;
	КонецПопытки;

	Если ТипЗнч(Значение) = Тип("Строка") Тогда
		Ид = 0;
		Для Сч = 0 По ПредставлениеСпискаВыбора.Количество() - 1 Цикл
			Если НРег(ПредставлениеСпискаВыбора[Сч].ОтображаемыйТекст) = НРег(Значение) Тогда
				Ид = Сч;
			КонецЕсли;
		КонецЦикла;
	Иначе
		Ид = Значение;
	КонецЕсли;

	ТекстJavaScript = "
	|{
	|function pos(){
	|    let r = document.querySelector('#editDropDown').querySelectorAll('li')[%1].getBoundingClientRect();
	|    return {
	|       x: Math.round(r.left + r.width / 2) + window.screenLeft,
	|       y: Math.round(r.top + r.height / 2) + window.screenTop + window.outerHeight - window.innerHeight,
	|       sw: screen.width,
	|       sh:screen.height,
	|    }
	|}; JSON.stringify(pos())
	|}
	|";

	ТекстJavaScript = СтрЗаменить(ТекстJavaScript,"%1", Ид);

	КоординатыЭлемента = ВыполнитьJavaScriptБраузерСлужебный(ТекстJavaScript);

	Попытка
		СтрокаКоординаты = КоординатыЭлемента.result.result.value;
	Исключение
		СтрокаКоординаты = Неопределено;
	КонецПопытки;

	Если СтрокаКоординаты = Неопределено Тогда
		ТекстСообщения = ПодставитьПараметрыВСтроку(
			Локализовать("Не вышло получить координаты элемента <%1> в браузере: %2."),
			Элемент.ТекстЗаголовка,
			СтрокаКоординаты);
		Попытка
			ТекстСообщения = ТекстСообщения + Символы.ПС + КоординатыЭлемента.result.exceptionDetails.exception.description;
		Исключение
		КонецПопытки;

		ЗаписатьЛогВЖРОшибка("КликПоЗначениюВыпадающегоСпискаБраузер", ТекстСообщения);
		ВызватьИсключение ТекстСообщения;
	КонецЕсли;

	Попытка
		ЧтениеJSON = Новый ЧтениеJSON();
		ЧтениеJSON.УстановитьСтроку(СтрокаКоординаты);
		ДанныеКоординат = ПрочитатьJSON(ЧтениеJSON);
	Исключение
		ДанныеКоординат = Неопределено;
	КонецПопытки;

	Если ДанныеКоординат = Неопределено Тогда
		ТекстСообщения = ПодставитьПараметрыВСтроку(
			Локализовать("Не вышло получить координаты элемента <%1> в браузере: %2."),
			Элемент.ТекстЗаголовка,
			СтрокаКоординаты
		);
		Попытка
			ТекстСообщения = ТекстСообщения + Символы.ПС + КоординатыЭлемента.result.exceptionDetails.exception.description;
		Исключение
		КонецПопытки;
		ЗаписатьЛогВЖРОшибка("КликПоЗначениюВыпадающегоСпискаБраузер", ТекстСообщения);
		ВызватьИсключение ТекстСообщения;
	КонецЕсли;

	X = 0;
	Y = 0;
	ПересчитатьДанныеКоординатСУчетомМасштабирования(ДанныеКоординат, X, Y);

	ВыполнитьПеремещениеМышкиВнешнейКомпонентой(X, Y);

	МодульРаботаСБраузером().АнимацияКлика(Элемент);
	Элемент.ВыполнитьВыборИзВыпадающегоСписка(Значение);

	#КонецЕсли
КонецПроцедуры

&НаКлиенте

[Assistant] Функция ПолучитьКартинкуНаСервере(Знач УникальныйИдентификатор, Знач Масштаб, ТипКнопки, Версия851ИлиВыше)


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции(КаталогКеша = Неопределено) Экспорт
	#Если НЕ ВебКлиент Тогда

	Если ДанныеКешОзвучкиИнтерактивнойСправки <> Неопределено Тогда
		Возврат ДанныеКешОзвучкиИнтерактивнойСправки;
	КонецЕсли;

	//Это значение кешируется в глобальных переменных
	ДанныеКешОзвучкиИнтерактивнойСправки = Новый Соответствие;

	Если НЕ ЗначениеЗаполнено(КаталогКеша) Тогда
		КаталогКеша = Объект.КаталогКешОзвучкиДляИнтерактивнойСправки;
	КонецЕсли;

	Если НЕ ЗначениеЗаполнено(КаталогКеша) Тогда
		ДанныеКешОзвучкиИнтерактивнойСправки = Неопределено;
		Возврат ДанныеКешОзвучкиИнтерактивнойСправки;
	КонецЕсли;

	ИмяФайла = ДополнитьСлешВПуть(КаталогКеша) + "Voices.json";

	Если НЕ ФайлСуществуетКомандаСистемы(ИмяФайла) Тогда
		ДанныеКешОзвучкиИнтерактивнойСправки = Неопределено;
		Отладка (ПодставитьПараметрыВСтроку(Локализовать("Файл <%1> не существует."),
			ИмяФайла
		));
		Возврат ДанныеКешОзвучкиИнтерактивнойСправки;
	КонецЕсли;

	ЧтениеJSON = Новый ЧтениеJSON();
	ЧтениеJSON.ОткрытьФайл(ИмяФайла);
	Попытка
		ДанныеФайла = ПрочитатьJSON(ЧтениеJSON);
	Исключение
		ДанныеФайла = Неопределено;
		ДанныеКешОзвучкиИнтерактивнойСправки = Неопределено;
	КонецПопытки;
	ЧтениеJSON.Закрыть();

	Если ДанныеФайла = Неопределено Тогда
		ДанныеКешОзвучкиИнтерактивнойСправки = Неопределено;
		Отладка (ПодставитьПараметрыВСтроку(Локализовать("Не получилось прочитать данные файла <%1>."),
			ИмяФайла
		));
		Возврат ДанныеКешОзвучкиИнтерактивнойСправки;
	КонецЕсли;

	Для Каждого Элем Из ДанныеФайла.data Цикл
		ИмяФайла = ДополнитьСлешВПуть(ДополнитьСлешВПуть(КаталогКеша) + Элем.Driver + "_" + Элем.Voice) + "data.json";
		Если НЕ ФайлСуществуетКомандаСистемы(ИмяФайла) Тогда
			ДанныеКешОзвучкиИнтерактивнойСправки = Неопределено;
			Отладка (ПодставитьПараметрыВСтроку(Локализовать("Файл <%1> не существует."),
				ИмяФайла
			));
			Возврат ДанныеКешОзвучкиИнтерактивнойСправки;
		КонецЕсли;

		Файл = Новый Файл(ИмяФайла);
		ЧастьПути = Файл.Путь;
		ЧтениеJSON = Новый ЧтениеJSON();
		ЧтениеJSON.ОткрытьФайл(ИмяФайла);
		Попытка
			ДанныеФайлаОзвучки = ПрочитатьJSON(ЧтениеJSON);
		Исключение
			ДанныеКешОзвучкиИнтерактивнойСправки = Неопределено;
			ДанныеФайлаОзвучки = Неопределено;
			Возврат ДанныеКешОзвучкиИнтерактивнойСправки;
		КонецПопытки;
		ЧтениеJSON.Закрыть();

		Для Каждого ДанныеMp3 Из ДанныеФайлаОзвучки.data Цикл
			Если НЕ ДанныеMp3.Свойство("Orig") Тогда
				Продолжить;
			КонецЕсли;
			Если Найти(ДанныеMp3.FileName, ЧастьПути) = 0 Тогда
				ДанныеMp3.FileName = ЧастьПути + ДанныеMp3.FileName;
			КонецЕсли;
			ДанныеКешОзвучкиИнтерактивнойСправки.Вставить(ДанныеMp3.Text, ДанныеMp3);

			//Также добавляются данные по оригинальной строке, чтобы можно было понять есть ли для текста озвучка
			ДанныеКешОзвучкиИнтерактивнойСправки.Вставить(ДанныеMp3.Orig, ДанныеMp3);
		КонецЦикла;

	КонецЦикла;

	Возврат ДанныеКешОзвучкиИнтерактивнойСправки;

	#КонецЕсли

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

// Выполняет проверку, что в для данной фичи есть озвучка в кеш
&НаКлиенте

Функция ВКешЕстьВсеMp3ДляДаннойФичи(ДанныеКеш, ИмяФайла) Экспорт

	Если ДанныеКеш = Неопределено Тогда
		Возврат Ложь;
	КонецЕсли;

	Текст = Новый ЧтениеТекста;
	Текст.Открыть(ИмяФайла, "UTF-8");
	ТекстФайла = Текст.Прочитать();
	Текст.Закрыть();

	МассивСтрок = _СтрРазделить(ТекстФайла, Символы.ПС);
	Для Сч = 0 По МассивСтрок.Количество()-1 Цикл
		Стр = СокрЛП(МассивСтрок[Сч]);

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

	Возврат Истина;

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

// Проверяет, что версия, указанная в кеш озвучки совпадает с мажорной версией релиза Vanessa Automation.
// Например, для версии 1.2.040.3 мажорной версией будет 1.2.040.1
&НаКлиенте

Функция ВерисияКешФайлаОзвучкиСовпадаетСМажорнойВерсией() Экспорт
	#Если НЕ ВебКлиент Тогда

	ИмяФайла = ДополнитьСлешВПуть(Объект.КаталогКешОзвучкиДляИнтерактивнойСправки) + "Voices.json";
	Если НЕ ФайлСуществуетКомандаСистемы(ИмяФайла) Тогда
		Возврат Ложь;
	КонецЕсли;

	ЧтениеJSON = Новый ЧтениеJSON();
	ЧтениеJSON.ОткрытьФайл(ИмяФайла);
	Попытка
		ДанныеФайла = ПрочитатьJSON(ЧтениеJSON);
	Исключение
		ДанныеФайла = Неопределено;
		ДанныеКешОзвучкиИнтерактивнойСправки = Неопределено;
	КонецПопытки;
	ЧтениеJSON.Закрыть();

	Если НЕ ДанныеФайла.Свойство("version") Тогда
		Возврат Ложь;
	КонецЕсли;

	Если ДанныеФайла.version = МажорнаяРелизнаяВерсия() Тогда
		Возврат Истина;
	КонецЕсли;

	#КонецЕсли

	Возврат Ложь;

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

// Сбрасывает кеш интерактивной справки
&НаКлиенте

Функция СброситьКешОзвучкиИнтерактивнойСправки() Экспорт
	ДанныеКешОзвучкиИнтерактивнойСправки = Неопределено;
КонецФункции

// Запускает урок интеракивной справки по имени фича файла
&НаКлиенте

Процедура ЗапуститьУрокИнтерактивнойСправки(Стр) Экспорт

	КаталогПоиска = КаталогУроков();
	ИмяФайла = Стр + ".feature";

	СписокКаталогов = Новый СписокЗначений;
	СписокФайлов    = Новый СписокЗначений;
	НайтиФайлыКомандаСистемы(КаталогПоиска, СписокКаталогов, СписокФайлов, Истина, ИмяФайла);

	Если СписокФайлов.Количество() = 0 Тогда
		Если Объект.ВерсияПоставки = "single" Тогда
			ДопПараметры = Новый Структура;
			ДопПараметры.Вставить("СкачатьУроки", Истина);
			ОткрытьМастерНастройкиИнтерактивнойСправки(Неопределено, Неопределено, ДопПараметры);
			Возврат;
		Иначе
			ВызватьИсключение ПодставитьПараметрыВСтроку(
				Локализовать("Файл <%1> не найден."),
				ИмяФайла
			);
		КонецЕсли;
	КонецЕсли;

	ПолноеИмяФайла = СписокФайлов[0].Значение.ПолноеИмя;

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

	ПрочитатьДанныеКешОзвучкиИнтерактивнойСправки();

	Объект.КаталогФич = ПолноеИмяФайла;

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

КонецПроцедуры

// Возвращает заголовок элемента формы Vanessa Automation с помощью данных объекта
&НаКлиенте

Функция ЗаголовокЭлементаФормыVAИзДанныхОбъекта(ИмяЭлемента) Экспорт

	Возврат ЗаголовокЭлементаФормыVAИзДанныхОбъектаСервер(ИмяЭлемента);

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

// Возвращает имя связанного объекта данных
&НаКлиенте

Функция ИмяОбъектаДанныхЭлементаФормыVAИзДанныхОбъекта(ИмяЭлемента) Экспорт

	Возврат ИмяОбъектаДанныхЭлементаФормыVAИзДанныхОбъектаСервер(ИмяЭлемента);

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

// Позволяет выполнить текст в контексте основной формы Vanessa Automation
&НаКлиенте

Процедура ВыполнитьКодВКонтекстеОсновнойФормыVanessaAutomation(Текст) Экспорт

	Выполнить(Текст);

КонецПроцедуры

// Возвращает настройки по умолчанию для отрисовки эффектов компонентой VanessaExt
&НаКлиенте

Функция ПолучитьНастройкиРисования() Экспорт

	ВремСтруктура = Новый Структура;
	ВремСтруктура.Вставить("color", ОсновнойЗеленыйЦвет());
	ВремСтруктура.Вставить("transparency", 127);
	ВремСтруктура.Вставить("duration", 4000);
	ВремСтруктура.Вставить("thickness", 6);
	ВремСтруктура.Вставить("frameDelay", 20);
	ВремСтруктура.Вставить("text", "Текст");
	Возврат ВремСтруктура;

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

// Выполняет подготовку сеанса, чтобы на нём можно было проводить обучение
&НаКлиенте

[Assistant] Функция ПрочитатьДанныеКешОзвучкиИнтерактивнойСправки(КаталогКеша = Неопределено)


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции() Экспорт

	PID = ПолучитьКорректныйPID("ЭтотСеанс");
	ОтборЭлементов = Новый Структура("ProcessId", Число(PID));

	ТипЭлемента = "Document";
	ОтборЭлементов.Вставить("ControlType", ТипЭлемента);
	ОтборЭлементовJSON = ЗаписатьОбъектJSON(ОтборЭлементов);
	РезультатПоискаJSON = ВнешняяКомпонентаДляСкриншотов.НайтиЭлементы(ОтборЭлементовJSON);
	ДанныеПолей = ПрочитатьОбъектJSON(РезультатПоискаJSON);

	Если ДанныеПолей = Неопределено Тогда
		ВызватьИсключение ПодставитьПараметрыВСтроку(
		Локализовать("Не получилось найти элемент UI Automation. PID <%1>, заголовок <%2>, тип <%3>."), PID, "", ТипЭлемента);
	КонецЕсли;

	Если ДанныеПолей.Количество() = 0 Тогда
		ВызватьИсключение ПодставитьПараметрыВСтроку(
		Локализовать("Не получилось найти элемент UI Automation. PID <%1>, заголовок <%2>, тип <%3>."), PID, "", ТипЭлемента);
	КонецЕсли;

	Возврат ДанныеПолей[0];

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

// Добавляет к переданным настройкам значения из второго параметра
&НаКлиенте

Функция ДополнитьПараметрыОтрисовкиПереданныеПользователем(НастройкиРисования, ПараметрыОтрисовки) Экспорт

	Если ПараметрыОтрисовки = Неопределено Тогда
		Возврат НастройкиРисования;
	КонецЕсли;

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

	Возврат НастройкиРисования;

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

// Возвращает данные реквизитов формы для работы алгоритма Onboarding
&НаКлиенте

Функция ДанныеРеквизитовФормыOnboarding(ФормаOnboarding) Экспорт

	ИмяФормыOnboarding = ФормаOnboarding.ИмяФормы;

	Если КешДанныхФормOnboarding[ИмяФормыOnboarding] <> Неопределено Тогда
		Возврат КешДанныхФормOnboarding[ИмяФормыOnboarding];
	КонецЕсли;

	Если Найти(ФормаOnboarding.ИмяФормы, "VanessaAutomation") > 0 Тогда
		Результат = ФормаOnboarding.ДанныеРеквизитовФормыOnboardingVA();
	Иначе
		Результат = ФормаOnboarding.ДанныеРеквизитовФормыOnboarding();
	КонецЕсли;

	КешДанныхФормOnboarding.Вставить(ИмяФормыOnboarding, Результат);

	Возврат Результат;

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

// Возвращает данные реквизитов формы для работы OnBoarding по форме VA
&НаСервере

Функция ДанныеРеквизитовФормыOnboardingVA() Экспорт
	Результат = Новый Структура;
	Результат.Вставить("ДанныеМетаданных", Новый Структура);
	Результат.Вставить("ДанныеФормы", Новый Структура);
	ДанныеФормы = Результат.ДанныеФормы;

	ДополнитьДанныеМетаданныхVA(Объект().Метаданные().Реквизиты, Результат.ДанныеМетаданных);

	Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл
		ДанныеФормы.Вставить(ЭлементФормы.Имя, ДанныеЭлементаФормыVA(ЭлементФормы));
	КонецЦикла;

	Возврат Результат;
КонецФункции

// Возвращает числовое значение PID
// Можно передать значение ЭтотСеанс или ЭтотПроцесс, тогда будет возвращён PID сеанса, где запущена VA
&НаКлиенте

Функция ПолучитьКорректныйPID(PID) Экспорт

	НайденныйКлиент = ДанныеКлиентовТестирования.НайтиСтроки(Новый Структура("Имя", PID));

    Если НайденныйКлиент.Количество() > 0 Тогда
          Возврат НайденныйКлиент[0].PIDКлиентаТестирования;
    КонецЕсли;

    Если PID = "" Тогда
        Для Каждого КлиентТеста Из ДанныеКлиентовТестирования Цикл
            Если КлиентТеста.Подключен Тогда
                Возврат КлиентТеста.PIDКлиентаТестирования;
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;

	Если НРег(PID) <> НРег("ЭтотСеанс") И НРег(PID) <> НРег("ЭтотПроцесс")
		И НРег(PID) <> НРег("Этот сеанс") И НРег(PID) <> НРег("This session") Тогда
		Попытка
			Возврат Число(PID);
		Исключение
			ТекстОшибки = Локализовать(ПодставитьПараметрыВСтроку("Не получилось вычислить PID по строке <%1>. Должно быть передано число.", PID)) + Символы.ПС + ОписаниеОшибки();
			ВызватьИсключение ТекстОшибки;
		КонецПопытки;
	КонецЕсли;

	Если ЗначениеЗаполнено(PIDЭтогоСеанса) Тогда
		Возврат Число(PIDЭтогоСеанса);
	КонецЕсли;

	ВычислитьPIDЭтогоСеансаСлужебный();

	Возврат Число(PIDЭтогоСеанса);

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

// Открывает список уроков
&НаКлиенте

Функция ОткрытьСписокУроков() Экспорт

	ОткрытьСписокУроковСлужебный();

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

// Закрывает группы, чтобы тест мог выполняться повторно
&НаКлиенте

Процедура ЗакрытьГруппыКоторыеОткрываютсяВРежимеСамотестирования() Экспорт
	РазвернутьСвернутьГруппыСтраницыДляРаботыТестов(Ложь);
КонецПроцедуры

// Отменяет действия, которые могли остаться после работы интерактивной справки
&НаКлиенте

Процедура СкрытьЭлементыКоторыеМоглиБытьПоказаныПриРаботеИнтерактивнойСправки() Экспорт
	Объект.ПовторноЗапускатьСеансКлиентаТестированияПриПодключенииЕслиНеНайденЕгоПроцесс = Ложь;
	Объект.ЗапускатьТестКлиентВРежимеОтладки = Ложь;
	Объект.КомандаЗапускаБраузера = "";
	Объект.ВыполнятьШагиАсинхронно = Ложь;
	Объект.ДобавлятьКИмениСценарияУсловияВыгрузки = Ложь;
	Объект.ВыгружатьСтатусВыполненияСценариевВФайл = Ложь;
	Объект.ЗаписыватьВидеоВыполненияТестов = Ложь;
	Объект.ДелатьЛогВыполненияСценариевВТекстовыйФайл = Ложь;
	Объект.ДелатьОтчетВФорматеАллюр = Ложь;
	Объект.ДелатьОтчетВФорматеjUnit = Ложь;
	Объект.ДелатьОтчетВФорматеСППР = Ложь;
	Объект.ДелатьОтчетВФорматеCucumberJson = Ложь;
	Объект.ДелатьЛогОшибокВТекстовыйФайл = Ложь;
	Объект.ДелатьОтчетВоВнутреннемФормате = Ложь;
	Объект.ЗвуковоеОповещениеПриОкончанииВыполненияСценария = Ложь;
	Объект.СоздаватьИнструкциюHTML = Ложь;
	Объект.СоздаватьИнструкциюMarkdown = Ложь;
	Объект.ЗаписьВидеоТипОзвучкиTTS = 1;
	Объект.ЗаписьВидеоКэшироватьФайлыTTS = Ложь;
	Объект.СоздаватьИнструкциюВидео = Ложь;

	Объект.ПоказыватьСтрокиПодсценариевVanessaEditor = Истина;
	Объект.ПоказыватьМиниатюруКода = Истина;
	Объект.ПоказыватьЗначенияПеременныхВСтрокахРедактора = Истина;
	Объект.ПроверкаСинтаксисаВРедакторе = Истина;
	Объект.ПоказыватьРазличияВРедактореОтдельно = Истина;

	УстановитьУсловноеОформление();
КонецПроцедуры

// Проверяет, что перевод уроков был выполнен корректно и в тексте подсказки нет русских букв.
&НаКлиенте

Процедура ПроверитьКорректностьПараметровДляВыполненияУроков(НастройкиРисования) Экспорт
	Если ТипЗнч(ОбъектКонтекстСохраняемый) = Тип("Структура") И ОбъектКонтекстСохраняемый.Свойство("ПроверкаУроковEN")
		И ОбъектКонтекстСохраняемый.ПроверкаУроковEN Тогда
		Если НастройкиРисования.Свойство("Text") И ВСтрокеЕстьРусскиеБуквы(НастройкиРисования.text) Тогда
			ВызватьИсключение ПодставитьПараметрыВСтроку(
				Локализовать("В строке <%1> есть русские буквы."),
				НастройкиРисования.text
			);
		КонецЕсли;
	КонецЕсли;
КонецПроцедуры

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

#Область ВыполнениеСценариевСЗакрытойФормой

// Устанавливает фича файл для выполнения
&НаКлиенте

Процедура УстановитьФичаФайл(ИмяФайла) Экспорт
	Объект.КаталогФич = ИмяФайла;
	ПереданныйТекстФичаФайла = Неопределено;
	ФичаФайлПереданТекстом = Ложь;
	Объект.ЗагрузкаФичПриОткрытии = "Не загружать";
КонецПроцедуры

// Выполняет сценарии согласно текущим настройкам без открытия формы
&НаКлиенте

Процедура ВыполнитьСценарииБезОткрытияФормы() Экспорт
	ВыполнениеСценариевБезОткрытияФормы = Истина;

	УстанановитьЗначениеДополнительногоПараметра("ВыполнениеСценариевБезОткрытияФормы", Истина);

	Если НЕ ВыполняласьИнициализацияФормы = Истина Тогда
		ПриОткрытии(Ложь);
	Иначе
		ПерезагрузитьИВыполнить(Неопределено);
	КонецЕсли;

КонецПроцедуры

// Выполняет сценарии согласно текущим настройкам без открытия формы
&НаКлиенте

Процедура ВыполнитьСценарииСЧтениемПараметровИзКоманднойСтроки() Экспорт
	ВыполнениеСценариевБезОткрытияФормы = Истина;
	ВыполнитьСценарииСЧтениемПараметровИзКоманднойСтроки = Истина;

	УстанановитьЗначениеДополнительногоПараметра("ВыполнениеСценариевБезОткрытияФормы", Истина);

	ПриОткрытии(Ложь);

КонецПроцедуры

// Открывает основную форму VA
&НаКлиенте

Процедура ОткрытьОсновнуюФорму() Экспорт
	УстановитьУсловноеОформление();
	Открыть();
КонецПроцедуры

// Устанавливает настройки для режима работы без октрытия формы
&НаКлиенте

[Assistant] Функция ЭлементРедактораUIAutomation()


[System] Ты пишешь корректный код на 1С:Enterprise Script и отвечаешь только кодом, если тебя просят дописать код.

[User]
Дополни код на 1С. Ниже начало процедура `ВывестиДанныеЭлементаформыВМакет`.
Сохрани стиль и синтаксис, верни только готовый код без пояснений.

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

	// Синоним
	Попытка
		ТабДок.Область(НомерСтроки, 2, НомерСтроки, 2).Текст = ЭлементОкна.ТекстЗаголовка;
	Исключение
	КонецПопытки;

	// Тип
	Попытка
		ТабДок.Область(НомерСтроки, 3, НомерСтроки, 3).Текст = Строка(ТипЗнч(ЭлементОкна));
	Исключение
	КонецПопытки;

	// Вид
	Попытка
		ТабДок.Область(НомерСтроки, 4, НомерСтроки, 4).Текст = ЭлементОкна.Вид;
	Исключение
	КонецПопытки;

	// ПредставлениеДанных
	Попытка
		Если ТипЗнч(ЭлементОкна) = Тип("ТестируемоеПолеФормы") Тогда
			Если Найти(ЭлементОкна.Имя, "УсловноеОформление") = 0 Тогда
				ТабДок.Область(НомерСтроки, 5, НомерСтроки, 5).Текст = ЭлементОкна.ПолучитьПредставлениеДанных();
			КонецЕсли;
		КонецЕсли;
	Исключение
	КонецПопытки;

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

		Если СтрокиТаблицы <> Неопределено И СтрокиТаблицы.Количество() > 0 Тогда
			НомерСтроки = НомерСтроки + 2;
    // TODO: допиши оставшуюся часть

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

	// Синоним
	Попытка
		ТабДок.Область(НомерСтроки, 2, НомерСтроки, 2).Текст = ЭлементОкна.ТекстЗаголовка;
	Исключение
	КонецПопытки;

	// Тип
	Попытка
		ТабДок.Область(НомерСтроки, 3, НомерСтроки, 3).Текст = Строка(ТипЗнч(ЭлементОкна));
	Исключение
	КонецПопытки;

	// Вид
	Попытка
		ТабДок.Область(НомерСтроки, 4, НомерСтроки, 4).Текст = ЭлементОкна.Вид;
	Исключение
	КонецПопытки;

	// ПредставлениеДанных
	Попытка
		Если ТипЗнч(ЭлементОкна) = Тип("ТестируемоеПолеФормы") Тогда
			Если Найти(ЭлементОкна.Имя, "УсловноеОформление") = 0 Тогда
				ТабДок.Область(НомерСтроки, 5, НомерСтроки, 5).Текст = ЭлементОкна.ПолучитьПредставлениеДанных();
			КонецЕсли;
		КонецЕсли;
	Исключение
	КонецПопытки;

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

		Если СтрокиТаблицы <> Неопределено И СтрокиТаблицы.Количество() > 0 Тогда
			НомерСтроки = НомерСтроки + 2;

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

			ИменаКолонок = Новый Массив;
			Ном = 0;
			Для Каждого Элем Из СписокКлючей Цикл
				Ном = Ном + 1;
				ИменаКолонок.Добавить(Элем.Значение);
				ТабДок.Область(НомерСтроки, Ном, НомерСтроки, Ном).Текст = Элем.Значение;
			КонецЦикла;

			//Строки таблицы
			Для Каждого СтрокаТаблицы Из СтрокиТаблицы Цикл
				НомерСтроки = НомерСтроки + 1;
				Ном = 0;
				Для Каждого Элем Из ИменаКолонок Цикл
					Ном = Ном + 1;
					ТабДок.Область(НомерСтроки, Ном, НомерСтроки, Ном).Текст = СтрокаТаблицы[Элем];
				КонецЦикла;
			КонецЦикла;

			НомерСтроки = НомерСтроки + 1;
		КонецЕсли;
	КонецЕсли;

	// ОтображаемыйТекст
	Попытка
		ТабДок.Область(НомерСтроки, 6, НомерСтроки, 6).Текст = ЭлементОкна.ПолучитьОтображаемыйТекст();
	Исключение
	КонецПопытки;
КонецПроцедуры

// получает состояние всех форм в виде макета
&НаКлиенте

Функция СостояниеВсехФормВВидеМакета()
	Если НЕ ОбъектКонтекстСохраняемый.Свойство("ТестовоеПриложение") Тогда
		Возврат Неопределено;
	КонецЕсли;

	Попытка
		АктивныеОкна = ОбъектКонтекстСохраняемый.ТестовоеПриложение.НайтиОбъекты(Тип("ТестируемоеОкноКлиентскогоПриложения"));
	Исключение
		Возврат Неопределено;
	КонецПопытки;

	Если АктивныеОкна = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;

	ТабДок = ТабличныйДокументДляСостоянияФормы();

	НомерСтроки = 1;

	Для Каждого АктивноеОкно Из АктивныеОкна Цикл
		НомерСтроки = НомерСтроки + 1;

		ТабДок.Область(НомерСтроки, 2, НомерСтроки, 2).Текст = АктивноеОкно.Заголовок;
		ТабДок.Область(НомерСтроки, 2, НомерСтроки, 2).Шрифт = Новый Шрифт(, 12);
		ТабДок.Область(НомерСтроки, 3, НомерСтроки, 3).Текст = Строка(ТипЗнч(АктивноеОкно));

		НомерСтроки = НомерСтроки + 1;
		ТабДок.Область(НомерСтроки, 2, НомерСтроки, 2).Текст = "Окно сообщений";

		Попытка
			ТекстОкноСообщений = МассивВСтроку(АктивноеОкно.ПолучитьТекстыСообщенийПользователю());
		Исключение
			ТекстОкноСообщений = Локализовать("Окно сообщений пустое.");
		КонецПопытки;
		ТабДок.Область(НомерСтроки, 5, НомерСтроки, 5).Текст = ТекстОкноСообщений;

		ЭлементыОкна = АктивноеОкно.НайтиОбъекты();
		ЭлементыОкна = СортироватьЭлементыОкнаПоИмени(ЭлементыОкна);
		Для Каждого ЭлементОкна Из ЭлементыОкна Цикл
			НомерСтроки = НомерСтроки + 1;
			ВывестиДанныеЭлементаформыВМакет(ЭлементОкна, ТабДок, НомерСтроки);
		КонецЦикла;

		// чтобы раздедить окна
		НомерСтроки = НомерСтроки + 1;
	КонецЦикла;

	ТабДок.ФиксацияСверху = 1;
	Возврат ТабДок;
КонецФункции

&НаКлиенте

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

	Спс.СортироватьПоПредставлению();
	Возврат Спс.ВыгрузитьЗначения();
КонецФункции

// получает данные активной формы в виде макета
&НаКлиенте

Функция СостояниеФормыВВидеМакета()
	Если НЕ ОбъектКонтекстСохраняемый.Свойство("ТестовоеПриложение") Тогда
		Возврат Неопределено;
	КонецЕсли;

	Попытка
		АктивноеОкно = ОбъектКонтекстСохраняемый.ТестовоеПриложение.ПолучитьАктивноеОкно();
	Исключение
		Возврат Неопределено;
	КонецПопытки;

	Если АктивноеОкно = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;

	ТабДок = ТабличныйДокументДляСостоянияФормы();

	НомерСтроки = 1;

	НомерСтроки = НомерСтроки + 1;
	ТабДок.Область(НомерСтроки, 2, НомерСтроки, 2).Текст = АктивноеОкно.Заголовок;
	ТабДок.Область(НомерСтроки, 2, НомерСтроки, 2).Шрифт = Новый Шрифт(, 12);
	ТабДок.Область(НомерСтроки, 3, НомерСтроки, 3).Текст = Строка(ТипЗнч(АктивноеОкно));

	НомерСтроки = НомерСтроки + 1;
	ТабДок.Область(НомерСтроки, 2, НомерСтроки, 2).Текст = "Окно сообщений";

	Попытка
		ТекстОкноСообщений = МассивВСтроку(АктивноеОкно.ПолучитьТекстыСообщенийПользователю());
	Исключение
		ТекстОкноСообщений = Локализовать("Окно сообщений пустое.");
	КонецПопытки;
	ТабДок.Область(НомерСтроки, 5, НомерСтроки, 5).Текст = ТекстОкноСообщений;

	ЭлементыОкна = АктивноеОкно.НайтиОбъекты();
	ЭлементыОкна = СортироватьЭлементыОкнаПоИмени(ЭлементыОкна);
	Для Каждого ЭлементОкна Из ЭлементыОкна Цикл
		НомерСтроки = НомерСтроки + 1;
		ВывестиДанныеЭлементаформыВМакет(ЭлементОкна, ТабДок, НомерСтроки);
	КонецЦикла;

	ТабДок.ФиксацияСверху = 1;
	Возврат ТабДок;
КонецФункции

// Позволяет сделать поиск в строке "ПроверяемаяСтрока" подстроки "Шаблон"
// при этом подстрока "Шаблон" может содержать символы *
// например СтрокаСоответствуетШаблону("Привет","*вет")
&НаСервереБезКонтекста

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

	Если ЭтоLinux() Тогда
		Шаблон = ПодготовитьШаблонКИспользованиюВРегулярке(Шаблон, Истина);
		Возврат ПроверитьСтрокуRegExpLinux(ПроверяемаяСтрока, Шаблон);
	Иначе
		Шаблон = ПодготовитьШаблонКИспользованиюВРегулярке(Шаблон, Ложь);
		Регулярка = Новый COMОбъект("VBScript.RegExp");
		Регулярка.Global = Истина;
		Регулярка.Multiline = Истина;
		// для VBScript.RegExp явно указываем что есть начало и конец строки
		Шаблон            = "^" + Шаблон + "$";
		Регулярка.Pattern = Шаблон;
		Результат = Регулярка.Test(ПроверяемаяСтрока);
		Регулярка = Неопределено;
		Возврат Результат;
	КонецЕсли;
КонецФункции

&НаСервереБезКонтекста


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции(ТЗБыло, СтрокаТЗБыло, Построитель, ИдКолонкиПропуск)
	ИдКолонки = -1;
	Для каждого Колонка Из ТЗБыло.Колонки Цикл
		ИдКолонки = ИдКолонки + 1;
		Если ИдКолонки = ИдКолонкиПропуск Тогда
			Продолжить;
		КонецЕсли;

		ЗначениеПоиска = СтрокаТЗБыло[Колонка.Имя];
		Если ЗначениеПоиска = Неопределено ИЛИ СокрЛП(ЗначениеПоиска) = "*" Тогда
			Продолжить;
		КонецЕсли;

		ЗначениеПоиска = СтрЗаменить(ЗначениеПоиска, "\n", Символы.ПС);

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

	Построитель.Выполнить();
	ТабРезультат = Построитель.Результат.Выгрузить();

	Возврат ТабРезультат;
КонецФункции

&НаСервереБезКонтекста

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

		Если СтрокаСовпала Тогда
			Возврат Истина;
		КонецЕсли;
	КонецЦикла;

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

&НаСервереБезКонтекста

Процедура УбратьИзИмениКолонокСпецСимволы(Массив)
	Для Ккк = 0 По Массив.Количество() - 1 Цикл
		Если Лев(Массив[Ккк], 1) = "_" Тогда
			Массив[Ккк] = Сред(Массив[Ккк], 2);
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры

&НаСервереБезКонтекста

Функция ПолучитьМассивКолонокКоторыеЕстьТолькоВБыло(ТЗБыло, ТЗСтало)
	Массив = Новый Массив;

	Для Каждого Колонка Из ТЗБыло.Колонки Цикл
		Если ТЗСтало.Колонки.Найти(Колонка.Имя) = Неопределено Тогда
			ТекИмя = Колонка.Имя;
			ТекИмя = ЗаменитьЭкранированноеЗначениеПереносаСтрокиНаПустуюСтроку(ТекИмя);
			Если ТЗСтало.Колонки.Найти(ТекИмя) = Неопределено Тогда
				Массив.Добавить(Колонка.Имя);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;

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

&НаСервереБезКонтекста

Функция УбратьВсеЗапрещенныеСимволы(Знач Стр)

	Стр = СтрЗаменить(Стр, """", "");
	Стр = СтрЗаменить(Стр, Символы.ПС, "");
	Стр = СтрЗаменить(Стр, Символы.ВК, "");
	ЗапрещенныеСимволы = " <>.,\/|':;!№%?*()@#$%^&*+-`~↓↑«»³";

	Для НомерСимвола = 1 По СтрДлина(ЗапрещенныеСимволы) Цикл
		ЗапрещенныйСимвол = Сред(ЗапрещенныеСимволы, НомерСимвола, 1);
		Стр = СтрЗаменить(Стр, ЗапрещенныйСимвол, "_");
	КонецЦикла;

	Если Стр = "" Тогда
		Стр = "_";
	КонецЕсли;

	// Чтобы экранировать служебные слова построителя запросов, т.к. колонки таблицы могут назвать с их использованием
	Стр = "_" + Стр;

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

&НаСервереБезКонтекста

Функция СделатьЭкранированиеПереносаСтрокиИмяКолонки(Знач Стр)
	Возврат СтрЗаменить(Стр, "\n", "_переносстроки_");
КонецФункции

&НаСервереБезКонтекста

Функция ЗаменитьЭкранированноеЗначениеПереносаСтрокиНаПустуюСтроку(Знач Стр)
	Возврат СтрЗаменить(Стр, "_переносстроки_", "");
КонецФункции

&НаСервереБезКонтекста

Функция ПолучитьТЗПроверяемыхДанных(ТабПарам, ДопПараметры)

	СтрокаШапки = ТабПарам[0];

	ТЗБыло = Новый ТаблицаЗначений;
	Для каждого Колонка Из СтрокаШапки Цикл
		ИмяКолонкиСтарое = УбратьВсеЗапрещенныеСимволы(СделатьЭкранированиеПереносаСтрокиИмяКолонки(СтрокаШапки[Колонка.Ключ]));

		Попытка
			ТЗБыло.Колонки.Добавить(ИмяКолонкиСтарое, Новый ОписаниеТипов("Строка"));
		Исключение
			ТекстСообщения = ТекстСообщенияПользователюВызовСервера("В эталонной таблице существуют две колонки с одинаковым заголовком: %1",
				ДопПараметры.ТекстСообщенийПользователю);
			ТекстСообщения = СтрЗаменить(ТекстСообщения, "%1", СтрокаШапки[Колонка.Ключ]);
			ВызватьИсключение ТекстСообщения;
		КонецПопытки;
	КонецЦикла;

	Для СтрокаБыло = 1 По ТабПарам.Количество() - 1 Цикл // в первой строке шапка
		СтрокаТЗБыло = ТЗБыло.Добавить();
		Для каждого Колонка Из СтрокаШапки Цикл
			ИмяКолонкиСтарое = УбратьВсеЗапрещенныеСимволы(СделатьЭкранированиеПереносаСтрокиИмяКолонки(СтрокаШапки[Колонка.Ключ]));
			ЗначениеБыло = Неопределено;
			ТабПарам[СтрокаБыло].Свойство(Колонка.Ключ, ЗначениеБыло);
			СтрокаТЗБыло[ИмяКолонкиСтарое] = ЗначениеБыло;
		КонецЦикла;
	КонецЦикла;

	Возврат ТЗБыло;

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

&НаСервереБезКонтекста

Функция ПолучитьТЗТекущихДанных(ЗначениеТЧ, ДопПараметры)

	ТЗСтало = Новый ТаблицаЗначений;

	Если ТЗСтало = Неопределено Тогда
		ВызватьИсключение ТекстСообщенияПользователюВызовСервера("Не вышло получить строки таблицы.", ДопПараметры.ТекстСообщенийПользователю);
	КонецЕсли;

	// создаем колонки
	Для каждого Колонка Из ЗначениеТЧ[0] Цикл
		Попытка
			ТЗСтало.Колонки.Добавить(УбратьВсеЗапрещенныеСимволы(Колонка.Ключ), Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(1000)));
		Исключение
			ТекстСообщения = ТекстСообщенияПользователюВызовСервера("В результирующей таблице существуют две колонки с одинаковым заголовком: %1",
				ДопПараметры.ТекстСообщенийПользователю);
			ТекстСообщения = СтрЗаменить(ТекстСообщения, "%1", Колонка.Ключ);
			ВызватьИсключение ТекстСообщения;
		КонецПопытки;
	КонецЦикла;

	// создаем строки
	Для каждого СтрокаКолонки Из ЗначениеТЧ Цикл
		СтрокаТЗСтало = ТЗСтало.Добавить();
		Для каждого Колонка Из СтрокаКолонки Цикл
			СтрокаТЗСтало[УбратьВсеЗапрещенныеСимволы(Колонка.Ключ)] = Колонка.Значение;
		КонецЦикла;
	КонецЦикла;

	Возврат ТЗСтало;

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

&НаСервереБезКонтекста

[Assistant] Функция ПоискВхожденияСтроки(ТЗБыло, СтрокаТЗБыло, Построитель, ИдКолонкиПропуск)


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции(ИмяТаблицы, ТабПарам, ЗначениеТЧ, МассивОшибок, ДопПараметры)
	Отказ = Ложь;

	ПоШаблону = Ложь;
	Если ТипЗнч(ДопПараметры) = Тип("Структура") И ДопПараметры.Свойство("ПоШаблону") Тогда
		ПоШаблону = ДопПараметры.ПоШаблону;
	КонецЕсли;

	ПроверятьВхождение = Истина;
	Если ТипЗнч(ДопПараметры) = Тип("Структура") И ДопПараметры.Свойство("ПроверятьВхождение") Тогда
		ПроверятьВхождение = ДопПараметры.ПроверятьВхождение;
	КонецЕсли;

	ТолькоСтрокиИзЭталона = Ложь;
	Если ТипЗнч(ДопПараметры) = Тип("Структура") И ДопПараметры.Свойство("ТолькоСтрокиИзЭталона") Тогда
		ТолькоСтрокиИзЭталона = ДопПараметры.ТолькоСтрокиИзЭталона;
	КонецЕсли;

	// преобразовать в Таблицу Значений
	ТЗБыло  = ПолучитьТЗПроверяемыхДанных(ТабПарам, ДопПараметры);
	ТЗСтало = ПолучитьТЗТекущихДанных(ЗначениеТЧ, ДопПараметры);

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

		Стр = Лев(Стр, СтрДлина(Стр) - 2);
		ВызватьИсключение Стр;
	КонецЕсли;

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

			Если (НЕ Результат И ПроверятьВхождение) ИЛИ (Результат И НЕ ПроверятьВхождение) Тогда
				Стр = "";
				Для Каждого Элем Из ЗначениеСтроки Цикл
					Стр = Стр + "| ' " + Элем.Значение + "' ";
				КонецЦикла;
				Стр = Стр + "|";

				МассивОшибок.Добавить(Стр);
				Отказ = Истина;
			КонецЕсли;
		Иначе
			ТабРезультат = ПоискВхожденияСтроки(ТЗБыло, СтрокаТЗБыло, Построитель, Неопределено);
			Если ТабРезультат.Количество() <> 0 Тогда
				Продолжить;
			КонецЕсли;

			Стр = "|";
			Для каждого Колонка Из ТЗБыло.Колонки Цикл
				Стр = Стр + " '" + СтрокаТЗБыло[Колонка.Имя] + "' |";
			КонецЦикла;

			ИдКолонки = -1;
			ТекстСообщения = "";
			КоличествоРешений = 0;
			Если ТЗБыло.Колонки.Количество() > 0 Тогда
				Для каждого Колонка Из ТЗБыло.Колонки Цикл
					ИдКолонки = ИдКолонки + 1;
					Построитель = Новый ПостроительЗапроса;
					Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТЗСтало);
					ТабРезультат = ПоискВхожденияСтроки(ТЗБыло, СтрокаТЗБыло, Построитель, ИдКолонки);

					Если ТабРезультат.Количество() = 0 Тогда
						Продолжить;
					КонецЕсли;

					// значит нашли проблемную колонку
					Попытка
						ИмяКолонки      = ТабПарам[0]["Кол" + Формат((ИдКолонки + 1), "ЧГ=; ЧН=0")];
						ЗначениеКолонки = СтрокаТЗБыло[Колонка.Имя];
						ЗначениеКолонки = СтрЗаменить(ЗначениеКолонки, Символы.ПС, "\n");
					Исключение
						// не получилось получить имя колонки
						Прервать;
					КонецПопытки;

					ТекстСообщения = ТекстСообщенияПользователюВызовСервера("Не найдено значение <%1> из колонки <%2>.", ДопПараметры.ТекстСообщенийПользователю);
					ТекстСообщения = СтрЗаменить(ТекстСообщения, "%1", ЗначениеКолонки);
					ТекстСообщения = СтрЗаменить(ТекстСообщения, "%2", ИмяКолонки);
					КоличествоРешений = КоличествоРешений + 1;

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

			Если ЗначениеЗаполнено(ТекстСообщения) И КоличествоРешений = 1 Тогда
				Стр = Стр + Символы.ПС + ТекстСообщения;
			КонецЕсли;

			МассивОшибок.Добавить(Стр);
			Отказ = Истина;

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

	Если Отказ Тогда
		Возврат Отказ;
	КонецЕсли;

	Если ТолькоСтрокиИзЭталона Тогда
		Сч = 0;
		КолСтрокБыло = ТабПарам.Количество() - 1;
		ПерваяСтрокаБыло = ТабПарам[0];
		Для Каждого СтрСтало Из ЗначениеТЧ Цикл
			СтрокаСовпала = Ложь;
			Сч = Сч + 1;

			Для Ном = 1 По КолСтрокБыло Цикл
				СтрБыло = ТабПарам[Ном];

				НомКол = 0;
				КолонкиСовпали = Истина;
				Для каждого ТекДанныеКолонки Из ПерваяСтрокаБыло Цикл
					НомКол = НомКол + 1;

					Попытка
						//Если ЧтениеИзТабличногоДокумента Тогда
							ЗнБыло = СтрБыло[ТекДанныеКолонки.Ключ];
						//Иначе
						//	ЗнБыло = СтрБыло["Кол" + НомКол];
						//КонецЕсли;
					Исключение
						// Не совпало количество колонок
						КолонкиСовпали = Ложь;
						Прервать;
					КонецПопытки;

					ЗнСтало = СтрСтало[ТекДанныеКолонки.Значение];

					ЗнБыло  = СокрЛП(СтрЗаменить(ЗнБыло,Символы.НПП," "));
					ЗнСтало = СокрЛП(СтрЗаменить(ЗнСтало,Символы.НПП," "));

					ЗнБыло = СтрЗаменить(ЗнБыло,Символы.ПС,"\n");
					ЗнСтало = СтрЗаменить(ЗнСтало,Символы.ПС,"\n");

					Если ЗнСтало <> ЗнБыло Тогда
						Если ПоШаблону Тогда
							Если СтрокаСоответствуетШаблонуСервер(ЗнСтало, ЗнБыло) Тогда
								Продолжить;
							КонецЕсли;
						КонецЕсли;

						Если ЗнБыло <> "*" Тогда
							КолонкиСовпали = Ложь;
							Прервать;
						КонецЕсли;
					КонецЕсли;
				КонецЦикла;

				Если КолонкиСовпали Тогда
					СтрокаСовпала = Истина;
					Прервать;
				КонецЕсли;
			КонецЦикла;

			Если НЕ СтрокаСовпала Тогда

				БылаОшибка = Истина;

				ПроблемнаяСтрока = "|";
				Для каждого ТекДанныеКолонки Из ПерваяСтрокаБыло Цикл
					ЗнСтало = СтрСтало[ТекДанныеКолонки.Значение];
					ПроблемнаяСтрока = "'" + ПроблемнаяСтрока + ЗнСтало + "'|";
				КонецЦикла;

				ТекстСообщения = ТекстСообщенияПользователюВызовСервера("Строка №%1 таблицы клиента тестирования не найдена в эталоне.", ДопПараметры.ТекстСообщенийПользователю);
				ТекстСообщения = СтрЗаменить(ТекстСообщения,"%1",Сч);
				ТекстСообщения = ТекстСообщения + Символы.ПС + ПроблемнаяСтрока;
				МассивОшибок.Добавить(ТекстСообщения);
				Отказ = Истина;

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

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

&НаСервереБезКонтекста

Процедура УстановитьЗначениеКонстантыСервер(Знач ИмяКонстанты, Знач Значение)

	ТекЗначение = Константы[ИмяКонстанты].Получить();
	Если ТекЗначение <> Значение Тогда
		Константы[ИмяКонстанты].Установить(Значение);
	КонецЕсли;

КонецПроцедуры

&НаКлиенте

Процедура ПриИзмененииТипаВидеоИнструкции()
	Если НЕ Объект.ЗаписьВидеоФормироватьИнструкциюТипВидео
	И    НЕ Объект.ЗаписьВидеоФормироватьИнструкциюТипHTML
	И    НЕ Объект.ЗаписьВидеоФормироватьИнструкциюТипMarkdown
	Тогда
		Объект.ЗаписьВидеоФормироватьИнструкциюТипВидео = Истина;
	КонецЕсли;
КонецПроцедуры

// Функция - Получить строку вызова Sikuli
//
// Возвращаемое значение:
//  Строка - строка для запуска Sikuli-скриптов
//
&НаКлиенте

Функция ПолучитьСтрокуВызоваSikuli()

	Если ЭтоLinux Тогда
		Возврат "runsikulix -r ";
	Иначе
		Возврат "call runsikulix -r ";
	КонецЕсли;

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

&НаКлиенте

Функция ПолучитьWshShell() Экспорт

	Если WshShell = Неопределено Тогда
		Попытка
			WshShell = Новый COMОбъект("WScript.Shell");
		Исключение
			ВызватьИсключение Локализовать("Не удалось подключить COM объект <WScript.Shell>");
		КонецПопытки;
	КонецЕсли;

	Возврат WshShell;

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

&НаКлиентеНаСервереБезКонтекста

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

	Возврат Результат;
КонецФункции

&НаКлиентеНаСервереБезКонтекста

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

	Возврат Результат;
КонецФункции

&НаСервереБезКонтекста

[Assistant] Функция ПроизвестиСравнениеТаблицНаВхождениеСтрокНаСервере(ИмяТаблицы, ТабПарам, ЗначениеТЧ, МассивОшибок, ДопПараметры)


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции(ИмяФайла)
	ДанныеФичи = Новый Структура;
	ДанныеФичи.Вставить("ЯзыкФичи", Неопределено);
	ДанныеФичи.Вставить("ТаблицаСтрокФичи", Неопределено);

	Если ФреймворкЗапущенВWebКлиенте Тогда
		Возврат ДанныеФичи;
	КонецЕсли;

	Если НЕ ФайлСуществуетКомандаСистемы(ИмяФайла) Тогда
		Возврат ДанныеФичи;
	КонецЕсли;

	Если Прав(НРег(ИмяФайла), 8) <> ".feature" Тогда
		Возврат ДанныеФичи;
	КонецЕсли;

	Попытка
		Текст = Новый ЧтениеТекста;
		Текст.Открыть(ИмяФайла, "UTF-8");

		ТаблицаСтрокФичи = РазложитьСтрокуВМассивПодстрокКлиент(Текст.Прочитать(), Символы.ПС);
		Текст.Закрыть();

		ДанныеФичи.Вставить("ТаблицаСтрокФичи", ТаблицаСтрокФичи);

		Для Каждого Стр Из ТаблицаСтрокФичи Цикл
			Стр = СокрЛП(НРег(Стр));

			Если Лев(Стр, 1) = "#" Тогда
				Стр = СокрЛ(Сред(Стр, 2));

				Если Найти(Стр, "language:") > 0 Тогда
					ДанныеФичи.Вставить("ЯзыкФичи", Прав(Стр, 2));
					Прервать;
				КонецЕсли;

				Продолжить;
			КонецЕсли;

			Если ЭтоОпределениеСценария(Стр) Тогда
				ДанныеФичи.Вставить("ЯзыкФичи", "ru");
				Прервать;
			КонецЕсли;

		КонецЦикла;

	Исключение
		Возврат ДанныеФичи;
	КонецПопытки;

	Возврат ДанныеФичи;
КонецФункции

&НаКлиенте

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

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

	Если Брейкпоинты.Количество() > 0 И Объект.ИспользоватьРедакторVanessaEditor Тогда
		Элементы.ДеревоТестов.ПодчиненныеЭлементы.ДеревоТестовБрейкпоинт.Видимость = Истина;
	КонецЕсли;

	Если НЕ Объект.ИспользоватьРедакторVanessaEditor И НЕ Объект.ЗапускИзКоманднойСтроки И НЕ ВыполнениеСценариевБезОткрытияФормы Тогда
		ПоказатьОповещениеПользователя(Локализовать("Фичи загружены"));
	КонецЕсли;

	Если СтруктураПараметров.БылиОшибкиЗагрузкиФич И Объект.ЗавершитьРаботуСистемыПослеВыполненияВсехСценариев Тогда
		ПрекратитьРаботуСеансаVanessaAutomation();
	ИначеЕсли Объект.ВыполнитьСценарииПослеЗагрузкиФич И НЕ СтруктураПараметров.БылиОшибкиЗагрузкиФич Тогда
		Объект.ВыполнитьСценарииПослеЗагрузкиФич = Ложь;
		ВыполнитьСценарии();
	ИначеЕсли Объект.ВыполнитьСценарииПослеЗагрузкиФичОдинРаз Тогда
		Объект.ВыполнитьСценарииПослеЗагрузкиФичОдинРаз = Ложь;
		МассивИд = Неопределено;
		ДопПараметры = Неопределено;
		Если ЗначениеЗаполнено(ИмяСценарияКоторыйНадоВыполнитьПослеПерезагрузки) Тогда
			ИдСтроки = НайтиИДСтрокиСценарияПоИмени(ИмяСценарияКоторыйНадоВыполнитьПослеПерезагрузки);
			ИмяСценарияКоторыйНадоВыполнитьПослеПерезагрузки = "";
			Если ИдСтроки <> Неопределено Тогда
				МассивИд = Новый Массив;
				МассивИд.Добавить(ИдСтроки);
			КонецЕсли;

			ДопПараметры = Новый Структура;
			ДопПараметры.Вставить("ЭтоПример", СтрокаСценарияКоторыйНадоВыполнитьПослеПереазгрузкиЭтоПример);
		КонецЕсли;

		ВыполнитьСценарии(МассивИд, ДопПараметры);
	КонецЕсли;

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

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

	Если СтруктураПараметров.Свойство("СделатьПереходкКТексту") Тогда
		глЗначениеПереходкКТекстуВРедакторе = СтруктураПараметров.СделатьПереходкКТексту;
		ПодключитьОбработчикОжидания("СделатьПереходкКТекстуВРедакторе",0.5, Истина);
	КонецЕсли;

	ПодключитьОбработчикОжидания("АсинхронноеОбновлениеФормыПослеЗагрузкиФичи", 0.1, Истина);

КонецПроцедуры

&НаКлиенте

[Assistant] Функция ДанныеФичи(ИмяФайла)


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

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

			Если ШагИмеетТег(СтруктураШага, "screenshot") Тогда
				НадоСнятьСкриншотШага = Истина;
			КонецЕсли;

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

		Если СтрСтроки.ПроизвольныеЗначения.Свойство("МассивКомментариевШага") Тогда
			СтруктураШага.Вставить("МассивКомментариевШага", СтрСтроки.ПроизвольныеЗначения.МассивКомментариевШага);
		КонецЕсли;

		Если СтрСтроки.ПроизвольныеЗначения.Свойство("ЭтоОбычныйШагОбернутыйВУсловие") И СтрСтроки.ПроизвольныеЗначения.ЭтоОбычныйШагОбернутыйВУсловие Тогда
			СтруктураШага.Вставить("ЭтоОбычныйШагОбернутыйВУсловие", Истина);
		КонецЕсли;

	КонецЕсли;

	Если НадоСнятьСкриншотШага Тогда
		СтруктураШага.Вставить("НадоСнятьСкриншотШага", НадоСнятьСкриншотШага);
	КонецЕсли;

	Если НадоНачатьЗаписьВыполненияТестов Тогда
		СтруктураШага.Вставить("НадоНачатьЗаписьВыполненияТестов", НадоНачатьЗаписьВыполненияТестов);
	КонецЕсли;

	ЭтоКлиент = Ложь;
	Если ДопПараметры.Свойство("ЭтоКлиент") Тогда
		ЭтоКлиент = ДопПараметры.ЭтоКлиент;
	КонецЕсли;

	Если СтрСтроки.ШагСПараметрамиВТаблице = Истина Тогда
		ПараметрыТаблицы = Новый Массив;
		Если ЭтоКлиент Тогда
			Коллекция = СтрСтроки.ПолучитьЭлементы();
		Иначе
			Коллекция = СтрСтроки.Строки;
		КонецЕсли;

		Для каждого ПодчиненнаяСтрока Из Коллекция Цикл
			Если НЕ ПодчиненнаяСтрока.СтрокаПараметровШагаВВидеТаблицы Тогда
				Прервать;
			КонецЕсли;
			ПараметрыТаблицы.Добавить(ПодчиненнаяСтрока.Имя);
		КонецЦикла;
		СтруктураШага.Вставить("ШагСПараметрамиВТаблице", Истина);
		СтруктураШага.Вставить("ПараметрыТаблицы", ПараметрыТаблицы);
	КонецЕсли;

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

&НаСервере

Процедура ДобавитьОбычныйСценарий(СтрокаДерева, МассивСценариевДляВыполнения, ДопПараметры)
	Если СтрокаДерева.ДопТип = "Контекст" Тогда
		Если НЕ ДопПараметры.Свойство("БратьШагиТолькоИзВеткиДерева") Тогда
			Возврат;
		КонецЕсли;
	КонецЕсли;

	Если СтрокаДерева.Строки.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;

	Если ТипЗнч(СтрокаДерева.ПроизвольныеЗначения) = Тип("Структура") Тогда
		ОчиститьПроизвольныеЗначения(СтрокаДерева.ПроизвольныеЗначения);
	КонецЕсли;

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

	Если ТипЗнч(СтрокаДерева.Родитель.ПроизвольныеЗначения) = Тип("Структура") Тогда
		Если СтрокаДерева.Родитель.ПроизвольныеЗначения.Свойство("Язык") Тогда
			СтруктураПараметров.Вставить("ЯзыкФичи", СтрокаДерева.Родитель.ПроизвольныеЗначения.Язык);
		КонецЕсли;
	КонецЕсли;

	Если НЕ СтруктураПараметров.Свойство("ЯзыкФичи") Тогда
		СтруктураПараметров.Вставить("ЯзыкФичи", "ru");
	КонецЕсли;

	Если ДопПараметры.Свойство("БратьШагиТолькоИзВеткиДерева") Тогда
		ДопПараметры.Вставить("ДобавлятьШаги", Ложь);
	КонецЕсли;

	Шаги = Новый Массив;

	Если СтрокаДерева.Родитель.Строки[0].ДопТип = "Контекст" И НЕ ДопПараметры.РежимВыполненияОдногоШага Тогда // значит надо добавить шаги контекста к нашим шагам
		ДопПараметры.Вставить("ЕстьЦиклы", Ложь);
		ДопПараметры.Вставить("МассивУсловий", Новый Массив);
		ДопПараметры.Вставить("МассивЦиклов", Новый Массив);
		ДопПараметры.Вставить("МассивПопытка", Новый Массив);
		ДопПараметры.Вставить("МассивИсключение", Новый Массив);
		ДопПараметры.Вставить("МожноВозвращатьИначе", Истина);
		ДопПараметры.Вставить("МожноВозвращатьСтрокиВСекцииИсключение", Истина);
		ДобавитьШагиДляВыполненияСценария(Шаги, СтрокаДерева.Родитель.Строки[0].Строки, СтрокаДерева, СтрокаДерева,
		   Истина, ДопПараметры);
	КонецЕсли;

	ДопПараметры.Вставить("ЕстьЦиклы", Ложь);
	ДопПараметры.Вставить("МассивУсловий", Новый Массив);
	ДопПараметры.Вставить("МассивЦиклов", Новый Массив);
	ДопПараметры.Вставить("МассивПопытка", Новый Массив);
	ДопПараметры.Вставить("МассивИсключение", Новый Массив);
	ДопПараметры.Вставить("МожноВозвращатьИначе", Истина);
	ДопПараметры.Вставить("МожноВозвращатьСтрокиВСекцииИсключение", Истина);
	ДобавитьШагиДляВыполненияСценария(Шаги, СтрокаДерева.Строки, СтрокаДерева, СтрокаДерева, Ложь, ДопПараметры);

	СтруктураПараметров.Вставить("Шаги", Шаги);

	МассивСценариевДляВыполнения.Добавить(СтруктураПараметров);

КонецПроцедуры

&НаСервере

Процедура ДобавитьСценарийВМассивСценариевДляВыполнения(СтрокаДерева, МассивСценариевДляВыполнения, ДопПараметры)

	ЭтоСценариоАутлайн = ЭтоСценарий_SceanrioOutline(СтрокаДерева);
	Если ЭтоСценариоАутлайн Тогда
		ДобавитьСценарийАутлайн(СтрокаДерева, МассивСценариевДляВыполнения, , ДопПараметры);
		Возврат;
	КонецЕсли;

	ДобавитьОбычныйСценарий(СтрокаДерева, МассивСценариевДляВыполнения, ДопПараметры);
КонецПроцедуры

&НаСервере

[Assistant] Функция ПолучитьСтруктуруШага(СтрСтроки, СтрокаДерева, СтрокаСценария, ЭтоШагКонтекста, ДопПараметры)


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции(ДанныеОшибки, ТекстОшибкиTestClientБезФорматирования = "")
	Если ТипЗнч(ДанныеОшибки) = Тип("ИнформацияОбОшибке") Тогда
		ПредставлениеОшибки = ПодробноеПредставлениеОшибки(ДанныеОшибки);
	Иначе
		ПредставлениеОшибки = ДанныеОшибки;
	КонецЕсли;

	ТекстОшибкиTestClientБезФорматирования = ПредставлениеОшибки;

	Отступ = "                ";
	Стр = "";
	МассивСтрок = РазложитьСтрокуВМассивПодстрокКлиент(ПредставлениеОшибки, Символы.ПС);
	Для Каждого Элем Из МассивСтрок Цикл
		Стр = Стр + Отступ + Элем + Символы.ПС;
	КонецЦикла;

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

&НаКлиенте

Функция ТипАктивногоКлиентаТестирования()
	Если ОбъектКонтекстСохраняемый.Свойство("ТекущийПрофильTestClient") Тогда
		Если ОбъектКонтекстСохраняемый.ТекущийПрофильTestClient <> Неопределено Тогда
			Попытка
				ДанныеКлиентаТестирования = ПолучитьДанныеКлиентаТестирования(ОбъектКонтекстСохраняемый.ТекущийПрофильTestClient);
				Возврат ДанныеКлиентаТестирования.ТипКлиента;
			Исключение
				Возврат Неопределено;
			КонецПопытки;
		КонецЕсли;
	КонецЕсли;

	Возврат Неопределено;
КонецФункции

&НаКлиенте

Функция ИмяАктивногоКлиентаТестирования()
	Если ОбъектКонтекстСохраняемый.Свойство("ТекущийПрофильTestClient") Тогда
		Если ОбъектКонтекстСохраняемый.ТекущийПрофильTestClient <> Неопределено Тогда
			Попытка
				ДанныеКлиентаТестирования = ПолучитьДанныеКлиентаТестирования(ОбъектКонтекстСохраняемый.ТекущийПрофильTestClient);
				Возврат ДанныеКлиентаТестирования.Имя;
			Исключение
				Возврат Неопределено;
			КонецПопытки;
		КонецЕсли;
	КонецЕсли;

	Возврат Неопределено;
КонецФункции

&НаКлиенте

Функция СинонимАктивногоКлиентаТестирования()
	Если ОбъектКонтекстСохраняемый.Свойство("ТекущийПрофильTestClient") Тогда
		Если ОбъектКонтекстСохраняемый.ТекущийПрофильTestClient <> Неопределено Тогда
			Попытка
				ДанныеКлиентаТестирования = ПолучитьДанныеКлиентаТестирования(ОбъектКонтекстСохраняемый.ТекущийПрофильTestClient);
				Возврат ДанныеКлиентаТестирования.Синоним;
			Исключение
				Возврат Неопределено;
			КонецПопытки;
		КонецЕсли;
	КонецЕсли;

	Возврат Неопределено;
КонецФункции

&НаКлиенте

Функция СтрокаСоединенияАктивногоКлиентаТестирования()
	Если ОбъектКонтекстСохраняемый.Свойство("ТекущийПрофильTestClient") Тогда
		Если ОбъектКонтекстСохраняемый.ТекущийПрофильTestClient <> Неопределено Тогда
			Попытка
				ДанныеКлиентаТестирования = ПолучитьДанныеКлиентаТестирования(ОбъектКонтекстСохраняемый.ТекущийПрофильTestClient);
				Возврат ДанныеКлиентаТестирования.ПутьКИнфобазе;
			Исключение
				Возврат Неопределено;
			КонецПопытки;
		КонецЕсли;
	КонецЕсли;

	Возврат Неопределено;
КонецФункции

&НаКлиенте

Функция ДопПараметрыАктивногоКлиентаТестирования()
	Если ОбъектКонтекстСохраняемый.Свойство("ТекущийПрофильTestClient") Тогда
		Если ОбъектКонтекстСохраняемый.ТекущийПрофильTestClient <> Неопределено Тогда
			Попытка
				ДанныеКлиентаТестирования = ПолучитьДанныеКлиентаТестирования(ОбъектКонтекстСохраняемый.ТекущийПрофильTestClient);
				ДополнительныеПараметры = ДанныеКлиентаТестирования.ДопПараметры;
				ДополнительныеПараметры =МаскироватьЧувствительныеДанныеДополнительныхПараметров(ДополнительныеПараметры);
				Возврат ДополнительныеПараметры;
			Исключение
				Возврат Неопределено;
			КонецПопытки;
		КонецЕсли;
	КонецЕсли;

	Возврат Неопределено;
КонецФункции

&НаКлиенте

Функция МаскироватьЧувствительныеДанныеДополнительныхПараметров(ДополнительныеПараметры)

	Если НЕ Объект.МаскироватьПарольВЛоге Тогда
		Возврат ДополнительныеПараметры;
	КонецЕсли;

	Возврат УбратьПарольПользователяИзСтроки(ДополнительныеПараметры);

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

&НаКлиенте

Функция СтрокаСеансКлиентаТестированияНеОбнаруженСлужебный()

	Стр = Локализовать("ОбнаруженоНештатноеЗавершениеКлиентаТестирования") + ": " + Локализовать("Нет");;

	Если НЕ Объект.ИспользоватьКомпонентуVanessaExt Тогда
		Возврат Стр;
	ИначеЕсли ЗапрещеныСинхронныеВызовы Тогда
		Возврат Стр;
	ИначеЕсли НЕ ОбъектКонтекстСохраняемый.Свойство("ТестовоеПриложение") Тогда
		Возврат Стр;
	ИначеЕсли ОбъектКонтекстСохраняемый.ТестовоеПриложение = Неопределено Тогда
		Возврат Стр;
	КонецЕсли;

	PID = PIDТекущегоКлиентаТестирования();
	Если НЕ ЗначениеЗаполнено(PID) Тогда
		Возврат Стр;
	КонецЕсли;

	Попытка
		РезультатВызова = ВнешняяКомпонентаДляСкриншотов.ПолучитьСвойстваПроцесса(PID);
		СвойстваПроцесса = ПрочитатьСтрокуJSON(РезультатВызова);
		Если СвойстваПроцесса.Свойство("Name") Тогда
			Возврат Локализовать("ОбнаруженоНештатноеЗавершениеКлиентаТестирования") + ": " + Локализовать("Нет");
		Иначе
			Возврат Локализовать("ОбнаруженоНештатноеЗавершениеКлиентаТестирования") + ": " + Локализовать("Да");
		КонецЕсли;
	Исключение
		ЗаписатьЛогВЖРИнформация("СтрокаСеансКлиентаТестированияНеОбнаруженСлужебный",ОписаниеОшибки());
		Возврат Локализовать("ОбнаруженоНештатноеЗавершениеКлиентаТестирования") + ": Да";
	КонецПопытки;

	Возврат Стр;

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

&НаКлиенте

Функция ТекстОшибкиЧерезДанныеОкнаОшибки()
	Если НЕ НадоПолучатьДанныеОшибкиИзАктивногоОкнаКлиентаТестирования() Тогда
		Возврат Неопределено;
	КонецЕсли;

	Попытка
		АктивноеОкно  = ПолучитьАктивноеОкноИзТестовоеПриложение();
		Кнопка = АктивноеОкно.НайтиОбъект(,,"OpenReport");
		Если Кнопка = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли;
		Кнопка.Нажать();
		Sleep(1);
		АктивноеОкно  = ПолучитьАктивноеОкноИзТестовоеПриложение();
		Поле = АктивноеОкно.НайтиОбъект(,,"SendErrorInfoDecoration");
		Если Поле = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли;
		Поле.НажатьНаГиперссылкуВФорматированнойСтроке(0);
		Sleep(1);
		АктивноеОкно  = ПолучитьАктивноеОкноИзТестовоеПриложение();
		Поле = АктивноеОкно.НайтиОбъект(,,"Str");
		Если Поле = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли;
		Возврат Поле.ПолучитьОтображаемыйТекст();
	Исключение
		ЗаписатьЛогВЖРОшибка("ТекстОшибкиЧерезДанныеОкнаОшибки", ОписаниеОшибки());
		Возврат Неопределено;
	КонецПопытки;
КонецФункции

&НаКлиенте

[Assistant] Функция ВывестиВСообщениеТекстОшибки(ДанныеОшибки, ТекстОшибкиTestClientБезФорматирования = "")


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции()
	#Если НЕ ВебКлиент Тогда

	Если ЗапрещеныСинхронныеВызовы Тогда
		Возврат Истина;
	КонецЕсли;

	Если НЕ Объект.СоздаватьИнструкциюHTML
		И НЕ Объект.ДелатьСкриншотПриВозникновенииОшибки
		И НЕ Объект.СоздаватьИнструкциюMarkdown Тогда
		Возврат Истина;
	КонецЕсли;

	Если Объект.СоздаватьИнструкциюHTML Тогда
		Если ПустаяСтрока(Объект.КаталогВыгрузкиИнструкцийHTML) Тогда
			СообщитьПользователю(Локализовать("КаталогВыгрузкиИнструкцийHTML не задан."));
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	Если Объект.СоздаватьИнструкциюMarkdown Тогда
		Если ПустаяСтрока(Объект.КаталогВыгрузкиИнструкцийMarkdown) Тогда
			СообщитьПользователю(Локализовать("КаталогВыгрузкиИнструкцийMarkdown не задан."));
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	Если Объект.ДелатьСкриншотПриВозникновенииОшибки Тогда
		Если ПустаяСтрока(Объект.КаталогВыгрузкиСкриншотов) Тогда
			СообщитьПользователю(Локализовать("КаталогВыгрузкиСкриншотов не задан."));
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	Если ЭтоLinux Тогда
		Возврат Истина;
	Иначе
		Если Объект.ИспользоватьКомпонентуVanessaExt
			И ВнешняяКомпонентаДляСкриншотов = Неопределено Тогда
			Возврат Ложь;
		КонецЕсли;

		ВременныйФайл = ПолучитьИмяВременногоФайла("png");

		ДопПараметры = Новый Структура;
		ДопПараметры.Вставить("ИмяФайла",ВременныйФайл);
		ДопПараметры.Вставить("Режим","Проверка");
		СделатьСкриншот(ДопПараметры);

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

		Попытка
			УдалитьФайлыКомандаСистемы(ВременныйФайл);
		Исключение
		КонецПопытки;

		Возврат Истина;
	КонецЕсли;

	#КонецЕсли
КонецФункции
//+++ ЦВ_ПР 22.05.2025  Новый вариант файла для скриншота - НомерШага_ТекущаяДатаВМиллисекундах + ИмяФичи
//
//В экспортных сценариях при включении одинаковых эффектов в цикле исчезали слайды (скриншоты).
//Выяснилось, что для формирования имени скриншота использовался номер шага, который при использовании одинаковых эффектов был одинаковым
//В результате скриншоты перезаписывались в один и тот же файл
//Для исправления поведения в логику записи имени было внесено изменение:
//Старый вариант - НомерШага + ИмяФичи
//Новый вариант - НомерШага_ТекущаяДатаВМиллисекундах + ИмяФичи
//
&НаКлиенте

Функция СоздатьИмяФайлаДляСкриншотаТекстовойИнструкции(Каталог, СтруктураШага, НомШага, ТекущиеДанныеИнструкции)
	ФайлФичи = Новый Файл(ТекущиеДанныеИнструкции.ПолныйПутьКФиче);

	НомШагаИзм = ПолучитьФорматированныйНомер(НомШага, 5)+"_"+Формат(ТекущаяУниверсальнаяДатаВМиллисекундах(), "ЧГ=; ЧН=0");

	ШаблонИмени = "%1%2_%3.png";
	//Старая логика формирования
	//ИмяФайла = _СтрШаблон(
	//	ШаблонИмени,
	//	ДополнитьСлешВПуть(Каталог),
	//	ПолучитьФорматированныйНомер(НомШага, 3),
	//	ФайлФичи.ИмяБезРасширения);
	//Новая логика формирования
	//Подмена номера шага для обеспечения уникальности имени файла

	ИмяФайла = _СтрШаблон(
		ШаблонИмени,
		ДополнитьСлешВПуть(Каталог),
		НомШагаИзм,
		ФайлФичи.ИмяБезРасширения);

		Возврат ИмяФайла;

КонецФункции
//--- ЦВ_ПР 22.05.2025

&НаКлиенте

[Assistant] Функция ПроверитьНаличиеИнструментаДляСозданияСкриншотов()


[System] Ты анализируешь код 1С и подбираешь точные имена для процедур и функций.

[User]
Восстанови осмысленное имя процедуры или функции на 1С по её телу. Верни только полную сигнатуру первой строки.

Функция ИмяФункции(ОписаниеОшибкиКратко)

	СтрДлинаОшибки = СтрДлина(ОписаниеОшибкиКратко);
	СтрПозНачалоExpected = Найти(ОписаниеОшибкиКратко, "[Expected]");
	СтрПозКонецExpected = СтрПозНачалоExpected + СтрДлина("[Expected]") + 1;
	СтрПозНачалоActual = Найти(ОписаниеОшибкиКратко, "[Actual]");
	СтрПозКонецActual = СтрПозНачалоActual + СтрДлина("[Actual]") + 1;
	СтрПозНачалоMessage = Найти(ОписаниеОшибкиКратко, "[Message]");

	Результат = СтруктураОшибкаАссерта(ОписаниеОшибкиКратко);
	Результат.ОписаниеОшибки = ОписаниеОшибкиКратко;

	Если СтрПозНачалоExpected > 0 И СтрПозНачалоActual > СтрПозКонецExpected
		И (СтрПозНачалоMessage = 0 Или СтрПозНачалоMessage > СтрПозКонецActual) Тогда

		Результат.ЗначениеExpected =
			Сред(
				ОписаниеОшибкиКратко,
				СтрПозКонецExpected,
				СтрПозНачалоActual - СтрПозКонецExpected - 1
			);
		Результат.ЗначениеActual =
			Сред(
				ОписаниеОшибкиКратко,
				СтрПозКонецActual,
				?(СтрПозНачалоMessage > 0,
					СтрПозНачалоMessage - СтрПозКонецActual - 1,
					СтрДлинаОшибки
				)
			);

		Результат.Вставить("ОшибкаAssert", Истина);
	Иначе
		Результат.Вставить("ОшибкаAssert", Ложь);
	КонецЕсли;

	Возврат Результат;

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

&НаКлиенте

[Assistant] Функция ОшибкаАссертаOSL(ОписаниеОшибкиКратко)