From 3c99a9a96939b49f117e98be830c54b32fa2709a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D0=B8=D0=BD=D0=B0=20=D0=A7=D1=83=D0=B1?= =?UTF-8?q?=D1=8B=D0=BA=D0=B8=D0=BD=D0=B0?= Date: Tue, 23 Apr 2024 22:23:21 +0400 Subject: [PATCH] =?UTF-8?q?2=20=D0=BB=D0=B0=D0=B1=D0=B0=20=D1=85=D0=B0?= =?UTF-8?q?=D1=80=D0=B4=20=D0=B2=20=D0=BF=D1=80=D0=BE=D1=86=D0=B5=D1=81?= =?UTF-8?q?=D1=81=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BindingModels/ShopBindingModel.cs | 2 + .../BusinessLogicsContracts/IShopLogic.cs | 1 + .../StoragesContracts/IShopStorage.cs | 2 + .../ViewModels/ShopViewModel.cs | 2 + .../Models/IShopModel.cs | 1 + .../BusinessLogics/OrderLogic.cs | 88 +++++++++++- .../BusinessLogics/ShopLogic.cs | 11 ++ .../DataFileSingleton.cs | 4 + .../Implements/ShopStorage.cs | 133 ++++++++++++++++++ .../ConfectioneryFileImplement/Models/Shop.cs | 113 +++++++++++++++ .../Implements/ShopStorage.cs | 6 + .../ConfectioneryListImplement/Models/Shop.cs | 10 +- .../FormPastrySale.Designer.cs | 39 +++++ .../ConfectioneryView/FormPastrySale.cs | 20 +++ .../ConfectioneryView/FormPastrySale.resx | 120 ++++++++++++++++ 15 files changed, 545 insertions(+), 7 deletions(-) create mode 100644 Confectionery/ConfectioneryFileImplement/Implements/ShopStorage.cs create mode 100644 Confectionery/ConfectioneryFileImplement/Models/Shop.cs create mode 100644 Confectionery/ConfectioneryView/FormPastrySale.Designer.cs create mode 100644 Confectionery/ConfectioneryView/FormPastrySale.cs create mode 100644 Confectionery/ConfectioneryView/FormPastrySale.resx diff --git a/Confectionery/ConfectionaryContracts/BindingModels/ShopBindingModel.cs b/Confectionery/ConfectionaryContracts/BindingModels/ShopBindingModel.cs index 8490887..da650e2 100644 --- a/Confectionery/ConfectionaryContracts/BindingModels/ShopBindingModel.cs +++ b/Confectionery/ConfectionaryContracts/BindingModels/ShopBindingModel.cs @@ -17,5 +17,7 @@ namespace ConfectioneryContracts.BindingModels get; set; } = new(); + + public int PastriesMaximum { get; set; } } } diff --git a/Confectionery/ConfectionaryContracts/BusinessLogicsContracts/IShopLogic.cs b/Confectionery/ConfectionaryContracts/BusinessLogicsContracts/IShopLogic.cs index 5cd6016..b0f6584 100644 --- a/Confectionery/ConfectionaryContracts/BusinessLogicsContracts/IShopLogic.cs +++ b/Confectionery/ConfectionaryContracts/BusinessLogicsContracts/IShopLogic.cs @@ -18,5 +18,6 @@ namespace ConfectioneryContracts.BusinessLogicsContracts bool Delete(ShopBindingModel model); bool Supply(ShopSearchModel shopModel, IPastryModel pastry, int count); + bool Sale(IPastryModel model, int count); } } diff --git a/Confectionery/ConfectionaryContracts/StoragesContracts/IShopStorage.cs b/Confectionery/ConfectionaryContracts/StoragesContracts/IShopStorage.cs index 04dd755..9e092e1 100644 --- a/Confectionery/ConfectionaryContracts/StoragesContracts/IShopStorage.cs +++ b/Confectionery/ConfectionaryContracts/StoragesContracts/IShopStorage.cs @@ -1,6 +1,7 @@ using ConfectioneryContracts.BindingModels; using ConfectioneryContracts.SearchModels; using ConfectioneryContracts.ViewModels; +using ConfectioneryDataModels.Models; namespace ConfectioneryContracts.StoragesContracts { @@ -17,5 +18,6 @@ namespace ConfectioneryContracts.StoragesContracts ShopViewModel? Update(ShopBindingModel model); ShopViewModel? Delete(ShopBindingModel model); + bool Sale(IPastryModel model, int count); } } diff --git a/Confectionery/ConfectionaryContracts/ViewModels/ShopViewModel.cs b/Confectionery/ConfectionaryContracts/ViewModels/ShopViewModel.cs index cd7f51e..767ac7b 100644 --- a/Confectionery/ConfectionaryContracts/ViewModels/ShopViewModel.cs +++ b/Confectionery/ConfectionaryContracts/ViewModels/ShopViewModel.cs @@ -21,5 +21,7 @@ namespace ConfectioneryContracts.ViewModels get; set; } = new(); + [DisplayName("Максимальное количество выпечки")] + public int PastriesMaximum { get; set; } } } diff --git a/Confectionery/ConfectionaryDataModels/Models/IShopModel.cs b/Confectionery/ConfectionaryDataModels/Models/IShopModel.cs index 38cc5ea..b9a8949 100644 --- a/Confectionery/ConfectionaryDataModels/Models/IShopModel.cs +++ b/Confectionery/ConfectionaryDataModels/Models/IShopModel.cs @@ -9,5 +9,6 @@ DateTime DateOpening { get; } Dictionary ShopPastries { get; } + int PastriesMaximum { get; } } } diff --git a/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/OrderLogic.cs b/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/OrderLogic.cs index a9f668d..250cc6d 100644 --- a/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/OrderLogic.cs +++ b/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/OrderLogic.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using ConfectioneryDataModels.Models; using ConfectioneryContracts.BindingModels; using ConfectioneryContracts.SearchModels; using ConfectioneryContracts.ViewModels; @@ -18,11 +19,20 @@ namespace ConfectioneryBusinessLogic.BusinessLogics private readonly ILogger _logger; private readonly IOrderStorage _orderStorage; + private readonly IPastryStorage _pastryStorage; - public OrderLogic(ILogger logger, IOrderStorage orderStorage) + private readonly IShopStorage _shopStorage; + + private readonly IShopLogic _shopLogic; + + public OrderLogic(ILogger logger, IOrderStorage orderStorage, IPastryStorage pastryStorage, + IShopStorage shopStorage, IShopLogic shopLogic) { _logger = logger; _orderStorage = orderStorage; + _pastryStorage = pastryStorage; + _shopStorage = shopStorage; + _shopLogic = shopLogic; } public bool CreateOrder(OrderBindingModel model) @@ -111,10 +121,20 @@ namespace ConfectioneryBusinessLogic.BusinessLogics newStatus, order.Status); return false; } - model.PastryId = order.PastryId; - model.Count = order.Count; - model.Sum = order.Sum; - model.DateCreate = order.DateCreate; + if (newStatus == OrderStatus.Выдан) + { + var pastry = _pastryStorage.GetElement(new PastrySearchModel() { Id = order.PastryId }); + if (pastry == null) + { + _logger.LogWarning("Change status operation failed. Pastry not found"); + return false; + } + if (!DeliverPastries(pastry, order.Count)) + { + _logger.LogWarning("Change status operation failed. Pastries delivery operation failed"); + return false; + } + } model.Status = newStatus; if (model.Status == OrderStatus.Готов) { @@ -131,5 +151,63 @@ namespace ConfectioneryBusinessLogic.BusinessLogics } return true; } + + private bool DeliverPastries(IPastryModel pastry, int count) + { + if (count <= 0) + { + _logger.LogWarning("Pastries delivery operation failed. Pastry count <= 0"); + return false; + } + + var shopList = _shopStorage.GetFullList(); + int shopsCapacity = shopList.Sum(x => x.PastriesMaximum); + int currentPastrys = shopList.Select(x => x.ShopPastries.Sum(y => y.Value.Item2)).Sum(); + int freePlaces = shopsCapacity - currentPastrys; + + if (freePlaces < count) + { + _logger.LogWarning("Pastries delivery operation failed. No space for new pastries"); + return false; + } + + foreach (var shop in shopList) + { + freePlaces = shop.PastriesMaximum - shop.ShopPastries.Sum(x => x.Value.Item2); + if (freePlaces == 0) + { + continue; + } + if (freePlaces >= count) + { + if (_shopLogic.Supply(new() { Id = shop.Id }, pastry, count)) + { + count = 0; + } + else + { + _logger.LogWarning("Pastries delivery operation failed"); + return false; + } + } + else + { + if (_shopLogic.Supply(new() { Id = shop.Id }, pastry, freePlaces)) + { + count -= freePlaces; + } + else + { + _logger.LogWarning("Pastries delivery operation failed"); + return false; + } + } + if (count == 0) + { + return true; + } + } + return false; + } } } diff --git a/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/ShopLogic.cs b/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/ShopLogic.cs index 97b650b..84946a7 100644 --- a/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/ShopLogic.cs +++ b/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/ShopLogic.cs @@ -105,6 +105,11 @@ namespace ConfectioneryBusinessLogic.BusinessLogics _logger.LogWarning("Supply(GetElement). Element not found"); return false; } + if (shop.PastriesMaximum - shop.ShopPastries.Sum(x => x.Value.Item2) < count) + { + _logger.LogWarning("MakeShipment error. No space for pastries"); + return false; + } if (shop.ShopPastries.ContainsKey(Pastry.Id)) { var shopP = shop.ShopPastries[Pastry.Id]; @@ -125,6 +130,7 @@ namespace ConfectioneryBusinessLogic.BusinessLogics ShopName = shop.ShopName, Address = shop.Address, DateOpening = shop.DateOpening, + PastriesMaximum = shop.PastriesMaximum, ShopPastries = shop.ShopPastries, }) == null) { @@ -134,6 +140,11 @@ namespace ConfectioneryBusinessLogic.BusinessLogics return true; } + public bool Sale(IPastryModel model, int count) + { + return _shopStorage.Sale(model, count); + } + private void CheckModel(ShopBindingModel model, bool withParams = true) { if (model == null) diff --git a/Confectionery/ConfectioneryFileImplement/DataFileSingleton.cs b/Confectionery/ConfectioneryFileImplement/DataFileSingleton.cs index 85ba816..527a969 100644 --- a/Confectionery/ConfectioneryFileImplement/DataFileSingleton.cs +++ b/Confectionery/ConfectioneryFileImplement/DataFileSingleton.cs @@ -15,9 +15,11 @@ namespace ConfectioneryFileImplement private readonly string ComponentFileName = "Component.xml"; private readonly string OrderFileName = "Order.xml"; private readonly string PastryFileName = "Pastry.xml"; + private readonly string ShopFileName = "Shop.xml"; public List Components { get; private set; } public List Orders { get; private set; } public List Pastries { get; private set; } + public List Shops { get; private set; } public static DataFileSingleton GetInstance() { if (instance == null) @@ -29,11 +31,13 @@ namespace ConfectioneryFileImplement public void SaveComponents() => SaveData(Components, ComponentFileName, "Components", x => x.GetXElement); public void SavePastries() => SaveData(Pastries, PastryFileName, "Pastries", x => x.GetXElement); public void SaveOrders() => SaveData(Orders, OrderFileName, "Orders", x => x.GetXElement); + public void SaveShops() => SaveData(Shops, ShopFileName, "Shops", x => x.GetXElement); private DataFileSingleton() { Components = LoadData(ComponentFileName, "Component", x => Component.Create(x)!)!; Pastries = LoadData(PastryFileName, "Pastry", x => Pastry.Create(x)!)!; Orders = LoadData(OrderFileName, "Order", x => Order.Create(x)!)!; + Shops = LoadData(ShopFileName, "Shop", x => Shop.Create(x)!)!; } private static List? LoadData(string filename, string xmlNodeName, Func selectFunction) diff --git a/Confectionery/ConfectioneryFileImplement/Implements/ShopStorage.cs b/Confectionery/ConfectioneryFileImplement/Implements/ShopStorage.cs new file mode 100644 index 0000000..653d2b5 --- /dev/null +++ b/Confectionery/ConfectioneryFileImplement/Implements/ShopStorage.cs @@ -0,0 +1,133 @@ +using ConfectioneryContracts.BindingModels; +using ConfectioneryContracts.SearchModels; +using ConfectioneryContracts.StoragesContracts; +using ConfectioneryContracts.ViewModels; +using ConfectioneryFileImplement.Models; +using ConfectioneryDataModels.Models; +using System.Collections.Generic; + +namespace ConfectioneryFileImplement.Implements +{ + public class ShopStorage : IShopStorage + { + private readonly DataFileSingleton source; + + public ShopStorage() + { + source = DataFileSingleton.GetInstance(); + } + + public List GetFullList() + { + return source.Shops + .Select(x => x.GetViewModel) + .ToList(); + } + + public List GetFilteredList(ShopSearchModel model) + { + if (string.IsNullOrEmpty(model.ShopName)) + { + return new(); + } + return source.Shops + .Where(x => x.ShopName.Contains(model.ShopName)) + .Select(x => x.GetViewModel) + .ToList(); + } + + public ShopViewModel? GetElement(ShopSearchModel model) + { + if (string.IsNullOrEmpty(model.ShopName) && !model.Id.HasValue) + { + return null; + } + return source.Shops + .FirstOrDefault(x => (!string.IsNullOrEmpty(model.ShopName) && x.ShopName == model.ShopName) || + (model.Id.HasValue && x.Id == model.Id)) + ?.GetViewModel; + } + + public ShopViewModel? Insert(ShopBindingModel model) + { + model.Id = source.Shops.Count > 0 ? source.Shops.Max(x => x.Id) + 1 : 1; + var newShop = Shop.Create(model); + if (newShop == null) + { + return null; + } + source.Shops.Add(newShop); + source.SaveShops(); + return newShop.GetViewModel; + } + + public ShopViewModel? Update(ShopBindingModel model) + { + var shop = source.Shops.FirstOrDefault(x => x.Id == model.Id); + if (shop == null) + { + return null; + } + shop.Update(model); + source.SaveShops(); + return shop.GetViewModel; + } + + public ShopViewModel? Delete(ShopBindingModel model) + { + var element = source.Shops.FirstOrDefault(x => x.Id == model.Id); + if (element != null) + { + source.Shops.Remove(element); + source.SaveShops(); + return element.GetViewModel; + } + return null; + } + + public bool Sale(IPastryModel model, int count) + { + var pastry = source.Pastries.FirstOrDefault(x => x.Id == model.Id); + int countInShops = source.Shops.SelectMany(x => x.ShopPastries).Sum(y => y.Key == model.Id ? y.Value.Item2 : 0); + + if (pastry == null || countInShops < count) + { + return false; + } + + foreach (var shop in source.Shops) + { + var shopPastries = shop.ShopPastries.Where(x => x.Key == model.Id); + if (shopPastries.Any()) + { + var shopPastry = shopPastries.First(); + int min = Math.Min(shopPastry.Value.Item2, count); + if (min == shopPastry.Value.Item2) + { + shop.ShopPastries.Remove(shopPastry.Key); + } + else + { + shop.ShopPastries[shopPastry.Key] = (shopPastry.Value.Item1, shopPastry.Value.Item2 - min); + } + shop.Update(new ShopBindingModel + { + Id = shop.Id, + ShopName = shop.ShopName, + Address = shop.Address, + DateOpening = shop.DateOpening, + ShopPastries = shop.ShopPastries, + PastriesMaximum = shop.PastriesMaximum + }); + count -= min; + if (count <= 0) + { + break; + } + } + } + source.SaveShops(); + return true; + } + } +} diff --git a/Confectionery/ConfectioneryFileImplement/Models/Shop.cs b/Confectionery/ConfectioneryFileImplement/Models/Shop.cs new file mode 100644 index 0000000..f1a75c6 --- /dev/null +++ b/Confectionery/ConfectioneryFileImplement/Models/Shop.cs @@ -0,0 +1,113 @@ +using ConfectioneryContracts.BindingModels; +using ConfectioneryContracts.ViewModels; +using ConfectioneryDataModels.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace ConfectioneryFileImplement.Models +{ + public class Shop + { + public int Id { get; private set; } + + public string ShopName { get; private set; } = string.Empty; + + public string Address { get; private set; } = string.Empty; + + public DateTime DateOpening { get; private set; } + + public Dictionary Pastries { get; private set; } = new(); + + private Dictionary? _shopPastries = null; + + public Dictionary ShopPastries + { + get + { + if (_shopPastries == null) + { + var source = DataFileSingleton.GetInstance(); + _shopPastries = Pastries.ToDictionary(x => x.Key, + y => ((source.Pastries.FirstOrDefault(z => z.Id == y.Key) as IPastryModel)!, y.Value)); + } + return _shopPastries; + } + } + + public int PastriesMaximum { get; private set; } + + public static Shop? Create(ShopBindingModel? model) + { + if (model == null) + { + return null; + } + return new Shop() + { + Id = model.Id, + ShopName = model.ShopName, + Address = model.Address, + DateOpening = model.DateOpening, + Pastries = model.ShopPastries.ToDictionary(x => x.Key, x => x.Value.Item2), + PastriesMaximum = model.PastriesMaximum + }; + } + + public static Shop? Create(XElement element) + { + if (element == null) + { + return null; + } + return new Shop() + { + Id = Convert.ToInt32(element.Attribute("Id")!.Value), + ShopName = element.Element("ShopName")!.Value, + Address = element.Element("Address")!.Value, + DateOpening = Convert.ToDateTime(element.Element("DateOpening")!.Value), + PastriesMaximum = Convert.ToInt32(element.Element("PastriesMaximum")!.Value), + Pastries = element.Element("ShopPastries")!.Elements("ShopPastry") + .ToDictionary(x => Convert.ToInt32(x.Element("Key")?.Value), x => Convert.ToInt32(x.Element("Value")?.Value)) + }; + } + + public void Update(ShopBindingModel? model) + { + if (model == null) + { + return; + } + ShopName = model.ShopName; + Address = model.Address; + DateOpening = model.DateOpening; + PastriesMaximum = model.PastriesMaximum; + Pastries = model.ShopPastries.ToDictionary(x => x.Key, x => x.Value.Item2); + _shopPastries = null; + } + + public ShopViewModel GetViewModel => new() + { + Id = Id, + ShopName = ShopName, + Address = Address, + DateOpening = DateOpening, + ShopPastries = ShopPastries, + PastriesMaximum = PastriesMaximum + }; + + public XElement GetXElement => new("Shop", + new XAttribute("Id", Id), + new XElement("ShopName", ShopName), + new XElement("Address", Address), + new XElement("DateOpening", DateOpening.ToString()), + new XElement("PastriesMaximum", PastriesMaximum.ToString()), + new XElement("ShopPastries", + Pastries.Select(x => new XElement("ShopPastry", + new XElement("Key", x.Key), + new XElement("Value", x.Value))).ToArray())); + } +} diff --git a/Confectionery/ConfectioneryListImplement/Implements/ShopStorage.cs b/Confectionery/ConfectioneryListImplement/Implements/ShopStorage.cs index 2a88b9a..e218b8e 100644 --- a/Confectionery/ConfectioneryListImplement/Implements/ShopStorage.cs +++ b/Confectionery/ConfectioneryListImplement/Implements/ShopStorage.cs @@ -3,6 +3,7 @@ using ConfectioneryContracts.SearchModels; using ConfectioneryContracts.StoragesContracts; using ConfectioneryContracts.ViewModels; using ConfectioneryListImplement.Models; +using ConfectioneryDataModels.Models; namespace ConfectioneryListImplement.Implements { @@ -105,5 +106,10 @@ namespace ConfectioneryListImplement.Implements } return null; } + + public bool Sale(IPastryModel model, int count) + { + throw new NotImplementedException(); + } } } diff --git a/Confectionery/ConfectioneryListImplement/Models/Shop.cs b/Confectionery/ConfectioneryListImplement/Models/Shop.cs index 6eecde0..361e482 100644 --- a/Confectionery/ConfectioneryListImplement/Models/Shop.cs +++ b/Confectionery/ConfectioneryListImplement/Models/Shop.cs @@ -1,6 +1,7 @@ using ConfectioneryContracts.BindingModels; using ConfectioneryContracts.ViewModels; using ConfectioneryDataModels.Models; +using System.Reflection; namespace ConfectioneryListImplement.Models { @@ -20,6 +21,8 @@ namespace ConfectioneryListImplement.Models private set; } = new Dictionary(); + public int PastriesMaximum { get; private set; } + public static Shop? Create(ShopBindingModel? model) { if (model == null) @@ -32,7 +35,8 @@ namespace ConfectioneryListImplement.Models ShopName = model.ShopName, Address = model.Address, DateOpening = model.DateOpening, - ShopPastries = model.ShopPastries + ShopPastries = model.ShopPastries, + PastriesMaximum = model.PastriesMaximum }; } @@ -46,6 +50,7 @@ namespace ConfectioneryListImplement.Models Address = model.Address; DateOpening = model.DateOpening; ShopPastries = model.ShopPastries; + PastriesMaximum = model.PastriesMaximum; } public ShopViewModel GetViewModel => new() @@ -54,7 +59,8 @@ namespace ConfectioneryListImplement.Models ShopName = ShopName, Address = Address, DateOpening = DateOpening, - ShopPastries = ShopPastries + ShopPastries = ShopPastries, + PastriesMaximum = PastriesMaximum }; } } diff --git a/Confectionery/ConfectioneryView/FormPastrySale.Designer.cs b/Confectionery/ConfectioneryView/FormPastrySale.Designer.cs new file mode 100644 index 0000000..6d16ae7 --- /dev/null +++ b/Confectionery/ConfectioneryView/FormPastrySale.Designer.cs @@ -0,0 +1,39 @@ +namespace ConfectioneryView +{ + partial class FormPastrySale + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Text = "FormPastrySale"; + } + + #endregion + } +} \ No newline at end of file diff --git a/Confectionery/ConfectioneryView/FormPastrySale.cs b/Confectionery/ConfectioneryView/FormPastrySale.cs new file mode 100644 index 0000000..2d444ef --- /dev/null +++ b/Confectionery/ConfectioneryView/FormPastrySale.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace ConfectioneryView +{ + public partial class FormPastrySale : Form + { + public FormPastrySale() + { + InitializeComponent(); + } + } +} diff --git a/Confectionery/ConfectioneryView/FormPastrySale.resx b/Confectionery/ConfectioneryView/FormPastrySale.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Confectionery/ConfectioneryView/FormPastrySale.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file