From 517472e29805cb2540e37930881831a155344f65 Mon Sep 17 00:00:00 2001 From: ole1986 Date: Mon, 11 Aug 2014 10:19:39 +0200 Subject: [PATCH] use user control to setup timer intervals --- plugins/Radegast.Plugin.EVOVend/EVOVend.cs | 260 -------------- .../EVOvendPlugin.Designer.cs | 97 +++++ plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.cs | 395 +++++++++++++++++++++ plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.resx | 120 +++++++ 4 files changed, 612 insertions(+), 260 deletions(-) delete mode 100644 plugins/Radegast.Plugin.EVOVend/EVOVend.cs create mode 100644 plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.Designer.cs create mode 100644 plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.cs create mode 100644 plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.resx diff --git a/plugins/Radegast.Plugin.EVOVend/EVOVend.cs b/plugins/Radegast.Plugin.EVOVend/EVOVend.cs deleted file mode 100644 index 2dac096..0000000 --- a/plugins/Radegast.Plugin.EVOVend/EVOVend.cs +++ /dev/null @@ -1,260 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Windows.Forms; -using Radegast; -using OpenMetaverse; - -using System.Text.RegularExpressions; -using System.Net; -using System.Linq; -using System.IO; - -namespace Radegast.Plugin.Demo -{ - [Radegast.Plugin(Name="EVOVend Plugin", Description="EVO Vendor Delivery System", Version="1.0")] - public class DemoPlugin : IRadegastPlugin - { - private System.Threading.Timer timer; - private InventoryManager Manager; - private OpenMetaverse.Inventory Inventory; - - private string vendURL = @"http://evosl.org/TREK/SL/index.php"; - List searchRes = new List(); - - private RadegastInstance Instance; - private GridClient Client { get { return Instance.Client; } } - - private string pluginName = "EVOVend"; - private string version = "1.0"; - - public DemoPlugin () - { - - } - - public void StartPlugin(RadegastInstance inst) - { - Instance = inst; - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + " version " + version + " loaded"); - - // setup timer - timer = new System.Threading.Timer(new TimerCallback(productCallback)); - timer.Change((5 * 1000), (60 * 1000)); - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Waiting 5 seconds for Inventory..."); - } - - public void StopPlugin(RadegastInstance instance) - { - // kill timer - timer.Dispose(); - } - - private string m_searchString; - public string searchString { - get - { - return m_searchString; - } - set - { - m_searchString = value; - if(!String.IsNullOrEmpty(value)) - PerformRecursiveSearch(0, Inventory.RootFolder.UUID); - } - } - - void PerformRecursiveSearch(int level, UUID folderID) - { - var me = Inventory.Items[folderID].Data; - var sorted = Inventory.GetContents(folderID); - - sorted.Sort((InventoryBase b1, InventoryBase b2) => - { - if (b1 is InventoryFolder && !(b2 is InventoryFolder)) - { - return -1; - } - else if (!(b1 is InventoryFolder) && b2 is InventoryFolder) - { - return 1; - } - else - { - return string.Compare(b1.Name, b2.Name); - } - }); - - foreach (var item in sorted) - { - if (item is InventoryFolder) - { - PerformRecursiveSearch(level + 1, item.UUID); - } - else - { - var it = item as InventoryItem; - - if (it.UUID.ToString().Contains(searchString)) - searchRes.Add(it); - } - } - } - - class DeliveryQueue { - public string ClassName { get; set; } - public string id {get;set;} - public string userUUID { get; set; } - public string objectUUID { get; set; } - public int price { get; set; } - public string created { get; set; } - public string delivered { get; set; } - } - - private string RequestVendor(string action, Dictionary param = null) - { - try - { - var webRequest = WebRequest.Create(this.vendURL); - - string postData = "action=" + action; - if (param != null && param.Count > 0) - { - var kv = param.Select(p => "&" + p.Key + "=" +p.Value); - postData += String.Join("", kv.ToArray()); - } - byte[] byteArray = Encoding.UTF8.GetBytes(postData); - - webRequest.Method = "POST"; - webRequest.ContentType = "application/x-www-form-urlencoded"; - webRequest.ContentLength = byteArray.Length; - - // add post data to request - Stream postStream = webRequest.GetRequestStream(); - postStream.Write(byteArray, 0, byteArray.Length); - postStream.Flush(); - postStream.Close(); - - using (var response = webRequest.GetResponse()) - using (var content = response.GetResponseStream()) - using (var reader = new System.IO.StreamReader(content)) - { - return reader.ReadToEnd(); - } - }catch { } - return null; - } - - private List parseResponse(string content) - { - List queue = new List(); - - if (String.IsNullOrEmpty(content)) return queue; - - try{ - System.Reflection.PropertyInfo[] propertyInfos = typeof(DeliveryQueue).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); - - string field_separator = "|"; - - var lines = content.Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); - foreach (string l in lines) - { - int lastPos = 0; - - var deliveryQ = new DeliveryQueue(); - foreach (System.Reflection.PropertyInfo pInfo in propertyInfos) - { - var nextPos = l.IndexOf(field_separator, lastPos); - if(nextPos > -1){ - object o = Convert.ChangeType(l.Substring(lastPos, nextPos - lastPos), pInfo.PropertyType); - pInfo.SetValue(deliveryQ, o, null); - } - lastPos = nextPos + 1; - } - - queue.Add(deliveryQ); - } - } catch(Exception ex){ - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Failed to read DeliveryQ - " + ex.Message, ChatBufferTextStyle.Error); - } - return queue; - } - - private bool SendObject(DeliveryQueue p) - { - searchRes.Clear(); - searchString = p.objectUUID; - if (searchRes.Count <= 0) - { - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Product not found '" + searchString + "' for user '"+p.userUUID+"'", ChatBufferTextStyle.Error); - return false; - } - if (searchRes.Count > 1) { - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": More then one product found for '" + searchString + "'", ChatBufferTextStyle.Error); - return false; - } - - var inv = searchRes[0] as InventoryItem; - if(inv == null) { - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Product found, but not an inventory item", ChatBufferTextStyle.Error); - return false; - } - - - Dictionary param = new Dictionary(); - param.Add("id", p.id); - var str = this.RequestVendor("SETDELIVERED", param); - if (str != "1") { - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Product found, but user " + p.userUUID + " might not have enough funds", ChatBufferTextStyle.Normal); - // a message to the user would be helpful later - return false; - } - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": SETDELIVERED: " + str, ChatBufferTextStyle.StatusBlue); - - Manager.GiveItem(inv.UUID, inv.Name, inv.AssetType, OpenMetaverse.UUID.Parse(p.userUUID), false); - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": PRODUCT '" + searchRes[0].Name + "' SENT TO " + p.userUUID, ChatBufferTextStyle.StatusBlue); - - return true; - } - - private bool isSending = false; - private void productCallback(object obj) - { - Manager = Client.Inventory; - Inventory = Manager.Store; - Inventory.RootFolder.OwnerID = Client.Self.AgentID; - - if (isSending == true) - { - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Waiting..."); - return; - } - isSending = true; - - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Queue List"); - - var strContent = this.RequestVendor("GETOUTSTANDING"); - List queue = this.parseResponse(strContent); - - // check if i have something to do - if (queue.Count <= 0) return; - - foreach (DeliveryQueue p in queue) - this.SendObject (p); - - /*var grouped = queue.GroupBy(p => p.objectUUID).Select(t=> new { count = t.Count(), UUID = t.Key }); - foreach (var g in grouped) - { - var userIds = queue.Where(p => p.objectUUID == g.UUID).Select(p => p.id); - if (userIds.Count() > 0) - { - var users = String.Join(",", userIds.ToArray()); - Instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ":" + users, ChatBufferTextStyle.Normal); - } - }*/ - - isSending = false; - } - } -} diff --git a/plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.Designer.cs b/plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.Designer.cs new file mode 100644 index 0000000..d332b83 --- /dev/null +++ b/plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.Designer.cs @@ -0,0 +1,97 @@ +namespace Radegast.Plugin.EVOVend +{ + partial class EVOvendPlugin + { + /// + /// 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 Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.numDeliveryInterval = new System.Windows.Forms.NumericUpDown(); + this.label2 = new System.Windows.Forms.Label(); + this.numStartupDelay = new System.Windows.Forms.NumericUpDown(); + this.label1 = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.numDeliveryInterval)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numStartupDelay)).BeginInit(); + this.SuspendLayout(); + // + // numDeliveryInterval + // + this.numDeliveryInterval.Location = new System.Drawing.Point(396, 19); + this.numDeliveryInterval.Name = "numDeliveryInterval"; + this.numDeliveryInterval.Size = new System.Drawing.Size(120, 20); + this.numDeliveryInterval.TabIndex = 7; + this.numDeliveryInterval.ValueChanged += new System.EventHandler(this.numDeliveryInterval_ValueChanged); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(281, 21); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(109, 13); + this.label2.TabIndex = 6; + this.label2.Text = "Delivery Interval [sec]"; + // + // numStartupDelay + // + this.numStartupDelay.Location = new System.Drawing.Point(118, 19); + this.numStartupDelay.Name = "numStartupDelay"; + this.numStartupDelay.Size = new System.Drawing.Size(120, 20); + this.numStartupDelay.TabIndex = 5; + this.numStartupDelay.ValueChanged += new System.EventHandler(this.numStartupDelay_ValueChanged); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(17, 21); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(95, 13); + this.label1.TabIndex = 4; + this.label1.Text = "Startup delay [sec]"; + // + // EVOvendPlugin + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.numDeliveryInterval); + this.Controls.Add(this.label2); + this.Controls.Add(this.numStartupDelay); + this.Controls.Add(this.label1); + this.Name = "EVOvendPlugin"; + this.Size = new System.Drawing.Size(538, 138); + ((System.ComponentModel.ISupportInitialize)(this.numDeliveryInterval)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numStartupDelay)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.NumericUpDown numDeliveryInterval; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.NumericUpDown numStartupDelay; + private System.Windows.Forms.Label label1; + } +} diff --git a/plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.cs b/plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.cs new file mode 100644 index 0000000..8a79683 --- /dev/null +++ b/plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.cs @@ -0,0 +1,395 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using System.Threading; +using System.IO; +using System.Net; + +namespace Radegast.Plugin.EVOVend +{ + [Radegast.Plugin(Name = "EVOvend Plugin", Description = "EVO Vendor Delivery System", Version = "1.0")] + public partial class EVOvendPlugin : RadegastTabControl, IRadegastPlugin + { + public int DELIVERY_INTERVAL + { + get + { + return (int)numDeliveryInterval.Value; + } + set + { + numDeliveryInterval.Value = value; + } + } + + public int STARTUP_DELAY + { + get + { + return (int)numStartupDelay.Value; + } + set + { + numStartupDelay.Value = value; + } + } + + public OSDMap config; + + private System.Threading.Timer timer; + private InventoryManager Manager; + private OpenMetaverse.Inventory Inventory; + + private string vendURL = @"http://evosl.org/TREK/SL/index.php"; + List searchRes = new List(); + + private GridClient Client { get { return instance.Client; } } + + static string tabID = "evovend_tab"; + static string tabLabel = "EVOvend"; + + private string pluginName = "EVOvend"; + private string version = "1.0"; + private ToolStripMenuItem EVOButton; + + public EVOvendPlugin() + { + //this.InitializeComponent(); + } + + public EVOvendPlugin(RadegastInstance instance, bool unused) : base(instance) + { + //this.instance = instance; + Init(); + Disposed += new EventHandler(EVOvendTab_Disposed); + RegisterClientEvents(client); + } + + void RegisterClientEvents(GridClient client) + { + //instance.ClientChanged += new EventHandler(instance_ClientChanged); + //client.Self.ChatFromSimulator += new EventHandler(Self_ChatFromSimulator); + } + void UnregisterClientEvents(GridClient client) + { + //if (client == null) return; + //client.Self.ChatFromSimulator -= new EventHandler(Self_ChatFromSimulator); + } + + void EVOvendTab_Disposed(object sender, EventArgs e) + { + this.writeConfig(); + UnregisterClientEvents(client); + //instance.ClientChanged -= new EventHandler(instance_ClientChanged); + } + + public void StartPlugin(RadegastInstance inst) + { + instance = inst; + instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + " version " + version + " loaded"); + + Init(); + + EVOButton = new ToolStripMenuItem(tabLabel, null, OnEVOButtonClicked); + instance.MainForm.PluginsMenu.DropDownItems.Add(EVOButton); + + // setup timer + timer = new System.Threading.Timer(new TimerCallback(productCallback)); + this.SetupTimer(); + } + + public void SetupTimer(){ + if (timer == null) return; + timer.Change((STARTUP_DELAY * 1000), (DELIVERY_INTERVAL * 1000)); + instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Waiting " + STARTUP_DELAY + " seconds before start..."); + } + + private void Init() + { + this.InitializeComponent(); + + if (instance != null) + { + this.readConfig(); + } + } + + private void readConfig() + { + config = instance.GlobalSettings["plugin." + pluginName] as OSDMap; + + if (config == null) + { + config = new OSDMap(); + config["startup_delay"] = new OSDInteger(60); + config["delivery_interval"] = new OSDInteger(60); + instance.GlobalSettings["plugin." + pluginName] = config; + } + + if (!config.ContainsKey("startup_delay")) + config["startup_delay"] = 60; + if (!config.ContainsKey("delivery_interval")) + config["delivery_interval"] = 60; + + STARTUP_DELAY = config["startup_delay"].AsInteger(); + DELIVERY_INTERVAL = config["delivery_interval"].AsInteger(); + } + + private void writeConfig() + { + config = instance.GlobalSettings["plugin." + pluginName] as OSDMap; + + if (config != null) + { + config["startup_delay"] = STARTUP_DELAY; + config["delivery_interval"] = DELIVERY_INTERVAL; + //instance.GlobalSettings["plugin." + pluginName] = config; + } + + instance.GlobalSettings.Save(); + } + + void OnEVOButtonClicked(object sender, EventArgs e) + { + if (instance.TabConsole.TabExists(tabID)) + { + instance.TabConsole.Tabs[tabID].Select(); + } + else + { + instance.TabConsole.AddTab(tabID, tabLabel, new EVOvendPlugin(instance, true)); + instance.TabConsole.Tabs[tabID].Select(); + } + } + + public void StopPlugin(RadegastInstance instance) + { + // kill timer + timer.Dispose(); + EVOButton.Dispose(); + } + + private string m_searchString; + public string searchString + { + get + { + return m_searchString; + } + set + { + m_searchString = value; + if (!String.IsNullOrEmpty(value)) + PerformRecursiveSearch(0, Inventory.RootFolder.UUID); + } + } + + void PerformRecursiveSearch(int level, UUID folderID) + { + var me = Inventory.Items[folderID].Data; + var sorted = Inventory.GetContents(folderID); + + sorted.Sort((InventoryBase b1, InventoryBase b2) => + { + if (b1 is InventoryFolder && !(b2 is InventoryFolder)) + { + return -1; + } + else if (!(b1 is InventoryFolder) && b2 is InventoryFolder) + { + return 1; + } + else + { + return string.Compare(b1.Name, b2.Name); + } + }); + + foreach (var item in sorted) + { + if (item is InventoryFolder) + { + PerformRecursiveSearch(level + 1, item.UUID); + } + else + { + var it = item as InventoryItem; + + if (it.UUID.ToString().Contains(searchString)) + searchRes.Add(it); + } + } + } + + class DeliveryQueue + { + public string ClassName { get; set; } + public string id { get; set; } + public string userUUID { get; set; } + public string objectUUID { get; set; } + public int price { get; set; } + public string created { get; set; } + public string delivered { get; set; } + } + + private string RequestVendor(string action, Dictionary param = null) + { + try + { + var webRequest = WebRequest.Create(this.vendURL); + + string postData = "action=" + action; + if (param != null && param.Count > 0) + { + var kv = param.Select(p => "&" + p.Key + "=" + p.Value); + postData += String.Join("", kv.ToArray()); + } + byte[] byteArray = Encoding.UTF8.GetBytes(postData); + + webRequest.Method = "POST"; + webRequest.ContentType = "application/x-www-form-urlencoded"; + webRequest.ContentLength = byteArray.Length; + + // add post data to request + Stream postStream = webRequest.GetRequestStream(); + postStream.Write(byteArray, 0, byteArray.Length); + postStream.Flush(); + postStream.Close(); + + using (var response = webRequest.GetResponse()) + using (var content = response.GetResponseStream()) + using (var reader = new System.IO.StreamReader(content)) + { + return reader.ReadToEnd(); + } + } + catch { } + return null; + } + + private List parseResponse(string content) + { + List queue = new List(); + + if (String.IsNullOrEmpty(content)) return queue; + + try + { + System.Reflection.PropertyInfo[] propertyInfos = typeof(DeliveryQueue).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + string field_separator = "|"; + + var lines = content.Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + foreach (string l in lines) + { + int lastPos = 0; + + var deliveryQ = new DeliveryQueue(); + foreach (System.Reflection.PropertyInfo pInfo in propertyInfos) + { + var nextPos = l.IndexOf(field_separator, lastPos); + if (nextPos > -1) + { + object o = Convert.ChangeType(l.Substring(lastPos, nextPos - lastPos), pInfo.PropertyType); + pInfo.SetValue(deliveryQ, o, null); + } + lastPos = nextPos + 1; + } + + queue.Add(deliveryQ); + } + } + catch (Exception ex) + { + instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Failed to read DeliveryQ - " + ex.Message, ChatBufferTextStyle.Error); + } + return queue; + } + + private bool SendObject(DeliveryQueue p) + { + searchRes.Clear(); + searchString = p.objectUUID; + if (searchRes.Count <= 0) + { + instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Product not found '" + searchString + "' for user '" + p.userUUID + "'", ChatBufferTextStyle.Error); + return false; + } + if (searchRes.Count > 1) + { + instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": More then one product found for '" + searchString + "'", ChatBufferTextStyle.Error); + return false; + } + + var inv = searchRes[0] as InventoryItem; + if (inv == null) + { + instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Product found, but not an inventory item", ChatBufferTextStyle.Error); + return false; + } + + + Dictionary param = new Dictionary(); + param.Add("id", p.id); + var str = this.RequestVendor("SETDELIVERED", param); + if (str != "1") + { + instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Product found, but user " + p.userUUID + " might not have enough funds", ChatBufferTextStyle.Normal); + // a message to the user would be helpful later + return false; + } + instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": SETDELIVERED: " + str, ChatBufferTextStyle.StatusBlue); + + Manager.GiveItem(inv.UUID, inv.Name, inv.AssetType, OpenMetaverse.UUID.Parse(p.userUUID), false); + instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": PRODUCT '" + searchRes[0].Name + "' SENT TO " + p.userUUID, ChatBufferTextStyle.StatusBlue); + + return true; + } + + private bool isSending = false; + private void productCallback(object obj) + { + Manager = Client.Inventory; + Inventory = Manager.Store; + Inventory.RootFolder.OwnerID = Client.Self.AgentID; + + if (isSending == true) + { + instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Waiting..."); + return; + } + isSending = true; + + instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Queue List"); + + var strContent = this.RequestVendor("GETOUTSTANDING"); + List queue = this.parseResponse(strContent); + + // check if i have something to do + if (queue.Count <= 0) return; + + foreach (DeliveryQueue p in queue) + this.SendObject(p); + + isSending = false; + } + + private void numStartupDelay_ValueChanged(object sender, EventArgs e) + { + this.SetupTimer(); + } + + private void numDeliveryInterval_ValueChanged(object sender, EventArgs e) + { + this.SetupTimer(); + } + } +} + \ No newline at end of file diff --git a/plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.resx b/plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.resx new file mode 100644 index 0000000..7080a7d --- /dev/null +++ b/plugins/Radegast.Plugin.EVOVend/EVOvendPlugin.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file -- 2.11.0