514 lines
30 KiB
C#

//using Adaptation.Eaf.Management.ConfigurationData.CellAutomation;
//using Adaptation.Ifx.Eaf.EquipmentConnector.File.Configuration;
//using Adaptation.Shared;
//using Adaptation.Shared.Metrology;
//using Infineon.Monitoring.MonA;
//using System;
//using System.Collections.Generic;
//using System.Diagnostics;
//using System.Globalization;
//using System.IO;
//using System.IO.Compression;
//using System.Linq;
//using System.Text.Json;
//using System.Threading;
//namespace Adaptation.Helpers
//{
// public partial class ConfigData : ConfigDataBase
// {
// internal const object NullData = null;
// internal const int MinFileLength = 100;
// public string IqsFile { get; private set; }
// public string TracePath { get; private set; }
// public Level? Duplicator { get; private set; }
// public string MemoryPath { get; private set; }
// public string VillachPath { get; private set; }
// public string ProgressPath { get; private set; }
// public string IqsQueryFilter { get; private set; }
// public string OriginalDataBioRad { get; private set; }
// public string OpenInsightSiViewer { get; private set; }
// public string OpenInsightFilePattern { get; private set; }
// public string OpenInsightMetrogyViewerAPI { get; private set; }
// public static Dictionary<string, List<long>> DummyRuns { get; private set; }
// private Timer _Timer;
// private int _LastDummyRunIndex;
// private readonly Calendar _Calendar;
// private readonly string _ReportFullPath;
// public ConfigData(ILogic logic, string cellName, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, IList<ModelObjectParameterDefinition> modelObjectParameterDefinitions, string parameterizedModelObjectDefinitionType, bool isEAFHosted) :
// base(cellName, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, isEAFHosted)
// {
// _LastDummyRunIndex = -1;
// UseCyclicalForDescription = false;
// OriginalDataBioRad = "OriginalDataBioRad_";
// CultureInfo cultureInfo = new CultureInfo("en-US");
// _Calendar = cultureInfo.Calendar;
// string firstSourceFileFilter = fileConnectorConfiguration.SourceFileFilter.Split('|')[0];
// if (DummyRuns is null)
// DummyRuns = new Dictionary<string, List<long>>();
// bool isDuplicator = cellInstanceConnectionName.StartsWith(cellName);
// int level = (cellInstanceConnectionName.Length - cellInstanceConnectionName.Replace("-", string.Empty).Length);
// if (!isDuplicator)
// Duplicator = null;
// else
// {
// CellNames.Add(cellName, cellName);
// MesEntities.Add(cellName, cellName);
// Duplicator = (Level)level;
// }
// if (isDuplicator)
// ProcessDataDescription = new Duplicator.Description();
// else
// ProcessDataDescription = new ProcessData.FileRead.Description();
// if (!isDuplicator)
// {
// //Verify(fileConnectorConfiguration, cellInstanceConnectionName);
// if (!EafHosted)
// VerifyProcessDataDescription(logic);
// else
// WriteExportAliases(logic, cellName, cellInstanceConnectionName);
// }
// if (!modelObjectParameterDefinitions.Any())
// {
// CellNames.Add(cellName, "****");
// MesEntities.Add(cellName, "****");
// }
// else
// {
// int index;
// string key;
// string variable = string.Empty;
// Dictionary<string, string> iqsSection = new Dictionary<string, string>();
// Dictionary<string, string> pathSection = new Dictionary<string, string>();
// Dictionary<string, string> commonSection = new Dictionary<string, string>();
// Dictionary<string, string> openInsightSection = new Dictionary<string, string>();
// foreach (ModelObjectParameterDefinition modelObjectParameterDefinition in modelObjectParameterDefinitions)
// {
// if (!modelObjectParameterDefinition.Name.Contains('.'))
// continue;
// else if (modelObjectParameterDefinition.Name.StartsWith("Description.") && (modelObjectParameterDefinition.Name.EndsWith(".EventName") || modelObjectParameterDefinition.Name.EndsWith(".EquipmentType")))
// continue;
// index = modelObjectParameterDefinition.Name.IndexOf(".");
// if (index <= -1)
// continue;
// key = modelObjectParameterDefinition.Name.Substring(0, index);
// variable = modelObjectParameterDefinition.Name.Substring(index + 1);
// if (key == "COMMON")
// commonSection.Add(variable, modelObjectParameterDefinition.Value);
// //else if (key == "CONNECTION STRINGS")
// // connectionStringsSection.Add(variable, modelObjectParameterDefinition.Value);
// else if (key == "IQS")
// iqsSection.Add(variable, modelObjectParameterDefinition.Value);
// else if (key == "OpenInsight")
// openInsightSection.Add(variable, modelObjectParameterDefinition.Value);
// else if (key == "PATH")
// pathSection.Add(variable, modelObjectParameterDefinition.Value);
// //else if (key == "REACTOR")
// // reactorTuples.Add(new Tuple<string, string>(variable, modelObjectParameterDefinition.Value));
// //else if (key == "TIBCO")
// // tibcoSection.Add(variable, modelObjectParameterDefinition.Value);
// else
// throw new Exception(cellInstanceConnectionName);
// }
// if (!iqsSection.Any())
// throw new Exception("IQS section is missing from configuration");
// else
// {
// key = "FILE";
// if (iqsSection.ContainsKey(key))
// IqsFile = iqsSection[key];
// else
// throw new Exception(string.Concat("Missing IQS Configuration entry for ", key));
// if (string.IsNullOrEmpty(IqsFile))
// throw new Exception(string.Format("IQS key {0} is empty", key));
// key = "QUERY";
// if (iqsSection.ContainsKey(key))
// IqsQueryFilter = iqsSection[key];
// else
// throw new Exception(string.Concat("Missing IQS Configuration entry for ", key));
// if (string.IsNullOrEmpty(IqsQueryFilter))
// throw new Exception(string.Format("IQS key {0} is empty", key));
// }
// if (!pathSection.Any())
// throw new Exception("Path section is missing from configuration");
// else
// {
// key = "TRACE";
// if (pathSection.ContainsKey(key) && pathSection[key].StartsWith(@"\\"))
// TracePath = pathSection[key];
// if (!string.IsNullOrEmpty(TracePath) && !Directory.Exists(TracePath))
// Directory.CreateDirectory(TracePath);
// key = "VILLACH";
// if (pathSection.ContainsKey(key) && pathSection[key].StartsWith(@"\\"))
// VillachPath = pathSection[key];
// if (!string.IsNullOrEmpty(VillachPath) && !Directory.Exists(VillachPath))
// Directory.CreateDirectory(VillachPath);
// key = "Progress";
// if (pathSection.ContainsKey(key) && pathSection[key].StartsWith(@"\\"))
// ProgressPath = pathSection[key];
// if (!string.IsNullOrEmpty(ProgressPath) && Directory.Exists(Path.GetPathRoot(ProgressPath)) && !Directory.Exists(ProgressPath))
// Directory.CreateDirectory(ProgressPath);
// key = "Memory";
// if (pathSection.ContainsKey(key) && pathSection[key].StartsWith(@"\\"))
// MemoryPath = pathSection[key];
// if (!string.IsNullOrEmpty(MemoryPath) && !Directory.Exists(MemoryPath))
// Directory.CreateDirectory(MemoryPath);
// }
// if (!commonSection.Any())
// throw new Exception("Common section is missing from configuration");
// else
// {
// key = "CELL_NAMES";
// if (!commonSection.ContainsKey(key) || !commonSection[key].Contains(';') || !commonSection[key].Contains(':'))
// throw new Exception(cellInstanceConnectionName);
// else
// {
// string[] segments;
// string[] cellNames = commonSection[key].Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
// foreach (string item in cellNames)
// {
// segments = item.Split(':');
// CellNames.Add(segments[0].Trim(), segments[1].Trim());
// }
// }
// if (!string.IsNullOrEmpty(cellName) && !CellNames.ContainsKey(cellName))
// throw new Exception(cellInstanceConnectionName);
// key = "MES_ENTITIES";
// if (!commonSection.ContainsKey(key) || !commonSection[key].Contains(';') || !commonSection[key].Contains(':')) throw new Exception(cellInstanceConnectionName);
// else
// {
// string[] segments;
// string[] mesEntity = commonSection[key].Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
// foreach (string item in mesEntity)
// {
// segments = item.Split(':');
// MesEntities.Add(segments[0].Trim(), segments[1].Trim());
// }
// }
// if (!string.IsNullOrEmpty(cellName) && !MesEntities.ContainsKey(cellName))
// throw new Exception(cellInstanceConnectionName);
// }
// if (!MesEntities.Any())
// throw new Exception(cellInstanceConnectionName);
// if (!openInsightSection.Any())
// throw new Exception("OpenInsight section is missing from configuration");
// else
// {
// key = "MetrologyViewerAPI";
// if (openInsightSection.ContainsKey(key))
// OpenInsightMetrogyViewerAPI = openInsightSection[key];
// if (string.IsNullOrEmpty(OpenInsightMetrogyViewerAPI))
// throw new Exception(string.Format("OpenInsight key {0} is empty", key));
// if (!OpenInsightMetrogyViewerAPI.Contains(":") || !OpenInsightMetrogyViewerAPI.Contains("."))
// throw new Exception(string.Format("OpenInsight key {0} is invalid", key));
// key = "SiViewer";
// if (openInsightSection.ContainsKey(key))
// OpenInsightSiViewer = openInsightSection[key];
// if (string.IsNullOrEmpty(OpenInsightSiViewer))
// throw new Exception(string.Format("OpenInsight key {0} is empty", key));
// if (!OpenInsightSiViewer.Contains(":") || !OpenInsightSiViewer.Contains("."))
// throw new Exception(string.Format("OpenInsight key {0} is invalid", key));
// key = "FilePattern";
// if (openInsightSection.ContainsKey(key))
// OpenInsightFilePattern = openInsightSection[key];
// else
// throw new Exception(string.Concat("Missing OpenInsight Configuration entry for ", key));
// if (string.IsNullOrEmpty(OpenInsightFilePattern))
// throw new Exception(string.Format("OpenInsight key {0} is empty", key));
// }
// if (IsSourceTimer || IsDatabaseExportToIPDSF || (Duplicator.HasValue && Duplicator.Value == Level.IsDummy))
// {
// if (!Directory.Exists(fileConnectorConfiguration.SourceFileLocation))
// Directory.CreateDirectory(fileConnectorConfiguration.SourceFileLocation);
// _ReportFullPath = string.Concat(fileConnectorConfiguration.SourceFileLocation, firstSourceFileFilter.Replace("*", @"\"));
// if (Debugger.IsAttached || fileConnectorConfiguration.PreProcessingMode == FileConnectorConfiguration.PreProcessingModeEnum.Process)
// Callback(null);
// else
// {
// int milliSeconds;
// milliSeconds = (int)((fileConnectorConfiguration.FileScanningIntervalInSeconds * 1000) / 2);
// _Timer = new Timer(Callback, null, milliSeconds, Timeout.Infinite); milliSeconds += 2000;
// }
// }
// }
// }
// public void CheckProcessDataDescription(Dictionary<Test, List<Duplicator.Description>> results, bool extra)
// {
// foreach (Test test in results.Keys)
// {
// if (test == Test.BioRadQS408M)
// {
// if (!(ProcessDataDescription is ProcessData.FileRead.Description))
// ProcessDataDescription = new ProcessData.FileRead.Description();
// }
// else
// throw new Exception();
// }
// }
// private void CallbackIsDummy(string traceDummyFile, List<Tuple<string, string, string, string, int>> tuples, bool fileConnectorConfigurationIncludeSubDirectories, bool includeSubDirectoriesExtra)
// {
// int fileCount;
// string[] files;
// string monARessource;
// string checkDirectory;
// string sourceArchiveFile;
// string inProcessDirectory;
// const string site = "sjc";
// const string monInURL = "http://moninhttp.sjc.infineon.com/input/text";
// MonIn monIn = MonIn.GetInstance(monInURL);
// string stateName = string.Concat("Dummy_", _EventName);
// foreach (Tuple<string, string, string, string, int> item in tuples)
// {
// monARessource = item.Item1;
// sourceArchiveFile = item.Item2;
// inProcessDirectory = item.Item3;
// checkDirectory = item.Item4;
// fileCount = item.Item5;
// try
// {
// if (fileCount > 0 || string.IsNullOrEmpty(checkDirectory))
// {
// File.AppendAllLines(traceDummyFile, new string[] { site, monARessource, stateName, State.Warning.ToString() });
// monIn.SendStatus(site, monARessource, stateName, State.Warning);
// for (int i = 1; i < 12; i++)
// Thread.Sleep(500);
// }
// else if (inProcessDirectory == checkDirectory)
// continue;
// if (!EafHosted)
// continue;
// if (!File.Exists(sourceArchiveFile))
// continue;
// if (!long.TryParse(Path.GetFileNameWithoutExtension(sourceArchiveFile).Replace("x", string.Empty), out long sequence))
// continue;
// ZipFile.ExtractToDirectory(sourceArchiveFile, inProcessDirectory);
// if (fileConnectorConfigurationIncludeSubDirectories && includeSubDirectoriesExtra)
// {
// if (_EventName == EventName.FileRead)
// checkDirectory = string.Concat(checkDirectory, @"\", sequence);
// else if (_EventName == EventName.FileReadDaily)
// checkDirectory = string.Concat(checkDirectory, @"\Source\", sequence);
// else
// throw new Exception();
// }
// if (fileConnectorConfigurationIncludeSubDirectories)
// files = Directory.GetFiles(inProcessDirectory, "*", SearchOption.AllDirectories);
// else
// files = Directory.GetFiles(inProcessDirectory, "*", SearchOption.TopDirectoryOnly);
// if (files.Length > 250)
// throw new Exception("Safety net!");
// foreach (string file in files)
// File.SetLastWriteTime(file, new DateTime(sequence));
// if (!fileConnectorConfigurationIncludeSubDirectories)
// {
// foreach (string file in files)
// File.Move(file, string.Concat(checkDirectory, @"\", Path.GetFileName(file)));
// }
// else
// {
// string[] directories = Directory.GetDirectories(inProcessDirectory, "*", SearchOption.AllDirectories);
// foreach (string directory in directories)
// Directory.CreateDirectory(string.Concat(checkDirectory, directory.Substring(inProcessDirectory.Length)));
// foreach (string file in files)
// File.Move(file, string.Concat(checkDirectory, file.Substring(inProcessDirectory.Length)));
// }
// File.AppendAllLines(traceDummyFile, new string[] { site, monARessource, stateName, State.Ok.ToString() });
// monIn.SendStatus(site, monARessource, stateName, State.Ok);
// }
// catch (Exception exception)
// {
// File.AppendAllLines(traceDummyFile, new string[] { site, monARessource, stateName, State.Critical.ToString(), exception.Message, exception.StackTrace });
// monIn.SendStatus(site, monARessource, stateName, State.Critical);
// try
// {
// Eaf.Core.Smtp.ISmtp smtp = Eaf.Core.Backbone.Instance.GetBackboneComponentsOfType<Eaf.Core.Smtp.ISmtp>().SingleOrDefault();
// Eaf.Core.Smtp.EmailMessage emailMessage = new Eaf.Core.Smtp.EmailMessage(string.Concat("Exception:", EquipmentElementName), string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace), Eaf.Core.Smtp.MailPriority.High);
// smtp.Send(emailMessage);
// }
// catch (Exception) { }
// }
// }
// }
// private void CallbackIsDummy()
// {
// DateTime dateTime = DateTime.Now;
// bool check = dateTime.Hour > 7 && dateTime.Hour < 18 && dateTime.DayOfWeek != DayOfWeek.Sunday && dateTime.DayOfWeek != DayOfWeek.Saturday;
// if (check)
// {
// int fileCount;
// string[] files;
// string monARessource;
// string checkDirectory;
// string sourceArchiveFile;
// string sourceFileLocation;
// string targetFileLocation;
// string inProcessDirectory;
// string weekOfYear = _Calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00");
// string traceDummyDirectory = string.Concat(Path.GetPathRoot(TracePath), @"\TracesDummy\", CellName, @"\Source\", dateTime.ToString("yyyy"), "___Week_", weekOfYear);
// if (!Directory.Exists(traceDummyDirectory))
// Directory.CreateDirectory(traceDummyDirectory);
// string traceDummyFile = string.Concat(traceDummyDirectory, @"\", dateTime.Ticks, " - ", CellName, ".txt");
// File.AppendAllText(traceDummyFile, string.Empty);
// List<Tuple<string, string, string, string, int>> tuples = new List<Tuple<string, string, string, string, int>>();
// foreach (var keyValuePair in CellNames)
// {
// monARessource = keyValuePair.Key;
// if (!keyValuePair.Value.Contains(@"\"))
// continue;
// foreach (string sourceFileFilter in FileConnectorConfiguration.SourceFileFilter.Split('|'))
// {
// if (sourceFileFilter.ToLower().StartsWith(keyValuePair.Value.Replace(@"\", string.Empty)))
// sourceFileLocation = Path.GetFullPath(FileConnectorConfiguration.SourceFileLocation);
// else if (FileConnectorConfiguration.SourceFileLocation.ToLower().EndsWith(keyValuePair.Value))
// sourceFileLocation = Path.GetFullPath(FileConnectorConfiguration.SourceFileLocation);
// else
// sourceFileLocation = Path.GetFullPath(string.Concat(FileConnectorConfiguration.SourceFileLocation, @"\", keyValuePair.Value));
// sourceArchiveFile = Path.GetFullPath(string.Concat(sourceFileLocation, @"\", sourceFileFilter));
// targetFileLocation = Path.GetFullPath(string.Concat(FileConnectorConfiguration.TargetFileLocation, @"\", keyValuePair.Value));
// if (!File.Exists(sourceArchiveFile))
// continue;
// if (!DummyRuns.ContainsKey(monARessource))
// DummyRuns.Add(monARessource, new List<long>());
// tuples.Add(new Tuple<string, string, string, string, int>(monARessource, sourceFileLocation, targetFileLocation, sourceArchiveFile, 0));
// }
// }
// File.AppendAllLines(traceDummyFile, from l in tuples select l.Item4);
// if (tuples.Any())
// {
// _LastDummyRunIndex += 1;
// if (_LastDummyRunIndex >= tuples.Count)
// _LastDummyRunIndex = 0;
// monARessource = tuples[_LastDummyRunIndex].Item1;
// sourceFileLocation = tuples[_LastDummyRunIndex].Item2;
// targetFileLocation = tuples[_LastDummyRunIndex].Item3;
// sourceArchiveFile = tuples[_LastDummyRunIndex].Item4;
// //fileCount = tuples[_LastDummyRunIndex].Item5;
// tuples.Clear();
// if (long.TryParse(Path.GetFileNameWithoutExtension(sourceArchiveFile).Replace("x", string.Empty), out long sequence))
// {
// if (!DummyRuns[monARessource].Contains(sequence))
// DummyRuns[monARessource].Add(sequence);
// inProcessDirectory = string.Concat(ProgressPath, @"\", monARessource, @"\Dummy_in process\", sequence);
// checkDirectory = inProcessDirectory;
// if (!Directory.Exists(checkDirectory))
// Directory.CreateDirectory(checkDirectory);
// files = Directory.GetFiles(checkDirectory, "*", SearchOption.AllDirectories);
// fileCount = files.Length;
// if (files.Any())
// {
// if (files.Length > 250)
// throw new Exception("Safety net!");
// try
// {
// foreach (string file in files)
// File.Delete(file);
// }
// catch (Exception) { }
// }
// tuples.Add(new Tuple<string, string, string, string, int>(monARessource, sourceArchiveFile, inProcessDirectory, checkDirectory, fileCount));
// checkDirectory = targetFileLocation;
// files = Directory.GetFiles(checkDirectory, string.Concat("*", sequence, "*"), SearchOption.TopDirectoryOnly);
// fileCount = files.Length;
// tuples.Add(new Tuple<string, string, string, string, int>(monARessource, sourceArchiveFile, inProcessDirectory, checkDirectory, fileCount));
// }
// }
// if (tuples.Any())
// CallbackIsDummy(traceDummyFile, tuples, FileConnectorConfiguration.IncludeSubDirectories.Value, includeSubDirectoriesExtra: false);
// }
// }
// private void Callback(object state)
// {
// try
// {
// if (Duplicator is null)
// {
// if (File.Exists(_ReportFullPath))
// File.Delete(_ReportFullPath);
// File.WriteAllText(_ReportFullPath, string.Empty);
// }
// else if (Duplicator.Value == Level.IsDummy)
// CallbackIsDummy();
// else
// throw new Exception();
// }
// catch (Exception exception)
// {
// try
// {
// Eaf.Core.Smtp.ISmtp smtp = Eaf.Core.Backbone.Instance.GetBackboneComponentsOfType<Eaf.Core.Smtp.ISmtp>().SingleOrDefault();
// Eaf.Core.Smtp.EmailMessage emailMessage = new Eaf.Core.Smtp.EmailMessage(string.Concat("Exception:", EquipmentElementName), string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace), Eaf.Core.Smtp.MailPriority.High);
// smtp.Send(emailMessage);
// }
// catch (Exception) { }
// }
// try
// {
// TimeSpan timeSpan;
// if (IsDatabaseExportToIPDSF)
// timeSpan = new TimeSpan(DateTime.Now.AddMinutes(1).Ticks - DateTime.Now.Ticks);
// else if (IsSourceTimer)
// timeSpan = new TimeSpan(DateTime.Now.AddMinutes(15).Ticks - DateTime.Now.Ticks);
// else if (Duplicator.HasValue && Duplicator.Value == Level.IsDummy)
// timeSpan = new TimeSpan(DateTime.Now.AddSeconds(FileConnectorConfiguration.FileScanningIntervalInSeconds.Value).Ticks - DateTime.Now.Ticks);
// else if (Duplicator.HasValue)
// timeSpan = new TimeSpan(DateTime.Now.AddSeconds(30).Ticks - DateTime.Now.Ticks);
// else
// timeSpan = new TimeSpan(DateTime.Now.AddDays(.5).Ticks - DateTime.Now.Ticks);
// if (!(_Timer is null))
// _Timer.Change((long)timeSpan.TotalMilliseconds, Timeout.Infinite);
// else
// _Timer = new Timer(Callback, null, (long)timeSpan.TotalMilliseconds, Timeout.Infinite);
// }
// catch (Exception exception)
// {
// try
// {
// Eaf.Core.Smtp.ISmtp smtp = Eaf.Core.Backbone.Instance.GetBackboneComponentsOfType<Eaf.Core.Smtp.ISmtp>().SingleOrDefault();
// Eaf.Core.Smtp.EmailMessage emailMessage = new Eaf.Core.Smtp.EmailMessage(string.Concat("Exception:", EquipmentElementName), string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace), Eaf.Core.Smtp.MailPriority.High);
// smtp.Send(emailMessage);
// }
// catch (Exception) { }
// }
// }
// public Tuple<string, JsonElement?, List<FileInfo>> IsManualOIEntry(string reportFullPath)
// {
// Tuple<string, JsonElement?, List<FileInfo>> results;
// string monARessource;
// const string site = "sjc";
// string equipment = string.Empty;
// string description = string.Empty;
// string stateName = "MANUAL_OI_ENTRY";
// string json = File.ReadAllText(reportFullPath);
// JsonElement jsonElement = JsonSerializer.Deserialize<JsonElement>(json);
// results = new Tuple<string, JsonElement?, List<FileInfo>>(string.Empty, jsonElement, new List<FileInfo>());
// foreach (JsonProperty jsonProperty in jsonElement.EnumerateObject())
// {
// if (jsonProperty.Name == "Equipment")
// equipment = jsonProperty.Value.ToString();
// else if (jsonProperty.Name == "Description")
// description = jsonProperty.Value.ToString();
// }
// if (string.IsNullOrEmpty(equipment))
// monARessource = CellName;
// else
// monARessource = equipment;
// const string monInURL = "http://moninhttp.sjc.infineon.com/input/text";
// MonIn monIn = MonIn.GetInstance(monInURL);
// if (EafHosted)
// monIn.SendStatus(site, monARessource, stateName, State.Warning, description);
// return results;
// }
// }
//}