//ирПортативный Перем ирПортативный Экспорт;
//ирПортативный Перем ирОбщий Экспорт;
//ирПортативный Перем ирСервер Экспорт;
//ирПортативный Перем ирКэш Экспорт;
//ирПортативный Перем ирПривилегированный Экспорт;

Перем мТаблицаКолонок Экспорт;
Перем мСписокКолонок Экспорт;
Перем КлючиЗагруженныхСтрок;
Перем мСвойстваСИменамиБД Экспорт;
Перем RegExpПараметры;
Перем RegExpМета;
Перем шБуква;
Перем шГраничныйСимволИмени;
//Перем МинимальнаяДатаЗагрузки Экспорт;
Перем мЧисловыеСвойства;
Перем мТипСУБД Экспорт;
Перем мСерверныеТипыПроцессов Экспорт;
Перем мКартыФайлов Экспорт;
Перем мПлатформа Экспорт;
//Перем мСоставСвойствСобытий Экспорт;
Перем мСвойстваСобытий Экспорт;
Перем мАдресЧужойСхемыБД Экспорт;

//Трассировка
Перем КонецПериодаКлиента Экспорт;
Перем НачалоПериодаКлиента Экспорт;
Перем КонецПериодаСервера Экспорт;
Перем НачалоПериодаСервера Экспорт;
Перем мИдентификаторТрассы Экспорт;
Перем мНепустыеКолонкиЖурнала Экспорт;
Перем мСоответствиеКолонок;

