diff --git a/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/AbstractCompany.cs b/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/AbstractCompany.cs index f236836..7e66306 100644 --- a/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/AbstractCompany.cs +++ b/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/AbstractCompany.cs @@ -21,7 +21,7 @@ public abstract class AbstractCompany protected ICollectionGenericObjects _collection = null; - private int GetMaxCount => _pictureWidth * _pictureHeight / (_placeSizeWidth * _placeSizeHeight); + private int GetMaxCount => _pictureWidth / _placeSizeWidth * (_pictureHeight / _placeSizeHeight / 2 * 3); public AbstractCompany(int picWidth, int picHeigth, ICollectionGenericObjects collection) { diff --git a/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/ListGenericObjects.cs b/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/ListGenericObjects.cs index 087e88b..3c42b3f 100644 --- a/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/ListGenericObjects.cs +++ b/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/ListGenericObjects.cs @@ -1,4 +1,5 @@ -using System; +using ProjectAccordionBus.Exceptions; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -35,39 +36,30 @@ public class ListGenericObjects : ICollectionGenericObjects public T Get(int position) { - if (position < 0 || position >= _collection.Count || _collection == null || _collection.Count == 0) return null; - + if (position >= Count || position < 0) throw new PositionOutOfCollectionException(position); return _collection[position]; } public int Insert(T obj) { - if (Count == _maxCount) - { - return -1; - } - + if (Count == _maxCount) throw new CollectionOverflowException(Count); _collection.Add(obj); return Count; } public int Insert(T obj, int position) { - if (Count == _maxCount || position < 0 || position > Count) - { - return -1; - } - + if (Count == _maxCount) throw new CollectionOverflowException(Count); + if (position >= Count || position < 0) throw new PositionOutOfCollectionException(position); _collection.Insert(position, obj); - return 1; + return position; } public T? Remove(int position) { - if (_collection == null || position < 0 || position >= _collection.Count) return null; - - T? obj = _collection[position]; - _collection[position] = null; + if (position >= Count || position < 0) throw new PositionOutOfCollectionException(position); + T obj = _collection[position]; + _collection.RemoveAt(position); return obj; } diff --git a/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/MassiveGenericObjects.cs b/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/MassiveGenericObjects.cs index c94d1cb..3b4397a 100644 --- a/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/MassiveGenericObjects.cs +++ b/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/MassiveGenericObjects.cs @@ -1,4 +1,5 @@ -using System; +using ProjectAccordionBus.Exceptions; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -55,70 +56,60 @@ public class MassiveGenericObjects : ICollectionGenericObjects public T? Get(int position) { - if (position >= _collection.Length || position < 0) - { - return null; - } + if (position < 0 || position >= Count) throw new PositionOutOfCollectionException(position); + return _collection[position]; } public int Insert(T obj) { - int index = 0; + for (int i = 0; i < Count; i++) + { + if (_collection[i] == null) + { + _collection[i] = obj; + return i; + } + } + + throw new CollectionOverflowException(Count); + } + + public int Insert(T obj, int position) + { + if (position >= _collection.Length || position < 0) throw new PositionOutOfCollectionException(position); + if (_collection[position] == null) + { + _collection[position] = obj; + return position; + } + int index = position + 1; while (index < _collection.Length) { if (_collection[index] == null) { _collection[index] = obj; - return 1; + return index; } - index++; + ++index; } - return -1; - } - - public int Insert(T obj, int position) - { - - if (position >= _collection.Length || position < 0) - return -1; - - - if (_collection[position] != null) + index = position - 1; + while (index >= 0) { - // проверка, что после вставляемого элемента в массиве есть пустой элемент - int nullIndex = -1; - for (int i = position + 1; i < Count; i++) + if (_collection[index] == null) { - if (_collection[i] == null) - { - nullIndex = i; - break; - } + _collection[index] = obj; + return index; } - // Если пустого элемента нет, то выходим - if (nullIndex < 0) - { - return -1; - } - // сдвиг всех объектов, находящихся справа от позиции до первого пустого элемента - int j = nullIndex - 1; - while (j >= position) - { - _collection[j + 1] = _collection[j]; - j--; - } - } - _collection[position] = obj; - return 1; + --index; + } + throw new CollectionOverflowException(Count); } public T? Remove(int position) { - if (position >= _collection.Length || position < 0) - { - return null; - } + if (position < 0 || position >= Count) throw new PositionOutOfCollectionException(position); + if (_collection[position] == null) throw new ObjectNotFoundException(position); T? temp = _collection[position]; _collection[position] = null; return temp; diff --git a/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/StorageCollection.cs b/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/StorageCollection.cs index a34d8f3..9c8f4c8 100644 --- a/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/StorageCollection.cs +++ b/ProjectAccordionBus/ProjectAccordionBus/CollectionGenericObjects/StorageCollection.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using ProjectAccordionBus.Exceptions; namespace ProjectAccordionBus.CollectionGenericObjects; @@ -50,15 +51,19 @@ public class StorageCollection /// тип коллекции public void AddCollection(string name, CollectionType collectionType) { - if (_storages.ContainsKey(name) || name == "") return; - - if (collectionType == CollectionType.Massive) + if (name == null || _storages.ContainsKey(name)) + return; + switch (collectionType) { - _storages[name] = new MassiveGenericObjects(); - } - else - { - _storages[name] = new ListGenericObjects(); + case CollectionType.None: + return; + case CollectionType.Massive: + _storages[name] = new MassiveGenericObjects(); + return; + case CollectionType.List: + _storages[name] = new ListGenericObjects(); + return; + default: break; } } /// @@ -67,7 +72,8 @@ public class StorageCollection /// Название коллекции public void DelCollection(string name) { - _storages.Remove(name); + if (_storages.ContainsKey(name)) + _storages.Remove(name); } /// @@ -87,11 +93,11 @@ public class StorageCollection } } - public bool SaveData(string filename) + public void SaveData(string filename) { if (_storages.Count == 0) { - return false; + throw new ArgumentException("В хранилище отсутствуют коллекции для сохранения"); } if (File.Exists(filename)) { @@ -127,25 +133,25 @@ public class StorageCollection } } } - return true; } - public bool LoadData(string filename) + public void LoadData(string filename) { if (!File.Exists(filename)) { - return false; + throw new FileNotFoundException($"{filename} не существует"); } using (StreamReader reader = new(filename)) { string line = reader.ReadLine(); if (line == null || line.Length == 0) { - return false; + throw new IOException("Файл не подходит"); } if (!line.Equals(_collectionKey)) { - return false; + + throw new IOException("В файле неверные данные"); } _storages.Clear(); while ((line = reader.ReadLine()) != null) @@ -160,25 +166,31 @@ public class StorageCollection ICollectionGenericObjects? collection = StorageCollection.CreateCollection(collectionType); if (collection == null) { - return false; + throw new Exception("Не удалось создать коллекцию"); } collection.MaxCount = Convert.ToInt32(record[2]); string[] set = record[3].Split(_separatorItems, StringSplitOptions.RemoveEmptyEntries); foreach (string elem in set) { - if (elem?.CreateDrawningBus() is T truck) + if (elem?.CreateDrawningBus() is T armoredCar) { - if (collection.Insert(truck) == -1) + try { - return false; + if (collection.Insert(armoredCar) == -1) + { + throw new Exception("Объект не удалось добавить в коллекцию: " + record[3]); + } + } + catch (CollectionOverflowException ex) + { + throw new Exception("Коллекция переполнена", ex); } } } _storages.Add(record[0], collection); } } - return true; } /// diff --git a/ProjectAccordionBus/ProjectAccordionBus/Exceptions/CollectionOverflowException.cs b/ProjectAccordionBus/ProjectAccordionBus/Exceptions/CollectionOverflowException.cs new file mode 100644 index 0000000..ef79f45 --- /dev/null +++ b/ProjectAccordionBus/ProjectAccordionBus/Exceptions/CollectionOverflowException.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace ProjectAccordionBus.Exceptions; + +[Serializable] +internal class CollectionOverflowException : ApplicationException +{ + public CollectionOverflowException(int count) : base("В коллекции превышено допустимое количество: " + count) { } + public CollectionOverflowException() : base() { } + public CollectionOverflowException(string message) : base(message) { } + public CollectionOverflowException(string message, Exception exception) : + base(message, exception) + { } + protected CollectionOverflowException(SerializationInfo info, + StreamingContext contex) : base(info, contex) { } +} \ No newline at end of file diff --git a/ProjectAccordionBus/ProjectAccordionBus/Exceptions/ObjectNotFoundException.cs b/ProjectAccordionBus/ProjectAccordionBus/Exceptions/ObjectNotFoundException.cs new file mode 100644 index 0000000..aadce6b --- /dev/null +++ b/ProjectAccordionBus/ProjectAccordionBus/Exceptions/ObjectNotFoundException.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace ProjectAccordionBus.Exceptions; + +[Serializable] +internal class ObjectNotFoundException : ApplicationException +{ + public ObjectNotFoundException(int i) : base("Не найден объект по позиции " + i) { } + public ObjectNotFoundException() : base() { } + public ObjectNotFoundException(string message) : base(message) { } + public ObjectNotFoundException(string message, Exception exception) : base(message, exception) { } + protected ObjectNotFoundException(SerializationInfo info, StreamingContext contex) : base(info, contex) { } +} diff --git a/ProjectAccordionBus/ProjectAccordionBus/Exceptions/PositionOutOfCollectionException.cs b/ProjectAccordionBus/ProjectAccordionBus/Exceptions/PositionOutOfCollectionException.cs new file mode 100644 index 0000000..ae20702 --- /dev/null +++ b/ProjectAccordionBus/ProjectAccordionBus/Exceptions/PositionOutOfCollectionException.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace ProjectAccordionBus.Exceptions; + +[Serializable] +internal class PositionOutOfCollectionException : ApplicationException +{ + public PositionOutOfCollectionException(int i) : base("Выход за границы коллекции.Позиция " + i) { } + public PositionOutOfCollectionException() : base() { } + public PositionOutOfCollectionException(string message) : base(message) { } + public PositionOutOfCollectionException(string message, Exception exception) : base(message, exception) { } + protected PositionOutOfCollectionException(SerializationInfo info, StreamingContext contex) : base(info, contex) { } +} \ No newline at end of file diff --git a/ProjectAccordionBus/ProjectAccordionBus/FormBusCollection.cs b/ProjectAccordionBus/ProjectAccordionBus/FormBusCollection.cs index 752b192..fb51e0e 100644 --- a/ProjectAccordionBus/ProjectAccordionBus/FormBusCollection.cs +++ b/ProjectAccordionBus/ProjectAccordionBus/FormBusCollection.cs @@ -1,5 +1,7 @@ -using ProjectAccordionBus.CollectionGenericObjects; +using Microsoft.Extensions.Logging; +using ProjectAccordionBus.CollectionGenericObjects; using ProjectAccordionBus.Drawnings; +using ProjectAccordionBus.Exceptions; using System; using System.Collections.Generic; using System.ComponentModel; @@ -27,20 +29,28 @@ public partial class FormBusCollection : Form /// private AbstractCompany? _company = null; + private readonly ILogger _logger; + /// /// Конструктор /// - public FormBusCollection() + public FormBusCollection(ILogger logger) { InitializeComponent(); _storageCollection = new(); + _logger = logger; } /// /// Добавление улучшенного троллейбуса /// /// /// - private void ButtonAddAccordionBus_Click(object sender, EventArgs e) => CreateObject(nameof(DrawningAccordionBus)); + private void ButtonAddAccordionBus_Click(object sender, EventArgs e) + { + FormBusConfig form = new FormBusConfig(); + form.Show(); + form.AddEvent(SetBus); + } /// /// Создание объекта класса-перемещения @@ -106,18 +116,24 @@ public partial class FormBusCollection : Form private void SetBus(DrawningBus bus) { - if (_company == null || bus == null) return; - - bus.SetPictureSize(pictureBox.Width, pictureBox.Height); - - if (_company + bus != -1) + try { - MessageBox.Show("Объект добавлен"); - pictureBox.Image = _company.Show(); + if (_company == null || bus == null) + { + return; + } + if (_company + bus != -1) + { + MessageBox.Show("Объект добавлен"); + pictureBox.Image = _company.Show(); + _logger.LogInformation("Добавлен объект: {0}", bus.GetDataForSave()); + } + } - else + catch (CollectionOverflowException ex) { - MessageBox.Show("Объект не удалось добавить"); + MessageBox.Show(ex.Message); + _logger.LogError($"Ошибка: {ex.Message}"); } } @@ -128,37 +144,60 @@ public partial class FormBusCollection : Form return; } - if (MessageBox.Show("Удалить объект?", "Удаление", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) + if (MessageBox.Show("Удалить объект?", "Удаление", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) { return; } int pos = Convert.ToInt32(maskedTextBox.Text); - if (_company - pos != null) + try { - MessageBox.Show("Объект удалён"); - pictureBox.Image = _company.Show(); + if (_company - pos != null) + { + MessageBox.Show("Объект удален"); + pictureBox.Image = _company.Show(); + _logger.LogInformation("Удален объект по позиции " + pos); + } + else + { + MessageBox.Show($"Не удалось удалить объект"); + } } - else + catch (Exception ex) { - MessageBox.Show("Не удалось удалить объект"); + MessageBox.Show(ex.Message); + _logger.LogError("Ошибка: {Message}", ex.Message); } } private void buttonGoToCheck_Click(object sender, EventArgs e) { - if (_company == null) return; + if (_company == null) + { + return; + } DrawningBus? bus = null; int counter = 100; - while (bus == null || counter > 0) + while (bus == null) { - bus = _company.GetRandomObject(); - counter--; + try + { + bus = _company.GetRandomObject(); + } + catch (ObjectNotFoundException) + { + counter--; + if (counter <= 0) + { + break; + } + } + } + if (bus == null) + { + return; } - - if (bus == null) return; - FormAccordionBus form = new() { SetBus = bus @@ -193,10 +232,12 @@ public partial class FormBusCollection : Form private void buttonCollectionAdd_Click(object sender, EventArgs e) { - if (string.IsNullOrEmpty(textBoxCollectionName.Text) || (!radioButtonList.Checked && !radioButtonMassive.Checked)) + if (string.IsNullOrEmpty(textBoxCollectionName.Text) || + (!radioButtonList.Checked && !radioButtonMassive.Checked)) { MessageBox.Show("Не все данные заполнены", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); + _logger.LogWarning("Не заполненная коллекция"); return; } CollectionType collectionType = CollectionType.None; @@ -208,8 +249,8 @@ public partial class FormBusCollection : Form { collectionType = CollectionType.List; } - _storageCollection.AddCollection(textBoxCollectionName.Text, - collectionType); + _storageCollection.AddCollection(textBoxCollectionName.Text, collectionType); + _logger.LogInformation($"Добавлена коллекция: {textBoxCollectionName.Text}"); RefreshListBoxItems(); } @@ -229,43 +270,45 @@ public partial class FormBusCollection : Form private void buttonCollectionDel_Click(object sender, EventArgs e) { - if (listBoxCollection.SelectedItem == null) return; - - if (MessageBox.Show("Вы действительно хотите удалить выбранный элемент?", - "Удаление", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) + if (listBoxCollection.SelectedIndex < 0 || listBoxCollection.SelectedItem == null) { - _storageCollection.DelCollection(listBoxCollection.SelectedItem.ToString()); - RefreshListBoxItems(); - MessageBox.Show("Компания удалена"); + MessageBox.Show("Коллекция не выбрана"); + _logger.LogWarning("Удаление невыбранной коллекции"); + return; } - else + string name = listBoxCollection.SelectedItem.ToString() ?? string.Empty; + if (MessageBox.Show("Удалить коллекцию?", "Удаление", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) { - MessageBox.Show("Не удалось удалить компанию"); + return; } + _storageCollection.DelCollection(listBoxCollection.SelectedItem.ToString()); + _logger.LogInformation($"Удалена коллекция: {name}"); + RefreshListBoxItems(); } private void buttonCreateCompany_Click(object sender, EventArgs e) { - if (listBoxCollection.SelectedIndex < 0) + if (listBoxCollection.SelectedIndex < 0 || listBoxCollection.SelectedItem == null) { - MessageBox.Show("Компания не выбрана"); + MessageBox.Show("Коллекция не выбрана"); + _logger.LogWarning("Создание компании невыбранной коллекции"); return; } - - ICollectionGenericObjects collection = _storageCollection[listBoxCollection.SelectedItem?.ToString() ?? string.Empty]; + ICollectionGenericObjects? collection = + _storageCollection[listBoxCollection.SelectedItem.ToString() ?? string.Empty]; if (collection == null) { - MessageBox.Show("Компания не инициализирована"); + MessageBox.Show("Коллекция не проинициализирована"); + _logger.LogWarning("Не удалось инициализировать коллекцию"); return; } - switch (comboBoxSelectorCompany.Text) { case "Хранилище": - _company = new BusSharingService(pictureBox.Width, pictureBox.Height, collection); + _company = new BusSharingService(pictureBox.Width, + pictureBox.Height, collection); break; } - panelCompanyTools.Enabled = true; RefreshListBoxItems(); } @@ -274,13 +317,16 @@ public partial class FormBusCollection : Form { if (saveFileDialog.ShowDialog() == DialogResult.OK) { - if (_storageCollection.SaveData(saveFileDialog.FileName)) + try { + _storageCollection.SaveData(saveFileDialog.FileName); MessageBox.Show("Сохранение прошло успешно", "Результат", MessageBoxButtons.OK, MessageBoxIcon.Information); + _logger.LogInformation("Сохранение в файл: {filename}", saveFileDialog.FileName); } - else + catch (Exception ex) { - MessageBox.Show("Не сохранилось", "Результат", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(ex.Message, "Результат", MessageBoxButtons.OK, MessageBoxIcon.Error); + _logger.LogError("Ошибка: {Message}", ex.Message); } } } @@ -289,14 +335,17 @@ public partial class FormBusCollection : Form { if (openFileDialog.ShowDialog() == DialogResult.OK) { - if (_storageCollection.LoadData(openFileDialog.FileName)) + try { - MessageBox.Show("Загрузка прошла успешно", "Реузльтат", MessageBoxButtons.OK, MessageBoxIcon.Information); + _storageCollection.LoadData(openFileDialog.FileName); + MessageBox.Show("Загрузка прошла успешно", "Результат", MessageBoxButtons.OK, MessageBoxIcon.Information); + _logger.LogInformation("Загрузка из файла: {filename}", saveFileDialog.FileName); RefreshListBoxItems(); } - else + catch (Exception ex) { - MessageBox.Show("Не загрузилось", "Результат", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(ex.Message, "Результат", MessageBoxButtons.OK, MessageBoxIcon.Error); + _logger.LogError("Ошибка: {Message}", ex.Message); } } } diff --git a/ProjectAccordionBus/ProjectAccordionBus/Program.cs b/ProjectAccordionBus/ProjectAccordionBus/Program.cs index c0b1625..3940eed 100644 --- a/ProjectAccordionBus/ProjectAccordionBus/Program.cs +++ b/ProjectAccordionBus/ProjectAccordionBus/Program.cs @@ -1,17 +1,40 @@ -namespace ProjectAccordionBus +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Serilog; + +namespace ProjectAccordionBus; + +internal static class Program { - internal static class Program + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main() - { - // To customize application configuration such as set high DPI settings or default font, - // see https://aka.ms/applicationconfiguration. - ApplicationConfiguration.Initialize(); - Application.Run(new FormBusCollection()); - } + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + + ServiceCollection services = new(); + ConfigureServices(services); + using ServiceProvider serviceProvider = services.BuildServiceProvider(); + Application.Run(serviceProvider.GetRequiredService()); } + private static void ConfigureServices(ServiceCollection services) + { + services + .AddSingleton() + .AddLogging(option => + { + option.SetMinimumLevel(LogLevel.Information); + var config = new ConfigurationBuilder() + .AddJsonFile("serilogConfig.json", optional: false, reloadOnChange: true) + .Build(); + option.AddSerilog(Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(config) + .CreateLogger()); + }); +} } \ No newline at end of file diff --git a/ProjectAccordionBus/ProjectAccordionBus/ProjectAccordionBus.csproj b/ProjectAccordionBus/ProjectAccordionBus/ProjectAccordionBus.csproj index 244387d..75bea1d 100644 --- a/ProjectAccordionBus/ProjectAccordionBus/ProjectAccordionBus.csproj +++ b/ProjectAccordionBus/ProjectAccordionBus/ProjectAccordionBus.csproj @@ -8,6 +8,20 @@ enable + + + + + + + + + + + + + + True @@ -23,4 +37,13 @@ + + + Always + + + Always + + + \ No newline at end of file diff --git a/ProjectAccordionBus/ProjectAccordionBus/nlog.config b/ProjectAccordionBus/ProjectAccordionBus/nlog.config new file mode 100644 index 0000000..5c71e85 --- /dev/null +++ b/ProjectAccordionBus/ProjectAccordionBus/nlog.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/ProjectAccordionBus/ProjectAccordionBus/serilogConfig.json b/ProjectAccordionBus/ProjectAccordionBus/serilogConfig.json new file mode 100644 index 0000000..e9e9b9e --- /dev/null +++ b/ProjectAccordionBus/ProjectAccordionBus/serilogConfig.json @@ -0,0 +1,20 @@ +{ + "Serilog": { + "Using": [ "Serilog.Sinks.File" ], + "MinimumLevel": "Information", + "WriteTo": [ + { + "Name": "File", + "Args": { + "path": "Logs/log_.log", + "rollingInterval": "Day", + "outputTemplate": "[{Timestamp:HH:mm:ss.fff}]{Level:u4}: {Message:lj}{NewLine}{Exception}" + } + } + ], + "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ], + "Properties": { + "Application": "Linkor" + } + } +} \ No newline at end of file