// СдвигВремени - Число - в секундах задается, нужно для компенсации разницы времени между компьютерами
// ОтборПоПроцессу и ОтборПоСеансу частично игнорируются когда ЗагружатьТолькоТекущийСеанс = Истина
Функция ПрочитатьПроизвольныйЖурнал(СообщитьРазмер = Неопределено, СдвигВремени = 0, ОтборПоПроцессу = Неопределено, ОтборПоСеансу = Неопределено,
	НаСервере = Неопределено)
	
	#Если Сервер И Не Сервер Тогда
	    мПлатформа = Обработки.ирПлатформа.Создать();
	#КонецЕсли
	НеизвестныеСвойства = Новый Соответствие();
	Если Ложь
		Или НаСервере <> Неопределено
		Или Не ЗначениеЗаполнено(КаталогЖурнала) 
	Тогда
		КаталогЖурнала = ПолучитьКаталогТекущегоЖурнала(НаСервере = Истина); 
		Если Не ЗначениеЗаполнено(КаталогЖурнала) Тогда
			Возврат Ложь;
		КонецЕсли; 
	КонецЕсли;
	Если Не ирОбщий.ЛиКаталогДоступенЛкс(КаталогЖурнала) Тогда
		Возврат Ложь;
	КонецЕсли; 
	Если ЗагружатьТолькоТекущийСеанс Тогда
		Если Ложь
			Или ирКэш.ЭтоФайловаяБазаЛкс()
			Или Не НаСервере = Истина
		Тогда
			ОтборПоПроцессу = ирКэш.Получить().ПолучитьИдентификаторПроцессаОС();
		КонецЕсли;
		Если НаСервере = Истина Тогда
			ОтборПоСеансу = НомерСеансаИнформационнойБазы();
		КонецЕсли;
	КонецЕсли; 
	лПоследнееВремяНачалаЗагрузки = ТекущаяДата();
	Если ПериодПоследниеМинуты > 0 Тогда
		НачалоПериода = лПоследнееВремяНачалаЗагрузки - 60 * ПериодПоследниеМинуты;
		КонецПериода = Неопределено;
	КонецЕсли;
	//Если ТаблицаЖурнала.Количество() = 0 Тогда
	//	МинимальнаяДатаЗагрузки = ТекущаяДата() + 100000;
	//КонецЕсли; 
	//Если МинимальнаяДатаЗагрузки > НачалоПериода Тогда
	//	ТаблицаЖурнала.Очистить();
	//КонецЕсли; 
	//РежимДозагрузки = Истина
	//	И ТаблицаЖурнала.Количество() > 0
	//	И МинимальнаяДатаЗагрузки <= НачалоПериода;
	Если СообщитьРазмер = Неопределено Тогда
		СообщитьРазмер = (ТаблицаЖурнала.Количество() = 0) Или КомментироватьЗагрузку;
	КонецЕсли; 
	Если ТаблицаЖурнала.Количество() = 0 Тогда
		мКартыФайлов.Очистить();
	КонецЕсли; 
	
	ирОбщий.ЛиКаталогТехножурналаНедоступенЛкс(КаталогЖурнала);
	ФайлыЖурнала = НайтиФайлы(КаталогЖурнала, "*.log", Истина);
	ОбщийРазмер = 0;
	Для Каждого ФайлЖурнала Из ФайлыЖурнала Цикл
		ОбщийРазмер = ОбщийРазмер + ФайлЖурнала.Размер();
	КонецЦикла;
	Если СообщитьРазмер Тогда
		Сообщить("В каталоге """ + КаталогЖурнала + """ обнаружено для обработки " + Формат(Цел(ОбщийРазмер / 1024), "ЧН=") + "КБ логов");
		ПредставлениеОтбора = "";
		Если СписокЗагружаемыхТиповСобытий.Количество() > 0 Тогда
			ПредставлениеОтбора = ПредставлениеОтбора + " события " + СписокЗагружаемыхТиповСобытий;
		КонецЕсли; 
		Если ЗначениеЗаполнено(НачалоПериода) Тогда
			ПредставлениеОтбора = ПредставлениеОтбора + " с " + НачалоПериода;
		КонецЕсли; 
		Если ЗначениеЗаполнено(КонецПериода) Тогда
			ПредставлениеОтбора = ПредставлениеОтбора + " по " + КонецПериода;
		КонецЕсли;
		Если ЗначениеЗаполнено(ПредставлениеОтбора) Тогда
			Сообщить("Отбор загрузки:" + ПредставлениеОтбора);
		КонецЕсли;
		Если мПлатформа.ПолучитьИдентификаторПроцессаОтладчика() <> Неопределено Тогда 
			Сообщить("Отладчик подключен и замедляет загрузку логов. Отключите отладчик для ускорения загрузки.");
		КонецЕсли; 
	КонецЕсли; 
	//БезопасныйРазмерЖурнала = 10*1000*1000; // 10МБ
	//Если ОбщийРазмер > БезопасныйРазмерЖурнала Тогда
	//	Ответ = Вопрос("Размер журнала составляет " + Формат(Цел(ОбщийРазмер / 1000000)) + " МБ.
	//	|Чтение журнала может продолжаться длительное время, продолжить?", РежимДиалогаВопрос.ДаНет);
	//Иначе
	//	Ответ = КодВозвратаДиалога.Да;
	//КонецЕсли; 
	//Если Ответ = КодВозвратаДиалога.Нет Тогда 
	//	Возврат Ложь;
	//КонецЕсли; 
	НеОбрабатывать = Ложь;
	СтрокаСобытия = "";
	СтруктураЗаписиТЖ = Новый Структура();
	РеквизитыТЧ = Метаданные().ТабличныеЧасти.ТаблицаЖурнала.Реквизиты;
	шСимвол = "[" + шБуква + "\d\._#{}-]";
	////ШаблонСвойствоЗначение = ",([\w\:]+)=(?:'\s*([^']*)'|""\s*([^""]*)""|([^'""\n\r,]*))";
	////Шаблон = "(\d\d:\d\d)\.(\d+)-(\d+),(" + шСимвол + "+),\d+" 
	////+ "((?:" + ШаблонСвойствоЗначение + ")*)";
	//ШаблонСвойствоЗначение = "([\w\:]+)=(?:'\s*((?:.|\n|\r)*?)'|""\s*([^""]*)""|([^'""\n\r,]*))(?:,|\r|$)"; // Так были очень большие трассы вычисления RegExp
	ШаблонСвойствоЗначение = "([\w\:]+)=(?:'\s*([\s\S]*?)'|""\s*((?:""""|[^""])*)""|([^'""\n\r,]*))(?:,|\r|\n|$)+";
	Шаблон = "(\d\d:\d\d)\.(\d+)-(\d+),(" + шСимвол + "+),\d+" 
	+ ",((?:" + ШаблонСвойствоЗначение + ")*)";
	
	мПлатформа = ирКэш.Получить();
	RegExp = мПлатформа.RegExp;
	RegExp2 = мПлатформа.RegExp2;
	//: RegExp = Новый COMОбъект("VBScript.RegExp");
	RegExp.Pattern = Шаблон;
	//RegExp.Multiline = Истина;
	RegExp.Global = Истина;
	RegExp2.Pattern = ШаблонСвойствоЗначение;
	RegExp2.Global = Истина;
	
	Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ОбщийРазмер, "Загрузка файлов");
	ПустаяДата = Дата("00010101");
	РазмерОбработанныхДанных = 0;
	//лНачалоПериода = НачалоПериода;
	//Если Не РежимДозагрузки Тогда
	//	//ТаблицаЖурнала.Очистить();
	//	КлючиЗагруженныхСтрок = Новый Соответствие;
	//Иначе
	//	Если НаСервере = Истина Тогда
	//		лДатаЗагрузки = ПоследнееВремяНачалаЗагрузкиСервера;
	//	Иначе
	//		лДатаЗагрузки = ПоследнееВремяНачалаЗагрузки;
	//	КонецЕсли; 
	//	Если ЗначениеЗаполнено(лДатаЗагрузки) Тогда
	//		лНачалоПериода = лДатаЗагрузки - НаложениеПриДозагрузкеСекунд;
	//	КонецЕсли; 
	//КонецЕсли; 
	Если УдалятьДанныеВнеПериода Тогда
		ТаблицаЖурнала.Сортировать("МоментВремени");
		КоличествоСтрок = ТаблицаЖурнала.Количество();
		Пока Истина
			И КоличествоСтрок > 0
			И ТаблицаЖурнала[0].Дата < НачалоПериода
		Цикл
			ТаблицаЖурнала.Удалить(0);
			КоличествоСтрок = КоличествоСтрок - 1;
		КонецЦикла;
		Если ЗначениеЗаполнено(КонецПериода)  Тогда
			ИндексСтроки = КоличествоСтрок - 1;
			Пока Истина
				И КоличествоСтрок > 0
				И ТаблицаЖурнала[ИндексСтроки].Дата > КонецПериода
			Цикл
				ТаблицаЖурнала.Удалить(ИндексСтроки);
				ИндексСтроки = ИндексСтроки - 1;
			КонецЦикла;
		КонецЕсли; 
	КонецЕсли; 
	ДостигнутоПредельноеКоличество = Ложь;
	//НовыеКлючиЗагруженныхСтрок = Новый Соответствие();
	Для Каждого ФайлЖурнала Из ФайлыЖурнала Цикл
		#Если Сервер И Не Сервер Тогда
		    ФайлЖурнала = Новый файл;
		#КонецЕсли
		Попытка
			РазмерФайла = ФайлЖурнала.Размер();
		Исключение
			РазмерФайла = "?";
		КонецПопытки; 
		Если ТипЗнч(РазмерФайла) = Тип("Число") Тогда
			РазмерОбработанныхДанных = РазмерОбработанныхДанных + РазмерФайла;
		КонецЕсли;
		#Если Клиент Тогда
			ирОбщий.ОбработатьИндикаторЛкс(Индикатор, РазмерОбработанныхДанных);
		#КонецЕсли
		Если КомментироватьЗагрузку Тогда
			Сообщить("Читаем " + ФайлЖурнала.ПолноеИмя + ", размер - " + РазмерФайла);
		КонецЕсли; 
		ПолноеИмяКаталогаПроцесса = Лев(ФайлЖурнала.Путь, СтрДлина(ФайлЖурнала.Путь) - 1);
		Длина1 = СтрДлина(ПолноеИмяКаталогаПроцесса);
		СтрокаЧасаЗаписи = "20" + Сред(ФайлЖурнала.ПолноеИмя, Длина1 + 2, 8); 
		ДатаЧасЗаписи = Дата(СтрокаЧасаЗаписи + "0000");
		ИдентификаторПроцессаСтрока = ирОбщий.ПолучитьСтрокуБезКонцаЛкс(ирОбщий.ПолучитьПоследнийФрагментЛкс(ФайлЖурнала.Путь, "_"), 1);
		Попытка
			ИдентификаторПроцесса = Число(ИдентификаторПроцессаСтрока);
		Исключение
			Сообщить("Неверная структура каталогов техножурнала", СтатусСообщения.Внимание);
			Возврат Ложь;
		КонецПопытки; 
		//ЛиФайлВИнтервалеПолностью = ирОбщий.ЛиДатаВИнтервалеБезГраницЛкс(ДатаЧасЗаписи, НачалоЧаса(лНачалоПериода), НачалоЧаса(КонецПериода));
		//ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаЧасЗаписи, НачалоЧаса(лНачалоПериода), НачалоЧаса(КонецПериода));
		ЛиФайлВИнтервалеПолностью = ирОбщий.ЛиДатаВИнтервалеБезГраницЛкс(ДатаЧасЗаписи, НачалоЧаса(НачалоПериода), НачалоЧаса(КонецПериода));
		ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаЧасЗаписи, НачалоЧаса(НачалоПериода), НачалоЧаса(КонецПериода));
		Если Не ЛиДатаВИнтервале Тогда
			Продолжить;
		КонецЕсли; 
		Если Истина
			И ОтборПоПроцессу <> Неопределено
			И ИдентификаторПроцесса <> ОтборПоПроцессу
		Тогда
			Продолжить;
		КонецЕсли; 
		ПоследняяСтрокаТаблицыФайла = Неопределено;
		ТекстФайла = ""; // Уничтожаем старый текст, т.к. он может быть очень большим
		Попытка
			ЧтениеТекста = Новый ЧтениеТекста(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8, ,,Ложь);
			//ТекстовыйДокумент.Прочитать(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8);
		Исключение
			Сообщить("Не удалось прочитать данные из файла " + ФайлЖурнала.ПолноеИмя, СтатусСообщения.Внимание);
			Продолжить;
		КонецПопытки;
		СигнатураФайла = ЧтениеТекста.Прочитать(20); // Для идентификации файла
		Если ПустаяСтрока(СигнатураФайла) Тогда
			Продолжить;
		КонецЕсли; 
		РазмерПорции = 2 * 1000 * 1000; // Подобрано экспериментально
		КраткоеИмяКаталогаПроцесса = ирОбщий.ПолучитьПоследнийФрагментЛкс(ПолноеИмяКаталогаПроцесса, "\");
		ЧислоПорций = Цел(РазмерФайла / РазмерПорции) + 1;
		ЧтениеТекста = Новый ЧтениеТекста(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8, ,,Ложь);
		АбсолютнаяПозицияВФайле = 0;
		КлючКарты = Новый Структура("ИмяКаталогаПроцесса, ИмяТекущегоФайла, СигнатураТекущегоФайла, ОтборПоСеансу",
			КраткоеИмяКаталогаПроцесса, ФайлЖурнала.Имя, СигнатураФайла, ОтборПоСеансу);
		СтрокиКарт = мКартыФайлов.НайтиСтроки(КлючКарты);
		Если СтрокиКарт.Количество() > 0 Тогда
			КартаФайла = СтрокиКарт[0];
		Иначе
			КартаФайла = мКартыФайлов.Добавить();
			ЗаполнитьЗначенияСвойств(КартаФайла, КлючКарты); 
			КартаФайла.КонецПериода = Дата(1000, 1, 1);
		КонецЕсли;
		Если ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(НачалоПериода, КартаФайла.НачалоПериода, КартаФайла.КонецПериода) Тогда
			АбсолютнаяПозицияВФайле = КартаФайла.ПозицияКонца;
		ИначеЕсли Ложь
			Или НачалоПериода > КартаФайла.НачалоПериода
			Или КонецПериода < КартаФайла.КонецПериода
		Тогда
			// Периоды не сшиваются. Очищаем карту.
			КартаФайла.ПозицияНачала = -1;
			КартаФайла.ПозицияКонца = -1;
			КартаФайла.НачалоПериода = НачалоПериода;
			КартаФайла.КонецПериода = КонецПериода;
			КартаФайла.ДатаИзмененияФайла = Неопределено;
		КонецЕсли;
		Если АбсолютнаяПозицияВФайле > 0 Тогда
			Если ЗначениеЗаполнено(КартаФайла.ДатаИзмененияФайла) Тогда
				Если КартаФайла.ДатаИзмененияФайла = ФайлЖурнала.ПолучитьВремяИзменения() + ирКэш.ПолучитьСмещениеВремениЛкс() Тогда
					Продолжить;
				КонецЕсли; 
			КонецЕсли; 
			ЧтениеТекста.Прочитать(АбсолютнаяПозицияВФайле);
		КонецЕсли; 
		ПозицияНачалаСчитанныхДанных = -1;
		Если ЧислоПорций > 1 Тогда
			ИндикаторФайла = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ЧислоПорций, "" + КраткоеИмяКаталогаПроцесса + "\" + ФайлЖурнала.Имя);
		Иначе
			ИндикаторФайла = Неопределено;
		КонецЕсли; 
		РазрешенныеТипыСобытий = Неопределено;
		Если СписокЗагружаемыхТиповСобытий.Количество() > 0 Тогда
			РазрешенныеТипыСобытий = Новый Структура;
			Для Каждого ТипСобытия Из СписокЗагружаемыхТиповСобытий.ВыгрузитьЗначения() Цикл
				РазрешенныеТипыСобытий.Вставить(ТипСобытия);
			КонецЦикла;
		КонецЕсли; 
		СтрокаТЧ = Неопределено;
		РазмерТекущейПорции = 0;
		Пока Истина Цикл
			КартаФайла.ДатаИзмененияФайла = ФайлЖурнала.ПолучитьВремяИзменения() + ирКэш.ПолучитьСмещениеВремениЛкс();
			ПорцияТекстаФайла = ЧтениеТекста.Прочитать(РазмерПорции);
			Если Ложь
				Или ПорцияТекстаФайла = Неопределено 
				Или ПустаяСтрока(ПорцияТекстаФайла)
			Тогда
				Прервать;
			КонецЕсли; 
			#Если Клиент Тогда
			Если ИндикаторФайла <> Неопределено Тогда
				ирОбщий.ОбработатьИндикаторЛкс(ИндикаторФайла);
			КонецЕсли; 
			#КонецЕсли 
			Если Истина
				И АбсолютнаяПозицияВФайле >= КартаФайла.ПозицияНачала 
				И АбсолютнаяПозицияВФайле + СтрДлина(ПорцияТекстаФайла) + СтрДлина(ТекстФайла) < КартаФайла.ПозицияКонца 
			Тогда 
				АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле + СтрДлина(ПорцияТекстаФайла) + СтрДлина(ТекстФайла);
				Продолжить;
			КонецЕсли; 
			ТекстФайла = ТекстФайла + ПорцияТекстаФайла;
			РазборТекстаРазрешен = Истина;
			ОписаниеОшибки = "";
			МаксимальныйРазмерТекстДляАнализа = 20000000; // Экспериментально подобрано http://devtool1c.ucoz.ru/forum/2-270-1#1145
			Если СтрДлина(ТекстФайла) > МаксимальныйРазмерТекстДляАнализа Тогда 
				Если Истина
					И РазмерТекущейПорции = РазмерПорции
					И СтрокаТЧ <> Неопределено
				Тогда
					СтрокаТЧ.ТекстSDBL = "<?>";
					СтрокаТЧ.ТекстСУБД = "<?>";
					Сообщить("При анализе файла """ + ФайлЖурнала.ПолноеИмя + """ некоторые свойства события пропущены, т.к. оно превышает допустимый размер "
						+ XMLСтрока(Цел(МаксимальныйРазмерТекстДляАнализа/1024/1024)) + "МБ: " + Лев(СокрЛ(СтрЗаменить(ТекстФайла, Символы.ПС, "")), 80) + "...");
				Иначе
					ОписаниеОшибки = "Событие превышает допустимый размер 20МБ";
				КонецЕсли; 
				РазборТекстаРазрешен = Ложь;
			Иначе
				Если Истина
					И РазмерТекущейПорции = РазмерПорции
					И СтрокаТЧ <> Неопределено 
				Тогда
					ТаблицаЖурнала.Удалить(ТаблицаЖурнала.Количество() - 1);
				КонецЕсли;
			КонецЕсли; 
			Вхождения = RegExp.Execute("");
			Если РазборТекстаРазрешен Тогда
				Попытка
					Вхождения = RegExp.Execute(ТекстФайла);
				Исключение
					ОписаниеОшибки = ОписаниеОшибки();
				КонецПопытки;
			КонецЕсли; 
			Если ОписаниеОшибки <> "" Тогда
				Сообщить("При анализе файла """ + ФайлЖурнала.ПолноеИмя + """ пропущена порция """ + Лев(СокрЛ(СтрЗаменить(ТекстФайла, Символы.ПС, "")), 80) + "..."":
				|	" + ОписаниеОшибки);
			Иначе
				Если КомментироватьЗагрузку Тогда
					Сообщить("Анализ порции " + СтрДлина(ТекстФайла) + " символов обнаружил " + Вхождения.Count + " событий");
				КонецЕсли;
			КонецЕсли; 
			СтрокаТекущегоКонтекста = Неопределено;
			СтрокаТЧ = Неопределено;
			Вхождение = Неопределено;
			Для Каждого Вхождение Из Вхождения Цикл
				#Если Клиент Тогда
				ОбработкаПрерыванияПользователя();
				#КонецЕсли 
				СтрокаТЧ = Неопределено;
				АбсолютнаяПозицияВхождения = АбсолютнаяПозицияВФайле + Вхождение.FirstIndex;
				Если Истина
					И КартаФайла.ПозицияНачала > -1
					И АбсолютнаяПозицияВхождения >= КартаФайла.ПозицияНачала
					И АбсолютнаяПозицияВхождения < КартаФайла.ПозицияКонца
				Тогда
					Продолжить;
				КонецЕсли; 
				СтрокаВремениЗаписи = СтрокаЧасаЗаписи + СтрЗаменить(Вхождение.SubMatches(0), ":", "");
				ДатаТекущегоСобытия = Дата(СтрокаВремениЗаписи);
				Если Не ЛиФайлВИнтервалеПолностью Тогда
					//ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаТекущегоСобытия, лНачалоПериода, КонецПериода);
					//Если Не ЛиДатаВИнтервале Тогда
					//	Продолжить;
					//КонецЕсли; 
					Если Истина
						И ЗначениеЗаполнено(НачалоПериода)
						И ДатаТекущегоСобытия < НачалоПериода
					Тогда
						Продолжить;
					КонецЕсли; 
					Если Истина
						И ЗначениеЗаполнено(КонецПериода)
						И ДатаТекущегоСобытия > КонецПериода
					Тогда
						Вхождение = Неопределено;
						Прервать;
					КонецЕсли; 
				КонецЕсли;
				ТипСобытия = ВРег(Вхождение.SubMatches(3));
				Если Истина
					И РазрешенныеТипыСобытий <> Неопределено
					И Не РазрешенныеТипыСобытий.Свойство(ТипСобытия) 
				Тогда
					Продолжить;
				КонецЕсли; 
				Если ПозицияНачалаСчитанныхДанных = -1 Тогда
					ПозицияНачалаСчитанныхДанных = АбсолютнаяПозицияВхождения;
				КонецЕсли; 
				КонецМикросекунды = Вхождение.SubMatches(1);
				//КлючСтроки = МоментВремени + ";" + ФайлЖурнала.ПолноеИмя;
				//Если РежимДозагрузки Тогда
				//	Если КлючиЗагруженныхСтрок[КлючСтроки] = 1 Тогда
				//		Продолжить;
				//	КонецЕсли; 
				//КонецЕсли; 
				Если СтрДлина(КонецМикросекунды) = 6 Тогда
					//Это 8.3
					ЧислоМикросекунд = Число(КонецМикросекунды);
					ПродолжительностьВМикросекундах = Число(Вхождение.SubMatches(2));
				Иначе
					//Это 8.2
					ЧислоМикросекунд = Число(КонецМикросекунды) * 100;
					ПродолжительностьВМикросекундах = Число(Вхождение.SubMatches(2)) * 100;
				КонецЕсли;
				Если ТаблицаЖурнала.Количество() = МаксТысячСобытий * 1000 Тогда
					ДостигнутоПредельноеКоличество = Истина;
					Прервать;
				КонецЕсли; 
				СтрокаТЧ = ТаблицаЖурнала.Добавить();
				СтрокаТЧ.Дата = ДатаТекущегоСобытия - СдвигВремени;
				СтрокаТЧ.МоментВремени = ПолучитьМоментВремени(СтрокаТЧ.Дата, КонецМикросекунды);
				СтрокаТЧ.ИмяФайлаЛога = ФайлЖурнала.ПолноеИмя;
				СтрокаТЧ.ПроцессОС = ИдентификаторПроцесса;
				//СтрокаТЧ.ТекстЖурнала = Вхождение.Value; // Теперь это только для отладки будем включать
				СтрокаТЧ.Длительность = ПродолжительностьВМикросекундах / 1000; // Переводим длительность в миллисекунды
				Длительность1Секунды = Цел(ПродолжительностьВМикросекундах / 1000000);
				Длительность1Микросекунды = ПродолжительностьВМикросекундах - Длительность1Секунды * 1000000;
				ДатаНачала = СтрокаТЧ.Дата - Длительность1Секунды;
				НачалоМикросекунды = КонецМикросекунды - Длительность1Микросекунды;
				Если НачалоМикросекунды < 0 Тогда
					ДатаНачала = ДатаНачала - 1;
					НачалоМикросекунды = 1000000 + НачалоМикросекунды;
				КонецЕсли; 
				СтрокаТЧ.ДатаНачала = ДатаНачала;
				СтрокаТЧ.МоментВремениНачала = ПолучитьМоментВремени(ДатаНачала, НачалоМикросекунды);
				СтрокаТЧ.Событие = ТипСобытия;
				ВхожденияСвойств = RegExp2.Execute(Вхождение.SubMatches(4));

				// Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах.
				#Если Сервер И Не Сервер Тогда
				Для Каждого ВхождениеСвойства Из ВхожденияСвойств Цикл
					//Для Индекс = 0 По мТаблицаКолонок.Количество() - 1 Цикл
					//Индекс + СмещениеПервойКолонки
					ИмяСвойства = ВхождениеСвойства.SubMatches(0);
					ЗначениеСвойства = ВхождениеСвойства.SubMatches(3);
					//Если ирОбщий.ЛиПустаяПодгруппаRegExpЛкс(ЗначениеСвойства) Тогда
					Если ЗначениеСвойства = Неопределено Тогда // Скорость критична
						ЗначениеСвойства = ВхождениеСвойства.SubMatches(2);
					КонецЕсли; 
					//Если ирОбщий.ЛиПустаяПодгруппаRegExpЛкс(ЗначениеСвойства) Тогда
					Если ЗначениеСвойства = Неопределено Тогда // Скорость критична
						ЗначениеСвойства = ВхождениеСвойства.SubMatches(1);
					КонецЕсли; 
					//Если ирОбщий.ЛиПустаяПодгруппаRegExpЛкс(ЗначениеСвойства) Тогда
					Если ЗначениеСвойства = Неопределено Тогда // Скорость критична
						Продолжить;
					КонецЕсли;
					ИмяКолонкиТЧ = мСоответствиеКолонок[НРег(ИмяСвойства)];
					Если ИмяКолонкиТЧ = Неопределено Тогда
						Если НеизвестныеСвойства[ИмяСвойства] = Неопределено Тогда
							НеизвестныеСвойства[ИмяСвойства] = 1;
							Сообщить("Обнаружено неизвестное свойство """ + ИмяСвойства + """ события " + ТипСобытия);
						КонецЕсли; 
						СтрокаТЧ.НеизвестныеСвойства = СтрокаТЧ.НеизвестныеСвойства +  ИмяСвойства + "=" + ЗначениеСвойства + ", ";
					Иначе
						//Если мЧисловыеСвойства.Свойство(ИмяКолонкиТЧ) Тогда
						//	Если Не ЗначениеЗаполнено(ЗначениеСвойства) Тогда
						//		ЗначениеСвойства = 0;
						//	Иначе
						//		Попытка
						//			ЗначениеСвойства = Число(ЗначениеСвойства);
						//		Исключение
						//			ВызватьИсключение "Некорректное представление """ + ЗначениеСвойства + """ значения числового свойства """ + ИмяКолонкиТЧ + """";
						//		КонецПопытки;
						//	КонецЕсли; 
						//КонецЕсли;
						Если ТипЗнч(СтрокаТЧ[ИмяКолонкиТЧ]) = Тип("Булево") Тогда
							ЗначениеСвойства = ?(ЗначениеСвойства = "1" Или Нрег(ЗначениеСвойства) = "true", Истина, Ложь);
						КонецЕсли; 
						Если Не мНепустыеКолонкиЖурнала.Свойство(ИмяКолонкиТЧ) Тогда
							Если ЗначениеЗаполнено(ЗначениеСвойства) Тогда
								мНепустыеКолонкиЖурнала.Вставить(ИмяКолонкиТЧ);
							КонецЕсли; 
						КонецЕсли; 
						Попытка
							СтрокаТЧ[ИмяКолонкиТЧ] = ЗначениеСвойства;
						Исключение
							ВызватьИсключение "Некорректное представление """ + ЗначениеСвойства + """ значения свойства """ + ИмяКолонкиТЧ + """";
						КонецПопытки;
					КонецЕсли; 
				КонецЦикла;
				#КонецЕсли
				// Однострочный код использован для ускорения. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы ""Инструменты разработчика"" (http://devtool1c.ucoz.ru)
				Для Каждого ВхождениеСвойства Из ВхожденияСвойств Цикл      					ИмяСвойства = ВхождениеСвойства.SubMatches(0);  					ЗначениеСвойства = ВхождениеСвойства.SubMatches(3);    					Если ЗначениеСвойства = Неопределено Тогда  						ЗначениеСвойства = ВхождениеСвойства.SubMatches(2);  					КонецЕсли;    					Если ЗначениеСвойства = Неопределено Тогда  						ЗначениеСвойства = ВхождениеСвойства.SubMatches(1);  					КонецЕсли;    					Если ЗначениеСвойства = Неопределено Тогда  						Продолжить;  					КонецЕсли;  					ИмяКолонкиТЧ = мСоответствиеКолонок[НРег(ИмяСвойства)];  					Если ИмяКолонкиТЧ = Неопределено Тогда  						Если НеизвестныеСвойства[ИмяСвойства] = Неопределено Тогда  							НеизвестныеСвойства[ИмяСвойства] = 1;  							Сообщить("Обнаружено неизвестное свойство """ + ИмяСвойства + """ события " + ТипСобытия);  						КонецЕсли;  						СтрокаТЧ.НеизвестныеСвойства = СтрокаТЧ.НеизвестныеСвойства +  ИмяСвойства + "=" + ЗначениеСвойства + ", ";  					Иначе                        						Если ТипЗнч(СтрокаТЧ[ИмяКолонкиТЧ]) = Тип("Булево") Тогда  							ЗначениеСвойства = ?(ЗначениеСвойства = "1" Или Нрег(ЗначениеСвойства) = "true", Истина, Ложь);  						КонецЕсли;  						Если Не мНепустыеКолонкиЖурнала.Свойство(ИмяКолонкиТЧ) Тогда  							Если ЗначениеЗаполнено(ЗначениеСвойства) Тогда  								мНепустыеКолонкиЖурнала.Вставить(ИмяКолонкиТЧ);  							КонецЕсли;  						КонецЕсли;  						Попытка  							СтрокаТЧ[ИмяКолонкиТЧ] = ЗначениеСвойства;  						Исключение  							ВызватьИсключение "Некорректное представление """ + ЗначениеСвойства + """ значения свойства """ + ИмяКолонкиТЧ + """";  						КонецПопытки;  					КонецЕсли;  				КонецЦикла;  

				//АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле + Вхождение.Length;
				Если Истина
					И ОтборПоСеансу <> Неопределено
					И СтрокаТЧ.Сеанс <> ОтборПоСеансу
				Тогда
					ТаблицаЖурнала.Удалить(СтрокаТЧ);
					СтрокаТЧ = Неопределено;
					#Если Сервер И Не Сервер Тогда
					    СтрокаТЧ = ТаблицаЖурнала.Добавить();
					#КонецЕсли
					Продолжить;
				КонецЕсли; 
				//Если НаСервере <> Неопределено Тогда
				//	СтрокаТЧ.НаСервере = НаСервере;
				//Иначе
					Если Ложь
						Или ТипСобытия = "SCOM" 
					Тогда
					    СтрокаТЧ.НаСервере = Истина;
					Иначе
						ИмяТипаПроцесса = "_" + СтрЗаменить(СтрокаТЧ.ТипПроцессаОС, "#", "");
						Попытка
							СтрокаТЧ.НаСервере = мСерверныеТипыПроцессов.Свойство(ИмяТипаПроцесса);
						Исключение
							// Бывают типы процессов с UID, к сожалению тогда невозможно определить
						КонецПопытки; 
					КонецЕсли; 
				//КонецЕсли; 
				Если СтрокаТЧ.Контекст <> "" Тогда
					КонтекстТД = Новый ТекстовыйДокумент;
					КонтекстТД.УстановитьТекст(СтрокаТЧ.Контекст);
					СтрокаТЧ.СтрокаМодуля = СокрЛП(КонтекстТД.ПолучитьСтроку(КонтекстТД.КоличествоСтрок()));
					Если БазовыйУровеньСтека > 0 Тогда
						ЗаполнитьСтрокуБазовогоУровня(СтрокаТЧ);
					КонецЕсли; 
				КонецЕсли; 
				Если ВключитьСвойстваСИменамиМетаданных Тогда
					ЗаполнитьСвойстваСИменамиМетаданных(СтрокаТЧ);
				КонецЕсли; 
				//Если ДатаТекущегоСобытия > лПоследнееВремяНачалаЗагрузки - НаложениеПриДозагрузкеСекунд Тогда
				//	НовыеКлючиЗагруженныхСтрок[КлючСтроки] = 1;
				//КонецЕсли; 
				Если ирОбщий.СтрокиРавныЛкс(ТипСобытия, "Context") Тогда
					// Встроим контекст в предыдущие события
					Индекс = ТаблицаЖурнала.Количество() - 2;
					Пока Индекс >= 0 Цикл
						СтрокаБезКонтекста = ТаблицаЖурнала[Индекс];
						Индекс = Индекс - 1;
						Если Ложь
							Или СтрокаБезКонтекста.Сеанс <> СтрокаТЧ.Сеанс
							Или СтрокаБезКонтекста.Инфобаза <> СтрокаТЧ.Инфобаза
						Тогда
							Прервать;
						КонецЕсли;
						Если Не СтрокаБезКонтекста.СтрокаМодуля = "" Тогда
							Прервать;
						КонецЕсли; 
						ЗаполнитьЗначенияСвойств(СтрокаБезКонтекста, СтрокаТЧ, "СтрокаМодуля, Контекст"); 
					КонецЦикла; 
				КонецЕсли; 
			КонецЦикла;
			Если ДостигнутоПредельноеКоличество Тогда
				Прервать;
			КонецЕсли; 
			// Для отката к началу последнего события
			РазмерТекущейПорции = СтрДлина(ПорцияТекстаФайла);
			АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле + СтрДлина(ТекстФайла);
			Если РазмерТекущейПорции = РазмерПорции Тогда
				//Если СтрокаТЧ <> Неопределено Тогда
				//	ТаблицаЖурнала.Удалить(ТаблицаЖурнала.Количество() - 1);
				//КонецЕсли; 
				Если Вхождение <> Неопределено Тогда
					ТекстФайла = Сред(ТекстФайла, Вхождение.FirstIndex);
				Иначе
					ТекстФайла = Прав(ТекстФайла, 1000); // Страховка
				КонецЕсли; 
				АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле - СтрДлина(ТекстФайла);
			Иначе
				ТекстФайла = "";
			КонецЕсли;
		КонецЦикла;
		Если ИндикаторФайла <> Неопределено Тогда
			ирОбщий.ОсвободитьИндикаторПроцессаЛкс();
		КонецЕсли; 
		Если ДостигнутоПредельноеКоличество Тогда
			Сообщить("Загрузка остановлена по достижению максимального количества событий в таблице");
			Прервать;
		КонецЕсли; 
		КартаФайла.ПозицияКонца = АбсолютнаяПозицияВФайле;
		Если Истина
			И ПозицияНачалаСчитанныхДанных <> -1
			И (Ложь
				Или КартаФайла.ПозицияНачала = -1
				Или КартаФайла.ПозицияНачала > ПозицияНачалаСчитанныхДанных)
		Тогда
			КартаФайла.ПозицияНачала = ПозицияНачалаСчитанныхДанных;
		КонецЕсли; 
		Если Ложь
			Или Не ЗначениеЗаполнено(КонецПериода)
			Или КонецПериода > КартаФайла.КонецПериода
		Тогда
			КартаФайла.КонецПериода = КонецПериода;
		КонецЕсли;
		Если Ложь
			Или Не ЗначениеЗаполнено(НачалоПериода)
			Или НачалоПериода < КартаФайла.НачалоПериода
		Тогда
			КартаФайла.НачалоПериода = НачалоПериода;
		КонецЕсли;
	КонецЦикла;
	ирОбщий.ОсвободитьИндикаторПроцессаЛкс();

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

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

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

Функция ПолучитьМоментВремени(Дата, Микросекунды) Экспорт 
	
	Результат = Формат(Дата, "ДФ=yyyyMMddHHmmss") + Формат(Микросекунды, "ЧЦ=6; ЧВН=; ЧГ=");
	Возврат Результат;
	
КонецФункции

Функция РазностьМоментовВремени(МоментВремениУменьшаемый, МоментВремениВычитаемый) Экспорт 

	Если СтрДлина(МоментВремениВычитаемый) <> СтрДлина(МоментВремениВычитаемый) Тогда
		ВызватьИсключение "Размерность моментов времени не совпадает";
	КонецЕсли; 
	ДлинаЧастиДаты = 14;
	ДатаУменьшаемая = Дата(Лев(МоментВремениУменьшаемый, ДлинаЧастиДаты));
	ДатаВычитаемая = Дата(Лев(МоментВремениВычитаемый, ДлинаЧастиДаты));
	РазрядностьДолейСекунд = СтрДлина(МоментВремениУменьшаемый) - ДлинаЧастиДаты;
	РазностьСекунд = ДатаУменьшаемая - ДатаВычитаемая;
	Результат = РазностьСекунд;
	Для Счетчик = 1 По РазрядностьДолейСекунд Цикл
		Результат = Результат * 10;
	КонецЦикла;
	Результат = Результат + Число(Сред(МоментВремениУменьшаемый, ДлинаЧастиДаты + 1)) - Число(Сред(МоментВремениВычитаемый, ДлинаЧастиДаты + 1));
	Возврат Результат;

КонецФункции // РазностьМоментовВремени()

Функция ЗаполнитьСтрокуБазовогоУровня(СтрокаТЧ)

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

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

// ПопытокЧтения - Число, используется только при РежимТрассы = Истина
Функция ПрочитатьСобственныйЖурналДвухСторон(УдалитьДополнительныеСобытия = Истина, ИменаНеполезныхКолонок = "", РежимТрассы = Истина,
	ПопытокЧтения = 10, СмещениеБазовогоУровня = Неопределено)
	
	Если РежимТрассы Тогда
		Если мИдентификаторТрассы = Неопределено Тогда
			Если Не ирКэш.ЭтоФайловаяБазаЛкс() Тогда
				ирОбщий.ЛиТехножурналВключенЛкс(Истина, Истина);
			КонецЕсли; 
			ирОбщий.ЛиТехножурналВключенЛкс(, Истина);
			Возврат Ложь;
		КонецЕсли; 
	КонецЕсли; 
	Если РежимТрассы Тогда
		ЭтотОбъект.ВключитьСвойстваСИменамиМетаданных = Ложь; // Для ускорения выключаем, т.к. фильтрация будет многостадийной
		ЭтотОбъект.ЗагружатьЖурналКлиента = Истина;
		ЭтотОбъект.ЗагружатьЖурналСервера = Не ирКэш.ЭтоФайловаяБазаЛкс();
		ЭтотОбъект.ЗагружатьТолькоТекущийСеанс = Истина;
	КонецЕсли; 
	ВыраниватьДатуПоСерверу = Ложь;
	#Если Клиент Тогда
	ВыраниватьДатуПоСерверу = ирОбщий.ВосстановитьЗначениеЛкс("ирАнализТехножурнала.ВыраниватьДатуПоСерверу") = Истина;
	#КонецЕсли
	Если РежимТрассы Тогда
		РазницаВремениКлиентСервер = НачалоПериодаКлиента - НачалоПериодаСервера;
	Иначе
		РазницаВремениКлиентСервер = ирОбщий.ПолучитьТекущуюДатуЛкс() - ирОбщий.ПолучитьТекущуюДатуЛкс(Истина);
	КонецЕсли; 
	Если Истина
		И Не ирКэш.Получить().ЭтоФайловаяБаза 
		И ЗагружатьЖурналСервера
	Тогда
		ЭтотОбъект.КаталогЖурнала = "";
		Если ВыраниватьДатуПоСерверу Тогда
			СдвигВремени = 0;
		Иначе
			СдвигВремени = -РазницаВремениКлиентСервер;
		КонецЕсли; 
		РезультатСервера = ПрочитатьСобственныйЖурналОднойСтороны(НачалоПериодаСервера, КонецПериодаСервера, Истина, СдвигВремени,
			РежимТрассы, ПопытокЧтения, СмещениеБазовогоУровня);
	КонецЕсли; 
	Если ЗагружатьЖурналКлиента Тогда
		ЭтотОбъект.КаталогЖурнала = "";
		Если ВыраниватьДатуПоСерверу Тогда
			СдвигВремени = РазницаВремениКлиентСервер;
		Иначе
			СдвигВремени = 0;
		КонецЕсли;
		РезультатКлиента = ПрочитатьСобственныйЖурналОднойСтороны(НачалоПериодаКлиента, КонецПериодаКлиента, Ложь, СдвигВремени,
			РежимТрассы, ПопытокЧтения, СмещениеБазовогоУровня);
	КонецЕсли; 
	Если Истина
		И РезультатКлиента = Неопределено
		И РезультатСервера = Неопределено
	Тогда
		Возврат Ложь;
	КонецЕсли; 
	Если УдалитьДополнительныеСобытия Тогда
		УдалитьСтрокиПоОтбору(Новый Структура("Действие", "getExecSQLStatistics"));
		УдалитьСтрокиПоОтбору(Новый Структура("Событие", "CONTEXT"));
	КонецЕсли; 
	Если РежимТрассы Тогда
		ЭтотОбъект.ВключитьСвойстваСИменамиМетаданных = Истина;
	КонецЕсли; 
	Если ВключитьСвойстваСИменамиМетаданных Тогда
		ОбновитьСвойстваВТерминахМетаданных();
	КонецЕсли; 
	//ОбновитьСтрокиБазовогоУровня();
	Возврат Истина;

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

Функция ПрочитатьСобственныйЖурналОднойСтороны(НачалоПериода = Неопределено, КонецПериода = Неопределено, НаСервере = Истина, СдвигВремени = 0, 
	РежимТрассы = Истина, ПопытокЧтения = 10, СмещениеБазовогоУровня = Неопределено)

	Если НачалоПериода <> Неопределено Тогда
		ЭтотОбъект.НачалоПериода = НачалоПериода;
	КонецЕсли; 
	Если КонецПериода <> Неопределено Тогда
		ЭтотОбъект.КонецПериода = КонецПериода;
	КонецЕсли; 
	ТехножурналВключен = ирОбщий.ЛиТехножурналВключенЛкс(НаСервере);
	Если Истина
		И Не ТехножурналВключен 
		И РежимТрассы
	Тогда
		Возврат Неопределено;
	КонецЕсли; 
	МассивТиповСУБД = Новый Массив();
	Если ирКэш.ЭтоФайловаяБазаЛкс() Тогда
		МассивТиповСУБД.Добавить("DBV8DBENG");
		//ОтборТЧ = Новый Структура("Событие", "SDBL");
	Иначе
		МассивТиповСУБД.Добавить("DBMSSQL");
		МассивТиповСУБД.Добавить("DBPOSTGRS");
		МассивТиповСУБД.Добавить("DBORACLE");
		МассивТиповСУБД.Добавить("DB2");
		//ОтборТЧ = Новый Структура("Событие", "CONTEXT");
	КонецЕсли; 
	СообщитьРазмер = Неопределено;
	МаркерНачалаНайден = Ложь;
	Для Счетчик = 1 По ПопытокЧтения Цикл
		#Если Клиент Тогда
		ОбработкаПрерыванияПользователя();
		#КонецЕсли
		Если Счетчик > 1 Тогда
			#Если Клиент Тогда
			Состояние("Ожидание техножурнала");
			#КонецЕсли 
			мПлатформа.Sleep(0.5);
			СообщитьРазмер = Ложь;
		КонецЕсли; 
		ЖурналСчитан = ПрочитатьПроизвольныйЖурнал(СообщитьРазмер, СдвигВремени, , , НаСервере);
		Если Не ЖурналСчитан Тогда
			Возврат Неопределено;
		КонецЕсли;
		//ТехножурналВключен = ирОбщий.ЛиТехножурналВключенЛкс(Истина);
		//Если ТехножурналВключен Тогда
		//	Если АвтоочисткаТехножурнала Тогда
		//		КаталогТекущегоЖурнала = ПолучитьКаталогТекущегоЖурнала();
		//		Если ЗначениеЗаполнено(КаталогТекущегоЖурнала) Тогда
		//			ирОбщий.ОчиститьКаталогТехножурналаЛкс(КаталогТекущегоЖурнала, Истина, Ложь);
		//		КонецЕсли; 
		//	КонецЕсли; 
		//КонецЕсли; 
		Если РежимТрассы Тогда
			Если Ложь
				Или Не ирКэш.ЛиПортативныйРежимЛкс() 
				Или Не НаСервере
			Тогда
				МаркерНачала = Новый Структура("Описание", "{(1, 1)}: Ожидается выражение ""ВЫБРАТЬ""
					|<<?>>НачалоТрассы_" + мИдентификаторТрассы);
				МаркерКонца = Новый Структура("Описание", "{(1, 1)}: Ожидается выражение ""ВЫБРАТЬ""
					|<<?>>КонецТрассы_" + мИдентификаторТрассы);
			Иначе
				МаркерНачала = Новый Структура("ТекстSDBL", "SELECT
					|""НачалоТрассы_" + мИдентификаторТрассы + """
					|");
				МаркерКонца = Новый Структура("ТекстSDBL", "SELECT
					|""КонецТрассы_" + мИдентификаторТрассы + """
					|");
			КонецЕсли; 		
			
			// Удаляем лишние строки до маркера начала и после маркера конца
			Если Не МаркерНачалаНайден Тогда
				НайденныеСтроки = ТаблицаЖурнала.НайтиСтроки(МаркерНачала);
				Если НайденныеСтроки.Количество() = 0 Тогда
					Продолжить;
				КонецЕсли; 
				НачальнаяСтрока = НайденныеСтроки[0];
				#Если Сервер И Не Сервер Тогда
				    НачальнаяСтрока = ТаблицаЖурнала.Добавить();
				#КонецЕсли
				Если СмещениеБазовогоУровня <> Неопределено Тогда
					ЭтотОбъект.БазовыйУровеньСтека = СтрЧислоСтрок(НачальнаяСтрока.Контекст) + СмещениеБазовогоУровня;
				КонецЕсли; 
				КонечныйИндекс = ТаблицаЖурнала.Индекс(НачальнаяСтрока);
				Для Индекс = 0 По КонечныйИндекс Цикл
					Если ТаблицаЖурнала[0].НаСервере = НаСервере Тогда
						ТаблицаЖурнала.Удалить(0);
					КонецЕсли; 
				КонецЦикла;
				МаркерНачалаНайден = Истина;
			КонецЕсли; 
			
			НайденныеСтроки = ТаблицаЖурнала.НайтиСтроки(МаркерКонца);
			Если НайденныеСтроки.Количество() = 0 Тогда
				Продолжить;
			КонецЕсли; 
			КонечнаяСтрока = НайденныеСтроки[0];
			НачальныйИндекс = ТаблицаЖурнала.Индекс(КонечнаяСтрока);
			Если Ложь
				Или НаСервере 
				Или ирКэш.ЭтоФайловаяБазаЛкс()
			Тогда
				КонечнаяСтрока1 = ТаблицаЖурнала[НачальныйИндекс];
				Если МассивТиповСУБД.Найти(КонечнаяСтрока1.Событие) <> Неопределено Тогда // Опасно. Учитывается регистр букв
					мТипСУБД = КонечнаяСтрока1.Событие;
					НачальныйИндекс = НачальныйИндекс - 1;
				КонецЕсли; 
			КонецЕсли; 
			НачальноеКоличество = ТаблицаЖурнала.Количество(); 
			Для Индекс = 1 По НачальноеКоличество - НачальныйИндекс Цикл
				СтрокаЖурнала = ТаблицаЖурнала[НачальноеКоличество - Индекс];
				Если СтрокаЖурнала.НаСервере = НаСервере Тогда
					ТаблицаЖурнала.Удалить(СтрокаЖурнала);
				КонецЕсли; 
			КонецЦикла;
			
			Пока Истина
				И ТаблицаЖурнала.Количество() > 0
				И ТаблицаЖурнала[0].НаСервере = НаСервере
				И Найти(ТаблицаЖурнала[0].Контекст, "Обработка.ирАнализТехножурнала.МодульОбъекта") > 0 
			Цикл
				ТаблицаЖурнала.Удалить(0);
			КонецЦикла; 
			Пока Истина
				И ТаблицаЖурнала.Количество() > 0
				И ТаблицаЖурнала[ТаблицаЖурнала.Количество() - 1].НаСервере = НаСервере
				И Найти(ТаблицаЖурнала[ТаблицаЖурнала.Количество() - 1].Контекст, "Обработка.ирАнализТехножурнала.МодульОбъекта") > 0 
			Цикл
				ТаблицаЖурнала.Удалить(ТаблицаЖурнала.Количество() - 1);
			КонецЦикла; 
		КонецЕсли; 
		Прервать;
	КонецЦикла;
	Если РежимТрассы Тогда
		Если КонечнаяСтрока = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли; 
		//	ФрагментыНачальнойСтрокиМодуля = ирОбщий.ПолучитьМассивИзСтрокиСРазделителемЛкс(ТаблицаЖурнала[0].СтрокаМодуля, ":", Истина);
		//	ФрагментыКонечнойСтрокиМодуля = ирОбщий.ПолучитьМассивИзСтрокиСРазделителемЛкс(ТаблицаЖурнала[ТаблицаЖурнала.Количество() - 1].СтрокаМодуля, ":", Истина);
		//	ИмяМодуляНачальнойСтроки = ФрагментыНачальнойСтрокиМодуля[0];
		//	ИмяМодуляКонечнойСтроки = ФрагментыКонечнойСтрокиМодуля[0];
		//	НомерНачальнойСтроки = Число(ФрагментыНачальнойСтрокиМодуля[1]);
		//	НомерКонечнойСтроки = Число(ФрагментыКонечнойСтрокиМодуля[1]);
		//	ЕстьВызовыМетодовМодулей = Ложь
		//		Или ИмяМодуляНачальнойСтроки <> ИмяМодуляНачальнойСтроки
		//		Или НомерНачальнойСтроки > НомерКонечнойСтроки;
		//	СтрокиВызововМетодов = НайтиВызовыМетодовМодулей(ИмяМодуляНачальнойСтроки, НомерНачальнойСтроки, НомерКонечнойСтроки, Истина);
		//	Если СтрокиВызововМетодов.Количество() > 0 Тогда
		//		Ответ = Вопрос("В трассе обнаружены вызовы методов модулей. Хотите удалить их из трассы?", РежимДиалогаВопрос.ДаНет);
		//		Если Ответ = КодВозвратаДиалога.Да Тогда
		//			СтрокиВызововМетодов = НайтиВызовыМетодовМодулей(ИмяМодуляНачальнойСтроки, НомерНачальнойСтроки, НомерКонечнойСтроки, Ложь);
		//			Для Каждого СтрокаВызоваМетода Из СтрокиВызововМетодов Цикл
		//				ТаблицаЖурнала.Удалить(СтрокаВызоваМетода);
		//			КонецЦикла;
		//		КонецЕсли;
		//	КонецЕсли;
	КонецЕсли; 
	Возврат Истина;

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

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

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

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

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

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

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

Функция ЭтоЛокальныйПутьЛкс(Путь) Экспорт 

	ЭтоЛокальныйРесурс = Ложь
		Или Найти(НРег(Путь), "\\localhost") = 1
		Или Найти(НРег(Путь), "\\127.0.0.1") = 1
		Или Лев(Путь, 2) <> "\\";
	Возврат ЭтоЛокальныйРесурс;

КонецФункции // ЭтоЛокальныйПуть()
 
Функция ОткрытьСПараметрами(пКаталогЖурнала) Экспорт 
	
	Форма = ПолучитьФорму();
	Форма.Открыть();
	Форма.КаталогЖурнала = пКаталогЖурнала;
	Возврат Форма;
	
КонецФункции

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

Функция ПолучитьИмяСвойстваБезМета(Знач МестноеИмя) Экспорт

	Если ирОбщий.СтрокиРавныЛкс(Прав(МестноеИмя, 4), "мета") Тогда
		МестноеИмя = Лев(МестноеИмя, СтрДлина(МестноеИмя) - 4);
	КонецЕсли; 
	Возврат МестноеИмя;

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

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

Процедура ОбновитьСтрокиБазовогоУровня() Экспорт
	
	//Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ТаблицаЖурнала.Количество());
	Для Каждого СтрокаТаблицыЖурнала Из ТаблицаЖурнала Цикл
		//ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
		ЗаполнитьСтрокуБазовогоУровня(СтрокаТаблицыЖурнала);
	КонецЦикла;
	//Для Каждого СтрокаКонтекста Из Контексты Цикл
	//	ЗаполнитьСтрокуБазовогоУровня(СтрокаКонтекста);
	//КонецЦикла;
	
КонецПроцедуры

Функция ПолучитьШаблонТекстаБД(ТекстБД, ЗаменаПеременныхФрагментов = "7") Экспорт 
	
	ШаблонТекстаБД = RegExpПараметры.Replace(ТекстБД, "$1$2" + ЗаменаПеременныхФрагментов);
	Возврат ШаблонТекстаБД;
	
КонецФункции

Процедура ЗаполнитьСвойстваШаблоны() Экспорт

	Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ТаблицаЖурнала.Количество());
	Для Каждого СтрокаТаблицыЖурнала Из ТаблицаЖурнала Цикл
		ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
		Если Истина
			И СтрокаТаблицыЖурнала.ТекстSDBL <> ""
			И СтрокаТаблицыЖурнала.ТекстSDBLШаблон = ""
		Тогда
			СтрокаТаблицыЖурнала.ТекстSDBLШаблон = ПолучитьШаблонТекстаБД(СтрокаТаблицыЖурнала.ТекстSDBL);
		КонецЕсли; 
		Если Истина
			И СтрокаТаблицыЖурнала.ТекстСУБД <> ""
			И СтрокаТаблицыЖурнала.ТекстСУБДШаблон = ""
		Тогда
			СтрокаТаблицыЖурнала.ТекстСУБДШаблон = ПолучитьШаблонТекстаБД(СтрокаТаблицыЖурнала.ТекстСУБД);
		КонецЕсли; 
		Если Истина
			И СтрокаТаблицыЖурнала.Описание <> ""
			И СтрокаТаблицыЖурнала.ОписаниеШаблон = ""
		Тогда
			СтрокаТаблицыЖурнала.ОписаниеШаблон = ПолучитьШаблонТекстаБД(СтрокаТаблицыЖурнала.Описание);
		КонецЕсли; 
	КонецЦикла;
	
КонецПроцедуры

Процедура ОставитьТолькоСтрокиПоОтбору(СтруктураОтбора) Экспорт 
	
	НужныеСтроки = ТаблицаЖурнала.НайтиСтроки(СтруктураОтбора);
	КоличествоСтрок = ТаблицаЖурнала.Количество();
	Для Счетчик = 1 По КоличествоСтрок Цикл
		Индекс = КоличествоСтрок - Счетчик;
		СтрокаЖурнала = ТаблицаЖурнала[Индекс];
		Если НужныеСтроки.Найти(СтрокаЖурнала) = Неопределено Тогда
			ТаблицаЖурнала.Удалить(СтрокаЖурнала);
		КонецЕсли; 
	КонецЦикла;

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

Процедура УдалитьСтрокиПоОтбору(СтруктураОтбора) Экспорт 
	
	НенужныеСтроки = ТаблицаЖурнала.НайтиСтроки(СтруктураОтбора);
	Для Каждого НенужнаяСтрока Из НенужныеСтроки Цикл
		ТаблицаЖурнала.Удалить(НенужнаяСтрока);
	КонецЦикла;

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

Процедура ЗаписатьМаркерВТехножурнал(Маркер, ДляКлиента = Истина, ДляСервера = Истина) Экспорт
	
	ЗапросМаркер = Новый Запрос();
	Если ДляКлиента Тогда
		ЗапросМаркер.Текст = Маркер;
		Попытка
			ЗапросМаркер.Выполнить(); // Генерируем для клиента маркер-событие QERR
		Исключение
		КонецПопытки;
	КонецЕсли; 
	Если Истина
		И ДляСервера 
		И Не ирКэш.ЭтоФайловаяБазаЛкс()
	Тогда
		Если Не ирКэш.ЛиПортативныйРежимЛкс() Тогда
			Попытка
				ирСервер.ВыполнитьЗапросЛкс(Маркер); // Генерируем для сервера маркер-событие QERR
			Исключение
			КонецПопытки;
		Иначе
			ЗапросМаркер.Текст = "ВЫБРАТЬ """ + Маркер + """";
			Попытка
				ЗапросМаркер.Выполнить(); // Генерируем для клиента маркер-событие SDBL
			Исключение
				// Может возникнуть ошибка "В данной транзакции уже происходили ошибки!"
			КонецПопытки;
		КонецЕсли; 
	КонецЕсли; 
	
КонецПроцедуры

Функция НачатьТрассу(ПрефиксТрассы = "", ВыводитьСообщения = Ложь) Экспорт
	
	// Попробовать сделать проверку регистрации событий QERR в настройке техножурнала на сервере
	Если Не ирКэш.ЭтоФайловаяБазаЛкс() Тогда
		ТехножурналСервераВключен = ирОбщий.ЛиТехножурналВключенЛкс(Истина, ВыводитьСообщения);
	КонецЕсли; 
	ТехножурналКлиентаВключен = ирОбщий.ЛиТехножурналВключенЛкс(, ВыводитьСообщения);
	Если Истина
		И ТехножурналСервераВключен <> Истина
		И Не ТехножурналКлиентаВключен
	Тогда
		Возврат Ложь;
	КонецЕсли; 
	ЭтотОбъект.КонецПериодаСервера = Неопределено;
	ЭтотОбъект.КонецПериодаКлиента = Неопределено;
	ЭтотОбъект.НачалоПериодаСервера = ирОбщий.ПолучитьТекущуюДатуЛкс(Истина);
	ЭтотОбъект.НачалоПериодаКлиента = ирОбщий.ПолучитьТекущуюДатуЛкс(Ложь);
	мИдентификаторТрассы = ПрефиксТрассы + "_" + СтрЗаменить(Новый УникальныйИдентификатор(), "-", "");
	ЗаписатьМаркерВТехножурнал("НачалоТрассы_" + мИдентификаторТрассы);
	Возврат Истина;
	
КонецФункции

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

Функция ПолучитьТекстSQLДляПоискаВТехножурнале(Текст) Экспорт 
	
	RegExpМета.Pattern = "([^A-ZА-ЯЁ_0-9]|^)(?:@P\d+)";
	Результат = RegExpМета.Replace(Текст, "$1?");
	Возврат Результат;
	
КонецФункции

#Если Клиент Тогда
	
Функция ПоказатьТрассу(УдалитьДополнительныеСобытия = Истина, ИменаНеполезныхКолонок = "", ПопытокЧтения = 10, СмещениеБазовогоУровня = Неопределено) Экспорт
	
	Если ЭтотОбъект.КонецПериодаСервера = Неопределено Тогда 
		Предупреждение("Сформируйте трассу заново");
		Возврат Неопределено;
	КонецЕсли; 
	ОчиститьТаблицуЖурнала();
	ЖурналПрочитан = ПрочитатьСобственныйЖурналДвухСторон(УдалитьДополнительныеСобытия, ИменаНеполезныхКолонок, Истина, ПопытокЧтения, СмещениеБазовогоУровня);
	Если Не ЖурналПрочитан Тогда
		Сообщить("Не удалось найти маркеры трассы в логах. Проверьте включенность регистрации события QERR в настройке техножурнала");
		Возврат Неопределено;
	КонецЕсли; 
	ВыраниватьДатуПоСерверу = ирОбщий.ВосстановитьЗначениеЛкс("ирАнализТехножурнала.ВыраниватьДатуПоСерверу") = Истина;
	лКаталогЖурнала = КаталогЖурнала;
	ФормаАнализа = ПолучитьФорму();
	ФормаАнализа.ЭтоТрасса = Истина;
	ФормаАнализа.Открыть();
	ФормаАнализа.ЗагружатьТолькоТекущийСеанс = Истина;
	ФормаАнализа.ЗагружатьЖурналКлиента = Истина;
	ФормаАнализа.ЗагружатьЖурналСервера = Не ирКэш.ЭтоФайловаяБазаЛкс();
	Если ВыраниватьДатуПоСерверу Тогда
		ФормаАнализа.КонецПериода = КонецПериодаСервера;
		ФормаАнализа.НачалоПериода = НачалоПериодаСервера;
	Иначе
		ФормаАнализа.КонецПериода = КонецПериодаКлиента;
		ФормаАнализа.НачалоПериода = НачалоПериодаКлиента;
	КонецЕсли;
	ФормаАнализа.КаталогЖурнала = лКаталогЖурнала;
	ФормаАнализа.УстановитьРежимИтогов(ТаблицаЖурнала.Количество() > 20);
	ФормаАнализа.ПериодПоследниеМинуты = 0;
	ФормаАнализа.ОбновитьДоступность();
	ФормаАнализа.ЭлементыФормы.ПанельНастройки.ТекущаяСтраница = ФормаАнализа.ЭлементыФормы.ПанельНастройки.Страницы.Анализ;
	ФормаАнализа.УстановитьБесполезныеКолонки(ИменаНеполезныхКолонок);
	Возврат ФормаАнализа;

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

Функция ОчиститьТаблицуЖурнала() Экспорт

	мНепустыеКолонкиЖурнала = Новый Структура();
	ТаблицаЖурнала.Очистить();
	Возврат Неопределено;

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

Функция ОткрытьТекстБДВКонверторе(ТекстБД, СразуПеревестиВМета = Истина, КлючУникальности = Неопределено, ЭтоТекстSDBL = Истина) Экспорт

	ФормаЗапроса = ПолучитьФорму("КонверторТекстаСУБД", , КлючУникальности);
	ФормаЗапроса.ЭтоТекстSDBL = ЭтоТекстSDBL;
	ФормаЗапроса.ЭлементыФормы.ТекстБД.УстановитьТекст(ТекстБД);
	ФормаЗапроса.ПереводитьВМета = СразуПеревестиВМета;
	ФормаЗапроса.Открыть();
	Возврат Неопределено;

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

Процедура ОткрытьНастройкуТехножурналаДляРегистрацииВыполненияЗапроса(Знач ТекстБД, пЭтоТекстSDBL = Ложь, ТипСУБД = Неопределено, ИмяБазы = "") Экспорт 
    
	Если Не пЭтоТекстSDBL Тогда
		ТекстБД = ПолучитьТекстSQLДляПоискаВТехножурнале(ТекстБД);
	КонецЕсли; 
	ШаблонЗапроса = ПолучитьШаблонТекстаБД(Лев(ТекстБД, 1000), "%");
	ФормаНастройки = ирОбщий.ПолучитьФормуЛкс("Обработка.ирНастройкаТехножурнала.Форма");
	ФормаНастройки.Открыть();
	ФормаНастройки.НаСервере = Не ирКэш.Получить().ЭтоФайловаяБаза;
	ФормаНастройки.ПриИзмененииПравилаПолученияФайлаНастройки();
	Ответ = Вопрос("Хотите создать новую настройку?", РежимДиалогаВопрос.ДаНет);
	Если Ответ = КодВозвратаДиалога.Да Тогда
		ФормаНастройки.ЗагрузитьФайлНастройки("ШаблонЗаписьИсключительныхСитуаций", Истина, Истина, Ложь);
	КонецЕсли;
	СтрокаКаталога = ФормаНастройки.ТабличноеПолеЖурналы[0];
	ФормаНастройки.ЭлементыФормы.ТабличноеПолеЖурналы.ТекущаяСтрока = СтрокаКаталога;
	ФормаЖурнала = ФормаНастройки.ОткрытьФормуРедактированияЖурнала();
	Если пЭтоТекстSDBL Тогда
		УстановитьОтборПоСвойствуСобытияВФормеЖурнала(ФормаЖурнала, "SDBL", "sdbl", ШаблонЗапроса, , ИмяБазы);
	Иначе
		Если Не ЗначениеЗаполнено(ТипСУБД) Тогда
			ВызватьИсключение "Для текста СУБД необходимо указать тип СУБД";
		КонецЕсли; 
		УстановитьОтборПоСвойствуСобытияВФормеЖурнала(ФормаЖурнала, ТипСУБД, "sql", ШаблонЗапроса, , ИмяБазы);
	КонецЕсли;

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

// Сравнение - Строка - как оно задается в настройке техножурнала (eq, ne, like и т.д.)
Процедура УстановитьОтборПоСвойствуСобытияВФормеЖурнала(ФормаЖурнала, ИмяСобытия, Знач ИмяСвойства, Знач ШаблонЗапроса, Сравнение = "like", Знач ИмяБазы = "") Экспорт 
	
	ТабличноеПолеСписокСобытий = ФормаЖурнала.ЭлементыФормы.ТабличноеПолеСписокСобытий;
	ТабличноеПолеСписокСобытий.ВыделенныеСтроки.Очистить();
	СтрокаСобытия = ФормаЖурнала.УстановитьРегистрациюСобытия(ИмяСобытия, Истина);
	ТабличноеПолеСписокСобытий.ТекущаяСтрока = СтрокаСобытия;
	ФормаЖурнала.УстановитьЭлементОтбораВВыделенныхГруппахИ(ИмяСвойства, ШаблонЗапроса, Сравнение);
	Если Истина
		И ЗначениеЗаполнено(ИмяБазы) 
		И Не ирКэш.ЭтоФайловаяБазаЛкс() 
	Тогда
		// К сожалению в файловой СУБД это свойство не заполняется
		//ФормаЖурнала.КП_ДетальныйФильтрСобытийТекущаяБаза();
		ФормаЖурнала.УстановитьЭлементОтбораВВыделенныхГруппахИ("p:processname", ИмяБазы);
	КонецЕсли; 

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

#КонецЕсли 

Функция ПолучитьВариантПросмотраТекстПоИмениРеквизита(ИмяРеквизита) Экспорт

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

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

Функция ПреобразоватьЗначениеВSDBL(Ссылка) Экспорт
	
	СтруктураБД = ирКэш.ПолучитьСтруктуруХраненияБДЛкс(,, мАдресЧужойСхемыБД);
	Если ТипЗнч(Ссылка) = Тип("Строка") Тогда
		Текст = "";
	Иначе
		СтруктураПоиска = Новый Структура("Метаданные, Назначение", Ссылка.Метаданные().ПолноеИмя(), "Основная");
		СтрокаТаблицы = СтруктураБД.НайтиСтроки(СтруктураПоиска)[0];
		RegExp = ирКэш.Получить().RegExp;
		RegExp.Pattern = "\d+";
		РезультатПоиска = RegExp.Execute(СтрокаТаблицы.ИмяТаблицыХранения);
		Текст = РезультатПоиска.Item(0).Value + ":" + ирОбщий.ПолучитьГУИДИнверсныйИзПрямогоЛкс("" + Ссылка.УникальныйИдентификатор());
	КонецЕсли; 
	Возврат Текст;
	
КонецФункции

Функция ПолучитьСтруктуруЗапросаИзТекстаБД(ТекстБД, ТипСУБД = "", ПересобратьТекст = Ложь, ПеревестиИндексы = Истина, ПереводитьВМета = Истина, ЗаменитьHexЛитералы = Ложь,
	ВстраиватьПараметры = Истина) Экспорт
	
	Текст = ТекстБД;
	//ТаблицаПараметров = Новый ТаблицаЗначений;
	//ТаблицаПараметров.Колонки.Добавить("ЗначениеSDBL", Новый ОписаниеТипов("Строка"));
	//ТаблицаПараметров.Колонки.Добавить("Значение");
	//ТаблицаПараметров.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка"));
	ТаблицаПараметров = ПараметрыЗапроса.ВыгрузитьКолонки();
	ТаблицаПараметров.Индексы.Добавить("ЗначениеSDBL");
	ТаблицаПараметров.Индексы.Добавить("Имя");
	RegExp = мПлатформа.RegExp;
	RegExp.Global = Истина;
	RegExp.Multiline = Истина;
    Если ЗначениеЗаполнено(ТипСУБД) Тогда
		Если ПереводитьВМета Тогда
			RegExp.Pattern = "TRef\s*=\s*(0x[\da-z]+)"; // замена обращений к типам
			Вхождения = RegExp.Execute(Текст);
			ОбработанныеОбращения = Новый Соответствие;
			Для Каждого Вхождение Из Вхождения Цикл
				ЗначениеСУБД = Вхождение.Value;
				Если ОбработанныеОбращения[ЗначениеСУБД] = Неопределено Тогда
					ПолноеИмяМД = ирОбщий.ПолучитьМетаданныеПоНомеруСсылочнойТаблицыЛкс(ирОбщий.СтрокаHEXtoINTЛкс(Вхождение.SubMatches(0)), мАдресЧужойСхемыБД);
					Если ПолноеИмяМД <> Неопределено Тогда
						ЗаменаСтроки = "TRef = " + ПолноеИмяМД;
						ОбработанныеОбращения[ЗначениеСУБД] = ЗаменаСтроки;
						Текст = СтрЗаменить(Текст, ЗначениеСУБД, ЗаменаСтроки);
					Иначе
						ОбработанныеОбращения[ЗначениеСУБД] = 1;
					КонецЕсли; 
				КонецЕсли; 
			КонецЦикла;
			RegExp.Pattern = "^\s*\(@P\d+\s+\w+(?:\(\d+(?:,\d+)?\))?(,@P\d+\s+\w+(?:\(\d+(?:,\d+)?\))?)*\)"; // для удаления типов параметров MSSQL
			Текст = RegExp.Replace(Текст, "");
		КонецЕсли; 
    Иначе
		RegExp.Pattern = "([A-F0-9]+):([A-F0-9]+|0x[A-F0-9]+)"; // замена ссылочных констант
		Вхождения = RegExp.Execute(Текст);
		Для Каждого Вхождение Из Вхождения Цикл
			ЗначениеSDBL = Вхождение.Value;
			Если СтрДлина(ЗначениеSDBL) < 32 Тогда
				// Защита от частей литерала Дата
				Продолжить;
			КонецЕсли; 
			Если ТаблицаПараметров.Найти(ЗначениеSDBL, "ЗначениеSDBL") = Неопределено Тогда
				ЗначениеПараметра = ирОбщий.ПреобразоватьЗначениеИзSDBLЛкс(ЗначениеSDBL, мАдресЧужойСхемыБД);
				СтрокаПараметра = ирОбщий.НайтиДобавитьПараметрСсылкуВТаблицуЛкс(ТаблицаПараметров,,, ЗначениеПараметра);
				СтрокаПараметра.ЗначениеSDBL = ЗначениеSDBL;
				ОбъектМД = ирОбщий.ПолучитьМетаданныеЛкс(ЗначениеПараметра);
				Если ОбъектМД <> Неопределено Тогда
					СтрокаПараметра.Метаданные = ОбъектМД.ПолноеИмя();
				КонецЕсли; 
				Если ПереводитьВМета Тогда
					Текст = СтрЗаменить(Текст, ЗначениеSDBL, "&" + СтрокаПараметра.Имя);
				КонецЕсли; 
			КонецЕсли; 
		КонецЦикла;
	КонецЕсли;
	Если ЗаменитьHexЛитералы Тогда
		RegExp.Pattern = "0x[\da-z]+"; // замена значений констант
		Вхождения = RegExp.Execute(Текст);
		СоответствиеКонстант = Новый Соответствие;
		Для Каждого Вхождение Из Вхождения Цикл
			ЗначениеСУБД = Вхождение.Value;
			Если СоответствиеКонстант[ЗначениеСУБД] = Неопределено Тогда
				ЗаменаСтроки = "_" + ЗначениеСУБД;
				СоответствиеКонстант[ЗначениеСУБД] = ЗаменаСтроки;
				Текст = СтрЗаменить(Текст, ЗначениеСУБД, ЗаменаСтроки);
			КонецЕсли; 
		КонецЦикла;
	КонецЕсли; 
	//RegExp.Pattern = "#(T[\d_A-Z]+)"; // имена временных таблиц
	//Текст = RegExp.Replace(Текст, "_$1");
	RegExp.Pattern = "\{ts '(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)'\}"; // литералы Дата DBV8DBEng
	Текст = RegExp.Replace(Текст, "DATETIME($1,$2,$3,$4,$5,$6)");
	ТаблицаТаблиц = Новый ТаблицаЗначений;
	Если ПереводитьВМета Тогда
		RegExp.Pattern = "N'([^']*)'"; // для замены юникодных литералов типа Строка MSSQL
		Текст = RegExp.Replace(Текст, """$1""");
	КонецЕсли; 
	ТекстМета = ПеревестиТекстБДВТерминыМетаданных(Текст,,, ТипСУБД, ТаблицаТаблиц, 999999, ПеревестиИндексы, ПереводитьВМета);
	Если Не ПереводитьВМета Тогда
		ТекстМета = Текст;
	КонецЕсли; 
	ТаблицаТаблиц.Сортировать("ИмяМета");
	ЧастьПараметров = "";
	Если ЗначениеЗаполнено(ТипСУБД) Тогда
		ДиалектSQL = "MSSQL";
		ПозицияНачалаПараметров = Найти(ТекстМета, "p_0:");
		Если ПозицияНачалаПараметров > 0 Тогда
			ЧастьПараметров = Сред(ТекстМета, ПозицияНачалаПараметров);
			ТекстМета = Лев(ТекстМета, ПозицияНачалаПараметров - 1);
		КонецЕсли; 
	Иначе
		ДиалектSQL = "1С";
	КонецЕсли; 
	ШаблонИмениПараметра = "Parameter";
	Если ЗначениеЗаполнено(ЧастьПараметров) Тогда
		ТекстовыйДокумент = Новый ТекстовыйДокумент;
		ТекстовыйДокумент.УстановитьТекст(ЧастьПараметров);
		Для Счетчик = 1 По ТекстовыйДокумент.КоличествоСтрок() Цикл
			СтрокаПараметра = ТаблицаПараметров.Добавить();
			Фрагменты = ирОбщий.ПолучитьМассивИзСтрокиСРазделителемЛкс(ТекстовыйДокумент.ПолучитьСтроку(Счетчик), ":");
			СтрокаПараметра.Имя = СокрЛП(Фрагменты[0]);
			СтрокаПараметра.Значение = СокрЛП(Фрагменты[1]);
		КонецЦикла;
	КонецЕсли;
	
	// Встроим имена парамаетров вместо знаков "?"
	ЗаписьXML = Новый ЗаписьXML;
	ЗаписьXML.УстановитьСтроку("");
	ИндексПараметра = 0;
	СтрокаПоиска = "?";
	Пока ТекстМета <> "" Цикл
		ПозицияПараметра = Найти(ТекстМета, СтрокаПоиска);
		Если ПозицияПараметра > 0 Тогда
			Если ИндексПараметра < ТаблицаПараметров.Количество() Тогда
				СтрокаПараметра = ТаблицаПараметров[ИндексПараметра];
			Иначе
				СтрокаПараметра = ТаблицаПараметров.Добавить();
				СтрокаПараметра.Имя = ШаблонИмениПараметра + XMLСтрока(ТаблицаПараметров.Количество() - 1);
			КонецЕсли; 
			ЗаписьXML.ЗаписатьБезОбработки(Лев(ТекстМета, ПозицияПараметра - 1) + СтрокаПоиска + СтрокаПараметра.Имя);
			ТекстМета = Сред(ТекстМета, ПозицияПараметра + СтрДлина(СтрокаПоиска));
			ИндексПараметра = ИндексПараметра + 1;
		Иначе
			ЗаписьXML.ЗаписатьБезОбработки(ТекстМета);
			ТекстМета = "";
		КонецЕсли; 
	КонецЦикла;
	ТекстМета = ЗаписьXML.Закрыть();
	
	Если Истина
		И ПересобратьТекст 
		И ЗначениеЗаполнено(ТекстМета) 
	Тогда
		ПолеТекста = ирОбщий.ПолучитьОбъектПоПолномуИмениМетаданныхЛкс("Обработка.ирКлсПолеТекстовогоДокументаСКонтекстнойПодсказкой");
		ПолеТекста.ИнициализироватьНеинтерактивно(1);
		//ПолеТекста.ПолеТекстовогоДокумента = ПолеТекстаЗапроса;
		КонструкторЗапроса = ПолеТекста.ПолучитьФорму("КонструкторЗапроса");
		КонструкторЗапроса.Английский1С = Не ПереводитьВМета;
		ИменованныеПараметры = Истина;
		Если ПолеТекста.ЗагрузитьТекстВКонструктор(ТекстМета, КонструкторЗапроса,, ДиалектSQL, ИменованныеПараметры) Тогда 
			ТекстМета = КонструкторЗапроса.СобратьПолныйТекст(, Истина);
		КонецЕсли;
	КонецЕсли; 
	Если ВстраиватьПараметры Тогда
		ЗаписьXML = Новый ЗаписьXML;
		ЗаписьXML.УстановитьСтроку("");
		ИндексПараметра = 0;
		Пока ТекстМета <> "" Цикл
			ПозицияПараметра = 0;
			Если ИндексПараметра < ТаблицаПараметров.Количество() Тогда
				СтрокаПоиска = "?" + ТаблицаПараметров[ИндексПараметра].Имя;
				ПозицияПараметра = Найти(ТекстМета, СтрокаПоиска);
			КонецЕсли; 
			Если Истина
				И ПозицияПараметра > 0 
			Тогда
				ЗаписьXML.ЗаписатьБезОбработки(Лев(ТекстМета, ПозицияПараметра - 1) + ТаблицаПараметров[ИндексПараметра].Значение);
				ИндексПараметра = ИндексПараметра + 1;
				ТекстМета = Сред(ТекстМета, ПозицияПараметра + СтрДлина(СтрокаПоиска));
			Иначе
				ЗаписьXML.ЗаписатьБезОбработки(ТекстМета);
				ТекстМета = "";
			КонецЕсли; 
		КонецЦикла;
		ТекстМета = ЗаписьXML.Закрыть();
	КонецЕсли; 
	Результат = Новый Структура();
	Результат.Вставить("Текст", ТекстМета);
	Результат.Вставить("Параметры", ТаблицаПараметров);
	Результат.Вставить("Таблицы", ТаблицаТаблиц);
	Возврат Результат;
	
КонецФункции

Функция НайтиВызовыМетодовМодулей(ИмяМодуля, НомерНачальнойСтроки, НомерКонечнойСтроки, ТолькоОдну = Истина)

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

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

// Получить словарь имен таблиц входящих в запрос и соответствующих
// шаблонам словаря метаданных
//
// Параметры:
//  ТекстЗапроса - Строка, текст запроса для которого строится словарь
//  СловарьШаблоновМетаданных - Соответствие, словарь шаблонов метаданных
//  ТипСУБД - Строка (Перечисление.ТипСУБД)
//
// Возвращаемое значение:
//  Соответствие - Словарь имен таблиц запроса
//
Функция ПолучитьСловарьЗапроса(Знач ТекстЗапроса, СловарьШаблоновМетаданных, ТипСУБД = "") Экспорт
	
	Перем КоличествоСимволов;
	
	ТекстЗапроса = НРег(ТекстЗапроса);
	ДлинаТекстаЗапроса = СтрДлина(ТекстЗапроса);
	СловарьЗапроса = Новый Соответствие;
	
	//Если НРег(ТипСУБД) = НРег("DB2") Тогда
	//	ТекстЗапроса = ВРег(ТекстЗапроса);
	//КонецЕсли;
	ЗавершающиеСимволы = " )(.,][" + Символы.ПС + Символы.ВК;
	ЗавершающиеСимволы = ЗавершающиеСимволы + """"; // Для поддержки LOCKS в sp_whoisactive
	Для Каждого СтрокаСловаряМетаданных Из СловарьШаблоновМетаданных Цикл
		
		// Скопировать текст запроса для обработки
		Текст = ТекстЗапроса;
		
		// Искать имя таблицы по шаблону
		Пока Истина Цикл
			
			// Получить начало шаблона
			Если СтрокаСловаряМетаданных.Значение = 0 Тогда
				Шаблон = СтрокаСловаряМетаданных.Ключ;
			Иначе
				Шаблон = Лев(СтрокаСловаряМетаданных.Ключ, Найти(СтрокаСловаряМетаданных.Ключ, "1") - 1);
			КонецЕсли;
			
			ЭлементСловаря = Неопределено;
			ДлинаШаблона = СтрДлина(Шаблон);
			ДлинаТекста = СтрДлина(Текст);
			
			// Найти позицию вхождения шаблона в тексте запроса
			ПозицияШаблона = Найти(Текст, Шаблон);
			
			// Если шаблона в тексте запроса нет, прекратить поиск этого шаблона
			Если ПозицияШаблона = 0 Или ДлинаТекста < ПозицияШаблона + ДлинаШаблона - 1 Тогда
				Прервать;
			КонецЕсли;
			
			// Удалить из текста запроса обработанный фрагмент
			Текст = Прав(Текст, ДлинаТекста - ПозицияШаблона - ДлинаШаблона + 1);
			ЭлементСловаря = Шаблон;
			
			// Если шаблон содержит счетчик
			Если СтрокаСловаряМетаданных.Значение <> 0 Тогда
				
				// Получить значение счетчика
				ЗначениеЧисла = ПолучитьЧислоСтрокой(Текст, КоличествоСимволов);
				
				Если ЗначениеЧисла = Неопределено Тогда
					ЭлементСловаря = Неопределено;
					Продолжить;
				КонецЕсли;
				
				// Удалить из текста запроса текстовое представление счетчика имени
				ЭлементСловаря = ЭлементСловаря + ЗначениеЧисла;
				Текст = Прав(Текст, СтрДлина(Текст) - КоличествоСимволов);
				
				// Если счетчиков больше одного
				Для Сч = 1 По СтрокаСловаряМетаданных.Значение - 1 Цикл
					
					// Получить следующий фрагмент шаблона
					ПозицияПервогоСлота = Найти(СтрокаСловаряМетаданных.Ключ, Строка(Сч));
					ПозицияВторогоСлота = Найти(СтрокаСловаряМетаданных.Ключ, Строка(Сч + 1));
					ФрагментШаблона = Сред(СтрокаСловаряМетаданных.Ключ, ПозицияПервогоСлота + 1, ПозицияВторогоСлота - ПозицияПервогоСлота - 1);
					ДлинаФрагментаШаблона = СтрДлина(ФрагментШаблона);
					ДлинаТекста = СтрДлина(Текст);
					
					Если ДлинаФрагментаШаблона > ДлинаТекста Или Лев(Текст, ДлинаФрагментаШаблона) <> ФрагментШаблона Тогда
						ЭлементСловаря = Неопределено;
						Прервать;
					КонецЕсли;
					
					// Получить значение счетчика для фрагмента шаблона
					Текст = Прав(Текст, ДлинаТекста - ДлинаФрагментаШаблона);
					ЗначениеЧисла = ПолучитьЧислоСтрокой(Текст, КоличествоСимволов);
					Текст = Прав(Текст, СтрДлина(Текст) - КоличествоСимволов);
					
					Если ЗначениеЧисла = Неопределено Тогда
						ЭлементСловаря = Неопределено;
						Прервать;
					КонецЕсли;
					
					// Дополнить имя таблицы найденым значением шаблона
					ЭлементСловаря = ЭлементСловаря + ФрагментШаблона + ЗначениеЧисла;
				КонецЦикла;
				
				Если ЭлементСловаря = Неопределено Тогда
					Продолжить;
				КонецЕсли;
			КонецЕсли;
			
			// Если найдено имя таблицы по шаблону
			Если ЭлементСловаря <> Неопределено Тогда
				ДлинаТекста = СтрДлина(Текст);
				
				// Проверить окончание имени для полного соответствия шаблону
				Если ДлинаТекста > 0 Тогда
					ЗавершающийСимвол = Лев(Текст, 1);
					Текст = Прав(Текст, ДлинаТекста - 1);
					Если Найти(ЗавершающиеСимволы, ЗавершающийСимвол) = 0 Тогда
						Продолжить;
					КонецЕсли;
				КонецЕсли;
				
				// Сохранить найденное имя таблицы
				СловарьЗапроса.Вставить(ЭлементСловаря);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Возврат СловарьЗапроса;
	
КонецФункции // ПолучитьСловарьЗапроса()

// Получить число из строки в которой число находится в начале строки
//
// Праметры:
//  ИсходнаяСтрока - Строка, строка в которой находится число
//
// Возвращаемое значение:
//  Число - если оно есть, неопределено, если числа нет
//
Функция ПолучитьЧислоСтрокой(ИсходнаяСтрока, КоличествоСимволов)
	
	КоличествоСимволов = 0;
	ДлинаСтроки = СтрДлина(ИсходнаяСтрока);
	
	Для Сч = 1 По ДлинаСтроки Цикл
		
		ТекущийСимвол = КодСимвола(Сред(ИсходнаяСтрока, Сч, 1));
		
		Если 48 <= ТекущийСимвол И ТекущийСимвол <= 57 Тогда
			КоличествоСимволов = КоличествоСимволов + 1;
		Иначе
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если КоличествоСимволов > 0 Тогда
		Возврат Лев(ИсходнаяСтрока, КоличествоСимволов);
	Иначе
		Возврат Неопределено;
	КонецЕсли;
	
КонецФункции // ПолучитьЧислоСтрокой()

// Перевести часть запроса из терминов СУБД в термины метаданных
//
// Параметры:
//  Запрос - Строка, сапрос в терминах СУБД
//  СтруктураХраненияБазыДанных - ТаблицаЗначений
//  СловарьШаблоновМетаданных - Соответствие, подробности в функции
//                 ПолучитьСловарьШаблоновМетаданных()
//  ТипСУБД - Строка, (Перечисление.ТипСУБД)
//  выхТаблицы - ТаблицаЗначений, *Неопределено - описание использованных в тексте таблиц, заполняется только если таблица передана (без колонок)
//
// Возвращаемое значение:
//  Строка, запрос в терминах метаданных
//
Функция ПеревестиТекстБДВТерминыМетаданных(Знач Текст, СтруктураХраненияБазыДанных = Неопределено,
    СловарьШаблоновМетаданных = Неопределено, Знач ТипСУБД = "", выхТаблицы = Неопределено, ДопустимыйРазмер = 20000, ПереводитьИндексы = Истина, ПереводитьВМета = Истина,
	ЭтоГарантированоТекстСобственнойБазы = Ложь) Экспорт
										  
	Если выхТаблицы <> Неопределено Тогда
		#Если Сервер И Не Сервер Тогда
		    выхТаблицы = Новый ТаблицаЗначений;
		#КонецЕсли
		//выхТаблицы.Колонки.Очистить();
		Если выхТаблицы.Колонки.Найти("ИмяБД") = Неопределено Тогда
			выхТаблицы.Колонки.Добавить("ИмяБД", Новый ОписаниеТипов("Строка"));
		КонецЕсли; 
		Если выхТаблицы.Колонки.Найти("ИмяМета") = Неопределено Тогда
			выхТаблицы.Колонки.Добавить("ИмяМета", Новый ОписаниеТипов("Строка"));
		КонецЕсли; 
	КонецЕсли; 
	Если Ложь
		Или Не ЗначениеЗаполнено(Текст) 
	Тогда
		Возврат "";
	КонецЕсли; 
	Если Истина
		И ДопустимыйРазмер > 0 
		И СтрДлина(Текст) > ДопустимыйРазмер
		И ПереводитьВМета
	Тогда
		Возврат РезультатПереводаСлишкомБольшогоТекста();
	КонецЕсли; 
	Если ирОбщий.СтрокиРавныЛкс(ТипСУБД, "sdbl") Тогда
		ТипСУБД = "";
	КонецЕсли; 
	АдресЧужойСхемыБД = "";
	Если Не ЭтоГарантированоТекстСобственнойБазы Тогда
		АдресЧужойСхемыБД = мАдресЧужойСхемыБД;
	КонецЕсли; 
	Если СтруктураХраненияБазыДанных = Неопределено Тогда
		СтруктураХраненияБазыДанных = ирКэш.ПолучитьСтруктуруХраненияБДЛкс(ЗначениеЗаполнено(ТипСУБД),, АдресЧужойСхемыБД);
	КонецЕсли; 
	Если СловарьШаблоновМетаданных = Неопределено Тогда
		СловарьШаблоновМетаданных = ирКэш.ПолучитьСловарьШаблоновМетаданныхЛкс(ЗначениеЗаполнено(ТипСУБД), АдресЧужойСхемыБД);
	КонецЕсли; 
	Текст = Текст + Символы.ПС;
	СловарьЗапроса = ПолучитьСловарьЗапроса(Текст, СловарьШаблоновМетаданных, ТипСУБД);
	
	Если НРег(ТипСУБД) = НРег("DB2") Тогда
		Текст = ВРег(Текст);
	КонецЕсли;
	
	// Поиск имен таблиц в строке запроса
	Если СловарьЗапроса.Количество() > 10 Тогда
		Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(СловарьЗапроса.Количество(), "Преобразование в имена метаданных");
	КонецЕсли;
	Для Каждого СтрокаСловаряЗапроса Из СловарьЗапроса Цикл
		Если Индикатор <> Неопределено Тогда
			ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
		КонецЕсли;
		ОписаниеТаблицы = Неопределено;
		Если выхТаблицы <> Неопределено Тогда
			Если Найти(СтрокаСловаряЗапроса.Ключ, ".") = 0 Тогда
				ОписаниеТаблицы = выхТаблицы.Добавить();
				ОписаниеТаблицы.ИмяБД = СтрокаСловаряЗапроса.Ключ;
			КонецЕсли; 
		КонецЕсли;
		// Получить имя таблицы
		СтрокаСтруктуры = СтруктураХраненияБазыДанных.Найти(ирОбщий.ПолучитьПоследнийФрагментЛкс(СтрокаСловаряЗапроса.Ключ), "КраткоеИмяТаблицыХранения");
		Если СтрокаСтруктуры = Неопределено Тогда
			// Видимо чужие метаданные
			Продолжить;
		КонецЕсли; 
		ИмяТаблицы = СтрокаСтруктуры.КраткоеИмяТаблицыХранения;
		МетаПолноеИмяТаблицы = СтрокаСтруктуры.ИмяТаблицы;
		Если ОписаниеТаблицы <> Неопределено Тогда
			ОписаниеТаблицы.ИмяМета = МетаПолноеИмяТаблицы;
		КонецЕсли;
		Если Не ПереводитьВМета Тогда
			Продолжить;
		КонецЕсли; 
		Синонимы = ПолучитьСинонимы(Текст, ИмяТаблицы, МетаПолноеИмяТаблицы, ТипСУБД);
		//Синонимы.Вставить(ИмяТаблицы, МетаИмяТаблицы);
		ЭтоТабличнаяЧасть = СтрокаСтруктуры.Назначение = "ТабличнаяЧасть";
		Для Каждого СтрокаПоля Из СтрокаСтруктуры.Поля Цикл
			Если Найти(Текст, СтрокаПоля.ИмяПоляХранения) = 0 Тогда
				Продолжить;
			КонецЕсли; 
			ПредставлениеПоля = ирОбщий.ПолучитьПредставлениеПоляБДЛкс(СтрокаПоля, ТипСУБД <> "", ЭтоТабличнаяЧасть);
			Если Не ЗначениеЗаполнено(ПредставлениеПоля) Тогда
				Продолжить;
			КонецЕсли; 
			RegExpМета.Pattern = шГраничныйСимволИмени + СтрокаПоля.ИмяПоляХранения + "([^&" + шБуква + "\d]|Balance|Turnover|Receipt|Expense|^|$)";
			// Можно оптимизировать путем создания шаблона мультизамены
			Текст = RegExpМета.Replace(Текст, "$1" + ПредставлениеПоля + "$2"); 
		КонецЦикла;
		Если ПереводитьИндексы Тогда
			Для Каждого СтрокаИндекса Из СтрокаСтруктуры.Индексы Цикл
				ПредставлениеИндекса = СтрокаИндекса.ИмяИндекса;
				СтрокаДляЗамены = СтрокаИндекса.ИмяИндексаХранения;
				Если ирОбщий.СтрокиРавныЛкс(ТипСУБД, "DBPOSTGRS") Тогда
					СтрокаДляЗамены = ВРег(СтрокаИндекса.ИмяИндексаХранения);
				ИначеЕсли ирОбщий.СтрокиРавныЛкс(ТипСУБД, "DBV8DBEng") Тогда
					СтрокаДляЗамены = ВРег(СтрокаИндекса.ИмяИндексаХранения);
				КонецЕсли;
				// Имена индексов достаточно уникальны, чтобы использовать СтрЗаменить
				Текст = СтрЗаменить(Текст, СтрокаДляЗамены, ПредставлениеИндекса);
			КонецЦикла;
		КонецЕсли; 
		Для Каждого Синоним Из Синонимы Цикл
			// Заменить псевдоним таблицы
			RegExpМета.Pattern = шГраничныйСимволИмени + Синоним.Ключ + шГраничныйСимволИмени;
			Текст = RegExpМета.Replace(Текст, "$1" + Синоним.Значение + "$2");
			//RegExpМета.Pattern = ИмяТаблицы + " " + Синоним.Ключ + шГраничныйСимволИмени;
			//Запрос = RegExpМета.Replace(Текст, ИмяТаблицы + " AS " + Синоним.Значение + "$1");
		КонецЦикла;
		// Заменить имя таблицы
		RegExpМета.Pattern = шГраничныйСимволИмени + СтрокаСтруктуры.ИмяТаблицыХранения + шГраничныйСимволИмени;
		Текст = RegExpМета.Replace(Текст, "$1" + МетаПолноеИмяТаблицы + "$2");
		Если НРег(СтрокаСтруктуры.ИмяТаблицыХранения) <> СтрокаСтруктуры.КраткоеИмяТаблицыХранения Тогда
			RegExpМета.Pattern = шГраничныйСимволИмени + СтрокаСтруктуры.КраткоеИмяТаблицыХранения + шГраничныйСимволИмени;
			Текст = RegExpМета.Replace(Текст, "$1" + ирОбщий.ПолучитьПоследнийФрагментЛкс(МетаПолноеИмяТаблицы) + "$2");
		КонецЕсли; 
	КонецЦикла;
	Если Индикатор <> Неопределено Тогда
		ирОбщий.ОсвободитьИндикаторПроцессаЛкс(Индикатор);
	КонецЕсли; 
	// Заменим приведение к ссылочному типу 
	Если Не ЗначениеЗаполнено(ТипСУБД) Тогда
		Текст = СтрЗаменить(Текст, "AS REF(", "AS (");
	КонецЕсли; 
	Текст = СокрП(Текст);
	Возврат Текст;
	
КонецФункции

Функция РезультатПереводаСлишкомБольшогоТекста() Экспорт 
	
	Возврат "<Текст слишком большой для быстрого перевода>"

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

// Получить синонимы имени таблицы в запросе
//
// Параметры:
//  Запрос - Строка, текст запроса
//  ИмяТаблицы - Строка, имя таблицы для которой ищутся синонимы
//  МетаИмяТаблицы - Строка, имя таблицы в терминах метаданных
//
// Возвращаемое занчение:
//  Соответствие, имена синонимов и их мета имена
//
Функция ПолучитьСинонимы(Запрос, ИмяТаблицы, МетаИмяТаблицы, ТипСУБД = "") Экспорт
	
	// Построить список синонимом ими таблицы
	Синонимы = Новый Соответствие;
	RegExpМета.Pattern = ИмяТаблицы + " " + "(?:([" + шБуква + "\d]+)|\(([" + шБуква + "\d]+)\))" + шГраничныйСимволИмени;
	Вхождения = RegExpМета.Execute(Запрос);
	ПсевдонимТаблицы = ирОбщий.ПолучитьПоследнийФрагментЛкс(МетаИмяТаблицы, ".");
	Для Каждого Вхождение Из Вхождения Цикл
		Синоним = Вхождение.SubMatches(0);
		Если ирОбщий.ЛиПустаяПодгруппаRegExpЛкс(Синоним) Тогда
			Синоним = Вхождение.SubMatches(1);
		КонецЕсли; 
		Если Ложь
			Или (Истина
				И ирОбщий.СтрокиРавныЛкс(ТипСУБД, "DBMSSQL")
				И ирОбщий.СтрокиРавныЛкс(Синоним, "WITH"))
			Или ирОбщий.СтрокиРавныЛкс(Синоним, "WHERE")
			Или ирОбщий.СтрокиРавныЛкс(Синоним, "GROUP")
			Или ирОбщий.СтрокиРавныЛкс(Синоним, "HAVING")
			Или ирОбщий.СтрокиРавныЛкс(Синоним, "SET")
			Или ирОбщий.СтрокиРавныЛкс(Синоним, "ORDER")
			Или ирОбщий.СтрокиРавныЛкс(Синоним, "THEN")
		Тогда
			Продолжить;
		КонецЕсли; 
		Синонимы.Вставить(Синоним, ПсевдонимТаблицы + "_" + Синоним);
	КонецЦикла;
		
	Возврат Синонимы;
	
КонецФункции // ПолучитьСинонимы()

//ирПортативный лФайл = Новый Файл(ИспользуемоеИмяФайла);
//ирПортативный ПолноеИмяФайлаБазовогоМодуля = Лев(лФайл.Путь, СтрДлина(лФайл.Путь) - СтрДлина("Модули\")) + "ирПортативный.epf";
//ирПортативный #Если Клиент Тогда
//ирПортативный 	Контейнер = Новый Структура();
//ирПортативный 	Оповестить("ирПолучитьБазовуюФорму", Контейнер);
//ирПортативный 	Если Не Контейнер.Свойство("ирПортативный", ирПортативный) Тогда
//ирПортативный 		ирПортативный = ВнешниеОбработки.ПолучитьФорму(ПолноеИмяФайлаБазовогоМодуля);
//ирПортативный 		ирПортативный.Открыть();
//ирПортативный 	КонецЕсли; 
//ирПортативный #Иначе
//ирПортативный 	ирПортативный = ВнешниеОбработки.Создать(ПолноеИмяФайлаБазовогоМодуля, Ложь); // Это будет второй экземпляр объекта
//ирПортативный #КонецЕсли
//ирПортативный ирОбщий = ирПортативный.ПолучитьОбщийМодульЛкс("ирОбщий");
//ирПортативный ирКэш = ирПортативный.ПолучитьОбщийМодульЛкс("ирКэш");
//ирПортативный ирСервер = ирПортативный.ПолучитьОбщийМодульЛкс("ирСервер");
//ирПортативный ирПривилегированный = ирПортативный.ПолучитьОбщийМодульЛкс("ирПривилегированный");

мПлатформа = ирКэш.Получить();
мНепустыеКолонкиЖурнала = Новый Структура();
//ЭтотОбъект.НаложениеПриДозагрузкеСекунд = 30;
RegExpПараметры = мПлатформа.ПолучитьНовыйВычислительРегулярныхВыражений();
RegExpПараметры.IgnoreCase = Истина;
RegExpПараметры.Global = Истина;
RegExpПараметры.Pattern = "([^A-ZА-ЯЁ_0-9]|^)(?:[A-F0-9]+:[A-F0-9]+|0x[A-F0-9]+|[A-F0-9]+(?:-[A-F0-9]+)+-[A-F0-9]+|(#TT?)[_A-F0-9]+|[0-9]+)"; // для стирания констант и имен временных таблиц
RegExpМета = мПлатформа.ПолучитьНовыйВычислительРегулярныхВыражений();
RegExpМета.IgnoreCase = Истина;
RegExpМета.Global = Истина;

мСписокКолонок = Новый СписокЗначений;
//мСписокКолонок.Добавить("Name",                 "Событие"); // В некоторых случаях нужно
мСписокКолонок.Добавить("SrcName",              "Источник");
мСписокКолонок.Добавить("OSThread",             "ПотокОС");
мСписокКолонок.Добавить("process",              "ТипПроцессаОС");
мСписокКолонок.Добавить("p:processName",        "Инфобаза");
мСписокКолонок.Добавить("t:clientID",           "Соединение_");
мСписокКолонок.Добавить("t:applicationName",    "Приложение");
мСписокКолонок.Добавить("t:computerName",       "Компьютер");
мСписокКолонок.Добавить("t:connectID",          "TCPСоединение");
мСписокКолонок.Добавить("SessionID",            "Сеанс");
мСписокКолонок.Добавить("Usr",                  "Пользователь");
мСписокКолонок.Добавить("OSException",          "ИсключениеОС");
мСписокКолонок.Добавить("Interface",            "Интерфейс");
мСписокКолонок.Добавить("Method",               "Метод");
мСписокКолонок.Добавить("Exception",            "ТипИсключения");
мСписокКолонок.Добавить("Descr",                "Описание");
мСписокКолонок.Добавить("ClientComputerName",   "КомпьютерКлиента");
мСписокКолонок.Добавить("ServerComputerName",   "КомпьютерСервера");
мСписокКолонок.Добавить("UserName",             "Пользователь");
мСписокКолонок.Добавить("ConnectString",        "СтрокаСоединения");
мСписокКолонок.Добавить("ProcessName",          "ТипПроцессаОС");
мСписокКолонок.Добавить("SrcProcessName",       "Инфобаза");
//мСписокКолонок.Добавить("Trans",                "Транзакция");
мСписокКолонок.Добавить("Func",                 "Действие");
мСписокКолонок.Добавить("Sdbl",                 "ТекстSDBL");
мСписокКолонок.Добавить("dbpid",                "ПроцессСУБД");
мСписокКолонок.Добавить("Sql",                  "ТекстСУБД");
мСписокКолонок.Добавить("NParams",              "КоличествоПараметров");
мСписокКолонок.Добавить("Rows",                 "ЧислоСтрок");
мСписокКолонок.Добавить("RowsAffected",         "ЧислоИзменныхСтрок");
мСписокКолонок.Добавить("planSQLText",          "ПланСУБД");
мСписокКолонок.Добавить("Context",              "Контекст");
мСписокКолонок.Добавить("CatName",              "КаталогСУБД");
мСписокКолонок.Добавить("WaitConnections",      "Блокираторы");
мСписокКолонок.Добавить("FileName",             "ФайлСУБД");
мСписокКолонок.Добавить("DeadlockConnectionIntersections", "Взаимоблокировка");
мСписокКолонок.Добавить("Finish",               "ПричинаЗавершения");
мСписокКолонок.Добавить("Err",                  "ТипСообщения");
мСписокКолонок.Добавить("Txt",                  "ТекстСообщения");
мСписокКолонок.Добавить("URI",                  "Ресурс");
мСписокКолонок.Добавить("Administrator",        "Администратор");
мСписокКолонок.Добавить("Body",                 "РазмерЗапроса");
мСписокКолонок.Добавить("Cluster",              "НомерПорта");
мСписокКолонок.Добавить("Val",                  "ЗначениеПараметра");

// Свойства найденные экспериментально. Они не документированы.
мСписокКолонок.Добавить("Query",                "ТекстЗапроса1С"); // События: QERR
мСписокКолонок.Добавить("From",                 "From_"); // События: DBV8DBENG
//мСписокКолонок.Добавить("AppID",                "AppID"); // События: QERR, DBMSSQL (дублируется t:applicationName), SDBL (дублирует t:applicationName)
мСписокКолонок.Добавить("Index",                "Index_");
//мСписокКолонок.Добавить("setUnhandledExceptionFilter", "setUnhandledExceptionFilter");
мСписокКолонок.Добавить("Module",               "МодульКонфигурации"); // События: EXCPCNTX
мСписокКолонок.Добавить("ClientID",             "Клиент"); // События: EXCPCNTX, SCALL, EXCP (дублируется t:clientID ?)

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

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

мСвойстваСИменамиБД = Новый Структура();
мСвойстваСИменамиБД.Вставить("ТекстSDBL", Ложь);
мСвойстваСИменамиБД.Вставить("ТекстSDBLШаблон", Ложь);
мСвойстваСИменамиБД.Вставить("ТекстСУБД", Истина);
мСвойстваСИменамиБД.Вставить("ТекстСУБДШаблон", Ложь);
мСвойстваСИменамиБД.Вставить("ПланСУБД", Истина);
мСвойстваСИменамиБД.Вставить("Взаимоблокировка", Ложь);
мСвойстваСИменамиБД.Вставить("Regions", Ложь);
мСвойстваСИменамиБД.Вставить("Locks", Ложь);

мСерверныеТипыПроцессов = Новый Структура;
мСерверныеТипыПроцессов.Вставить("_adminprocess"); // ##AdminProcess##
мСерверныеТипыПроцессов.Вставить("_rphost");
мСерверныеТипыПроцессов.Вставить("_rmngr");
мСерверныеТипыПроцессов.Вставить("_ragent");

МаксТысячСобытий = 100;
мАдресЧужойСхемыБД = "";
шБуква = мПлатформа.шБуква;
шГраничныйСимволИмени = "([^&" + шБуква + "\d]|^|$)";

