From 180945a0ef44bdfbe07f64231b05ffe3235757ac Mon Sep 17 00:00:00 2001 From: unitycoder Date: Thu, 31 Aug 2017 22:21:53 +0800 Subject: [PATCH 01/81] fix icons, add install/uninstall registry key for explorer context menu, fix explore project button, --- UnityLauncher/Form1.Designer.cs | 64 +- UnityLauncher/Form1.cs | 50 +- UnityLauncher/Form1.resx | 2222 ++++++++++++++++------ UnityLauncher/Properties/AssemblyInfo.cs | 2 +- UnityLauncher/UnityLauncher.csproj | 6 + UnityLauncher/unitylauncher.ico | Bin 0 -> 52802 bytes 6 files changed, 1708 insertions(+), 636 deletions(-) create mode 100644 UnityLauncher/unitylauncher.ico diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index b4441de..9148e08 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -49,6 +49,7 @@ private void InitializeComponent() this._unityVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._unityPath = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabPackages = new System.Windows.Forms.TabPage(); + this.btnAddAssetStoreFolder = new System.Windows.Forms.Button(); this.btnExplorePackageFolder = new System.Windows.Forms.Button(); this.btnAddPackageFolder = new System.Windows.Forms.Button(); this.btnRemovePackFolder = new System.Windows.Forms.Button(); @@ -67,8 +68,9 @@ private void InitializeComponent() this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); this.btnAddPackFolder = new System.Windows.Forms.Button(); - this.btnAddAssetStoreFolder = new System.Windows.Forms.Button(); - this.statusStrip1.SuspendLayout(); + this.label4 = new System.Windows.Forms.Label(); + this.btnRemoveRegister = new System.Windows.Forms.Button(); + this.btnAddRegister = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -80,8 +82,6 @@ private void InitializeComponent() // // statusStrip1 // - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(544, 22); @@ -127,6 +127,7 @@ private void InitializeComponent() this.btnOpenUnityFolder.Text = "Explore"; this.toolTip1.SetToolTip(this.btnOpenUnityFolder, "Open File Explorer"); this.btnOpenUnityFolder.UseVisualStyleBackColor = true; + this.btnOpenUnityFolder.Click += new System.EventHandler(this.btn_openFolder_Click); // // btnLaunch // @@ -302,6 +303,16 @@ private void InitializeComponent() this.tabPackages.Text = "My Packages"; this.tabPackages.UseVisualStyleBackColor = true; // + // btnAddAssetStoreFolder + // + this.btnAddAssetStoreFolder.Location = new System.Drawing.Point(372, 232); + this.btnAddAssetStoreFolder.Name = "btnAddAssetStoreFolder"; + this.btnAddAssetStoreFolder.Size = new System.Drawing.Size(142, 23); + this.btnAddAssetStoreFolder.TabIndex = 29; + this.btnAddAssetStoreFolder.Text = "Add AssetStore Folder"; + this.btnAddAssetStoreFolder.UseVisualStyleBackColor = true; + this.btnAddAssetStoreFolder.Click += new System.EventHandler(this.btnAddAssetStoreFolder_Click); + // // btnExplorePackageFolder // this.btnExplorePackageFolder.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); @@ -354,6 +365,9 @@ private void InitializeComponent() // // tabPage3 // + this.tabPage3.Controls.Add(this.btnAddRegister); + this.tabPage3.Controls.Add(this.btnRemoveRegister); + this.tabPage3.Controls.Add(this.label4); this.tabPage3.Controls.Add(this.label2); this.tabPage3.Controls.Add(this.chkMinimizeToTaskbar); this.tabPage3.Controls.Add(this.label1); @@ -470,15 +484,34 @@ private void InitializeComponent() this.btnAddPackFolder.Text = "Add Folder"; this.btnAddPackFolder.UseVisualStyleBackColor = true; // - // btnAddAssetStoreFolder + // label4 // - this.btnAddAssetStoreFolder.Location = new System.Drawing.Point(372, 232); - this.btnAddAssetStoreFolder.Name = "btnAddAssetStoreFolder"; - this.btnAddAssetStoreFolder.Size = new System.Drawing.Size(142, 23); - this.btnAddAssetStoreFolder.TabIndex = 29; - this.btnAddAssetStoreFolder.Text = "Add AssetStore Folder"; - this.btnAddAssetStoreFolder.UseVisualStyleBackColor = true; - this.btnAddAssetStoreFolder.Click += new System.EventHandler(this.btnAddAssetStoreFolder_Click); + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(21, 423); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(117, 13); + this.label4.TabIndex = 28; + this.label4.Text = "Explorer Context Menu:"; + // + // btnRemoveRegister + // + this.btnRemoveRegister.Location = new System.Drawing.Point(211, 418); + this.btnRemoveRegister.Name = "btnRemoveRegister"; + this.btnRemoveRegister.Size = new System.Drawing.Size(64, 23); + this.btnRemoveRegister.TabIndex = 29; + this.btnRemoveRegister.Text = "uninstall"; + this.btnRemoveRegister.UseVisualStyleBackColor = true; + this.btnRemoveRegister.Click += new System.EventHandler(this.btnRemoveRegister_Click); + // + // btnAddRegister + // + this.btnAddRegister.Location = new System.Drawing.Point(141, 418); + this.btnAddRegister.Name = "btnAddRegister"; + this.btnAddRegister.Size = new System.Drawing.Size(64, 23); + this.btnAddRegister.TabIndex = 30; + this.btnAddRegister.Text = "Install"; + this.btnAddRegister.UseVisualStyleBackColor = true; + this.btnAddRegister.Click += new System.EventHandler(this.btnAddRegister_Click); // // Form1 // @@ -493,12 +526,10 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Potato Edition 5"; + this.Text = "UnityLauncher - Potato Edition 6"; this.Load += new System.EventHandler(this.Form1_Load); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); - this.statusStrip1.ResumeLayout(false); - this.statusStrip1.PerformLayout(); this.tabControl1.ResumeLayout(false); this.tabPage1.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).EndInit(); @@ -552,6 +583,9 @@ private void InitializeComponent() private System.Windows.Forms.Button btnRemovePackFolder; private System.Windows.Forms.Button btnAddPackFolder; private System.Windows.Forms.Button btnAddAssetStoreFolder; + private System.Windows.Forms.Button btnAddRegister; + private System.Windows.Forms.Button btnRemoveRegister; + private System.Windows.Forms.Label label4; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index a26306e..2a30a52 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -531,10 +531,53 @@ void AddPackageFolder() } } + void AddContextMenuRegistry() + { + RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Classes\\Directory\\Background\\shell", true); + if (key != null) + { + var appName = "UnityLauncher"; + key.CreateSubKey(appName); + + key = key.OpenSubKey(appName, true); + key.SetValue("", "Open with UnityLauncher"); + key.SetValue("Icon", "\"" + Application.ExecutablePath + "\""); + + key.CreateSubKey("command"); + key = key.OpenSubKey("command", true); + var executeString = "\"" + Application.ExecutablePath + "\""; + executeString += " -projectPath \"%V\""; + key.SetValue("", executeString); + SetStatus("Added context menu registry items"); + } + else + { + SetStatus("Error> Cannot find registry key: Software\\Classes\\Directory\\Background\\shell"); + } + } + void RemoveContextMenuRegistry() + { + RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Classes\\Directory\\Background\\shell", true); + if (key != null) + { + var appName = "UnityLauncher"; + key.DeleteSubKeyTree(appName); + SetStatus("Removed context menu registry items"); + } + else + { + SetStatus("Error> Cannot find registry key: Software\\Classes\\Directory\\Background\\shell"); + } + } #region Buttons and UI events + private void btnRemoveRegister_Click(object sender, EventArgs e) + { + RemoveContextMenuRegistry(); + } + private void chkMinimizeToTaskbar_CheckedChanged(object sender, EventArgs e) { Properties.Settings.Default.minimizeToTaskbar = chkMinimizeToTaskbar.Checked; @@ -737,8 +780,11 @@ private void btnAddAssetStoreFolder_Click(object sender, EventArgs e) } } - - + private void btnAddRegister_Click(object sender, EventArgs e) + { + AddContextMenuRegistry(); + } #endregion + } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index f48841a..64415dd 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -171,394 +171,887 @@ - AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAgAKgQAABGDgAAMDAAAAEA - IACoJQAA7h4AAEBAAAABAAgAKBYAAJZEAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAA - AAAAAAAACAgI/wcHB/8EBAT/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQE - BP8HBwf/CAgI/wcHB/8cHBz/TExM/01NTf9NTU3/TU1N/01NTf9NTU3/TU1N/01NTf9NTU3/TU1N/01N - Tf9MTEz/HBwc/wcHB/8EBAT/TExM//Pz8//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f3 - 9//39/f/8/Pz/0xMTP8EBAT/AwMD/01NTf/39/f//f39//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//f39//f39/9NTU3/AwMD/wMDA/9NTU3/9/f3//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/39/f/TU1N/wMDA/8DAwP/TU1N//f39//8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz/9/f3/01NTf8DAwP/AwMD/01NTf/39/f//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//f39/9NTU3/AwMD/wMDA/9NTU3/9/f3//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/39/f/TU1N/wMDA/8DAwP/TU1N//f39//8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/9/f3/01NTf8DAwP/AwMD/01NTf/39/f//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//f39/9NTU3/AwMD/wMDA/9NTU3/9/f3//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/39/f/TU1N/wMDA/8DAwP/TU1N//f3 - 9//8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/9/f3/01NTf8DAwP/AwMD/01N - Tf/39/f//f39//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//f39//f39/9NTU3/AwMD/wQE - BP9MTEz/8/Pz//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//z8/P/TExM/wQE - BP8HBwf/HBwc/0xMTP9NTU3/TU1N/01NTf9NTU3/TU1N/01NTf9NTU3/TU1N/01NTf9NTU3/TExM/xwc - HP8HBwf/CAgI/wcHB/8EBAT/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQE - BP8HBwf/CAgI/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAoAAAAGAAAADAAAAABACAAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAACAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8GBgb/AwMD/wMDA/8DAwP/AwMD/wMD - A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgYG/wgI - CP8ICAj/CAgI/wYGBv8tLS3/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dn - Z/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/LS0t/wYGBv8ICAj/CAgI/wMDA/9nZ2f///////7+ - /v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+ - /v//////Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMD - A/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMD - A/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMD - A/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMD - A/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMD - A/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMD - A/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMD - A/9nZ2f///////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+ - /v/+/v7//v7+//7+/v//////Z2dn/wMDA/8ICAj/CAgI/wYGBv8tLS3/Z2dn/2dnZ/9nZ2f/Z2dn/2dn - Z/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/LS0t/wYG - Bv8ICAj/CAgI/wgICP8GBgb/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD - A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgYG/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAA - AABAAAAAAQAgAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8GBgb/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD - A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgYG/wgICP8ICAj/CAgI/wgI - CP8ICAj/BgYG/0VFRf+EhIT/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KC - gv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4SEhP9FRUX/BgYG/wgI - CP8ICAj/CAgI/wgICP8DAwP/hISE//////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////4SE - hP8DAwP/CAgI/wgICP8ICAj/CAgI/wMDA/+CgoL///////z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P//////goKC/wMDA/8ICAj/CAgI/wgICP8ICAj/AwMD/4KCgv///////Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+CgoL/AwMD/wgICP8ICAj/CAgI/wgICP8DAwP/goKC///////8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//////4KCgv8DAwP/CAgI/wgICP8ICAj/CAgI/wMDA/+CgoL///////z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P//////goKC/wMDA/8ICAj/CAgI/wgICP8ICAj/AwMD/4KC - gv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+CgoL/AwMD/wgICP8ICAj/CAgI/wgI - CP8DAwP/goKC///////8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//////4KCgv8DAwP/CAgI/wgI - CP8ICAj/CAgI/wMDA/+CgoL///////z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P//////goKC/wMD - A/8ICAj/CAgI/wgICP8ICAj/AwMD/4KCgv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+CgoL/AwMD/wgICP8ICAj/CAgI/wgICP8DAwP/goKC///////8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//////4KCgv8DAwP/CAgI/wgICP8ICAj/CAgI/wMDA/+CgoL///////z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P//////goKC/wMDA/8ICAj/CAgI/wgICP8ICAj/AwMD/4KCgv///////Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+CgoL/AwMD/wgICP8ICAj/CAgI/wgICP8DAwP/goKC//// - ///8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//////4KCgv8DAwP/CAgI/wgICP8ICAj/CAgI/wMD - A/+CgoL///////z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P//////goKC/wMDA/8ICAj/CAgI/wgI - CP8ICAj/AwMD/4KCgv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+CgoL/AwMD/wgI - CP8ICAj/CAgI/wgICP8DAwP/goKC///////8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//////4KC - gv8DAwP/CAgI/wgICP8ICAj/CAgI/wMDA/+CgoL///////z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P//////goKC/wMDA/8ICAj/CAgI/wgICP8ICAj/AwMD/4KCgv///////Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+CgoL/AwMD/wgICP8ICAj/CAgI/wgICP8DAwP/goKC///////8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//////4KCgv8DAwP/CAgI/wgICP8ICAj/CAgI/wMDA/+CgoL///////z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P//////goKC/wMDA/8ICAj/CAgI/wgICP8ICAj/AwMD/4KC - gv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+CgoL/AwMD/wgICP8ICAj/CAgI/wgI - CP8DAwP/goKC///////8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//////4KCgv8DAwP/CAgI/wgI - CP8ICAj/CAgI/wMDA/+CgoL///////z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P//////goKC/wMD - A/8ICAj/CAgI/wgICP8ICAj/AwMD/4SEhP////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //+EhIT/AwMD/wgICP8ICAj/CAgI/wgICP8GBgb/RUVF/4SEhP+CgoL/goKC/4KCgv+CgoL/goKC/4KC - gv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KC - gv+CgoL/hISE/0VFRf8GBgb/CAgI/wgICP8ICAj/CAgI/wgICP8GBgb/AwMD/wMDA/8DAwP/AwMD/wMD - A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD - A/8DAwP/AwMD/wMDA/8DAwP/BgYG/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8AAAAAAAAAAAAA + AAABAA0AICAQAAEABADoAgAA1gAAABAQEAABAAQAKAEAAL4DAAAwMAAAAQAIAKgOAADmBAAAICAAAAEA + CACoCAAAjhMAABAQAAABAAgAaAUAADYcAAAAAAAAAQAgABwFAACeIQAAQEAAAAEAIAAoQgAAuiYAADAw + AAABACAAqCUAAOJoAAAoKAAAAQAgAGgaAACKjgAAICAAAAEAIACoEAAA8qgAABgYAAABACAAiAkAAJq5 + AAAUFAAAAQAgALgGAAAiwwAAEBAAAAEAIABoBAAA2skAACgAAAAgAAAAQAAAAAEABAAAAAAAgAIAAAAA + AAAAAAAAEAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD/ + /wD/AAAA/wD/AP//AAD///8A////////////////////////////////////////////AAAAAAAAAAAA + AAAAAAD//wAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAP//AA//////////////8AD//wAP//// + //////////AA//8AD//////////////wAP//AA//////////////8AD//wAP//////////////AA//8A + D//////////////wAP//AA//////////////8AD//wAP//////////////AA//8AD//////////////w + AP//AA//////////////8AD//wAP//////////////AA//8AD//////////////wAP//AA////////// + ////8AD//wAP//////////////AA//8AD//////////////wAP//AA//////////////8AD//wAP//// + //////////AA//8AD//////////////wAP//AA//////////////8AD//wAP//////////////AA//8A + D//////////////wAP//AA//////////////8AD//wAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAA + AP//AAAAAAAAAAAAAAAAAAD///////////////////////////////////////////8AAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgA - AAAwAAAAYAAAAAEAIAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAICAj/CAgI/wgICP8ICAj/CAgI/wgI + AAAQAAAAIAAAAAEABAAAAAAAwAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAA + gACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8A///////////wAAAAAAAAD/D/ + //////8P8P///////w/w////////D/D///////8P8P///////w/w////////D/D///////8P8P////// + /w/w////////D/D///////8P8P///////w/w////////D/AAAAAAAAAP//////////8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAADAA + AABgAAAAAQAIAAAAAACACgAAAAAAAAAAAAAAAQAAAAAAAAgICAD8/PwAAA5QAAAUcAAAGpAAACCwAAAm + zwAALPAAET3/ADFX/wBRcf8AcYv/AJGl/wCxv/8A0dr/AP///wAAAAAAABovAAAtUAAAP3AAAFGQAABj + sAAAds8AAIjwABGY/wAxpv8AUbP/AHHB/wCRz/8Asd3/ANHr/wD///8AAAAAAAAsLwAAS1AAAGhwAACG + kAAApbAAAMPPAADh8AAR7/8AMfH/AFHz/wBx9f8Akff/ALH5/wDR+/8A////AAAAAAAALyEAAFA3AABw + TAAAkGMAALB5AADPjwAA8KYAEf+0ADH/vgBR/8gAcf/TAJH/3ACx/+UA0f/wAP///wAAAAAAAC8OAABQ + GAAAcCIAAJAsAACwNgAAz0AAAPBKABH/WwAx/3EAUf+HAHH/nQCR/7IAsf/JANH/3wD///8AAAAAAAIv + AAAEUAAABnAAAAiQAAAKsAAAC88AAA7wAAAg/xIAPf8xAFv/UQB5/3EAmP+RALX/sQDU/9EA////AAAA + AAAULwAAIlAAADBwAAA9kAAATLAAAFnPAABn8AAAeP8RAIr/MQCc/1EArv9xAMD/kQDS/7EA5P/RAP// + /wAAAAAAJi8AAEBQAABacAAAdJAAAI6wAACpzwAAwvAAANH/EQDY/zEA3v9RAOP/cQDp/5EA7/+xAPb/ + 0QD///8AAAAAAC8mAABQQQAAcFsAAJB0AACwjgAAz6kAAPDDAAD/0hEA/9gxAP/dUQD/5HEA/+qRAP/w + sQD/9tEA////AAAAAAAvFAAAUCIAAHAwAACQPgAAsE0AAM9bAADwaQAA/3kRAP+KMQD/nVEA/69xAP/B + kQD/0rEA/+XRAP///wAAAAAALwMAAFAEAABwBgAAkAkAALAKAADPDAAA8A4AAP8gEgD/PjEA/1xRAP96 + cQD/l5EA/7axAP/U0QD///8AAAAAAC8ADgBQABcAcAAhAJAAKwCwADYAzwBAAPAASQD/EVoA/zFwAP9R + hgD/cZwA/5GyAP+xyAD/0d8A////AAAAAAAvACAAUAA2AHAATACQAGIAsAB4AM8AjgDwAKQA/xGzAP8x + vgD/UccA/3HRAP+R3AD/seUA/9HwAP///wAAAAAALAAvAEsAUABpAHAAhwCQAKUAsADEAM8A4QDwAPAR + /wDyMf8A9FH/APZx/wD3kf8A+bH/APvR/wD///8AAAAAABsALwAtAFAAPwBwAFIAkABjALAAdgDPAIgA + 8ACZEf8ApjH/ALRR/wDCcf8Az5H/ANyx/wDr0f8A////AAAAAAAIAC8ADgBQABUAcAAbAJAAIQCwACYA + zwAsAPAAPhH/AFgx/wBxUf8AjHH/AKaR/wC/sf8A2tH/AP///wABAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAIAAAAEAAAAABAAgAAAAAAIAEAAAAAAAAAAAAAAAB + AAAAAAAACAgIAPz8/AAADlAAABRwAAAakAAAILAAACbPAAAs8AARPf8AMVf/AFFx/wBxi/8AkaX/ALG/ + /wDR2v8A////AAAAAAAAGi8AAC1QAAA/cAAAUZAAAGOwAAB2zwAAiPAAEZj/ADGm/wBRs/8AccH/AJHP + /wCx3f8A0ev/AP///wAAAAAAACwvAABLUAAAaHAAAIaQAAClsAAAw88AAOHwABHv/wAx8f8AUfP/AHH1 + /wCR9/8Asfn/ANH7/wD///8AAAAAAAAvIQAAUDcAAHBMAACQYwAAsHkAAM+PAADwpgAR/7QAMf++AFH/ + yABx/9MAkf/cALH/5QDR//AA////AAAAAAAALw4AAFAYAABwIgAAkCwAALA2AADPQAAA8EoAEf9bADH/ + cQBR/4cAcf+dAJH/sgCx/8kA0f/fAP///wAAAAAAAi8AAARQAAAGcAAACJAAAAqwAAALzwAADvAAACD/ + EgA9/zEAW/9RAHn/cQCY/5EAtf+xANT/0QD///8AAAAAABQvAAAiUAAAMHAAAD2QAABMsAAAWc8AAGfw + AAB4/xEAiv8xAJz/UQCu/3EAwP+RANL/sQDk/9EA////AAAAAAAmLwAAQFAAAFpwAAB0kAAAjrAAAKnP + AADC8AAA0f8RANj/MQDe/1EA4/9xAOn/kQDv/7EA9v/RAP///wAAAAAALyYAAFBBAABwWwAAkHQAALCO + AADPqQAA8MMAAP/SEQD/2DEA/91RAP/kcQD/6pEA//CxAP/20QD///8AAAAAAC8UAABQIgAAcDAAAJA+ + AACwTQAAz1sAAPBpAAD/eREA/4oxAP+dUQD/r3EA/8GRAP/SsQD/5dEA////AAAAAAAvAwAAUAQAAHAG + AACQCQAAsAoAAM8MAADwDgAA/yASAP8+MQD/XFEA/3pxAP+XkQD/trEA/9TRAP///wAAAAAALwAOAFAA + FwBwACEAkAArALAANgDPAEAA8ABJAP8RWgD/MXAA/1GGAP9xnAD/kbIA/7HIAP/R3wD///8AAAAAAC8A + IABQADYAcABMAJAAYgCwAHgAzwCOAPAApAD/EbMA/zG+AP9RxwD/cdEA/5HcAP+x5QD/0fAA////AAAA + AAAsAC8ASwBQAGkAcACHAJAApQCwAMQAzwDhAPAA8BH/APIx/wD0Uf8A9nH/APeR/wD5sf8A+9H/AP// + /wAAAAAAGwAvAC0AUAA/AHAAUgCQAGMAsAB2AM8AiADwAJkR/wCmMf8AtFH/AMJx/wDPkf8A3LH/AOvR + /wD///8AAAAAAAgALwAOAFAAFQBwABsAkAAhALAAJgDPACwA8AA+Ef8AWDH/AHFR/wCMcf8AppH/AL+x + /wDa0f8A////AAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEAAAAB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEB + AAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAA + AQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQAAAAEBAQEAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEAAAABAQEBAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEAAAABAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAAAAAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAAAAAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQAAAAEBAQEAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQEBAQAAAAEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEAAAAB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEB + AAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAA + AQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAQAAAAIAAAAAEACAAAAAAAQAEAAAAAAAAAAAAAAAEAAAAA + AAAICAgA/Pz8AAAOUAAAFHAAABqQAAAgsAAAJs8AACzwABE9/wAxV/8AUXH/AHGL/wCRpf8Asb//ANHa + /wD///8AAAAAAAAaLwAALVAAAD9wAABRkAAAY7AAAHbPAACI8AARmP8AMab/AFGz/wBxwf8Akc//ALHd + /wDR6/8A////AAAAAAAALC8AAEtQAABocAAAhpAAAKWwAADDzwAA4fAAEe//ADHx/wBR8/8AcfX/AJH3 + /wCx+f8A0fv/AP///wAAAAAAAC8hAABQNwAAcEwAAJBjAACweQAAz48AAPCmABH/tAAx/74AUf/IAHH/ + 0wCR/9wAsf/lANH/8AD///8AAAAAAAAvDgAAUBgAAHAiAACQLAAAsDYAAM9AAADwSgAR/1sAMf9xAFH/ + hwBx/50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAIkAAACrAAAAvPAAAO8AAAIP8SAD3/ + MQBb/1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAwcAAAPZAAAEywAABZzwAAZ/AAAHj/ + EQCK/zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABAUAAAWnAAAHSQAACOsAAAqc8AAMLw + AADR/xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAvJgAAUEEAAHBbAACQdAAAsI4AAM+p + AADwwwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAAAAAALxQAAFAiAABwMAAAkD4AALBN + AADPWwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD///8AAAAAAC8DAABQBAAAcAYAAJAJ + AACwCgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/1NEA////AAAAAAAvAA4AUAAXAHAA + IQCQACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/scgA/9HfAP///wAAAAAALwAgAFAA + NgBwAEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/kdwA/7HlAP/R8AD///8AAAAAACwA + LwBLAFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2cf8A95H/APmx/wD70f8A////AAAA + AAAbAC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0Uf8AwnH/AM+R/wDcsf8A69H/AP// + /wAAAAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBYMf8AcVH/AIxx/wCmkf8Av7H/ANrR + /wD///8AAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAEBAAEBAQEBAQEBAQEBAQABAQABAQEB + AQEBAQEBAQEAAQEAAQEBAQEBAQEBAQEBAAEBAAEBAQEBAQEBAQEBAQABAQABAQEBAQEBAQEBAQEAAQEA + AQEBAQEBAQEBAQEBAAEBAAEBAQEBAQEBAQEBAQABAQABAQEBAQEBAQEBAQEAAQEAAQEBAQEBAQEBAQEB + AAEBAAEBAQEBAQEBAQEBAQABAQABAQEBAQEBAQEBAQEAAQEAAQEBAQEBAQEBAQEBAAEBAAAAAAAAAAAA + AAAAAAABAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACJUE5HDQoaCgAAAA1JSERSAAABAAAAAQAIBgAAAFxyqGYA + AATjSURBVHja7dQxTgNAEARByP3/lzq0BDkZBEPLW5WfdBtMf75er68P4KRPAYC7BAAOEwA4TADgMAGA + wwQADhMAOEwA4DABgMMEAA4TADhMAOCwPwXg8Xj897+BH57P56/fCAC8CQGAwwQADhMAOEwA4DABgMME + AA4TADhMAOAwAYDDBAAOEwA4TADgMAGAwwQADhMAOEwA4DABgMMEAA4TADhMAOAwAYDDBAAOEwA47K0C + 8JdjoKq6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsR + ABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAG + qpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepm + BAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGA + gepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6 + GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYA + YKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABio + bkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsR + ABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAG + qpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepm + BAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGA + gepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6 + GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYA + YKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABio + bkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsR + ABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobiYbAOB3BAAOEwA4TADg + MAGAwwQADhMAOEwA4DABgMMEAA4TADhMAOAwAYDDBAAOEwA4TADgMAGAwwQADhMAOEwA4DABgMMEAA4T + ADhMAOAwAYDDZgEA3oMAwGECAIcJABwmAHCYAMBhAgCHCQAcJgBwmADAYQIAhwkAHCYAcNg33r/CedAG + F2MAAAAASUVORK5CYIIoAAAAQAAAAIAAAAABACAAAAAAAABCAAAAAAAAAAAAAAAAAAAAAAAA/Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/4uL - i/++vr7/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6 - uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6 - uv+6urr/urq6/7q6uv+6urr/urq6/76+vv+Li4v/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/729vf////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////+9vb3/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/729vf////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////+9vb3/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/4uLi/++vr7/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6 - uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6 - uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/76+vv+Li4v/CAgI/wgI + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAQAAAAIAAAAABAAgAAAAAAAAQ - AAAAAAAAAAAAAAABAAAAAQAAAAAAAAEBAQACAgIAAwMDAAQEBAAFBQUABgYGAAcHBwAICAgACQkJAAoK - CgALCwsADAwMAA0NDQAODg4ADw8PABAQEAAREREAEhISABMTEwAUFBQAFRUVABYWFgAXFxcAGBgYABkZ - GQAaGhoAGxsbABwcHAAdHR0AHh4eAB8fHwAgICAAISEhACIiIgAjIyMAJCQkACUlJQAmJiYAJycnACgo - KAApKSkAKioqACsrKwAsLCwALS0tAC4uLgAvLy8AMDAwADExMQAyMjIAMzMzADQ0NAA1NTUANjY2ADc3 - NwA4ODgAOTk5ADo6OgA7OzsAPDw8AD09PQA+Pj4APz8/AEBAQABBQUEAQkJCAENDQwBEREQARUVFAEZG - RgBHR0cASEhIAElJSQBKSkoAS0tLAExMTABNTU0ATk5OAE9PTwBQUFAAUVFRAFJSUgBTU1MAVFRUAFVV - VQBWVlYAV1dXAFhYWABZWVkAWlpaAFtbWwBcXFwAXV1dAF5eXgBfX18AYGBgAGFhYQBiYmIAY2NjAGRk - ZABlZWUAZmZmAGdnZwBoaGgAaWlpAGpqagBra2sAbGxsAG1tbQBubm4Ab29vAHBwcABxcXEAcnJyAHNz - cwB0dHQAdXV1AHZ2dgB3d3cAeHh4AHl5eQB6enoAe3t7AHx8fAB9fX0Afn5+AH9/fwCAgIAAgYGBAIKC - ggCDg4MAhISEAIWFhQCGhoYAh4eHAIiIiACJiYkAioqKAIuLiwCMjIwAjY2NAI6OjgCPj48AkJCQAJGR - kQCSkpIAk5OTAJSUlACVlZUAlpaWAJeXlwCYmJgAmZmZAJqamgCbm5sAnJycAJ2dnQCenp4An5+fAKCg - oAChoaEAoqKiAKOjowCkpKQApaWlAKampgCnp6cAqKioAKmpqQCqqqoAq6urAKysrACtra0Arq6uAK+v - rwCwsLAAsbGxALKysgCzs7MAtLS0ALW1tQC2trYAt7e3ALi4uAC5ubkAurq6ALu7uwC8vLwAvb29AL6+ - vgC/v78AwMDAAMHBwQDCwsIAw8PDAMTExADFxcUAxsbGAMfHxwDIyMgAycnJAMrKygDLy8sAzMzMAM3N - zQDOzs4Az8/PANDQ0ADR0dEA0tLSANPT0wDU1NQA1dXVANbW1gDX19cA2NjYANnZ2QDa2toA29vbANzc - 3ADd3d0A3t7eAN/f3wDg4OAA4eHhAOLi4gDj4+MA5OTkAOXl5QDm5uYA5+fnAOjo6ADp6ekA6urqAOvr - 6wDs7OwA7e3tAO7u7gDv7+8A8PDwAPHx8QDy8vIA8/PzAPT09AD19fUA9vb2APf39wD4+PgA+fn5APr6 - +gD7+/sA/Pz8AP39/QD+/v4A////AAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgI - CPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgI - CAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgI - CAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwI - CAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgI - CPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgI - CAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgI - CAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwI - CAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgI - CPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgI - CAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgI - CAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwI - CAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgI - CPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgI - CAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgI - CAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwI - CAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAA== + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAADAAAABgAAAAAQAgAAAAAACAJQAAAAAAAAAA + AAAAAAAAAAAAAPz8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAACgAAAAoAAAAUAAAAAEAIAAAAAAAQBoAAAAAAAAAAAAAAAAAAAAAAAD8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAIAAAAEAA + AAABACAAAAAAAIAQAAAAAAAAAAAAAAAAAAAAAAAA/Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAABgA + AAAwAAAAAQAgAAAAAABgCQAAAAAAAAAAAAAAAAAAAAAAAPz8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAUAAAAKAAAAAEAIAAAAAAAkAYAAAAA + AAAAAAAAAAAAAAAAAAD8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAoAAAAEAAAACAAAAABACAAAAAAAEAEAAAAAAAAAAAAAAAAAAAAAAAA/Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP/8/Pz//Pz8/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj//Pz8//z8/P8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI//z8/P/8/Pz/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP/8/Pz//Pz8/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj//Pz8//z8/P8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI//z8/P/8/Pz/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP/8/Pz//Pz8/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj//Pz8//z8/P8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI//z8/P/8/Pz/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP/8/Pz//Pz8/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj//Pz8//z8/P8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA= @@ -566,394 +1059,887 @@ - AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAgAKgQAABGDgAAMDAAAAEA - IACoJQAA7h4AAEBAAAABAAgAKBYAAJZEAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAA - AAAAAAAACAgI/wcHB/8EBAT/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQE - BP8HBwf/CAgI/wcHB/8cHBz/TExM/01NTf9NTU3/TU1N/01NTf9NTU3/TU1N/01NTf9NTU3/TU1N/01N - Tf9MTEz/HBwc/wcHB/8EBAT/TExM//Pz8//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f3 - 9//39/f/8/Pz/0xMTP8EBAT/AwMD/01NTf/39/f//f39//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//f39//f39/9NTU3/AwMD/wMDA/9NTU3/9/f3//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/39/f/TU1N/wMDA/8DAwP/TU1N//f39//8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz/9/f3/01NTf8DAwP/AwMD/01NTf/39/f//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//f39/9NTU3/AwMD/wMDA/9NTU3/9/f3//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/39/f/TU1N/wMDA/8DAwP/TU1N//f39//8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/9/f3/01NTf8DAwP/AwMD/01NTf/39/f//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//f39/9NTU3/AwMD/wMDA/9NTU3/9/f3//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/39/f/TU1N/wMDA/8DAwP/TU1N//f3 - 9//8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/9/f3/01NTf8DAwP/AwMD/01N - Tf/39/f//f39//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//f39//f39/9NTU3/AwMD/wQE - BP9MTEz/8/Pz//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//z8/P/TExM/wQE - BP8HBwf/HBwc/0xMTP9NTU3/TU1N/01NTf9NTU3/TU1N/01NTf9NTU3/TU1N/01NTf9NTU3/TExM/xwc - HP8HBwf/CAgI/wcHB/8EBAT/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQE - BP8HBwf/CAgI/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAoAAAAGAAAADAAAAABACAAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAACAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8GBgb/AwMD/wMDA/8DAwP/AwMD/wMD - A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgYG/wgI - CP8ICAj/CAgI/wYGBv8tLS3/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dn - Z/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/LS0t/wYGBv8ICAj/CAgI/wMDA/9nZ2f///////7+ - /v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+ - /v//////Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMD - A/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMD - A/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMD - A/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMD - A/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMD - A/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMD - A/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMDA/9nZ2f//v7+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/+/v7/Z2dn/wMDA/8ICAj/CAgI/wMD - A/9nZ2f///////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+ - /v/+/v7//v7+//7+/v//////Z2dn/wMDA/8ICAj/CAgI/wYGBv8tLS3/Z2dn/2dnZ/9nZ2f/Z2dn/2dn - Z/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ2f/LS0t/wYG - Bv8ICAj/CAgI/wgICP8GBgb/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD - A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgYG/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAA - AABAAAAAAQAgAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8GBgb/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD - A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgYG/wgICP8ICAj/CAgI/wgI - CP8ICAj/BgYG/0VFRf+EhIT/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KC - gv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4SEhP9FRUX/BgYG/wgI - CP8ICAj/CAgI/wgICP8DAwP/hISE//////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////4SE - hP8DAwP/CAgI/wgICP8ICAj/CAgI/wMDA/+CgoL///////z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P//////goKC/wMDA/8ICAj/CAgI/wgICP8ICAj/AwMD/4KCgv///////Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+CgoL/AwMD/wgICP8ICAj/CAgI/wgICP8DAwP/goKC///////8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//////4KCgv8DAwP/CAgI/wgICP8ICAj/CAgI/wMDA/+CgoL///////z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P//////goKC/wMDA/8ICAj/CAgI/wgICP8ICAj/AwMD/4KC - gv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+CgoL/AwMD/wgICP8ICAj/CAgI/wgI - CP8DAwP/goKC///////8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//////4KCgv8DAwP/CAgI/wgI - CP8ICAj/CAgI/wMDA/+CgoL///////z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P//////goKC/wMD - A/8ICAj/CAgI/wgICP8ICAj/AwMD/4KCgv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+CgoL/AwMD/wgICP8ICAj/CAgI/wgICP8DAwP/goKC///////8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//////4KCgv8DAwP/CAgI/wgICP8ICAj/CAgI/wMDA/+CgoL///////z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P//////goKC/wMDA/8ICAj/CAgI/wgICP8ICAj/AwMD/4KCgv///////Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+CgoL/AwMD/wgICP8ICAj/CAgI/wgICP8DAwP/goKC//// - ///8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//////4KCgv8DAwP/CAgI/wgICP8ICAj/CAgI/wMD - A/+CgoL///////z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P//////goKC/wMDA/8ICAj/CAgI/wgI - CP8ICAj/AwMD/4KCgv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+CgoL/AwMD/wgI - CP8ICAj/CAgI/wgICP8DAwP/goKC///////8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//////4KC - gv8DAwP/CAgI/wgICP8ICAj/CAgI/wMDA/+CgoL///////z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P//////goKC/wMDA/8ICAj/CAgI/wgICP8ICAj/AwMD/4KCgv///////Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+CgoL/AwMD/wgICP8ICAj/CAgI/wgICP8DAwP/goKC///////8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//////4KCgv8DAwP/CAgI/wgICP8ICAj/CAgI/wMDA/+CgoL///////z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P//////goKC/wMDA/8ICAj/CAgI/wgICP8ICAj/AwMD/4KC - gv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+CgoL/AwMD/wgICP8ICAj/CAgI/wgI - CP8DAwP/goKC///////8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//////4KCgv8DAwP/CAgI/wgI - CP8ICAj/CAgI/wMDA/+CgoL///////z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P//////goKC/wMD - A/8ICAj/CAgI/wgICP8ICAj/AwMD/4SEhP////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //+EhIT/AwMD/wgICP8ICAj/CAgI/wgICP8GBgb/RUVF/4SEhP+CgoL/goKC/4KCgv+CgoL/goKC/4KC - gv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KC - gv+CgoL/hISE/0VFRf8GBgb/CAgI/wgICP8ICAj/CAgI/wgICP8GBgb/AwMD/wMDA/8DAwP/AwMD/wMD - A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD - A/8DAwP/AwMD/wMDA/8DAwP/BgYG/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8AAAAAAAAAAAAA + AAABAA0AICAQAAEABADoAgAA1gAAABAQEAABAAQAKAEAAL4DAAAwMAAAAQAIAKgOAADmBAAAICAAAAEA + CACoCAAAjhMAABAQAAABAAgAaAUAADYcAAAAAAAAAQAgABwFAACeIQAAQEAAAAEAIAAoQgAAuiYAADAw + AAABACAAqCUAAOJoAAAoKAAAAQAgAGgaAACKjgAAICAAAAEAIACoEAAA8qgAABgYAAABACAAiAkAAJq5 + AAAUFAAAAQAgALgGAAAiwwAAEBAAAAEAIABoBAAA2skAACgAAAAgAAAAQAAAAAEABAAAAAAAgAIAAAAA + AAAAAAAAEAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD/ + /wD/AAAA/wD/AP//AAD///8A////////////////////////////////////////////AAAAAAAAAAAA + AAAAAAD//wAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAP//AA//////////////8AD//wAP//// + //////////AA//8AD//////////////wAP//AA//////////////8AD//wAP//////////////AA//8A + D//////////////wAP//AA//////////////8AD//wAP//////////////AA//8AD//////////////w + AP//AA//////////////8AD//wAP//////////////AA//8AD//////////////wAP//AA////////// + ////8AD//wAP//////////////AA//8AD//////////////wAP//AA//////////////8AD//wAP//// + //////////AA//8AD//////////////wAP//AA//////////////8AD//wAP//////////////AA//8A + D//////////////wAP//AA//////////////8AD//wAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAA + AP//AAAAAAAAAAAAAAAAAAD///////////////////////////////////////////8AAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgA - AAAwAAAAYAAAAAEAIAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAICAj/CAgI/wgICP8ICAj/CAgI/wgI + AAAQAAAAIAAAAAEABAAAAAAAwAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAA + gACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8A///////////wAAAAAAAAD/D/ + //////8P8P///////w/w////////D/D///////8P8P///////w/w////////D/D///////8P8P////// + /w/w////////D/D///////8P8P///////w/w////////D/AAAAAAAAAP//////////8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAADAA + AABgAAAAAQAIAAAAAACACgAAAAAAAAAAAAAAAQAAAAAAAAgICAD8/PwAAA5QAAAUcAAAGpAAACCwAAAm + zwAALPAAET3/ADFX/wBRcf8AcYv/AJGl/wCxv/8A0dr/AP///wAAAAAAABovAAAtUAAAP3AAAFGQAABj + sAAAds8AAIjwABGY/wAxpv8AUbP/AHHB/wCRz/8Asd3/ANHr/wD///8AAAAAAAAsLwAAS1AAAGhwAACG + kAAApbAAAMPPAADh8AAR7/8AMfH/AFHz/wBx9f8Akff/ALH5/wDR+/8A////AAAAAAAALyEAAFA3AABw + TAAAkGMAALB5AADPjwAA8KYAEf+0ADH/vgBR/8gAcf/TAJH/3ACx/+UA0f/wAP///wAAAAAAAC8OAABQ + GAAAcCIAAJAsAACwNgAAz0AAAPBKABH/WwAx/3EAUf+HAHH/nQCR/7IAsf/JANH/3wD///8AAAAAAAIv + AAAEUAAABnAAAAiQAAAKsAAAC88AAA7wAAAg/xIAPf8xAFv/UQB5/3EAmP+RALX/sQDU/9EA////AAAA + AAAULwAAIlAAADBwAAA9kAAATLAAAFnPAABn8AAAeP8RAIr/MQCc/1EArv9xAMD/kQDS/7EA5P/RAP// + /wAAAAAAJi8AAEBQAABacAAAdJAAAI6wAACpzwAAwvAAANH/EQDY/zEA3v9RAOP/cQDp/5EA7/+xAPb/ + 0QD///8AAAAAAC8mAABQQQAAcFsAAJB0AACwjgAAz6kAAPDDAAD/0hEA/9gxAP/dUQD/5HEA/+qRAP/w + sQD/9tEA////AAAAAAAvFAAAUCIAAHAwAACQPgAAsE0AAM9bAADwaQAA/3kRAP+KMQD/nVEA/69xAP/B + kQD/0rEA/+XRAP///wAAAAAALwMAAFAEAABwBgAAkAkAALAKAADPDAAA8A4AAP8gEgD/PjEA/1xRAP96 + cQD/l5EA/7axAP/U0QD///8AAAAAAC8ADgBQABcAcAAhAJAAKwCwADYAzwBAAPAASQD/EVoA/zFwAP9R + hgD/cZwA/5GyAP+xyAD/0d8A////AAAAAAAvACAAUAA2AHAATACQAGIAsAB4AM8AjgDwAKQA/xGzAP8x + vgD/UccA/3HRAP+R3AD/seUA/9HwAP///wAAAAAALAAvAEsAUABpAHAAhwCQAKUAsADEAM8A4QDwAPAR + /wDyMf8A9FH/APZx/wD3kf8A+bH/APvR/wD///8AAAAAABsALwAtAFAAPwBwAFIAkABjALAAdgDPAIgA + 8ACZEf8ApjH/ALRR/wDCcf8Az5H/ANyx/wDr0f8A////AAAAAAAIAC8ADgBQABUAcAAbAJAAIQCwACYA + zwAsAPAAPhH/AFgx/wBxUf8AjHH/AKaR/wC/sf8A2tH/AP///wABAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAIAAAAEAAAAABAAgAAAAAAIAEAAAAAAAAAAAAAAAB + AAAAAAAACAgIAPz8/AAADlAAABRwAAAakAAAILAAACbPAAAs8AARPf8AMVf/AFFx/wBxi/8AkaX/ALG/ + /wDR2v8A////AAAAAAAAGi8AAC1QAAA/cAAAUZAAAGOwAAB2zwAAiPAAEZj/ADGm/wBRs/8AccH/AJHP + /wCx3f8A0ev/AP///wAAAAAAACwvAABLUAAAaHAAAIaQAAClsAAAw88AAOHwABHv/wAx8f8AUfP/AHH1 + /wCR9/8Asfn/ANH7/wD///8AAAAAAAAvIQAAUDcAAHBMAACQYwAAsHkAAM+PAADwpgAR/7QAMf++AFH/ + yABx/9MAkf/cALH/5QDR//AA////AAAAAAAALw4AAFAYAABwIgAAkCwAALA2AADPQAAA8EoAEf9bADH/ + cQBR/4cAcf+dAJH/sgCx/8kA0f/fAP///wAAAAAAAi8AAARQAAAGcAAACJAAAAqwAAALzwAADvAAACD/ + EgA9/zEAW/9RAHn/cQCY/5EAtf+xANT/0QD///8AAAAAABQvAAAiUAAAMHAAAD2QAABMsAAAWc8AAGfw + AAB4/xEAiv8xAJz/UQCu/3EAwP+RANL/sQDk/9EA////AAAAAAAmLwAAQFAAAFpwAAB0kAAAjrAAAKnP + AADC8AAA0f8RANj/MQDe/1EA4/9xAOn/kQDv/7EA9v/RAP///wAAAAAALyYAAFBBAABwWwAAkHQAALCO + AADPqQAA8MMAAP/SEQD/2DEA/91RAP/kcQD/6pEA//CxAP/20QD///8AAAAAAC8UAABQIgAAcDAAAJA+ + AACwTQAAz1sAAPBpAAD/eREA/4oxAP+dUQD/r3EA/8GRAP/SsQD/5dEA////AAAAAAAvAwAAUAQAAHAG + AACQCQAAsAoAAM8MAADwDgAA/yASAP8+MQD/XFEA/3pxAP+XkQD/trEA/9TRAP///wAAAAAALwAOAFAA + FwBwACEAkAArALAANgDPAEAA8ABJAP8RWgD/MXAA/1GGAP9xnAD/kbIA/7HIAP/R3wD///8AAAAAAC8A + IABQADYAcABMAJAAYgCwAHgAzwCOAPAApAD/EbMA/zG+AP9RxwD/cdEA/5HcAP+x5QD/0fAA////AAAA + AAAsAC8ASwBQAGkAcACHAJAApQCwAMQAzwDhAPAA8BH/APIx/wD0Uf8A9nH/APeR/wD5sf8A+9H/AP// + /wAAAAAAGwAvAC0AUAA/AHAAUgCQAGMAsAB2AM8AiADwAJkR/wCmMf8AtFH/AMJx/wDPkf8A3LH/AOvR + /wD///8AAAAAAAgALwAOAFAAFQBwABsAkAAhALAAJgDPACwA8AA+Ef8AWDH/AHFR/wCMcf8AppH/AL+x + /wDa0f8A////AAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEAAAAB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEB + AAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAA + AQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQAAAAEBAQEAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEAAAABAQEBAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEAAAABAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAAAAAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAAAAAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQAAAAEBAQEAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQEBAQAAAAEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEAAAAB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEB + AAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAA + AQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAQAAAAIAAAAAEACAAAAAAAQAEAAAAAAAAAAAAAAAEAAAAA + AAAICAgA/Pz8AAAOUAAAFHAAABqQAAAgsAAAJs8AACzwABE9/wAxV/8AUXH/AHGL/wCRpf8Asb//ANHa + /wD///8AAAAAAAAaLwAALVAAAD9wAABRkAAAY7AAAHbPAACI8AARmP8AMab/AFGz/wBxwf8Akc//ALHd + /wDR6/8A////AAAAAAAALC8AAEtQAABocAAAhpAAAKWwAADDzwAA4fAAEe//ADHx/wBR8/8AcfX/AJH3 + /wCx+f8A0fv/AP///wAAAAAAAC8hAABQNwAAcEwAAJBjAACweQAAz48AAPCmABH/tAAx/74AUf/IAHH/ + 0wCR/9wAsf/lANH/8AD///8AAAAAAAAvDgAAUBgAAHAiAACQLAAAsDYAAM9AAADwSgAR/1sAMf9xAFH/ + hwBx/50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAIkAAACrAAAAvPAAAO8AAAIP8SAD3/ + MQBb/1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAwcAAAPZAAAEywAABZzwAAZ/AAAHj/ + EQCK/zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABAUAAAWnAAAHSQAACOsAAAqc8AAMLw + AADR/xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAvJgAAUEEAAHBbAACQdAAAsI4AAM+p + AADwwwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAAAAAALxQAAFAiAABwMAAAkD4AALBN + AADPWwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD///8AAAAAAC8DAABQBAAAcAYAAJAJ + AACwCgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/1NEA////AAAAAAAvAA4AUAAXAHAA + IQCQACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/scgA/9HfAP///wAAAAAALwAgAFAA + NgBwAEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/kdwA/7HlAP/R8AD///8AAAAAACwA + LwBLAFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2cf8A95H/APmx/wD70f8A////AAAA + AAAbAC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0Uf8AwnH/AM+R/wDcsf8A69H/AP// + /wAAAAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBYMf8AcVH/AIxx/wCmkf8Av7H/ANrR + /wD///8AAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAEBAAEBAQEBAQEBAQEBAQABAQABAQEB + AQEBAQEBAQEAAQEAAQEBAQEBAQEBAQEBAAEBAAEBAQEBAQEBAQEBAQABAQABAQEBAQEBAQEBAQEAAQEA + AQEBAQEBAQEBAQEBAAEBAAEBAQEBAQEBAQEBAQABAQABAQEBAQEBAQEBAQEAAQEAAQEBAQEBAQEBAQEB + AAEBAAEBAQEBAQEBAQEBAQABAQABAQEBAQEBAQEBAQEAAQEAAQEBAQEBAQEBAQEBAAEBAAAAAAAAAAAA + AAAAAAABAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACJUE5HDQoaCgAAAA1JSERSAAABAAAAAQAIBgAAAFxyqGYA + AATjSURBVHja7dQxTgNAEARByP3/lzq0BDkZBEPLW5WfdBtMf75er68P4KRPAYC7BAAOEwA4TADgMAGA + wwQADhMAOEwA4DABgMMEAA4TADhMAOCwPwXg8Xj897+BH57P56/fCAC8CQGAwwQADhMAOEwA4DABgMME + AA4TADhMAOAwAYDDBAAOEwA4TADgMAGAwwQADhMAOEwA4DABgMMEAA4TADhMAOAwAYDDBAAOEwA47K0C + 8JdjoKq6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsR + ABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAG + qpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepm + BAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGA + gepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6 + GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYA + YKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABio + bkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsR + ABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAG + qpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepm + BAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGA + gepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6 + GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYA + YKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABio + bkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsR + ABiobkYAYKC6GQGAgepmBAAGqpsRABiobkYAYKC6GQGAgepmBAAGqpsRABiobiYbAOB3BAAOEwA4TADg + MAGAwwQADhMAOEwA4DABgMMEAA4TADhMAOAwAYDDBAAOEwA4TADgMAGAwwQADhMAOEwA4DABgMMEAA4T + ADhMAOAwAYDDZgEA3oMAwGECAIcJABwmAHCYAMBhAgCHCQAcJgBwmADAYQIAhwkAHCYAcNg33r/CedAG + F2MAAAAASUVORK5CYIIoAAAAQAAAAIAAAAABACAAAAAAAABCAAAAAAAAAAAAAAAAAAAAAAAA/Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/4uL - i/++vr7/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6 - uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6 - uv+6urr/urq6/7q6uv+6urr/urq6/76+vv+Li4v/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/729vf////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////+9vb3/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//// - //+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6uv///////Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/7q6 - uv///////Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//////+6urr/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/729vf////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////+9vb3/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8ICAj/CAgI/4uLi/++vr7/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6 - uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6 - uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/7q6uv+6urr/urq6/76+vv+Li4v/CAgI/wgI + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI - CP8ICAj/CAgI/wgICP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAQAAAAIAAAAABAAgAAAAAAAAQ - AAAAAAAAAAAAAAABAAAAAQAAAAAAAAEBAQACAgIAAwMDAAQEBAAFBQUABgYGAAcHBwAICAgACQkJAAoK - CgALCwsADAwMAA0NDQAODg4ADw8PABAQEAAREREAEhISABMTEwAUFBQAFRUVABYWFgAXFxcAGBgYABkZ - GQAaGhoAGxsbABwcHAAdHR0AHh4eAB8fHwAgICAAISEhACIiIgAjIyMAJCQkACUlJQAmJiYAJycnACgo - KAApKSkAKioqACsrKwAsLCwALS0tAC4uLgAvLy8AMDAwADExMQAyMjIAMzMzADQ0NAA1NTUANjY2ADc3 - NwA4ODgAOTk5ADo6OgA7OzsAPDw8AD09PQA+Pj4APz8/AEBAQABBQUEAQkJCAENDQwBEREQARUVFAEZG - RgBHR0cASEhIAElJSQBKSkoAS0tLAExMTABNTU0ATk5OAE9PTwBQUFAAUVFRAFJSUgBTU1MAVFRUAFVV - VQBWVlYAV1dXAFhYWABZWVkAWlpaAFtbWwBcXFwAXV1dAF5eXgBfX18AYGBgAGFhYQBiYmIAY2NjAGRk - ZABlZWUAZmZmAGdnZwBoaGgAaWlpAGpqagBra2sAbGxsAG1tbQBubm4Ab29vAHBwcABxcXEAcnJyAHNz - cwB0dHQAdXV1AHZ2dgB3d3cAeHh4AHl5eQB6enoAe3t7AHx8fAB9fX0Afn5+AH9/fwCAgIAAgYGBAIKC - ggCDg4MAhISEAIWFhQCGhoYAh4eHAIiIiACJiYkAioqKAIuLiwCMjIwAjY2NAI6OjgCPj48AkJCQAJGR - kQCSkpIAk5OTAJSUlACVlZUAlpaWAJeXlwCYmJgAmZmZAJqamgCbm5sAnJycAJ2dnQCenp4An5+fAKCg - oAChoaEAoqKiAKOjowCkpKQApaWlAKampgCnp6cAqKioAKmpqQCqqqoAq6urAKysrACtra0Arq6uAK+v - rwCwsLAAsbGxALKysgCzs7MAtLS0ALW1tQC2trYAt7e3ALi4uAC5ubkAurq6ALu7uwC8vLwAvb29AL6+ - vgC/v78AwMDAAMHBwQDCwsIAw8PDAMTExADFxcUAxsbGAMfHxwDIyMgAycnJAMrKygDLy8sAzMzMAM3N - zQDOzs4Az8/PANDQ0ADR0dEA0tLSANPT0wDU1NQA1dXVANbW1gDX19cA2NjYANnZ2QDa2toA29vbANzc - 3ADd3d0A3t7eAN/f3wDg4OAA4eHhAOLi4gDj4+MA5OTkAOXl5QDm5uYA5+fnAOjo6ADp6ekA6urqAOvr - 6wDs7OwA7e3tAO7u7gDv7+8A8PDwAPHx8QDy8vIA8/PzAPT09AD19fUA9vb2APf39wD4+PgA+fn5APr6 - +gD7+/sA/Pz8AP39/QD+/v4A////AAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgI - CPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgI - CAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgI - CAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwI - CAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgI - CPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgI - CAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgI - CAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwI - CAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgI - CPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgI - CAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgI - CAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwI - CAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgICAgICAj8/Pz8/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgICAgICAgICAgI/Pz8 - /Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwICAgICAgICAgICAgI - CPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8CAgICAgICAgI - CAgICAj8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/AgICAgI - CAgICAgICAgI/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/PwI - CAgICAgICAgICAgICPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8 - /Pz8CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI - CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAA== + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAADAAAABgAAAAAQAgAAAAAACAJQAAAAAAAAAA + AAAAAAAAAAAAAPz8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAACgAAAAoAAAAUAAAAAEAIAAAAAAAQBoAAAAAAAAAAAAAAAAAAAAAAAD8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAIAAAAEAA + AAABACAAAAAAAIAQAAAAAAAAAAAAAAAAAAAAAAAA/Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgI + CP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAABgA + AAAwAAAAAQAgAAAAAABgCQAAAAAAAAAAAAAAAAAAAAAAAPz8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgI + CP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgI + CP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8 + /P8ICAj/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAUAAAAKAAAAAEAIAAAAAAAkAYAAAAA + AAAAAAAAAAAAAAAAAAD8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP8ICAj//Pz8//z8/P8ICAj/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI/wgICP/8/Pz//Pz8/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI//z8/P/8/Pz/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAoAAAAEAAAACAAAAABACAAAAAAAEAEAAAAAAAAAAAAAAAAAAAAAAAA/Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI//z8 + /P/8/Pz/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgI + CP/8/Pz//Pz8/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P8ICAj//Pz8//z8/P8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz/CAgI//z8/P/8/Pz/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8/wgICP/8/Pz//Pz8/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P8ICAj//Pz8//z8/P8ICAj//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz/CAgI//z8/P/8/Pz/CAgI//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP/8/Pz//Pz8/wgICP/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj//Pz8//z8/P8ICAj//Pz8//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI//z8/P/8/Pz/CAgI//z8/P/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wgICP/8/Pz//Pz8/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P8ICAj//Pz8//z8/P8ICAj//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/CAgI//z8/P/8/Pz/CAgI/wgI + CP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP/8/Pz//Pz8//z8 + /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA= \ No newline at end of file diff --git a/UnityLauncher/Properties/AssemblyInfo.cs b/UnityLauncher/Properties/AssemblyInfo.cs index 002ed6b..721ded3 100644 --- a/UnityLauncher/Properties/AssemblyInfo.cs +++ b/UnityLauncher/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("UnityCoder.com")] [assembly: AssemblyProduct("UnityLauncher")] -[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyCopyright("Copyright © 2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/UnityLauncher/UnityLauncher.csproj b/UnityLauncher/UnityLauncher.csproj index 9f523e1..e28656b 100644 --- a/UnityLauncher/UnityLauncher.csproj +++ b/UnityLauncher/UnityLauncher.csproj @@ -58,6 +58,9 @@ true + + unitylauncher.ico + @@ -113,5 +116,8 @@ false + + + \ No newline at end of file diff --git a/UnityLauncher/unitylauncher.ico b/UnityLauncher/unitylauncher.ico new file mode 100644 index 0000000000000000000000000000000000000000..9aa7a1831195e46599579fff770fbce160aa3a14 GIT binary patch literal 52802 zcmeHQZ;Vt|6+a7GvY^0jizx*X2NE|V(k%OhstK?l{=p*7HYRFm%qj`eFJ{M(3Vv~_ zNkKHY^TB}H)_y32HnHrsXtWyGf{8SKSho^G2&L2(|FoJ;t3sM$uD`dlclYhtxqtTT z+jj@{zV^+1=brOBzu&pC&42zg{F-RVlA8Uic|@zuYW@Q4hPI0@A|Ln* z*g*>&=)_h=ZF)o6)K-QQX1QEz@QOq1Wf~kDghP$|Pf8_6*zsS|mDsKg@u@9=rMEiv z;_-~tgeKZ!1Cq&jq=$dxG^RTypN}!}`Uh!nh~s3QCv&-gUC;AD9P2IXd0wq0URKAr?uF7uqW$SvXvK%G_{weTGP_fLN{*QAX-$!BGXH>tPg|RPt-m{ zw5CdJ>lJl=K~Z-}QR(}NDn}I!oK`e^abzv1C0W)%bT{xDf$s)>C-4see*pL+z#jwt zIpALaehB!NfqyfFUjzKT!0!hB5#Wyke-`*xfqx75w}JmR@c#w=I`HoT|6U5;fd#jC z4^i(nqQ0F({riZ9en?b3Ms4aOb*fX;tLx7l6ME{Aci_oJbwP(JQ6>ZLYP7dlD3+)e8B5~(*Tq^bj?t__dr@4&sOh@tCU3;YJ)KMOo^ zRUZU?UmK}|ounS?CUv4j>V*n&4v@M!JdU3Wd^7O4xAozE*N=HR^nT!RT2$e7QX4u+ zJY#g( z;X!2Bj|@kV;djXJDl$~t6ur}_=s(?xu9XyBuPAzVK+$`{{ci(NIOvr2$264v*tofKNu?1Hdl_ekJhjz^?&*Lz|*6cH-LU zR`i1sa#a+a9#C{~xQ1_<@vXK*_`N1#{32^n4IA$s)sX_m^v8HU0&#r!h)lHO_)HuR zZpHE8BQnvB<1=wQxYgL>GosG@k`(2R8jonicz$BCwa06ZM0Rmf*71GH*z?%pFXqikMr)tj~R%zeq#HUXEyhICwULrg}scui3)hdwz<}%U-5em z756v>aSq&2cy2r^cGJ0z^~du+8|FZq|Ml;8v*Fw)HOBKl_498UvqtT=&1I8j3C5Hw zbibq)2_|%%CVojR5{!vIbibq)2_|%%CVojR5{!vIbibq)2_|%%CVojR5{!vIbibq) z2_|%%CVojR5{!vIbibq)2_|%%CVojR5{!vIbibq)2_|%%CVojR5{!vIbibq)2_|%% zCVojR5{!vIbibq)2_|%%CVojR5{!vIbibq)2_|%%CVojR5{!vIbibq)2_|%%CVojR z5{!vIbibq)2_|%%CVojR5{!vIbibq)2_|%%CVojR5{!vIbibq)2_|%%CVojR5{!vI zbibq)2_|%%CVojR5{!vIbibq)2_|%%CVojR5{!vIbibq)2_|%%CVojR5{!vIbibq) z2_|%%CVojR5{!vIbibq)2_|%%CVojR5{!vIbibq)2_|%%CVojR5{!vIbibq)2_|%% zCVojR5{!vIbibq)2_|%%CVojR5{!vIbibq)8|GH>na<6vRHLnySpU?2|85)4o6Q%` ze?0&7=D^K1kEMF+)gJrmUlVa$ZtZbN|1E%cJo`o<`8yH#rx>UQyZ$>7W&FECe2eQq zW2^(xdtN9UpEsd&NO`0FuzwR_HjF>7F_c~J8sS=eVmKx*+ee#EOkR39kB>H=7@jvT z+ee#EOkR39kB>H=7@jvT+ee#EOkR39kB>H=7@jvT+ee#EOkR39kB>H=7@jvT+ee#E zOkR39kB>H=7@jvT+ee#EOkR39kB>H=7@jvT+ee#EOkR39kB>H=7@jvT+ee#EOkR39 zkB>H=7@jvT+ee#EOkR39kB>H=7@jvT+ee#EOkR39kB>H=7@jvT+ee#EOkR39kB>H= z7@jvT+ee#EOkR39kB>H=7@jvT+ee#EOkR39kB>H=7@jvT+ee#EOkR39kB>H=7@jvT z+ee#EOkR39kB>H=7@jvT+ee#EOkR39kB>H=7@jvT+ecfym`3j7W7o)9>uHPnMpXbZkcJaIXS?l5XT>LIS&zH6B;&=J8 z*2D9;_+5UUFKgSy@A7A@hv#$gyZk&~*0zh^<Ws(&vA=$9n!v zH;)OQSANYi6Yb=8MA`Nv@57d0Pg?yxtZ&|Aj+v;we#sIIF9GG zj`M9fp4+~8bR5TXTgUmf9M5gvJUWi!xvk@TTaMTEbX(0o-8>qv^JUpizN1X9C%IoG zKWivp*Y~ZiW*BVCq6R%KQ*AYOg44&oZ5oq4j(Gd~Z#_QgF-sq7zpG7S(#I~G_NOuF rW9@gfX-xXqh132tCVi~^t~QNHAG>hcpT;D|l3nMTPRo{qDVzTXgQY-f literal 0 HcmV?d00001 From 37c03f19807a2f0ac1a482150a76b3fd615b0a72 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Mon, 4 Sep 2017 22:44:26 +0800 Subject: [PATCH 02/81] fix download assistant url parsing, add setting: close after explorer launch --- UnityLauncher/App.config | 3 + UnityLauncher/Form1.Designer.cs | 76 ++++++----- UnityLauncher/Form1.cs | 125 ++++++++++-------- UnityLauncher/Program.cs | 15 ++- UnityLauncher/Properties/Settings.Designer.cs | 12 ++ UnityLauncher/Properties/Settings.settings | 3 + 6 files changed, 150 insertions(+), 84 deletions(-) diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index a44ae39..ee64511 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -27,6 +27,9 @@ xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> + + True + \ No newline at end of file diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 9148e08..4cbba59 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -56,6 +56,9 @@ private void InitializeComponent() this.label3 = new System.Windows.Forms.Label(); this.lstPackageFolders = new System.Windows.Forms.ListBox(); this.tabPage3 = new System.Windows.Forms.TabPage(); + this.btnAddRegister = new System.Windows.Forms.Button(); + this.btnRemoveRegister = new System.Windows.Forms.Button(); + this.label4 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.chkMinimizeToTaskbar = new System.Windows.Forms.CheckBox(); this.label1 = new System.Windows.Forms.Label(); @@ -68,9 +71,7 @@ private void InitializeComponent() this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); this.btnAddPackFolder = new System.Windows.Forms.Button(); - this.label4 = new System.Windows.Forms.Label(); - this.btnRemoveRegister = new System.Windows.Forms.Button(); - this.btnAddRegister = new System.Windows.Forms.Button(); + this.chkQuitAfterCommandline = new System.Windows.Forms.CheckBox(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -365,6 +366,7 @@ private void InitializeComponent() // // tabPage3 // + this.tabPage3.Controls.Add(this.chkQuitAfterCommandline); this.tabPage3.Controls.Add(this.btnAddRegister); this.tabPage3.Controls.Add(this.btnRemoveRegister); this.tabPage3.Controls.Add(this.label4); @@ -383,6 +385,35 @@ private void InitializeComponent() this.tabPage3.Text = "Settings"; this.tabPage3.UseVisualStyleBackColor = true; // + // btnAddRegister + // + this.btnAddRegister.Location = new System.Drawing.Point(139, 442); + this.btnAddRegister.Name = "btnAddRegister"; + this.btnAddRegister.Size = new System.Drawing.Size(64, 23); + this.btnAddRegister.TabIndex = 30; + this.btnAddRegister.Text = "Install"; + this.btnAddRegister.UseVisualStyleBackColor = true; + this.btnAddRegister.Click += new System.EventHandler(this.btnAddRegister_Click); + // + // btnRemoveRegister + // + this.btnRemoveRegister.Location = new System.Drawing.Point(209, 442); + this.btnRemoveRegister.Name = "btnRemoveRegister"; + this.btnRemoveRegister.Size = new System.Drawing.Size(64, 23); + this.btnRemoveRegister.TabIndex = 29; + this.btnRemoveRegister.Text = "uninstall"; + this.btnRemoveRegister.UseVisualStyleBackColor = true; + this.btnRemoveRegister.Click += new System.EventHandler(this.btnRemoveRegister_Click); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(19, 447); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(117, 13); + this.label4.TabIndex = 28; + this.label4.Text = "Explorer Context Menu:"; + // // label2 // this.label2.AutoSize = true; @@ -484,34 +515,16 @@ private void InitializeComponent() this.btnAddPackFolder.Text = "Add Folder"; this.btnAddPackFolder.UseVisualStyleBackColor = true; // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(21, 423); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(117, 13); - this.label4.TabIndex = 28; - this.label4.Text = "Explorer Context Menu:"; - // - // btnRemoveRegister - // - this.btnRemoveRegister.Location = new System.Drawing.Point(211, 418); - this.btnRemoveRegister.Name = "btnRemoveRegister"; - this.btnRemoveRegister.Size = new System.Drawing.Size(64, 23); - this.btnRemoveRegister.TabIndex = 29; - this.btnRemoveRegister.Text = "uninstall"; - this.btnRemoveRegister.UseVisualStyleBackColor = true; - this.btnRemoveRegister.Click += new System.EventHandler(this.btnRemoveRegister_Click); - // - // btnAddRegister + // chkQuitAfterCommandline // - this.btnAddRegister.Location = new System.Drawing.Point(141, 418); - this.btnAddRegister.Name = "btnAddRegister"; - this.btnAddRegister.Size = new System.Drawing.Size(64, 23); - this.btnAddRegister.TabIndex = 30; - this.btnAddRegister.Text = "Install"; - this.btnAddRegister.UseVisualStyleBackColor = true; - this.btnAddRegister.Click += new System.EventHandler(this.btnAddRegister_Click); + this.chkQuitAfterCommandline.AutoSize = true; + this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 409); + this.chkQuitAfterCommandline.Name = "chkQuitAfterCommandline"; + this.chkQuitAfterCommandline.Size = new System.Drawing.Size(189, 17); + this.chkQuitAfterCommandline.TabIndex = 31; + this.chkQuitAfterCommandline.Text = "Close after launching from Explorer"; + this.chkQuitAfterCommandline.UseVisualStyleBackColor = true; + this.chkQuitAfterCommandline.CheckedChanged += new System.EventHandler(this.chkQuitAfterCommandline_CheckedChanged); // // Form1 // @@ -526,7 +539,7 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Potato Edition 6"; + this.Text = "UnityLauncher - Potato Edition 7"; this.Load += new System.EventHandler(this.Form1_Load); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); @@ -586,6 +599,7 @@ private void InitializeComponent() private System.Windows.Forms.Button btnAddRegister; private System.Windows.Forms.Button btnRemoveRegister; private System.Windows.Forms.Label label4; + private System.Windows.Forms.CheckBox chkQuitAfterCommandline; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 2a30a52..a80d958 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -23,6 +23,11 @@ public Form1() } private void Form1_Load(object sender, EventArgs e) + { + Start(); + } + + void Start() { SetStatus("Initializing.."); @@ -35,13 +40,7 @@ private void Form1_Load(object sender, EventArgs e) SetStatus("Ready"); } - // update settings window - chkMinimizeToTaskbar.Checked = Properties.Settings.Default.minimizeToTaskbar; - - // update installations folder listbox - lstRootFolders.Items.AddRange(Properties.Settings.Default.rootFolders.Cast().ToArray()); - // update packages folder listbox - lstPackageFolders.Items.AddRange(Properties.Settings.Default.packageFolders.Cast().ToArray()); + LoadSettings(); // scan installed unitys, TODO: could cache results, at least fileinfo's bool foundedUnitys = ScanUnityInstallations(); @@ -63,13 +62,17 @@ private void Form1_Load(object sender, EventArgs e) SetStatus("Launching from commandline.."); var pathArg = args[2]; - // Console.WriteLine("\nPATH: " + pathArg); LaunchProject(pathArg); SetStatus("Ready"); + + // quit after launch if enabled in settings + if (Properties.Settings.Default.closeAfterExplorer == true) + { + Application.Exit(); + } } else { - // Console.WriteLine("Invalid arguments:" + args[1]); SetStatus("Error> Invalid arguments:" + args[1]); } @@ -81,6 +84,18 @@ private void Form1_Load(object sender, EventArgs e) gridRecent.Select(); } + void LoadSettings() + { + // update settings window + chkMinimizeToTaskbar.Checked = Properties.Settings.Default.minimizeToTaskbar; + chkQuitAfterCommandline.Checked = Properties.Settings.Default.closeAfterExplorer; + + // update installations folder listbox + lstRootFolders.Items.AddRange(Properties.Settings.Default.rootFolders.Cast().ToArray()); + // update packages folder listbox + lstPackageFolders.Items.AddRange(Properties.Settings.Default.packageFolders.Cast().ToArray()); + } + /// /// returns true if we have exact version installed /// @@ -339,64 +354,64 @@ void LaunchProject(string pathArg = null) } } + // parse unity installer exe from release page + // thanks to https://github.com/softfruit + string GetDownloadUrlForUnityVersion(string releaseUrl) + { + string url = ""; + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + using (WebClient client = new WebClient()) + { + string html = client.DownloadString(releaseUrl); + Regex regex = new Regex(@"(http).+(UnityDownloadAssistant)+[^\s*]*(.exe)"); + Match match = regex.Match(html); + url = match.Groups[0].Captures[0].Value; + Console.WriteLine(url); + } + return url; + } + /// /// downloads unity installer and launches it /// /// void DownloadAndRun(string url) { - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - using (WebClient client = new WebClient()) - { - string html = client.DownloadString(url); + string exeURL = GetDownloadUrlForUnityVersion(url); - string foundedURL = ""; - var allLines = html.Split('\n'); - for (int i = 0, length = allLines.Length; i < length; i++) + if (string.IsNullOrEmpty(exeURL) == false) + { + SetStatus("Download installer: " + exeURL); + // download temp file + using (WebClient downloader = new WebClient()) { - if (allLines[i].Contains("UnityDownloadAssistant") && allLines[i].Contains(".exe")) + var f = GetFileNameFromUrl(exeURL); + FileInfo fileInfo = new FileInfo(f); + downloader.DownloadFile(exeURL, f); + if (File.Exists(fileInfo.FullName)) { - var dlURL = allLines[i].Split('\"'); - if (dlURL.Length > 1) + SetStatus("Running installer"); + try { - Console.WriteLine(dlURL[1]); - foundedURL = dlURL[1]; - break; + Process myProcess = new Process(); + myProcess.StartInfo.FileName = fileInfo.FullName; + myProcess.Start(); + myProcess.WaitForExit(); } - break; - } - } - - if (string.IsNullOrEmpty(foundedURL) == false) - { - // download temp file - using (WebClient downloader = new WebClient()) - { - var f = GetFileNameFromUrl(foundedURL); - FileInfo fileInfo = new FileInfo(f); - downloader.DownloadFile(foundedURL, f); - if (File.Exists(fileInfo.FullName)) + catch (Exception ex) { - try - { - Process myProcess = new Process(); - myProcess.StartInfo.FileName = fileInfo.FullName; - myProcess.Start(); - myProcess.WaitForExit(); - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - + Console.WriteLine(ex); + SetStatus("Failed running installer"); } + } } - else // not found - { - Console.WriteLine("Cannot parse exe.. opening website instead"); - Process.Start(url); - } + SetStatus("Finished Running installer"); + } + else // not found + { + SetStatus("Error> Cannot find installer exe.. opening website instead"); + Process.Start(url); } } @@ -407,6 +422,7 @@ void DownloadAndRun(string url) /// string GetFileNameFromUrl(string url) { + Console.WriteLine(url); var uri = new Uri(url); var filename = uri.Segments.Last(); return filename; @@ -786,5 +802,10 @@ private void btnAddRegister_Click(object sender, EventArgs e) } #endregion + private void chkQuitAfterCommandline_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.closeAfterExplorer = chkQuitAfterCommandline.Checked; + Properties.Settings.Default.Save(); + } } } diff --git a/UnityLauncher/Program.cs b/UnityLauncher/Program.cs index 8ed1598..eeeb145 100644 --- a/UnityLauncher/Program.cs +++ b/UnityLauncher/Program.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; @@ -14,9 +13,23 @@ static class Program [STAThread] static void Main() { + /* + // TODO allow only single instance https://stackoverflow.com/a/6486341/5452781 + bool result = false; + var mutex = new System.Threading.Mutex(true, "UniqueAppId", out result); + + if (result == false) + { + // another instance already running, decide what to do + MessageBox.Show("Another instance is already running."); + return; + }*/ + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); + + //GC.KeepAlive(mutex); } } } diff --git a/UnityLauncher/Properties/Settings.Designer.cs b/UnityLauncher/Properties/Settings.Designer.cs index 7b435b4..73bd910 100644 --- a/UnityLauncher/Properties/Settings.Designer.cs +++ b/UnityLauncher/Properties/Settings.Designer.cs @@ -61,5 +61,17 @@ public bool minimizeToTaskbar { this["packageFolders"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool closeAfterExplorer { + get { + return ((bool)(this["closeAfterExplorer"])); + } + set { + this["closeAfterExplorer"] = value; + } + } } } diff --git a/UnityLauncher/Properties/Settings.settings b/UnityLauncher/Properties/Settings.settings index 7a8ab9b..9719d60 100644 --- a/UnityLauncher/Properties/Settings.settings +++ b/UnityLauncher/Properties/Settings.settings @@ -15,5 +15,8 @@ <?xml version="1.0" encoding="utf-16"?> <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> + + True + \ No newline at end of file From c3936f427c625840acd2a31d55063bc407dcd5e6 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Tue, 5 Sep 2017 21:34:22 +0800 Subject: [PATCH 03/81] add run unity button, fix: open correct tab at start if missing root folder, fixed uninstall registry key error if no key --- UnityLauncher/Form1.Designer.cs | 40 ++++++++++++++------- UnityLauncher/Form1.cs | 61 +++++++++++++++++++++------------ UnityLauncher/Form1.resx | 6 ++-- 3 files changed, 70 insertions(+), 37 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 4cbba59..a4f7abe 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -56,6 +56,7 @@ private void InitializeComponent() this.label3 = new System.Windows.Forms.Label(); this.lstPackageFolders = new System.Windows.Forms.ListBox(); this.tabPage3 = new System.Windows.Forms.TabPage(); + this.chkQuitAfterCommandline = new System.Windows.Forms.CheckBox(); this.btnAddRegister = new System.Windows.Forms.Button(); this.btnRemoveRegister = new System.Windows.Forms.Button(); this.label4 = new System.Windows.Forms.Label(); @@ -71,7 +72,7 @@ private void InitializeComponent() this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); this.btnAddPackFolder = new System.Windows.Forms.Button(); - this.chkQuitAfterCommandline = new System.Windows.Forms.CheckBox(); + this.btnRunUnityOnly = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -109,6 +110,7 @@ private void InitializeComponent() // // tabPage1 // + this.tabPage1.Controls.Add(this.btnRunUnityOnly); this.tabPage1.Controls.Add(this.btnOpenUnityFolder); this.tabPage1.Controls.Add(this.btnLaunch); this.tabPage1.Controls.Add(this.gridRecent); @@ -133,9 +135,9 @@ private void InitializeComponent() // btnLaunch // this.btnLaunch.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnLaunch.Location = new System.Drawing.Point(3, 511); + this.btnLaunch.Location = new System.Drawing.Point(86, 511); this.btnLaunch.Name = "btnLaunch"; - this.btnLaunch.Size = new System.Drawing.Size(444, 35); + this.btnLaunch.Size = new System.Drawing.Size(361, 35); this.btnLaunch.TabIndex = 10; this.btnLaunch.Text = "Launch Project"; this.toolTip1.SetToolTip(this.btnLaunch, "Launch selected project"); @@ -385,6 +387,17 @@ private void InitializeComponent() this.tabPage3.Text = "Settings"; this.tabPage3.UseVisualStyleBackColor = true; // + // chkQuitAfterCommandline + // + this.chkQuitAfterCommandline.AutoSize = true; + this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 409); + this.chkQuitAfterCommandline.Name = "chkQuitAfterCommandline"; + this.chkQuitAfterCommandline.Size = new System.Drawing.Size(189, 17); + this.chkQuitAfterCommandline.TabIndex = 31; + this.chkQuitAfterCommandline.Text = "Close after launching from Explorer"; + this.chkQuitAfterCommandline.UseVisualStyleBackColor = true; + this.chkQuitAfterCommandline.CheckedChanged += new System.EventHandler(this.chkQuitAfterCommandline_CheckedChanged); + // // btnAddRegister // this.btnAddRegister.Location = new System.Drawing.Point(139, 442); @@ -515,16 +528,16 @@ private void InitializeComponent() this.btnAddPackFolder.Text = "Add Folder"; this.btnAddPackFolder.UseVisualStyleBackColor = true; // - // chkQuitAfterCommandline + // btnRunUnityOnly // - this.chkQuitAfterCommandline.AutoSize = true; - this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 409); - this.chkQuitAfterCommandline.Name = "chkQuitAfterCommandline"; - this.chkQuitAfterCommandline.Size = new System.Drawing.Size(189, 17); - this.chkQuitAfterCommandline.TabIndex = 31; - this.chkQuitAfterCommandline.Text = "Close after launching from Explorer"; - this.chkQuitAfterCommandline.UseVisualStyleBackColor = true; - this.chkQuitAfterCommandline.CheckedChanged += new System.EventHandler(this.chkQuitAfterCommandline_CheckedChanged); + this.btnRunUnityOnly.Location = new System.Drawing.Point(3, 511); + this.btnRunUnityOnly.Name = "btnRunUnityOnly"; + this.btnRunUnityOnly.Size = new System.Drawing.Size(80, 35); + this.btnRunUnityOnly.TabIndex = 15; + this.btnRunUnityOnly.Text = "Run Unity"; + this.toolTip1.SetToolTip(this.btnRunUnityOnly, "Open File Explorer"); + this.btnRunUnityOnly.UseVisualStyleBackColor = true; + this.btnRunUnityOnly.Click += new System.EventHandler(this.btnRunUnityOnly_Click); // // Form1 // @@ -539,7 +552,7 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Potato Edition 7"; + this.Text = "UnityLauncher - Potato Edition 8"; this.Load += new System.EventHandler(this.Form1_Load); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); @@ -600,6 +613,7 @@ private void InitializeComponent() private System.Windows.Forms.Button btnRemoveRegister; private System.Windows.Forms.Label label4; private System.Windows.Forms.CheckBox chkQuitAfterCommandline; + private System.Windows.Forms.Button btnRunUnityOnly; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index a80d958..599428d 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -17,6 +17,9 @@ public partial class Form1 : Form // version,exe path (example: 5.6.1f1,c:\prog\unity561\editor\unity.exe) Dictionary unityList = new Dictionary(); + const int settingsTabIndex = 3; + const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; + public Form1() { InitializeComponent(); @@ -48,7 +51,7 @@ void Start() { SetStatus("Error> Did not found any Unity installations, try setting correct root folder.."); UpdateRecentProjectsList(); - tabControl1.SelectedIndex = 2; // settings tab + tabControl1.SelectedIndex = settingsTabIndex; return; } @@ -62,7 +65,7 @@ void Start() SetStatus("Launching from commandline.."); var pathArg = args[2]; - LaunchProject(pathArg); + LaunchProject(pathArg, true); SetStatus("Ready"); // quit after launch if enabled in settings @@ -75,7 +78,6 @@ void Start() { SetStatus("Error> Invalid arguments:" + args[1]); } - } UpdateRecentProjectsList(); @@ -285,30 +287,31 @@ void UpdateRecentProjectsList() } } - void LaunchProject(string pathArg = null) + void LaunchProject(string pathArg = null, bool openProject = true) { - // check if path is unity project folder if (Directory.Exists(pathArg) == true) { - // validate folder if (Directory.Exists(Path.Combine(pathArg, "Assets"))) { var version = GetProjectVersion(pathArg); - Console.WriteLine("Detected project version: " + version); + //Console.WriteLine("Detected project version: " + version); bool installed = HaveExactVersionInstalled(version); if (installed == true) { - // TODO: open? - Console.WriteLine("Opening unity version " + version); + //Console.WriteLine("Opening unity version " + version); + SetStatus("Launching project in unity " + version); try { Process myProcess = new Process(); var cmd = "\"" + unityList[version] + "\""; - var pars = " -projectPath " + "\"" + pathArg + "\""; myProcess.StartInfo.FileName = cmd; - myProcess.StartInfo.Arguments = pars; + if (openProject == true) + { + var pars = " -projectPath " + "\"" + pathArg + "\""; + myProcess.StartInfo.Arguments = pars; + } myProcess.Start(); } catch (Exception ex) @@ -317,8 +320,10 @@ void LaunchProject(string pathArg = null) } } - else + else // we dont have this version installed { + SetStatus("Missing unity version: " + version); + var yesno = MessageBox.Show("Unity version " + version + " is not installed! Yes = Download, No = Open Webpage", "UnityLauncher", MessageBoxButtons.YesNoCancel); string url = GetUnityReleaseURL(version); @@ -480,13 +485,13 @@ private void ShowForm() notifyIcon.Visible = false; } - void LaunchSelectedProject() + void LaunchSelectedProject(bool openProject = true) { var selected = gridRecent.CurrentCell.RowIndex; if (selected > -1) { SetStatus("Launching project.."); - LaunchProject(gridRecent.Rows[selected].Cells["_path"].Value.ToString()); + LaunchProject(gridRecent.Rows[selected].Cells["_path"].Value.ToString(), openProject); SetStatus("Ready"); } } @@ -549,7 +554,7 @@ void AddPackageFolder() void AddContextMenuRegistry() { - RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Classes\\Directory\\Background\\shell", true); + RegistryKey key = Registry.CurrentUser.OpenSubKey(contextRegRoot, true); if (key != null) { var appName = "UnityLauncher"; @@ -568,22 +573,30 @@ void AddContextMenuRegistry() } else { - SetStatus("Error> Cannot find registry key: Software\\Classes\\Directory\\Background\\shell"); + SetStatus("Error> Cannot find registry key: " + contextRegRoot); } } void RemoveContextMenuRegistry() { - RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Classes\\Directory\\Background\\shell", true); + RegistryKey key = Registry.CurrentUser.OpenSubKey(contextRegRoot, true); if (key != null) { var appName = "UnityLauncher"; - key.DeleteSubKeyTree(appName); - SetStatus("Removed context menu registry items"); + RegistryKey appKey = Registry.CurrentUser.OpenSubKey(contextRegRoot + "\\" + appName, false); + if (appKey != null) + { + key.DeleteSubKeyTree(appName); + SetStatus("Removed context menu registry items"); + } + else + { + SetStatus("Nothing to uninstall.."); + } } else { - SetStatus("Error> Cannot find registry key: Software\\Classes\\Directory\\Background\\shell"); + SetStatus("Error> Cannot find registry key: " + contextRegRoot); } } @@ -800,12 +813,18 @@ private void btnAddRegister_Click(object sender, EventArgs e) { AddContextMenuRegistry(); } - #endregion private void chkQuitAfterCommandline_CheckedChanged(object sender, EventArgs e) { Properties.Settings.Default.closeAfterExplorer = chkQuitAfterCommandline.Checked; Properties.Settings.Default.Save(); } + + private void btnRunUnityOnly_Click(object sender, EventArgs e) + { + LaunchSelectedProject(openProject: false); + } + + #endregion } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 64415dd..0761bdd 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -120,9 +120,6 @@ 376, 18 - - 14, 20 - True @@ -1054,6 +1051,9 @@ AAA= + + 14, 20 + 43 From 248ec5e8867cabaf887283d979e0ed4167ab7176 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Fri, 8 Sep 2017 22:22:26 +0800 Subject: [PATCH 04/81] fix missing statusbar, fix crash if no downloadassist url in html page, adding upgrade project dialog (not finished) --- UnityLauncher/Form1.Designer.cs | 85 ++++++++++++-------- UnityLauncher/Form1.cs | 89 +++++++++++++++++++-- UnityLauncher/Form1.resx | 11 +-- UnityLauncher/Form2.Designer.cs | 123 +++++++++++++++++++++++++++++ UnityLauncher/Form2.cs | 49 ++++++++++++ UnityLauncher/Form2.resx | 123 +++++++++++++++++++++++++++++ UnityLauncher/UnityLauncher.csproj | 9 +++ 7 files changed, 443 insertions(+), 46 deletions(-) create mode 100644 UnityLauncher/Form2.Designer.cs create mode 100644 UnityLauncher/Form2.cs create mode 100644 UnityLauncher/Form2.resx diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index a4f7abe..bb8cf0e 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -30,10 +30,9 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); - this.statusStrip1 = new System.Windows.Forms.StatusStrip(); - this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); + this.btnRunUnityOnly = new System.Windows.Forms.Button(); this.btnOpenUnityFolder = new System.Windows.Forms.Button(); this.btnLaunch = new System.Windows.Forms.Button(); this.gridRecent = new System.Windows.Forms.DataGridView(); @@ -72,7 +71,9 @@ private void InitializeComponent() this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); this.btnAddPackFolder = new System.Windows.Forms.Button(); - this.btnRunUnityOnly = new System.Windows.Forms.Button(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.btnUpgradeProject = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -80,22 +81,9 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.gridUnityList)).BeginInit(); this.tabPackages.SuspendLayout(); this.tabPage3.SuspendLayout(); + this.statusStrip1.SuspendLayout(); this.SuspendLayout(); // - // statusStrip1 - // - this.statusStrip1.Location = new System.Drawing.Point(0, 590); - this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(544, 22); - this.statusStrip1.TabIndex = 6; - this.statusStrip1.Text = "statusStrip1"; - // - // toolStripStatusLabel1 - // - this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; - this.toolStripStatusLabel1.Size = new System.Drawing.Size(39, 17); - this.toolStripStatusLabel1.Text = "Status"; - // // tabControl1 // this.tabControl1.Controls.Add(this.tabPage1); @@ -110,6 +98,7 @@ private void InitializeComponent() // // tabPage1 // + this.tabPage1.Controls.Add(this.btnUpgradeProject); this.tabPage1.Controls.Add(this.btnRunUnityOnly); this.tabPage1.Controls.Add(this.btnOpenUnityFolder); this.tabPage1.Controls.Add(this.btnLaunch); @@ -121,11 +110,22 @@ private void InitializeComponent() this.tabPage1.Text = "Projects"; this.tabPage1.UseVisualStyleBackColor = true; // + // btnRunUnityOnly + // + this.btnRunUnityOnly.Location = new System.Drawing.Point(105, 511); + this.btnRunUnityOnly.Name = "btnRunUnityOnly"; + this.btnRunUnityOnly.Size = new System.Drawing.Size(67, 35); + this.btnRunUnityOnly.TabIndex = 15; + this.btnRunUnityOnly.Text = "Run Unity"; + this.toolTip1.SetToolTip(this.btnRunUnityOnly, "Open File Explorer"); + this.btnRunUnityOnly.UseVisualStyleBackColor = true; + this.btnRunUnityOnly.Click += new System.EventHandler(this.btnRunUnityOnly_Click); + // // btnOpenUnityFolder // - this.btnOpenUnityFolder.Location = new System.Drawing.Point(453, 511); + this.btnOpenUnityFolder.Location = new System.Drawing.Point(466, 511); this.btnOpenUnityFolder.Name = "btnOpenUnityFolder"; - this.btnOpenUnityFolder.Size = new System.Drawing.Size(80, 35); + this.btnOpenUnityFolder.Size = new System.Drawing.Size(67, 35); this.btnOpenUnityFolder.TabIndex = 14; this.btnOpenUnityFolder.Text = "Explore"; this.toolTip1.SetToolTip(this.btnOpenUnityFolder, "Open File Explorer"); @@ -135,9 +135,9 @@ private void InitializeComponent() // btnLaunch // this.btnLaunch.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnLaunch.Location = new System.Drawing.Point(86, 511); + this.btnLaunch.Location = new System.Drawing.Point(176, 511); this.btnLaunch.Name = "btnLaunch"; - this.btnLaunch.Size = new System.Drawing.Size(361, 35); + this.btnLaunch.Size = new System.Drawing.Size(287, 35); this.btnLaunch.TabIndex = 10; this.btnLaunch.Text = "Launch Project"; this.toolTip1.SetToolTip(this.btnLaunch, "Launch selected project"); @@ -528,24 +528,40 @@ private void InitializeComponent() this.btnAddPackFolder.Text = "Add Folder"; this.btnAddPackFolder.UseVisualStyleBackColor = true; // - // btnRunUnityOnly + // statusStrip1 // - this.btnRunUnityOnly.Location = new System.Drawing.Point(3, 511); - this.btnRunUnityOnly.Name = "btnRunUnityOnly"; - this.btnRunUnityOnly.Size = new System.Drawing.Size(80, 35); - this.btnRunUnityOnly.TabIndex = 15; - this.btnRunUnityOnly.Text = "Run Unity"; - this.toolTip1.SetToolTip(this.btnRunUnityOnly, "Open File Explorer"); - this.btnRunUnityOnly.UseVisualStyleBackColor = true; - this.btnRunUnityOnly.Click += new System.EventHandler(this.btnRunUnityOnly_Click); + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabel1}); + this.statusStrip1.Location = new System.Drawing.Point(0, 590); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(544, 22); + this.statusStrip1.TabIndex = 7; + this.statusStrip1.Text = "statusStrip1"; + // + // toolStripStatusLabel1 + // + this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); + this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; + // + // btnUpgradeProject + // + this.btnUpgradeProject.Location = new System.Drawing.Point(3, 511); + this.btnUpgradeProject.Name = "btnUpgradeProject"; + this.btnUpgradeProject.Size = new System.Drawing.Size(98, 35); + this.btnUpgradeProject.TabIndex = 16; + this.btnUpgradeProject.Text = "Upgrade Project"; + this.toolTip1.SetToolTip(this.btnUpgradeProject, "Open File Explorer"); + this.btnUpgradeProject.UseVisualStyleBackColor = true; + this.btnUpgradeProject.Click += new System.EventHandler(this.btnUpgradeProject_Click); // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(544, 612); - this.Controls.Add(this.tabControl1); this.Controls.Add(this.statusStrip1); + this.Controls.Add(this.tabControl1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.KeyPreview = true; @@ -565,14 +581,14 @@ private void InitializeComponent() this.tabPackages.PerformLayout(); this.tabPage3.ResumeLayout(false); this.tabPage3.PerformLayout(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); } #endregion - private System.Windows.Forms.StatusStrip statusStrip1; - private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; private System.Windows.Forms.TabControl tabControl1; private System.Windows.Forms.TabPage tabPage1; private System.Windows.Forms.Button btnOpenUnityFolder; @@ -614,6 +630,9 @@ private void InitializeComponent() private System.Windows.Forms.Label label4; private System.Windows.Forms.CheckBox chkQuitAfterCommandline; private System.Windows.Forms.Button btnRunUnityOnly; + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; + private System.Windows.Forms.Button btnUpgradeProject; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 599428d..b30c766 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -15,7 +15,7 @@ namespace UnityLauncher public partial class Form1 : Form { // version,exe path (example: 5.6.1f1,c:\prog\unity561\editor\unity.exe) - Dictionary unityList = new Dictionary(); + public static Dictionary unityList = new Dictionary(); const int settingsTabIndex = 3; const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; @@ -296,8 +296,8 @@ void LaunchProject(string pathArg = null, bool openProject = true) var version = GetProjectVersion(pathArg); //Console.WriteLine("Detected project version: " + version); - bool installed = HaveExactVersionInstalled(version); - if (installed == true) + bool haveExactVersion = HaveExactVersionInstalled(version); + if (haveExactVersion == true) { //Console.WriteLine("Opening unity version " + version); SetStatus("Launching project in unity " + version); @@ -370,8 +370,15 @@ string GetDownloadUrlForUnityVersion(string releaseUrl) string html = client.DownloadString(releaseUrl); Regex regex = new Regex(@"(http).+(UnityDownloadAssistant)+[^\s*]*(.exe)"); Match match = regex.Match(html); - url = match.Groups[0].Captures[0].Value; - Console.WriteLine(url); + if (match.Success == true) + { + url = match.Groups[0].Captures[0].Value; + // Console.WriteLine(url); + } + else + { + SetStatus("Cannot find UnityDownloadAssistant.exe for this version.."); + } } return url; } @@ -825,6 +832,76 @@ private void btnRunUnityOnly_Click(object sender, EventArgs e) LaunchSelectedProject(openProject: false); } - #endregion + private void btnUpgradeProject_Click(object sender, EventArgs e) + { + UpgradeProject(); + } + #endregion UI events + + + public static string FindNearestVersion(string version, List allAvailable) + { + if (version.Contains("2017")) + { + return FindNearestVersionFromSimilarVersions(version, allAvailable.Where(x => x.Contains("2017"))); + } + return FindNearestVersionFromSimilarVersions(version, allAvailable.Where(x => !x.Contains("2017"))); + } + + private static string FindNearestVersionFromSimilarVersions(string version, IEnumerable allAvailable) + { + Dictionary stripped = new Dictionary(); + var enumerable = allAvailable as string[] ?? allAvailable.ToArray(); + + foreach (var t in enumerable) + { + stripped.Add(new Regex("[a-zA-z]").Replace(t, "."), t); + } + + var comparableVersion = new Regex("[a-zA-z]").Replace(version, "."); + if (!stripped.ContainsKey(comparableVersion)) + { + stripped.Add(comparableVersion, version); + Console.WriteLine(comparableVersion + " : " + version); + } + + var comparables = stripped.Keys.OrderBy(x => x).ToList(); + var actualIndex = comparables.IndexOf(comparableVersion); + + if (actualIndex < stripped.Count) return stripped[comparables[actualIndex + 1]]; + return null; + } + + void UpgradeProject() + { + var selected = gridRecent.CurrentCell.RowIndex; + if (selected > -1) + { + SetStatus("Upgrading project.."); + + var path = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); + var currentVersion = GetProjectVersion(path); + + bool haveExactVersion = HaveExactVersionInstalled(currentVersion); + if (haveExactVersion == true) + { + // you already have same version, are you sure? + } + + Form2 upgradeDialog = new Form2(); + Form2.currentVersion = currentVersion; + + if (upgradeDialog.ShowDialog(this) == DialogResult.OK) + { + // yes, upgrade + } + else + { + // cancelled + } + upgradeDialog.Close(); + + } + } } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 0761bdd..82ee6d8 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -117,8 +117,8 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 376, 18 + + 14, 20 True @@ -156,9 +156,6 @@ True - - 14, 20 - 111, 20 @@ -1051,8 +1048,8 @@ AAA= - - 14, 20 + + 492, 18 43 diff --git a/UnityLauncher/Form2.Designer.cs b/UnityLauncher/Form2.Designer.cs new file mode 100644 index 0000000..9ab187f --- /dev/null +++ b/UnityLauncher/Form2.Designer.cs @@ -0,0 +1,123 @@ +namespace UnityLauncher +{ + partial class Form2 + { + /// + /// 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.label1 = new System.Windows.Forms.Label(); + this.lstUnityVersions = new System.Windows.Forms.ListBox(); + this.btnCancelUpgrade = new System.Windows.Forms.Button(); + this.btnConfirmUpgrade = new System.Windows.Forms.Button(); + this.txtUpgradeCurrentVersion = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 21); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(118, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Current Project Version:"; + // + // lstUnityVersions + // + this.lstUnityVersions.FormattingEnabled = true; + this.lstUnityVersions.Location = new System.Drawing.Point(15, 66); + this.lstUnityVersions.Name = "lstUnityVersions"; + this.lstUnityVersions.Size = new System.Drawing.Size(237, 290); + this.lstUnityVersions.TabIndex = 1; + // + // btnCancelUpgrade + // + this.btnCancelUpgrade.Location = new System.Drawing.Point(15, 362); + this.btnCancelUpgrade.Name = "btnCancelUpgrade"; + this.btnCancelUpgrade.Size = new System.Drawing.Size(95, 56); + this.btnCancelUpgrade.TabIndex = 2; + this.btnCancelUpgrade.Text = "Cancel"; + this.btnCancelUpgrade.UseVisualStyleBackColor = true; + // + // btnConfirmUpgrade + // + this.btnConfirmUpgrade.Location = new System.Drawing.Point(116, 362); + this.btnConfirmUpgrade.Name = "btnConfirmUpgrade"; + this.btnConfirmUpgrade.Size = new System.Drawing.Size(136, 56); + this.btnConfirmUpgrade.TabIndex = 3; + this.btnConfirmUpgrade.Text = "Upgrade"; + this.btnConfirmUpgrade.UseVisualStyleBackColor = true; + // + // txtUpgradeCurrentVersion + // + this.txtUpgradeCurrentVersion.Enabled = false; + this.txtUpgradeCurrentVersion.Location = new System.Drawing.Point(136, 18); + this.txtUpgradeCurrentVersion.Name = "txtUpgradeCurrentVersion"; + this.txtUpgradeCurrentVersion.Size = new System.Drawing.Size(100, 20); + this.txtUpgradeCurrentVersion.TabIndex = 4; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 50); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(120, 13); + this.label2.TabIndex = 5; + this.label2.Text = "Available Unity Versions"; + // + // Form2 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(267, 426); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtUpgradeCurrentVersion); + this.Controls.Add(this.btnConfirmUpgrade); + this.Controls.Add(this.btnCancelUpgrade); + this.Controls.Add(this.lstUnityVersions); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "Form2"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Upgrade existing project"; + this.Load += new System.EventHandler(this.Form2_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.ListBox lstUnityVersions; + private System.Windows.Forms.Button btnCancelUpgrade; + private System.Windows.Forms.Button btnConfirmUpgrade; + private System.Windows.Forms.TextBox txtUpgradeCurrentVersion; + private System.Windows.Forms.Label label2; + } +} \ No newline at end of file diff --git a/UnityLauncher/Form2.cs b/UnityLauncher/Form2.cs new file mode 100644 index 0000000..15b1f89 --- /dev/null +++ b/UnityLauncher/Form2.cs @@ -0,0 +1,49 @@ +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 UnityLauncher +{ + public partial class Form2 : Form + { + public static string currentVersion = ""; + + public Form2() + { + InitializeComponent(); + } + + private void Form2_Load(object sender, EventArgs e) + { + // fill textbox + txtUpgradeCurrentVersion.Text = currentVersion; + + // update unity installations list + lstUnityVersions.Items.AddRange(Form1.unityList.Keys.ToArray()); + + // show available versions, autoselect nearest one + if (string.IsNullOrEmpty(currentVersion) == false) + { + string nearestVersion = Form1.FindNearestVersion(currentVersion, Form1.unityList.Keys.ToList()); + Console.WriteLine("nearest:" + nearestVersion); + + // preselect most likely version + int likelyIndex = lstUnityVersions.FindString(currentVersion); + if (likelyIndex > -1) + { + lstUnityVersions.SetSelected(likelyIndex, true); + } + } + else // we dont know current version + { + + } + } + } +} diff --git a/UnityLauncher/Form2.resx b/UnityLauncher/Form2.resx new file mode 100644 index 0000000..61bc649 --- /dev/null +++ b/UnityLauncher/Form2.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + True + + \ No newline at end of file diff --git a/UnityLauncher/UnityLauncher.csproj b/UnityLauncher/UnityLauncher.csproj index e28656b..890845b 100644 --- a/UnityLauncher/UnityLauncher.csproj +++ b/UnityLauncher/UnityLauncher.csproj @@ -81,11 +81,20 @@ Form1.cs + + Form + + + Form2.cs + Form1.cs + + Form2.cs + ResXFileCodeGenerator Resources.Designer.cs From 3b36a39fc5dd6e9ac519d5e22d72bceaf98359ea Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sat, 9 Sep 2017 09:56:43 +0800 Subject: [PATCH 05/81] fix project upgrader --- UnityLauncher/Form1.cs | 31 ++++++++++++++++++++----------- UnityLauncher/Form2.Designer.cs | 2 ++ UnityLauncher/Form2.cs | 20 +++++++++++++++++++- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index b30c766..e0a40cb 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -64,8 +64,11 @@ void Start() { SetStatus("Launching from commandline.."); - var pathArg = args[2]; - LaunchProject(pathArg, true); + var projectPathArgument = args[2]; + + var version = GetProjectVersion(projectPathArgument); + + LaunchProject(projectPathArgument, version, true); SetStatus("Ready"); // quit after launch if enabled in settings @@ -287,13 +290,13 @@ void UpdateRecentProjectsList() } } - void LaunchProject(string pathArg = null, bool openProject = true) + void LaunchProject(string projectPath, string version, bool openProject = true) { - if (Directory.Exists(pathArg) == true) + if (Directory.Exists(projectPath) == true) { - if (Directory.Exists(Path.Combine(pathArg, "Assets"))) + if (Directory.Exists(Path.Combine(projectPath, "Assets"))) { - var version = GetProjectVersion(pathArg); + //var version = GetProjectVersion(projectPath); //Console.WriteLine("Detected project version: " + version); bool haveExactVersion = HaveExactVersionInstalled(version); @@ -309,7 +312,7 @@ void LaunchProject(string pathArg = null, bool openProject = true) myProcess.StartInfo.FileName = cmd; if (openProject == true) { - var pars = " -projectPath " + "\"" + pathArg + "\""; + var pars = " -projectPath " + "\"" + projectPath + "\""; myProcess.StartInfo.Arguments = pars; } myProcess.Start(); @@ -350,12 +353,12 @@ void LaunchProject(string pathArg = null, bool openProject = true) } else { - SetStatus("No Assets folder founded in: " + pathArg); + SetStatus("No Assets folder founded in: " + projectPath); } } else // given path doesnt exists, strange { - SetStatus("Invalid Path:" + pathArg); + SetStatus("Invalid Path: " + projectPath); } } @@ -498,7 +501,9 @@ void LaunchSelectedProject(bool openProject = true) if (selected > -1) { SetStatus("Launching project.."); - LaunchProject(gridRecent.Rows[selected].Cells["_path"].Value.ToString(), openProject); + var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); + var version = GetProjectVersion(projectPath); + LaunchProject(projectPath, version, openProject); SetStatus("Ready"); } } @@ -862,7 +867,7 @@ private static string FindNearestVersionFromSimilarVersions(string version, IEnu if (!stripped.ContainsKey(comparableVersion)) { stripped.Add(comparableVersion, version); - Console.WriteLine(comparableVersion + " : " + version); + //Console.WriteLine(comparableVersion + " : " + version); } var comparables = stripped.Keys.OrderBy(x => x).ToList(); @@ -894,10 +899,14 @@ void UpgradeProject() if (upgradeDialog.ShowDialog(this) == DialogResult.OK) { // yes, upgrade + SetStatus("Upgrading project to " + Form2.currentVersion); + var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); + LaunchProject(projectPath, Form2.currentVersion); } else { // cancelled + SetStatus("Cancelled project upgrade"); } upgradeDialog.Close(); diff --git a/UnityLauncher/Form2.Designer.cs b/UnityLauncher/Form2.Designer.cs index 9ab187f..b227791 100644 --- a/UnityLauncher/Form2.Designer.cs +++ b/UnityLauncher/Form2.Designer.cs @@ -61,6 +61,7 @@ private void InitializeComponent() this.btnCancelUpgrade.TabIndex = 2; this.btnCancelUpgrade.Text = "Cancel"; this.btnCancelUpgrade.UseVisualStyleBackColor = true; + this.btnCancelUpgrade.Click += new System.EventHandler(this.btnCancelUpgrade_Click); // // btnConfirmUpgrade // @@ -70,6 +71,7 @@ private void InitializeComponent() this.btnConfirmUpgrade.TabIndex = 3; this.btnConfirmUpgrade.Text = "Upgrade"; this.btnConfirmUpgrade.UseVisualStyleBackColor = true; + this.btnConfirmUpgrade.Click += new System.EventHandler(this.btnConfirmUpgrade_Click); // // txtUpgradeCurrentVersion // diff --git a/UnityLauncher/Form2.cs b/UnityLauncher/Form2.cs index 15b1f89..5636331 100644 --- a/UnityLauncher/Form2.cs +++ b/UnityLauncher/Form2.cs @@ -31,7 +31,7 @@ private void Form2_Load(object sender, EventArgs e) if (string.IsNullOrEmpty(currentVersion) == false) { string nearestVersion = Form1.FindNearestVersion(currentVersion, Form1.unityList.Keys.ToList()); - Console.WriteLine("nearest:" + nearestVersion); + //Console.WriteLine("nearest:" + nearestVersion); // preselect most likely version int likelyIndex = lstUnityVersions.FindString(currentVersion); @@ -45,5 +45,23 @@ private void Form2_Load(object sender, EventArgs e) } } + + private void btnConfirmUpgrade_Click(object sender, EventArgs e) + { + if (lstUnityVersions.SelectedIndex>-1) + { + currentVersion = lstUnityVersions.Items[lstUnityVersions.SelectedIndex].ToString(); + DialogResult = DialogResult.OK; + } + else + { + // no version selected + } + } + + private void btnCancelUpgrade_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + } } } From 853eb2687bf84c1fbdee5767b5c0c36c718f56d0 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sat, 9 Sep 2017 14:38:37 +0800 Subject: [PATCH 06/81] fix autoselected most likely next version --- UnityLauncher/Form1.Designer.cs | 28 +++++++++++++--------------- UnityLauncher/Form2.Designer.cs | 1 + UnityLauncher/Form2.cs | 2 +- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index bb8cf0e..d0e02ac 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -32,6 +32,7 @@ private void InitializeComponent() System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); + this.btnUpgradeProject = new System.Windows.Forms.Button(); this.btnRunUnityOnly = new System.Windows.Forms.Button(); this.btnOpenUnityFolder = new System.Windows.Forms.Button(); this.btnLaunch = new System.Windows.Forms.Button(); @@ -73,7 +74,6 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this.btnUpgradeProject = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -110,6 +110,17 @@ private void InitializeComponent() this.tabPage1.Text = "Projects"; this.tabPage1.UseVisualStyleBackColor = true; // + // btnUpgradeProject + // + this.btnUpgradeProject.Location = new System.Drawing.Point(3, 511); + this.btnUpgradeProject.Name = "btnUpgradeProject"; + this.btnUpgradeProject.Size = new System.Drawing.Size(98, 35); + this.btnUpgradeProject.TabIndex = 16; + this.btnUpgradeProject.Text = "Upgrade Project"; + this.toolTip1.SetToolTip(this.btnUpgradeProject, "Open File Explorer"); + this.btnUpgradeProject.UseVisualStyleBackColor = true; + this.btnUpgradeProject.Click += new System.EventHandler(this.btnUpgradeProject_Click); + // // btnRunUnityOnly // this.btnRunUnityOnly.Location = new System.Drawing.Point(105, 511); @@ -530,8 +541,6 @@ private void InitializeComponent() // // statusStrip1 // - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(544, 22); @@ -544,17 +553,6 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // - // btnUpgradeProject - // - this.btnUpgradeProject.Location = new System.Drawing.Point(3, 511); - this.btnUpgradeProject.Name = "btnUpgradeProject"; - this.btnUpgradeProject.Size = new System.Drawing.Size(98, 35); - this.btnUpgradeProject.TabIndex = 16; - this.btnUpgradeProject.Text = "Upgrade Project"; - this.toolTip1.SetToolTip(this.btnUpgradeProject, "Open File Explorer"); - this.btnUpgradeProject.UseVisualStyleBackColor = true; - this.btnUpgradeProject.Click += new System.EventHandler(this.btnUpgradeProject_Click); - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -568,7 +566,7 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Potato Edition 8"; + this.Text = "UnityLauncher - Potato Edition 9"; this.Load += new System.EventHandler(this.Form1_Load); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); diff --git a/UnityLauncher/Form2.Designer.cs b/UnityLauncher/Form2.Designer.cs index b227791..c0cf895 100644 --- a/UnityLauncher/Form2.Designer.cs +++ b/UnityLauncher/Form2.Designer.cs @@ -65,6 +65,7 @@ private void InitializeComponent() // // btnConfirmUpgrade // + this.btnConfirmUpgrade.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.btnConfirmUpgrade.Location = new System.Drawing.Point(116, 362); this.btnConfirmUpgrade.Name = "btnConfirmUpgrade"; this.btnConfirmUpgrade.Size = new System.Drawing.Size(136, 56); diff --git a/UnityLauncher/Form2.cs b/UnityLauncher/Form2.cs index 5636331..2a4bf4b 100644 --- a/UnityLauncher/Form2.cs +++ b/UnityLauncher/Form2.cs @@ -34,7 +34,7 @@ private void Form2_Load(object sender, EventArgs e) //Console.WriteLine("nearest:" + nearestVersion); // preselect most likely version - int likelyIndex = lstUnityVersions.FindString(currentVersion); + int likelyIndex = lstUnityVersions.FindString(nearestVersion); if (likelyIndex > -1) { lstUnityVersions.SetSelected(likelyIndex, true); From fa78e52f89ee0ed2d1b784e215f4680caee090f8 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sun, 10 Sep 2017 20:36:37 +0800 Subject: [PATCH 07/81] can create new project to any folder with explorer context menu "open with unitylauncher" --- UnityLauncher/Form1.cs | 121 +++++++++++++++++++++++------------------ UnityLauncher/Form2.cs | 15 +++-- 2 files changed, 79 insertions(+), 57 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index e0a40cb..4547a9f 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -59,16 +59,16 @@ void Start() string[] args = Environment.GetCommandLineArgs(); if (args != null && args.Length > 2) { - var commandArg = args[1]; - if (commandArg == "-projectPath") + var commandLineArgs = args[1]; + if (commandLineArgs == "-projectPath") { SetStatus("Launching from commandline.."); var projectPathArgument = args[2]; - var version = GetProjectVersion(projectPathArgument); LaunchProject(projectPathArgument, version, true); + SetStatus("Ready"); // quit after launch if enabled in settings @@ -272,7 +272,6 @@ void UpdateRecentProjectsList() gridRecent.Rows[gridRecent.Rows.Count - 1].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; } } - SetStatus("Ready"); } @@ -294,36 +293,44 @@ void LaunchProject(string projectPath, string version, bool openProject = true) { if (Directory.Exists(projectPath) == true) { - if (Directory.Exists(Path.Combine(projectPath, "Assets"))) + // no assets path, probably we want to create new project then + var assetsFolder = Path.Combine(projectPath, "Assets"); + if (Directory.Exists(assetsFolder) == false) { - //var version = GetProjectVersion(projectPath); - //Console.WriteLine("Detected project version: " + version); + // TODO could ask if want to create project + Directory.CreateDirectory(assetsFolder); + } - bool haveExactVersion = HaveExactVersionInstalled(version); - if (haveExactVersion == true) - { - //Console.WriteLine("Opening unity version " + version); - SetStatus("Launching project in unity " + version); + bool haveExactVersion = HaveExactVersionInstalled(version); + if (haveExactVersion == true) + { + //Console.WriteLine("Opening unity version " + version); + SetStatus("Launching project in unity " + version); - try - { - Process myProcess = new Process(); - var cmd = "\"" + unityList[version] + "\""; - myProcess.StartInfo.FileName = cmd; - if (openProject == true) - { - var pars = " -projectPath " + "\"" + projectPath + "\""; - myProcess.StartInfo.Arguments = pars; - } - myProcess.Start(); - } - catch (Exception ex) + try + { + Process myProcess = new Process(); + var cmd = "\"" + unityList[version] + "\""; + myProcess.StartInfo.FileName = cmd; + if (openProject == true) { - Console.WriteLine(ex); + var pars = " -projectPath " + "\"" + projectPath + "\""; + myProcess.StartInfo.Arguments = pars; } - + myProcess.Start(); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + else // we dont have this version installed (or no version info available) + { + if (string.IsNullOrEmpty(version) == true) + { + DisplayUpgradeDialog(version, projectPath); } - else // we dont have this version installed + else // offer to download or open web { SetStatus("Missing unity version: " + version); @@ -351,10 +358,6 @@ void LaunchProject(string projectPath, string version, bool openProject = true) } } } - else - { - SetStatus("No Assets folder founded in: " + projectPath); - } } else // given path doesnt exists, strange { @@ -877,6 +880,7 @@ private static string FindNearestVersionFromSimilarVersions(string version, IEnu return null; } + // displays version selector to upgrade project void UpgradeProject() { var selected = gridRecent.CurrentCell.RowIndex; @@ -884,33 +888,46 @@ void UpgradeProject() { SetStatus("Upgrading project.."); - var path = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); - var currentVersion = GetProjectVersion(path); - - bool haveExactVersion = HaveExactVersionInstalled(currentVersion); - if (haveExactVersion == true) - { - // you already have same version, are you sure? - } - - Form2 upgradeDialog = new Form2(); - Form2.currentVersion = currentVersion; + var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); + var currentVersion = GetProjectVersion(projectPath); - if (upgradeDialog.ShowDialog(this) == DialogResult.OK) + if (string.IsNullOrEmpty(currentVersion) == true) { - // yes, upgrade - SetStatus("Upgrading project to " + Form2.currentVersion); - var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); - LaunchProject(projectPath, Form2.currentVersion); + // TODO no version info available, should handle errors? } - else + else // have version info { - // cancelled - SetStatus("Cancelled project upgrade"); + bool haveExactVersion = HaveExactVersionInstalled(currentVersion); + if (haveExactVersion == true) + { + // you already have exact version, are you sure about upgrade? + } } - upgradeDialog.Close(); + DisplayUpgradeDialog(currentVersion, projectPath, true); + } + } + + void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launchProject = true) + { + // display upgrade dialog (version selector) + Form2 upgradeDialog = new Form2(); + Form2.currentVersion = currentVersion; + + if (upgradeDialog.ShowDialog(this) == DialogResult.OK) + { + // yes, upgrade + SetStatus("Upgrading project to " + Form2.currentVersion); + if (launchProject == true) LaunchProject(projectPath, Form2.currentVersion); + } + else + { + // cancelled + SetStatus("Cancelled project upgrade"); } + + upgradeDialog.Close(); } + } } diff --git a/UnityLauncher/Form2.cs b/UnityLauncher/Form2.cs index 2a4bf4b..af7831f 100644 --- a/UnityLauncher/Form2.cs +++ b/UnityLauncher/Form2.cs @@ -21,9 +21,11 @@ public Form2() private void Form2_Load(object sender, EventArgs e) { - // fill textbox - txtUpgradeCurrentVersion.Text = currentVersion; + Start(); + } + void Start() + { // update unity installations list lstUnityVersions.Items.AddRange(Form1.unityList.Keys.ToArray()); @@ -40,15 +42,18 @@ private void Form2_Load(object sender, EventArgs e) lstUnityVersions.SetSelected(likelyIndex, true); } } - else // we dont know current version + else // we dont have current version { - + currentVersion = "None"; } + + // fill textbox + txtUpgradeCurrentVersion.Text = currentVersion; } private void btnConfirmUpgrade_Click(object sender, EventArgs e) { - if (lstUnityVersions.SelectedIndex>-1) + if (lstUnityVersions.SelectedIndex > -1) { currentVersion = lstUnityVersions.Items[lstUnityVersions.SelectedIndex].ToString(); DialogResult = DialogResult.OK; From afeabff86e001f716dab606742d61a44747c6512 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Fri, 22 Sep 2017 18:12:03 +0800 Subject: [PATCH 08/81] make window wider, open log folder button, fix missing status bar --- UnityLauncher/Form1.Designer.cs | 133 ++++++++++++++++++-------------- UnityLauncher/Form1.cs | 11 +++ UnityLauncher/Form1.resx | 27 ++++--- 3 files changed, 100 insertions(+), 71 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index d0e02ac..e6f07b5 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -37,10 +37,6 @@ private void InitializeComponent() this.btnOpenUnityFolder = new System.Windows.Forms.Button(); this.btnLaunch = new System.Windows.Forms.Button(); this.gridRecent = new System.Windows.Forms.DataGridView(); - this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabPage2 = new System.Windows.Forms.TabPage(); this.btnOpenReleasePage = new System.Windows.Forms.Button(); this.btnExploreUnity = new System.Windows.Forms.Button(); @@ -74,6 +70,11 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.btnOpenLogFolder = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -93,7 +94,7 @@ private void InitializeComponent() this.tabControl1.Location = new System.Drawing.Point(0, 12); this.tabControl1.Name = "tabControl1"; this.tabControl1.SelectedIndex = 0; - this.tabControl1.Size = new System.Drawing.Size(544, 575); + this.tabControl1.Size = new System.Drawing.Size(588, 575); this.tabControl1.TabIndex = 0; // // tabPage1 @@ -105,7 +106,7 @@ private void InitializeComponent() this.tabPage1.Controls.Add(this.gridRecent); this.tabPage1.Location = new System.Drawing.Point(4, 22); this.tabPage1.Name = "tabPage1"; - this.tabPage1.Size = new System.Drawing.Size(536, 549); + this.tabPage1.Size = new System.Drawing.Size(580, 549); this.tabPage1.TabIndex = 0; this.tabPage1.Text = "Projects"; this.tabPage1.UseVisualStyleBackColor = true; @@ -134,7 +135,7 @@ private void InitializeComponent() // // btnOpenUnityFolder // - this.btnOpenUnityFolder.Location = new System.Drawing.Point(466, 511); + this.btnOpenUnityFolder.Location = new System.Drawing.Point(510, 511); this.btnOpenUnityFolder.Name = "btnOpenUnityFolder"; this.btnOpenUnityFolder.Size = new System.Drawing.Size(67, 35); this.btnOpenUnityFolder.TabIndex = 14; @@ -148,7 +149,7 @@ private void InitializeComponent() this.btnLaunch.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.btnLaunch.Location = new System.Drawing.Point(176, 511); this.btnLaunch.Name = "btnLaunch"; - this.btnLaunch.Size = new System.Drawing.Size(287, 35); + this.btnLaunch.Size = new System.Drawing.Size(330, 35); this.btnLaunch.TabIndex = 10; this.btnLaunch.Text = "Launch Project"; this.toolTip1.SetToolTip(this.btnLaunch, "Launch selected project"); @@ -178,41 +179,10 @@ private void InitializeComponent() this.gridRecent.ShowCellErrors = false; this.gridRecent.ShowCellToolTips = false; this.gridRecent.ShowEditingIcon = false; - this.gridRecent.Size = new System.Drawing.Size(530, 502); + this.gridRecent.Size = new System.Drawing.Size(574, 502); this.gridRecent.TabIndex = 0; this.gridRecent.KeyDown += new System.Windows.Forms.KeyEventHandler(this.gridRecent_KeyDown); // - // _project - // - this._project.HeaderText = "Project"; - this._project.Name = "_project"; - this._project.ReadOnly = true; - this._project.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._project.Width = 135; - // - // _version - // - this._version.HeaderText = "Version"; - this._version.Name = "_version"; - this._version.ReadOnly = true; - this._version.Width = 65; - // - // _path - // - this._path.HeaderText = "Path"; - this._path.Name = "_path"; - this._path.ReadOnly = true; - this._path.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._path.Width = 178; - // - // _dateModified - // - this._dateModified.HeaderText = "Modified"; - this._dateModified.Name = "_dateModified"; - this._dateModified.ReadOnly = true; - this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._dateModified.Width = 77; - // // tabPage2 // this.tabPage2.Controls.Add(this.btnOpenReleasePage); @@ -221,14 +191,14 @@ private void InitializeComponent() this.tabPage2.Controls.Add(this.gridUnityList); this.tabPage2.Location = new System.Drawing.Point(4, 22); this.tabPage2.Name = "tabPage2"; - this.tabPage2.Size = new System.Drawing.Size(536, 549); + this.tabPage2.Size = new System.Drawing.Size(580, 549); this.tabPage2.TabIndex = 1; this.tabPage2.Text = "Unity\'s"; this.tabPage2.UseVisualStyleBackColor = true; // // btnOpenReleasePage // - this.btnOpenReleasePage.Location = new System.Drawing.Point(367, 511); + this.btnOpenReleasePage.Location = new System.Drawing.Point(411, 511); this.btnOpenReleasePage.Name = "btnOpenReleasePage"; this.btnOpenReleasePage.Size = new System.Drawing.Size(80, 35); this.btnOpenReleasePage.TabIndex = 17; @@ -239,7 +209,7 @@ private void InitializeComponent() // // btnExploreUnity // - this.btnExploreUnity.Location = new System.Drawing.Point(453, 511); + this.btnExploreUnity.Location = new System.Drawing.Point(497, 511); this.btnExploreUnity.Name = "btnExploreUnity"; this.btnExploreUnity.Size = new System.Drawing.Size(80, 35); this.btnExploreUnity.TabIndex = 16; @@ -253,7 +223,7 @@ private void InitializeComponent() this.btnLaunchUnity.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.btnLaunchUnity.Location = new System.Drawing.Point(3, 511); this.btnLaunchUnity.Name = "btnLaunchUnity"; - this.btnLaunchUnity.Size = new System.Drawing.Size(358, 35); + this.btnLaunchUnity.Size = new System.Drawing.Size(402, 35); this.btnLaunchUnity.TabIndex = 15; this.btnLaunchUnity.Text = "Run Unity"; this.toolTip1.SetToolTip(this.btnLaunchUnity, "Launch selected project"); @@ -281,7 +251,7 @@ private void InitializeComponent() this.gridUnityList.ShowCellErrors = false; this.gridUnityList.ShowCellToolTips = false; this.gridUnityList.ShowEditingIcon = false; - this.gridUnityList.Size = new System.Drawing.Size(530, 502); + this.gridUnityList.Size = new System.Drawing.Size(574, 502); this.gridUnityList.TabIndex = 10; this.gridUnityList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.unityGridView_KeyDown); // @@ -312,14 +282,14 @@ private void InitializeComponent() this.tabPackages.Controls.Add(this.lstPackageFolders); this.tabPackages.Location = new System.Drawing.Point(4, 22); this.tabPackages.Name = "tabPackages"; - this.tabPackages.Size = new System.Drawing.Size(536, 549); + this.tabPackages.Size = new System.Drawing.Size(580, 549); this.tabPackages.TabIndex = 4; this.tabPackages.Text = "My Packages"; this.tabPackages.UseVisualStyleBackColor = true; // // btnAddAssetStoreFolder // - this.btnAddAssetStoreFolder.Location = new System.Drawing.Point(372, 232); + this.btnAddAssetStoreFolder.Location = new System.Drawing.Point(416, 232); this.btnAddAssetStoreFolder.Name = "btnAddAssetStoreFolder"; this.btnAddAssetStoreFolder.Size = new System.Drawing.Size(142, 23); this.btnAddAssetStoreFolder.TabIndex = 29; @@ -332,7 +302,7 @@ private void InitializeComponent() this.btnExplorePackageFolder.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.btnExplorePackageFolder.Location = new System.Drawing.Point(3, 511); this.btnExplorePackageFolder.Name = "btnExplorePackageFolder"; - this.btnExplorePackageFolder.Size = new System.Drawing.Size(530, 35); + this.btnExplorePackageFolder.Size = new System.Drawing.Size(574, 35); this.btnExplorePackageFolder.TabIndex = 28; this.btnExplorePackageFolder.Text = "Explore"; this.toolTip1.SetToolTip(this.btnExplorePackageFolder, "Open File Explorer"); @@ -374,11 +344,12 @@ private void InitializeComponent() this.lstPackageFolders.FormattingEnabled = true; this.lstPackageFolders.Location = new System.Drawing.Point(19, 40); this.lstPackageFolders.Name = "lstPackageFolders"; - this.lstPackageFolders.Size = new System.Drawing.Size(495, 186); + this.lstPackageFolders.Size = new System.Drawing.Size(539, 186); this.lstPackageFolders.TabIndex = 21; // // tabPage3 // + this.tabPage3.Controls.Add(this.btnOpenLogFolder); this.tabPage3.Controls.Add(this.chkQuitAfterCommandline); this.tabPage3.Controls.Add(this.btnAddRegister); this.tabPage3.Controls.Add(this.btnRemoveRegister); @@ -393,7 +364,7 @@ private void InitializeComponent() this.tabPage3.Controls.Add(this.btnRefresh); this.tabPage3.Location = new System.Drawing.Point(4, 22); this.tabPage3.Name = "tabPage3"; - this.tabPage3.Size = new System.Drawing.Size(536, 549); + this.tabPage3.Size = new System.Drawing.Size(580, 549); this.tabPage3.TabIndex = 3; this.tabPage3.Text = "Settings"; this.tabPage3.UseVisualStyleBackColor = true; @@ -494,14 +465,14 @@ private void InitializeComponent() this.lstRootFolders.FormattingEnabled = true; this.lstRootFolders.Location = new System.Drawing.Point(20, 31); this.lstRootFolders.Name = "lstRootFolders"; - this.lstRootFolders.Size = new System.Drawing.Size(495, 186); + this.lstRootFolders.Size = new System.Drawing.Size(552, 186); this.lstRootFolders.TabIndex = 20; // // lbl_unityCount // this.lbl_unityCount.AutoSize = true; this.lbl_unityCount.Enabled = false; - this.lbl_unityCount.Location = new System.Drawing.Point(418, 15); + this.lbl_unityCount.Location = new System.Drawing.Point(475, 15); this.lbl_unityCount.Name = "lbl_unityCount"; this.lbl_unityCount.Size = new System.Drawing.Size(97, 13); this.lbl_unityCount.TabIndex = 18; @@ -509,7 +480,7 @@ private void InitializeComponent() // // btnRefresh // - this.btnRefresh.Location = new System.Drawing.Point(378, 223); + this.btnRefresh.Location = new System.Drawing.Point(435, 223); this.btnRefresh.Name = "btnRefresh"; this.btnRefresh.Size = new System.Drawing.Size(137, 23); this.btnRefresh.TabIndex = 19; @@ -541,9 +512,11 @@ private void InitializeComponent() // // statusStrip1 // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(544, 22); + this.statusStrip1.Size = new System.Drawing.Size(588, 22); this.statusStrip1.TabIndex = 7; this.statusStrip1.Text = "statusStrip1"; // @@ -553,11 +526,52 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // + // _project + // + this._project.HeaderText = "Project"; + this._project.Name = "_project"; + this._project.ReadOnly = true; + this._project.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this._project.Width = 150; + // + // _version + // + this._version.HeaderText = "Version"; + this._version.Name = "_version"; + this._version.ReadOnly = true; + this._version.Width = 72; + // + // _path + // + this._path.HeaderText = "Path"; + this._path.Name = "_path"; + this._path.ReadOnly = true; + this._path.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this._path.Width = 185; + // + // _dateModified + // + this._dateModified.HeaderText = "Modified"; + this._dateModified.Name = "_dateModified"; + this._dateModified.ReadOnly = true; + this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this._dateModified.Width = 120; + // + // btnOpenLogFolder + // + this.btnOpenLogFolder.Location = new System.Drawing.Point(435, 380); + this.btnOpenLogFolder.Name = "btnOpenLogFolder"; + this.btnOpenLogFolder.Size = new System.Drawing.Size(137, 23); + this.btnOpenLogFolder.TabIndex = 32; + this.btnOpenLogFolder.Text = "Open Editor Log Folder"; + this.btnOpenLogFolder.UseVisualStyleBackColor = true; + this.btnOpenLogFolder.Click += new System.EventHandler(this.btnOpenLogFolder_Click); + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(544, 612); + this.ClientSize = new System.Drawing.Size(588, 612); this.Controls.Add(this.statusStrip1); this.Controls.Add(this.tabControl1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; @@ -593,10 +607,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolTip toolTip1; private System.Windows.Forms.Button btnLaunch; private System.Windows.Forms.DataGridView gridRecent; - private System.Windows.Forms.DataGridViewTextBoxColumn _project; - private System.Windows.Forms.DataGridViewTextBoxColumn _version; - private System.Windows.Forms.DataGridViewTextBoxColumn _path; - private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; private System.Windows.Forms.TabPage tabPage2; private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1; private System.Windows.Forms.NotifyIcon notifyIcon; @@ -631,6 +641,11 @@ private void InitializeComponent() private System.Windows.Forms.StatusStrip statusStrip1; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; private System.Windows.Forms.Button btnUpgradeProject; + private System.Windows.Forms.DataGridViewTextBoxColumn _project; + private System.Windows.Forms.DataGridViewTextBoxColumn _version; + private System.Windows.Forms.DataGridViewTextBoxColumn _path; + private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; + private System.Windows.Forms.Button btnOpenLogFolder; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 4547a9f..da3cc7e 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -844,6 +844,16 @@ private void btnUpgradeProject_Click(object sender, EventArgs e) { UpgradeProject(); } + + private void btnOpenLogFolder_Click(object sender, EventArgs e) + { + var logfolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Unity", "Editor"); + Console.WriteLine(logfolder); + if (Directory.Exists(logfolder) == true) + { + LaunchExplorer(logfolder); + } + } #endregion UI events @@ -929,5 +939,6 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch upgradeDialog.Close(); } + } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 82ee6d8..1252872 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -132,18 +132,6 @@ True - - True - - - True - - - True - - - True - True @@ -156,6 +144,9 @@ True + + 14, 20 + 111, 20 @@ -1051,6 +1042,18 @@ 492, 18 + + True + + + True + + + True + + + True + 43 From d835ca2189f775f3b5ad3127d6e931a2b7e55945 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sun, 22 Oct 2017 14:12:17 +0800 Subject: [PATCH 09/81] upgrade dialog for explorer projects also, fixed #13, more status updates, text changes --- UnityLauncher/Form1.Designer.cs | 96 ++++++++++++++------------- UnityLauncher/Form1.cs | 111 ++++++++++++++++---------------- UnityLauncher/Form1.resx | 24 +++---- UnityLauncher/Form2.Designer.cs | 46 ++++++++++--- UnityLauncher/Form2.cs | 24 ++++++- UnityLauncher/Form2.resx | 3 - 6 files changed, 172 insertions(+), 132 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index e6f07b5..273be79 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -37,6 +37,10 @@ private void InitializeComponent() this.btnOpenUnityFolder = new System.Windows.Forms.Button(); this.btnLaunch = new System.Windows.Forms.Button(); this.gridRecent = new System.Windows.Forms.DataGridView(); + this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabPage2 = new System.Windows.Forms.TabPage(); this.btnOpenReleasePage = new System.Windows.Forms.Button(); this.btnExploreUnity = new System.Windows.Forms.Button(); @@ -52,6 +56,7 @@ private void InitializeComponent() this.label3 = new System.Windows.Forms.Label(); this.lstPackageFolders = new System.Windows.Forms.ListBox(); this.tabPage3 = new System.Windows.Forms.TabPage(); + this.btnOpenLogFolder = new System.Windows.Forms.Button(); this.chkQuitAfterCommandline = new System.Windows.Forms.CheckBox(); this.btnAddRegister = new System.Windows.Forms.Button(); this.btnRemoveRegister = new System.Windows.Forms.Button(); @@ -70,11 +75,6 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.btnOpenLogFolder = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -183,6 +183,37 @@ private void InitializeComponent() this.gridRecent.TabIndex = 0; this.gridRecent.KeyDown += new System.Windows.Forms.KeyEventHandler(this.gridRecent_KeyDown); // + // _project + // + this._project.HeaderText = "Project"; + this._project.Name = "_project"; + this._project.ReadOnly = true; + this._project.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this._project.Width = 150; + // + // _version + // + this._version.HeaderText = "Version"; + this._version.Name = "_version"; + this._version.ReadOnly = true; + this._version.Width = 72; + // + // _path + // + this._path.HeaderText = "Path"; + this._path.Name = "_path"; + this._path.ReadOnly = true; + this._path.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this._path.Width = 185; + // + // _dateModified + // + this._dateModified.HeaderText = "Modified"; + this._dateModified.Name = "_dateModified"; + this._dateModified.ReadOnly = true; + this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this._dateModified.Width = 120; + // // tabPage2 // this.tabPage2.Controls.Add(this.btnOpenReleasePage); @@ -369,6 +400,16 @@ private void InitializeComponent() this.tabPage3.Text = "Settings"; this.tabPage3.UseVisualStyleBackColor = true; // + // btnOpenLogFolder + // + this.btnOpenLogFolder.Location = new System.Drawing.Point(435, 380); + this.btnOpenLogFolder.Name = "btnOpenLogFolder"; + this.btnOpenLogFolder.Size = new System.Drawing.Size(137, 23); + this.btnOpenLogFolder.TabIndex = 32; + this.btnOpenLogFolder.Text = "Open Editor Log Folder"; + this.btnOpenLogFolder.UseVisualStyleBackColor = true; + this.btnOpenLogFolder.Click += new System.EventHandler(this.btnOpenLogFolder_Click); + // // chkQuitAfterCommandline // this.chkQuitAfterCommandline.AutoSize = true; @@ -512,8 +553,6 @@ private void InitializeComponent() // // statusStrip1 // - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(588, 22); @@ -526,47 +565,6 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // - // _project - // - this._project.HeaderText = "Project"; - this._project.Name = "_project"; - this._project.ReadOnly = true; - this._project.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._project.Width = 150; - // - // _version - // - this._version.HeaderText = "Version"; - this._version.Name = "_version"; - this._version.ReadOnly = true; - this._version.Width = 72; - // - // _path - // - this._path.HeaderText = "Path"; - this._path.Name = "_path"; - this._path.ReadOnly = true; - this._path.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._path.Width = 185; - // - // _dateModified - // - this._dateModified.HeaderText = "Modified"; - this._dateModified.Name = "_dateModified"; - this._dateModified.ReadOnly = true; - this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._dateModified.Width = 120; - // - // btnOpenLogFolder - // - this.btnOpenLogFolder.Location = new System.Drawing.Point(435, 380); - this.btnOpenLogFolder.Name = "btnOpenLogFolder"; - this.btnOpenLogFolder.Size = new System.Drawing.Size(137, 23); - this.btnOpenLogFolder.TabIndex = 32; - this.btnOpenLogFolder.Text = "Open Editor Log Folder"; - this.btnOpenLogFolder.UseVisualStyleBackColor = true; - this.btnOpenLogFolder.Click += new System.EventHandler(this.btnOpenLogFolder_Click); - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -580,7 +578,7 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Potato Edition 9"; + this.Text = "UnityLauncher - Potato Edition 10"; this.Load += new System.EventHandler(this.Form1_Load); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index da3cc7e..0174267 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -55,7 +55,7 @@ void Start() return; } - // check if received -projectPath argument (that means, should try open the project) + // check if received -projectPath argument (that means opening from explorer / cmdline) string[] args = Environment.GetCommandLineArgs(); if (args != null && args.Length > 2) { @@ -67,6 +67,7 @@ void Start() var projectPathArgument = args[2]; var version = GetProjectVersion(projectPathArgument); + // try launching it LaunchProject(projectPathArgument, version, true); SetStatus("Ready"); @@ -239,8 +240,7 @@ void UpdateRecentProjectsList() //Console.WriteLine(key); if (key == null) { - // no recent list founded - Console.WriteLine("No recent projects list founded"); + SetStatus("No recent projects list founded"); return; } @@ -297,7 +297,7 @@ void LaunchProject(string projectPath, string version, bool openProject = true) var assetsFolder = Path.Combine(projectPath, "Assets"); if (Directory.Exists(assetsFolder) == false) { - // TODO could ask if want to create project + // TODO could ask if want to create project.. Directory.CreateDirectory(assetsFolder); } @@ -326,37 +326,8 @@ void LaunchProject(string projectPath, string version, bool openProject = true) } else // we dont have this version installed (or no version info available) { - if (string.IsNullOrEmpty(version) == true) - { - DisplayUpgradeDialog(version, projectPath); - } - else // offer to download or open web - { - SetStatus("Missing unity version: " + version); - - var yesno = MessageBox.Show("Unity version " + version + " is not installed! Yes = Download, No = Open Webpage", "UnityLauncher", MessageBoxButtons.YesNoCancel); - - string url = GetUnityReleaseURL(version); - - // download file - if (yesno == DialogResult.Yes) - { - Console.WriteLine("download unity: " + url); - if (string.IsNullOrEmpty(url) == false) - { - DownloadAndRun(url); - } - } - - // open page - if (yesno == DialogResult.No) - { - if (string.IsNullOrEmpty(url) == false) - { - Process.Start(url); - } - } - } + SetStatus("Missing unity version: " + version); + DisplayUpgradeDialog(version, projectPath); } } else // given path doesnt exists, strange @@ -429,7 +400,7 @@ void DownloadAndRun(string url) else // not found { SetStatus("Error> Cannot find installer exe.. opening website instead"); - Process.Start(url); + Process.Start(url + "#installer-exe-not-found"); } } @@ -440,7 +411,6 @@ void DownloadAndRun(string url) /// string GetFileNameFromUrl(string url) { - Console.WriteLine(url); var uri = new Uri(url); var filename = uri.Segments.Last(); return filename; @@ -647,11 +617,7 @@ private void btnOpenReleasePage_Click(object sender, EventArgs e) if (selected > -1) { var version = gridUnityList.Rows[selected].Cells["_unityVersion"].Value.ToString(); - var url = GetUnityReleaseURL(version); - if (string.IsNullOrEmpty(url) == false) - { - Process.Start(url); - } + OpenReleaseNotes(version); } } @@ -802,7 +768,7 @@ private void btn_openFolder_Click(object sender, EventArgs e) private void btnExplorePackageFolder_Click(object sender, EventArgs e) { var selected = lstPackageFolders.SelectedIndex; - Console.WriteLine(lstPackageFolders.Items[selected].ToString()); + //Console.WriteLine(lstPackageFolders.Items[selected].ToString()); if (selected > -1) { var path = lstPackageFolders.Items[selected].ToString(); @@ -848,7 +814,7 @@ private void btnUpgradeProject_Click(object sender, EventArgs e) private void btnOpenLogFolder_Click(object sender, EventArgs e) { var logfolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Unity", "Editor"); - Console.WriteLine(logfolder); + //Console.WriteLine(logfolder); if (Directory.Exists(logfolder) == true) { LaunchExplorer(logfolder); @@ -856,6 +822,19 @@ private void btnOpenLogFolder_Click(object sender, EventArgs e) } #endregion UI events + void OpenReleaseNotes(string version) + { + SetStatus("Opening release notes for version " + version); + var url = GetUnityReleaseURL(version); + if (string.IsNullOrEmpty(url) == false) + { + Process.Start(url); + } + else + { + SetStatus("Failed opening Release Notes URL for version " + version); + } + } public static string FindNearestVersion(string version, List allAvailable) { @@ -880,13 +859,12 @@ private static string FindNearestVersionFromSimilarVersions(string version, IEnu if (!stripped.ContainsKey(comparableVersion)) { stripped.Add(comparableVersion, version); - //Console.WriteLine(comparableVersion + " : " + version); } var comparables = stripped.Keys.OrderBy(x => x).ToList(); var actualIndex = comparables.IndexOf(comparableVersion); - if (actualIndex < stripped.Count) return stripped[comparables[actualIndex + 1]]; + if (actualIndex < stripped.Count - 1) return stripped[comparables[actualIndex + 1]]; return null; } @@ -913,7 +891,6 @@ void UpgradeProject() // you already have exact version, are you sure about upgrade? } } - DisplayUpgradeDialog(currentVersion, projectPath, true); } } @@ -924,18 +901,38 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch Form2 upgradeDialog = new Form2(); Form2.currentVersion = currentVersion; - if (upgradeDialog.ShowDialog(this) == DialogResult.OK) + // check what user selected + var results = upgradeDialog.ShowDialog(this); + switch (results) { - // yes, upgrade - SetStatus("Upgrading project to " + Form2.currentVersion); - if (launchProject == true) LaunchProject(projectPath, Form2.currentVersion); - } - else - { - // cancelled - SetStatus("Cancelled project upgrade"); + case DialogResult.Ignore: // view release notes page + OpenReleaseNotes(currentVersion); + // display window again for now.. + DisplayUpgradeDialog(currentVersion, projectPath, launchProject); + break; + case DialogResult.Cancel: // cancelled + SetStatus("Cancelled project upgrade"); + break; + case DialogResult.Retry: // download and install missing version + SetStatus("Download and Install missing version " + currentVersion); + string url = GetUnityReleaseURL(currentVersion); + if (string.IsNullOrEmpty(url) == false) + { + DownloadAndRun(url); + } + else + { + SetStatus("Failed getting Unity Installer URL"); + } + break; + case DialogResult.Yes: // upgrade + SetStatus("Upgrading project to " + Form2.currentVersion); + if (launchProject == true) LaunchProject(projectPath, Form2.currentVersion); + break; + default: + Console.WriteLine("Unknown DialogResult: " + results); + break; } - upgradeDialog.Close(); } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 1252872..a1bd7de 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -132,6 +132,18 @@ True + + True + + + True + + + True + + + True + True @@ -1042,18 +1054,6 @@ 492, 18 - - True - - - True - - - True - - - True - 43 diff --git a/UnityLauncher/Form2.Designer.cs b/UnityLauncher/Form2.Designer.cs index c0cf895..ce7d9fe 100644 --- a/UnityLauncher/Form2.Designer.cs +++ b/UnityLauncher/Form2.Designer.cs @@ -34,12 +34,14 @@ private void InitializeComponent() this.btnConfirmUpgrade = new System.Windows.Forms.Button(); this.txtUpgradeCurrentVersion = new System.Windows.Forms.TextBox(); this.label2 = new System.Windows.Forms.Label(); + this.btn_GoInstallMissingVersion = new System.Windows.Forms.Button(); + this.btn_OpenMissingVersionReleasePage = new System.Windows.Forms.Button(); this.SuspendLayout(); // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 21); + this.label1.Location = new System.Drawing.Point(16, 21); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(118, 13); this.label1.TabIndex = 0; @@ -48,14 +50,14 @@ private void InitializeComponent() // lstUnityVersions // this.lstUnityVersions.FormattingEnabled = true; - this.lstUnityVersions.Location = new System.Drawing.Point(15, 66); + this.lstUnityVersions.Location = new System.Drawing.Point(12, 104); this.lstUnityVersions.Name = "lstUnityVersions"; - this.lstUnityVersions.Size = new System.Drawing.Size(237, 290); + this.lstUnityVersions.Size = new System.Drawing.Size(235, 303); this.lstUnityVersions.TabIndex = 1; // // btnCancelUpgrade // - this.btnCancelUpgrade.Location = new System.Drawing.Point(15, 362); + this.btnCancelUpgrade.Location = new System.Drawing.Point(12, 413); this.btnCancelUpgrade.Name = "btnCancelUpgrade"; this.btnCancelUpgrade.Size = new System.Drawing.Size(95, 56); this.btnCancelUpgrade.TabIndex = 2; @@ -66,11 +68,11 @@ private void InitializeComponent() // btnConfirmUpgrade // this.btnConfirmUpgrade.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnConfirmUpgrade.Location = new System.Drawing.Point(116, 362); + this.btnConfirmUpgrade.Location = new System.Drawing.Point(113, 413); this.btnConfirmUpgrade.Name = "btnConfirmUpgrade"; this.btnConfirmUpgrade.Size = new System.Drawing.Size(136, 56); this.btnConfirmUpgrade.TabIndex = 3; - this.btnConfirmUpgrade.Text = "Upgrade"; + this.btnConfirmUpgrade.Text = "Upgrade Project"; this.btnConfirmUpgrade.UseVisualStyleBackColor = true; this.btnConfirmUpgrade.Click += new System.EventHandler(this.btnConfirmUpgrade_Click); // @@ -79,23 +81,45 @@ private void InitializeComponent() this.txtUpgradeCurrentVersion.Enabled = false; this.txtUpgradeCurrentVersion.Location = new System.Drawing.Point(136, 18); this.txtUpgradeCurrentVersion.Name = "txtUpgradeCurrentVersion"; - this.txtUpgradeCurrentVersion.Size = new System.Drawing.Size(100, 20); + this.txtUpgradeCurrentVersion.Size = new System.Drawing.Size(111, 20); this.txtUpgradeCurrentVersion.TabIndex = 4; // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(12, 50); + this.label2.Location = new System.Drawing.Point(9, 85); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(120, 13); this.label2.TabIndex = 5; this.label2.Text = "Available Unity Versions"; // + // btn_GoInstallMissingVersion + // + this.btn_GoInstallMissingVersion.Location = new System.Drawing.Point(136, 44); + this.btn_GoInstallMissingVersion.Name = "btn_GoInstallMissingVersion"; + this.btn_GoInstallMissingVersion.Size = new System.Drawing.Size(111, 22); + this.btn_GoInstallMissingVersion.TabIndex = 6; + this.btn_GoInstallMissingVersion.Text = "Download && Install"; + this.btn_GoInstallMissingVersion.UseVisualStyleBackColor = true; + this.btn_GoInstallMissingVersion.Click += new System.EventHandler(this.btn_GoInstallMissingVersion_Click); + // + // btn_OpenMissingVersionReleasePage + // + this.btn_OpenMissingVersionReleasePage.Location = new System.Drawing.Point(19, 44); + this.btn_OpenMissingVersionReleasePage.Name = "btn_OpenMissingVersionReleasePage"; + this.btn_OpenMissingVersionReleasePage.Size = new System.Drawing.Size(111, 22); + this.btn_OpenMissingVersionReleasePage.TabIndex = 7; + this.btn_OpenMissingVersionReleasePage.Text = "Open Release Page"; + this.btn_OpenMissingVersionReleasePage.UseVisualStyleBackColor = true; + this.btn_OpenMissingVersionReleasePage.Click += new System.EventHandler(this.btn_OpenMissingVersionReleasePage_Click); + // // Form2 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(267, 426); + this.ClientSize = new System.Drawing.Size(259, 476); + this.Controls.Add(this.btn_OpenMissingVersionReleasePage); + this.Controls.Add(this.btn_GoInstallMissingVersion); this.Controls.Add(this.label2); this.Controls.Add(this.txtUpgradeCurrentVersion); this.Controls.Add(this.btnConfirmUpgrade); @@ -107,7 +131,7 @@ private void InitializeComponent() this.MinimizeBox = false; this.Name = "Form2"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Upgrade existing project"; + this.Text = "Missing Exact Unity Version"; this.Load += new System.EventHandler(this.Form2_Load); this.ResumeLayout(false); this.PerformLayout(); @@ -122,5 +146,7 @@ private void InitializeComponent() private System.Windows.Forms.Button btnConfirmUpgrade; private System.Windows.Forms.TextBox txtUpgradeCurrentVersion; private System.Windows.Forms.Label label2; + private System.Windows.Forms.Button btn_GoInstallMissingVersion; + private System.Windows.Forms.Button btn_OpenMissingVersionReleasePage; } } \ No newline at end of file diff --git a/UnityLauncher/Form2.cs b/UnityLauncher/Form2.cs index af7831f..4d5e919 100644 --- a/UnityLauncher/Form2.cs +++ b/UnityLauncher/Form2.cs @@ -41,9 +41,17 @@ void Start() { lstUnityVersions.SetSelected(likelyIndex, true); } + + // enable release and dl buttons + btn_GoInstallMissingVersion.Enabled = true; + btn_OpenMissingVersionReleasePage.Enabled = true; + } else // we dont have current version { + btn_GoInstallMissingVersion.Enabled = false; + btn_OpenMissingVersionReleasePage.Enabled = false; + currentVersion = "None"; } @@ -51,12 +59,14 @@ void Start() txtUpgradeCurrentVersion.Text = currentVersion; } + #region UI Events + private void btnConfirmUpgrade_Click(object sender, EventArgs e) { if (lstUnityVersions.SelectedIndex > -1) { currentVersion = lstUnityVersions.Items[lstUnityVersions.SelectedIndex].ToString(); - DialogResult = DialogResult.OK; + DialogResult = DialogResult.Yes; } else { @@ -68,5 +78,17 @@ private void btnCancelUpgrade_Click(object sender, EventArgs e) { DialogResult = DialogResult.Cancel; } + + private void btn_OpenMissingVersionReleasePage_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Ignore; // opens release notes + } + + private void btn_GoInstallMissingVersion_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Retry; // download package + } + + #endregion } } diff --git a/UnityLauncher/Form2.resx b/UnityLauncher/Form2.resx index 61bc649..1af7de1 100644 --- a/UnityLauncher/Form2.resx +++ b/UnityLauncher/Form2.resx @@ -117,7 +117,4 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - True - \ No newline at end of file From c09377509c2d85fdb6a06e379f9f0a9a895b6915 Mon Sep 17 00:00:00 2001 From: Youri Schuurmans Date: Fri, 3 Nov 2017 11:12:49 +0100 Subject: [PATCH 10/81] Added possibility to search through recent projects --- UnityLauncher/Form1.Designer.cs | 19 ++++++++++++++----- UnityLauncher/Form1.cs | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 273be79..8dbcd32 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -75,6 +75,7 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.tbSearchBar = new System.Windows.Forms.TextBox(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -82,7 +83,6 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.gridUnityList)).BeginInit(); this.tabPackages.SuspendLayout(); this.tabPage3.SuspendLayout(); - this.statusStrip1.SuspendLayout(); this.SuspendLayout(); // // tabControl1 @@ -99,6 +99,7 @@ private void InitializeComponent() // // tabPage1 // + this.tabPage1.Controls.Add(this.tbSearchBar); this.tabPage1.Controls.Add(this.btnUpgradeProject); this.tabPage1.Controls.Add(this.btnRunUnityOnly); this.tabPage1.Controls.Add(this.btnOpenUnityFolder); @@ -170,7 +171,7 @@ private void InitializeComponent() this._path, this._dateModified}); this.gridRecent.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; - this.gridRecent.Location = new System.Drawing.Point(3, 3); + this.gridRecent.Location = new System.Drawing.Point(3, 30); this.gridRecent.MultiSelect = false; this.gridRecent.Name = "gridRecent"; this.gridRecent.ReadOnly = true; @@ -179,7 +180,7 @@ private void InitializeComponent() this.gridRecent.ShowCellErrors = false; this.gridRecent.ShowCellToolTips = false; this.gridRecent.ShowEditingIcon = false; - this.gridRecent.Size = new System.Drawing.Size(574, 502); + this.gridRecent.Size = new System.Drawing.Size(574, 475); this.gridRecent.TabIndex = 0; this.gridRecent.KeyDown += new System.Windows.Forms.KeyEventHandler(this.gridRecent_KeyDown); // @@ -565,6 +566,14 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // + // tbSearchBar + // + this.tbSearchBar.Location = new System.Drawing.Point(9, 4); + this.tbSearchBar.Name = "tbSearchBar"; + this.tbSearchBar.Size = new System.Drawing.Size(563, 20); + this.tbSearchBar.TabIndex = 17; + this.tbSearchBar.TextChanged += new System.EventHandler(this.FilterRecentProject); + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -584,6 +593,7 @@ private void InitializeComponent() this.Resize += new System.EventHandler(this.Form1_Resize); this.tabControl1.ResumeLayout(false); this.tabPage1.ResumeLayout(false); + this.tabPage1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).EndInit(); this.tabPage2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.gridUnityList)).EndInit(); @@ -591,8 +601,6 @@ private void InitializeComponent() this.tabPackages.PerformLayout(); this.tabPage3.ResumeLayout(false); this.tabPage3.PerformLayout(); - this.statusStrip1.ResumeLayout(false); - this.statusStrip1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -644,6 +652,7 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn _path; private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; private System.Windows.Forms.Button btnOpenLogFolder; + private System.Windows.Forms.TextBox tbSearchBar; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 0174267..ed227bd 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -228,6 +228,16 @@ private string GetUnityVersion(string path) return fvi.ProductName.Replace("(64-bit)", "").Trim(); } + void FilterRecentProject(object sender, EventArgs e) + { + SetStatus("Filtering recent projects list.."); + foreach (DataGridViewRow recentProject in gridRecent.Rows) + { + if (recentProject.Cells["_project"].Value.ToString().ToLower().Contains(tbSearchBar.Text.ToLower())) + recentProject.Visible = true; + else recentProject.Visible = false; + } + } // returns already sorted list of recent entries void UpdateRecentProjectsList() @@ -691,6 +701,12 @@ private void Form1_KeyPress(object sender, KeyPressEventArgs e) tabControl1.SelectedIndex = 3; break; default: + if (!tbSearchBar.Focused) + { + tbSearchBar.Focus(); + tbSearchBar.Text += e.KeyChar; + tbSearchBar.Select(tbSearchBar.Text.Length,0); + } break; } } From 9b01e1deadfdc4baa0133954f6840f045ed1d7a2 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sun, 5 Nov 2017 11:15:24 +0800 Subject: [PATCH 11/81] try to make window on top of others when maximized --- UnityLauncher/Form1.Designer.cs | 20 ++++++++++---------- UnityLauncher/Form1.cs | 3 +-- UnityLauncher/Form1.resx | 21 --------------------- 3 files changed, 11 insertions(+), 33 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 8dbcd32..3c7b24c 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -32,6 +32,7 @@ private void InitializeComponent() System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); + this.tbSearchBar = new System.Windows.Forms.TextBox(); this.btnUpgradeProject = new System.Windows.Forms.Button(); this.btnRunUnityOnly = new System.Windows.Forms.Button(); this.btnOpenUnityFolder = new System.Windows.Forms.Button(); @@ -75,7 +76,6 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this.tbSearchBar = new System.Windows.Forms.TextBox(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -112,6 +112,14 @@ private void InitializeComponent() this.tabPage1.Text = "Projects"; this.tabPage1.UseVisualStyleBackColor = true; // + // tbSearchBar + // + this.tbSearchBar.Location = new System.Drawing.Point(9, 4); + this.tbSearchBar.Name = "tbSearchBar"; + this.tbSearchBar.Size = new System.Drawing.Size(563, 20); + this.tbSearchBar.TabIndex = 17; + this.tbSearchBar.TextChanged += new System.EventHandler(this.FilterRecentProject); + // // btnUpgradeProject // this.btnUpgradeProject.Location = new System.Drawing.Point(3, 511); @@ -566,14 +574,6 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // - // tbSearchBar - // - this.tbSearchBar.Location = new System.Drawing.Point(9, 4); - this.tbSearchBar.Name = "tbSearchBar"; - this.tbSearchBar.Size = new System.Drawing.Size(563, 20); - this.tbSearchBar.TabIndex = 17; - this.tbSearchBar.TextChanged += new System.EventHandler(this.FilterRecentProject); - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -587,7 +587,7 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Potato Edition 10"; + this.Text = "UnityLauncher - Potato Edition 11"; this.Load += new System.EventHandler(this.Form1_Load); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index ed227bd..20f88fa 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -473,6 +473,7 @@ void SetStatus(string msg) private void ShowForm() { + this.WindowState = FormWindowState.Minimized; this.Show(); this.WindowState = FormWindowState.Normal; notifyIcon.Visible = false; @@ -951,7 +952,5 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch } upgradeDialog.Close(); } - - } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index a1bd7de..c15df1a 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -132,33 +132,12 @@ True - - True - - - True - - - True - - - True - - - True - - - True - True True - - 14, 20 - 111, 20 From 1fb1b7bf2522e6d2eae266e816439c8feeaa23a4 Mon Sep 17 00:00:00 2001 From: Peter Witt Date: Fri, 15 Dec 2017 19:51:40 +0100 Subject: [PATCH 12/81] You can now double click to launch a project --- UnityLauncher/Form1.Designer.cs | 1 + UnityLauncher/Form1.cs | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 3c7b24c..f44f4a9 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -192,6 +192,7 @@ private void InitializeComponent() this.gridRecent.TabIndex = 0; this.gridRecent.KeyDown += new System.Windows.Forms.KeyEventHandler(this.gridRecent_KeyDown); // + this.gridRecent.CellMouseDoubleClick += GridRecent_CellMouseDoubleClick; // _project // this._project.HeaderText = "Project"; diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 20f88fa..b1cc099 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -734,6 +734,15 @@ private void gridRecent_KeyDown(object sender, KeyEventArgs e) } } + //Checks if you are doubleclicking the current cell + private void GridRecent_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) + { + if(e.RowIndex == gridRecent.CurrentCell.RowIndex) + { + LaunchSelectedProject(); + } + } + // set basefolder of all unity installations private void btn_setinstallfolder_Click(object sender, EventArgs e) { From 96aef6d6222e8cb15118e5435c7afcf0dfc4ede9 Mon Sep 17 00:00:00 2001 From: Peter Witt Date: Fri, 15 Dec 2017 20:28:56 +0100 Subject: [PATCH 13/81] Added option to close after launching a project --- UnityLauncher/App.config | 3 +++ UnityLauncher/Form1.Designer.cs | 22 +++++++++++++++---- UnityLauncher/Form1.cs | 12 ++++++++++ UnityLauncher/Properties/Settings.Designer.cs | 12 ++++++++++ UnityLauncher/Properties/Settings.settings | 3 +++ 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index ee64511..cf12cb6 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -30,6 +30,9 @@ True + + False + \ No newline at end of file diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index f44f4a9..0cc6f71 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -57,6 +57,7 @@ private void InitializeComponent() this.label3 = new System.Windows.Forms.Label(); this.lstPackageFolders = new System.Windows.Forms.ListBox(); this.tabPage3 = new System.Windows.Forms.TabPage(); + this.ChkQuitAfterOpen = new System.Windows.Forms.CheckBox(); this.btnOpenLogFolder = new System.Windows.Forms.Button(); this.chkQuitAfterCommandline = new System.Windows.Forms.CheckBox(); this.btnAddRegister = new System.Windows.Forms.Button(); @@ -390,6 +391,7 @@ private void InitializeComponent() // // tabPage3 // + this.tabPage3.Controls.Add(this.ChkQuitAfterOpen); this.tabPage3.Controls.Add(this.btnOpenLogFolder); this.tabPage3.Controls.Add(this.chkQuitAfterCommandline); this.tabPage3.Controls.Add(this.btnAddRegister); @@ -410,6 +412,17 @@ private void InitializeComponent() this.tabPage3.Text = "Settings"; this.tabPage3.UseVisualStyleBackColor = true; // + // ChkQuitAfterOpen + // + this.ChkQuitAfterOpen.AutoSize = true; + this.ChkQuitAfterOpen.Location = new System.Drawing.Point(20, 409); + this.ChkQuitAfterOpen.Name = "ChkQuitAfterOpen"; + this.ChkQuitAfterOpen.Size = new System.Drawing.Size(172, 17); + this.ChkQuitAfterOpen.TabIndex = 33; + this.ChkQuitAfterOpen.Text = "Close after launching a project"; + this.ChkQuitAfterOpen.UseVisualStyleBackColor = true; + this.ChkQuitAfterOpen.CheckedChanged += new System.EventHandler(this.ChkQuitAfterOpen_CheckedChanged); + // // btnOpenLogFolder // this.btnOpenLogFolder.Location = new System.Drawing.Point(435, 380); @@ -423,7 +436,7 @@ private void InitializeComponent() // chkQuitAfterCommandline // this.chkQuitAfterCommandline.AutoSize = true; - this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 409); + this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 432); this.chkQuitAfterCommandline.Name = "chkQuitAfterCommandline"; this.chkQuitAfterCommandline.Size = new System.Drawing.Size(189, 17); this.chkQuitAfterCommandline.TabIndex = 31; @@ -433,7 +446,7 @@ private void InitializeComponent() // // btnAddRegister // - this.btnAddRegister.Location = new System.Drawing.Point(139, 442); + this.btnAddRegister.Location = new System.Drawing.Point(139, 465); this.btnAddRegister.Name = "btnAddRegister"; this.btnAddRegister.Size = new System.Drawing.Size(64, 23); this.btnAddRegister.TabIndex = 30; @@ -443,7 +456,7 @@ private void InitializeComponent() // // btnRemoveRegister // - this.btnRemoveRegister.Location = new System.Drawing.Point(209, 442); + this.btnRemoveRegister.Location = new System.Drawing.Point(209, 465); this.btnRemoveRegister.Name = "btnRemoveRegister"; this.btnRemoveRegister.Size = new System.Drawing.Size(64, 23); this.btnRemoveRegister.TabIndex = 29; @@ -454,7 +467,7 @@ private void InitializeComponent() // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(19, 447); + this.label4.Location = new System.Drawing.Point(19, 470); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(117, 13); this.label4.TabIndex = 28; @@ -654,6 +667,7 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; private System.Windows.Forms.Button btnOpenLogFolder; private System.Windows.Forms.TextBox tbSearchBar; + private System.Windows.Forms.CheckBox ChkQuitAfterOpen; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index b1cc099..3e0a50f 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -95,6 +95,7 @@ void LoadSettings() // update settings window chkMinimizeToTaskbar.Checked = Properties.Settings.Default.minimizeToTaskbar; chkQuitAfterCommandline.Checked = Properties.Settings.Default.closeAfterExplorer; + ChkQuitAfterOpen.Checked = Properties.Settings.Default.closeAfterProject; // update installations folder listbox lstRootFolders.Items.AddRange(Properties.Settings.Default.rootFolders.Cast().ToArray()); @@ -328,6 +329,11 @@ void LaunchProject(string projectPath, string version, bool openProject = true) myProcess.StartInfo.Arguments = pars; } myProcess.Start(); + + if (Properties.Settings.Default.closeAfterProject) + { + Environment.Exit(0); + } } catch (Exception ex) { @@ -821,6 +827,12 @@ private void btnAddRegister_Click(object sender, EventArgs e) AddContextMenuRegistry(); } + private void ChkQuitAfterOpen_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.closeAfterProject = ChkQuitAfterOpen.Checked; + Properties.Settings.Default.Save(); + } + private void chkQuitAfterCommandline_CheckedChanged(object sender, EventArgs e) { Properties.Settings.Default.closeAfterExplorer = chkQuitAfterCommandline.Checked; diff --git a/UnityLauncher/Properties/Settings.Designer.cs b/UnityLauncher/Properties/Settings.Designer.cs index 73bd910..ecf2236 100644 --- a/UnityLauncher/Properties/Settings.Designer.cs +++ b/UnityLauncher/Properties/Settings.Designer.cs @@ -73,5 +73,17 @@ public bool closeAfterExplorer { this["closeAfterExplorer"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool closeAfterProject { + get { + return ((bool)(this["closeAfterProject"])); + } + set { + this["closeAfterProject"] = value; + } + } } } diff --git a/UnityLauncher/Properties/Settings.settings b/UnityLauncher/Properties/Settings.settings index 9719d60..9c749ba 100644 --- a/UnityLauncher/Properties/Settings.settings +++ b/UnityLauncher/Properties/Settings.settings @@ -18,5 +18,8 @@ True + + False + \ No newline at end of file From 2a731c708c96932f8aabc163026150d55e4a0add Mon Sep 17 00:00:00 2001 From: Peter Witt Date: Fri, 15 Dec 2017 20:37:50 +0100 Subject: [PATCH 14/81] Changed default value of close after launch --- UnityLauncher/App.config | 2 +- UnityLauncher/Properties/Settings.Designer.cs | 2 +- UnityLauncher/Properties/Settings.settings | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index cf12cb6..276d37d 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -31,7 +31,7 @@ True - False + True diff --git a/UnityLauncher/Properties/Settings.Designer.cs b/UnityLauncher/Properties/Settings.Designer.cs index ecf2236..78dd54b 100644 --- a/UnityLauncher/Properties/Settings.Designer.cs +++ b/UnityLauncher/Properties/Settings.Designer.cs @@ -76,7 +76,7 @@ public bool closeAfterExplorer { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("False")] + [global::System.Configuration.DefaultSettingValueAttribute("True")] public bool closeAfterProject { get { return ((bool)(this["closeAfterProject"])); diff --git a/UnityLauncher/Properties/Settings.settings b/UnityLauncher/Properties/Settings.settings index 9c749ba..c70e9e9 100644 --- a/UnityLauncher/Properties/Settings.settings +++ b/UnityLauncher/Properties/Settings.settings @@ -19,7 +19,7 @@ True - False + True \ No newline at end of file From f431ab906d5a235c55830590857afc1eb3e80856 Mon Sep 17 00:00:00 2001 From: Peter Witt Date: Fri, 15 Dec 2017 20:45:17 +0100 Subject: [PATCH 15/81] Changed so double click only works with left click --- UnityLauncher/Form1.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 3e0a50f..c0430ff 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -743,7 +743,7 @@ private void gridRecent_KeyDown(object sender, KeyEventArgs e) //Checks if you are doubleclicking the current cell private void GridRecent_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) { - if(e.RowIndex == gridRecent.CurrentCell.RowIndex) + if(e.Button == MouseButtons.Left && e.RowIndex == gridRecent.CurrentCell.RowIndex) { LaunchSelectedProject(); } From 4110ccc078811daf72d38118a7d28eaa13321f29 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Mon, 1 Jan 2018 12:49:47 +0800 Subject: [PATCH 16/81] add dialog to restore crashed scene on project launch --- UnityLauncher/Form1.Designer.cs | 3 +- UnityLauncher/Form1.cs | 50 ++++++++++++++++++++++++++++++--- UnityLauncher/Form1.resx | 21 ++++++++++++++ 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 0cc6f71..70ac129 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -193,7 +193,6 @@ private void InitializeComponent() this.gridRecent.TabIndex = 0; this.gridRecent.KeyDown += new System.Windows.Forms.KeyEventHandler(this.gridRecent_KeyDown); // - this.gridRecent.CellMouseDoubleClick += GridRecent_CellMouseDoubleClick; // _project // this._project.HeaderText = "Project"; @@ -601,7 +600,7 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Potato Edition 11"; + this.Text = "UnityLauncher - CryptoCrash Edition 12"; this.Load += new System.EventHandler(this.Form1_Load); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index c0430ff..b7fb6d6 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -312,8 +312,15 @@ void LaunchProject(string projectPath, string version, bool openProject = true) Directory.CreateDirectory(assetsFolder); } - bool haveExactVersion = HaveExactVersionInstalled(version); - if (haveExactVersion == true) + // check for crashed backup scene first + var cancelLaunch = CheckCrashBackupScene(projectPath); + Console.WriteLine(cancelLaunch); + if (cancelLaunch == true) + { + return; + } + + if (HaveExactVersionInstalled(version) == true) { //Console.WriteLine("Opening unity version " + version); SetStatus("Launching project in unity " + version); @@ -352,6 +359,41 @@ void LaunchProject(string projectPath, string version, bool openProject = true) } } + bool CheckCrashBackupScene(string projectPath) + { + var cancelRunningUnity = false; + var recoveryFile = Path.Combine(projectPath, "Temp", "__Backupscenes", "0.backup"); + if (File.Exists(recoveryFile)) + { + DialogResult dialogResult = MessageBox.Show("Crash recovery scene founded, do you want to copy it into Assets/_Recovery/-folder?", "UnityLauncher - Scene Recovery", MessageBoxButtons.YesNoCancel); + if (dialogResult == DialogResult.Yes) // restore + { + var restoreFolder = Path.Combine(projectPath, "Assets", "_Recovery"); + if (Directory.Exists(restoreFolder) == false) + { + Directory.CreateDirectory(restoreFolder); + } + if (Directory.Exists(restoreFolder) == true) + { + Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; + var uniqueFileName = "Recovered_Scene" + unixTimestamp + ".unity"; + File.Copy(recoveryFile, Path.Combine(restoreFolder, uniqueFileName)); + SetStatus("Recovered crashed scene into: " + restoreFolder); + } + else + { + SetStatus("Error: Failed to create restore folder: " + restoreFolder); + cancelRunningUnity = true; + } + } + else if (dialogResult == DialogResult.Cancel) // dont do restore, but run unity + { + cancelRunningUnity = true; + } + } + return cancelRunningUnity; + } + // parse unity installer exe from release page // thanks to https://github.com/softfruit string GetDownloadUrlForUnityVersion(string releaseUrl) @@ -712,7 +754,7 @@ private void Form1_KeyPress(object sender, KeyPressEventArgs e) { tbSearchBar.Focus(); tbSearchBar.Text += e.KeyChar; - tbSearchBar.Select(tbSearchBar.Text.Length,0); + tbSearchBar.Select(tbSearchBar.Text.Length, 0); } break; } @@ -743,7 +785,7 @@ private void gridRecent_KeyDown(object sender, KeyEventArgs e) //Checks if you are doubleclicking the current cell private void GridRecent_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) { - if(e.Button == MouseButtons.Left && e.RowIndex == gridRecent.CurrentCell.RowIndex) + if (e.Button == MouseButtons.Left && e.RowIndex == gridRecent.CurrentCell.RowIndex) { LaunchSelectedProject(); } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index c15df1a..a1bd7de 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -132,12 +132,33 @@ True + + True + + + True + + + True + + + True + + + True + + + True + True True + + 14, 20 + 111, 20 From e73cb6c7cdc6fea1f3687c72b748561dafc6de06 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Mon, 1 Jan 2018 14:10:54 +0800 Subject: [PATCH 17/81] fix missing event call (vs sometimes drops them..?) --- UnityLauncher/Form1.Designer.cs | 1 + UnityLauncher/Form1.resx | 21 --------------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 70ac129..ed919cd 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -191,6 +191,7 @@ private void InitializeComponent() this.gridRecent.ShowEditingIcon = false; this.gridRecent.Size = new System.Drawing.Size(574, 475); this.gridRecent.TabIndex = 0; + this.gridRecent.CellMouseDoubleClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.GridRecent_CellMouseDoubleClick); this.gridRecent.KeyDown += new System.Windows.Forms.KeyEventHandler(this.gridRecent_KeyDown); // // _project diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index a1bd7de..c15df1a 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -132,33 +132,12 @@ True - - True - - - True - - - True - - - True - - - True - - - True - True True - - 14, 20 - 111, 20 From 90e04b758cd32076a2077e44e8ecc19a1e8a6029 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Thu, 18 Jan 2018 17:28:44 +0800 Subject: [PATCH 18/81] check forward and backslash in project name, fix statuslabel visibility --- UnityLauncher/Form1.Designer.cs | 7 ++++++- UnityLauncher/Form1.cs | 35 ++++++++++++++++++++++++++++----- UnityLauncher/Form1.resx | 26 ++++++++++++++++++++---- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index ed919cd..64cec4b 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -84,6 +84,7 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.gridUnityList)).BeginInit(); this.tabPackages.SuspendLayout(); this.tabPage3.SuspendLayout(); + this.statusStrip1.SuspendLayout(); this.SuspendLayout(); // // tabControl1 @@ -576,6 +577,8 @@ private void InitializeComponent() // // statusStrip1 // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(588, 22); @@ -601,7 +604,7 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - CryptoCrash Edition 12"; + this.Text = "UnityLauncher - HODL Edition 13"; this.Load += new System.EventHandler(this.Form1_Load); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); @@ -615,6 +618,8 @@ private void InitializeComponent() this.tabPackages.PerformLayout(); this.tabPage3.ResumeLayout(false); this.tabPage3.PerformLayout(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index b7fb6d6..4063009 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -248,7 +248,6 @@ void UpdateRecentProjectsList() var hklm = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); RegistryKey key = hklm.OpenSubKey(@"SOFTWARE\Unity Technologies\Unity Editor 5.x"); - //Console.WriteLine(key); if (key == null) { SetStatus("No recent projects list founded"); @@ -261,9 +260,34 @@ void UpdateRecentProjectsList() { if (valueName.IndexOf("RecentlyUsedProjectPaths-") == 0) { - byte[] projectPathBytes = (byte[])key.GetValue(valueName); - string projectPath = Encoding.Default.GetString(projectPathBytes, 0, projectPathBytes.Length - 1); - string projectName = projectPath.Substring(projectPath.LastIndexOf("/") + 1); + string projectPath = ""; + // check if binary or not + var valueKind = key.GetValueKind(valueName); + if (valueKind == RegistryValueKind.Binary) + { + byte[] projectPathBytes = (byte[])key.GetValue(valueName); + projectPath = Encoding.Default.GetString(projectPathBytes, 0, projectPathBytes.Length - 1); + } + else // should be string then + { + projectPath = (string)key.GetValue(valueName); + } + + string projectName = ""; + + // get project name from full path + if (projectPath.IndexOf(Path.PathSeparator) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.PathSeparator) + 1); + } + else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); + } + else // no path separator founded + { + projectName = projectPath; + } string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); @@ -314,7 +338,6 @@ void LaunchProject(string projectPath, string version, bool openProject = true) // check for crashed backup scene first var cancelLaunch = CheckCrashBackupScene(projectPath); - Console.WriteLine(cancelLaunch); if (cancelLaunch == true) { return; @@ -1015,5 +1038,7 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch } upgradeDialog.Close(); } + + } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index c15df1a..8696020 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -132,12 +132,33 @@ True + + True + + + True + + + True + + + True + True True + + True + + + True + + + 14, 20 + 111, 20 @@ -1031,10 +1052,7 @@ - 492, 18 - - - 43 + 374, 17 From f1805a8f8f5a72170596963870bea6a8b10e43ec Mon Sep 17 00:00:00 2001 From: geo Date: Sun, 21 Jan 2018 11:03:49 +0100 Subject: [PATCH 19/81] Fail gracefully with an error message if the ProjectVersion.txt file is corrupt. This also enables the Launcher to list all other projects even if some are corrupt. Before this patch it halted with an exception. --- UnityLauncher/Form1.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 4063009..7045b4a 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -146,12 +146,12 @@ string GetProjectVersion(string path) } else { - throw new InvalidDataException("Cannot find m_EditorVersion:" + dd); + MessageBox.Show("Cannot find m_EditorVersion in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); } } else { - throw new InvalidDataException("invalid projectversion data:" + data.ToString()); + MessageBox.Show("Invalid projectversion data found in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); } } } From 799ba7f8993a2fa58496aebd3af4689c5fbd9a2a Mon Sep 17 00:00:00 2001 From: geo Date: Sun, 21 Jan 2018 11:26:45 +0100 Subject: [PATCH 20/81] Made columns resizeable. --- UnityLauncher/Form1.Designer.cs | 77 ++++++++++++++++----------------- UnityLauncher/Form1.resx | 21 --------- 2 files changed, 38 insertions(+), 60 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 64cec4b..0cbe1b1 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -38,10 +38,6 @@ private void InitializeComponent() this.btnOpenUnityFolder = new System.Windows.Forms.Button(); this.btnLaunch = new System.Windows.Forms.Button(); this.gridRecent = new System.Windows.Forms.DataGridView(); - this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabPage2 = new System.Windows.Forms.TabPage(); this.btnOpenReleasePage = new System.Windows.Forms.Button(); this.btnExploreUnity = new System.Windows.Forms.Button(); @@ -77,6 +73,10 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -171,7 +171,6 @@ private void InitializeComponent() // this.gridRecent.AllowUserToAddRows = false; this.gridRecent.AllowUserToDeleteRows = false; - this.gridRecent.AllowUserToResizeColumns = false; this.gridRecent.AllowUserToResizeRows = false; this.gridRecent.CausesValidation = false; this.gridRecent.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; @@ -195,37 +194,6 @@ private void InitializeComponent() this.gridRecent.CellMouseDoubleClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.GridRecent_CellMouseDoubleClick); this.gridRecent.KeyDown += new System.Windows.Forms.KeyEventHandler(this.gridRecent_KeyDown); // - // _project - // - this._project.HeaderText = "Project"; - this._project.Name = "_project"; - this._project.ReadOnly = true; - this._project.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._project.Width = 150; - // - // _version - // - this._version.HeaderText = "Version"; - this._version.Name = "_version"; - this._version.ReadOnly = true; - this._version.Width = 72; - // - // _path - // - this._path.HeaderText = "Path"; - this._path.Name = "_path"; - this._path.ReadOnly = true; - this._path.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._path.Width = 185; - // - // _dateModified - // - this._dateModified.HeaderText = "Modified"; - this._dateModified.Name = "_dateModified"; - this._dateModified.ReadOnly = true; - this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._dateModified.Width = 120; - // // tabPage2 // this.tabPage2.Controls.Add(this.btnOpenReleasePage); @@ -591,6 +559,37 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // + // _project + // + this._project.HeaderText = "Project"; + this._project.Name = "_project"; + this._project.ReadOnly = true; + this._project.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._project.Width = 150; + // + // _version + // + this._version.HeaderText = "Version"; + this._version.Name = "_version"; + this._version.ReadOnly = true; + this._version.Width = 72; + // + // _path + // + this._path.HeaderText = "Path"; + this._path.Name = "_path"; + this._path.ReadOnly = true; + this._path.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._path.Width = 185; + // + // _dateModified + // + this._dateModified.HeaderText = "Modified"; + this._dateModified.Name = "_dateModified"; + this._dateModified.ReadOnly = true; + this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._dateModified.Width = 120; + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -666,13 +665,13 @@ private void InitializeComponent() private System.Windows.Forms.StatusStrip statusStrip1; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; private System.Windows.Forms.Button btnUpgradeProject; + private System.Windows.Forms.Button btnOpenLogFolder; + private System.Windows.Forms.TextBox tbSearchBar; + private System.Windows.Forms.CheckBox ChkQuitAfterOpen; private System.Windows.Forms.DataGridViewTextBoxColumn _project; private System.Windows.Forms.DataGridViewTextBoxColumn _version; private System.Windows.Forms.DataGridViewTextBoxColumn _path; private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; - private System.Windows.Forms.Button btnOpenLogFolder; - private System.Windows.Forms.TextBox tbSearchBar; - private System.Windows.Forms.CheckBox ChkQuitAfterOpen; } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 8696020..37f8bf3 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -132,33 +132,12 @@ True - - True - - - True - - - True - - - True - - - True - - - True - True True - - 14, 20 - 111, 20 From eb83828be362772ece41846aa1643edc83202e6b Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sat, 27 Jan 2018 14:01:20 +0800 Subject: [PATCH 21/81] make first column smaller, fix tab stop order in main tab controls, press ESC to clear project search, remove 1-2-3 shortcut keys for tabs, don't focus to search field if type in other tabs, disable TAB character appearing to search field, add Refresh button to unity list tab --- UnityLauncher/Form1.Designer.cs | 107 ++++++++++++++++++-------------- UnityLauncher/Form1.cs | 33 +++++----- UnityLauncher/Form1.resx | 3 + 3 files changed, 83 insertions(+), 60 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 0cbe1b1..a799056 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -38,7 +38,12 @@ private void InitializeComponent() this.btnOpenUnityFolder = new System.Windows.Forms.Button(); this.btnLaunch = new System.Windows.Forms.Button(); this.gridRecent = new System.Windows.Forms.DataGridView(); + this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabPage2 = new System.Windows.Forms.TabPage(); + this.btn_refreshUnityList = new System.Windows.Forms.Button(); this.btnOpenReleasePage = new System.Windows.Forms.Button(); this.btnExploreUnity = new System.Windows.Forms.Button(); this.btnLaunchUnity = new System.Windows.Forms.Button(); @@ -73,10 +78,6 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -97,7 +98,7 @@ private void InitializeComponent() this.tabControl1.Name = "tabControl1"; this.tabControl1.SelectedIndex = 0; this.tabControl1.Size = new System.Drawing.Size(588, 575); - this.tabControl1.TabIndex = 0; + this.tabControl1.TabIndex = 6; // // tabPage1 // @@ -119,7 +120,7 @@ private void InitializeComponent() this.tbSearchBar.Location = new System.Drawing.Point(9, 4); this.tbSearchBar.Name = "tbSearchBar"; this.tbSearchBar.Size = new System.Drawing.Size(563, 20); - this.tbSearchBar.TabIndex = 17; + this.tbSearchBar.TabIndex = 0; this.tbSearchBar.TextChanged += new System.EventHandler(this.FilterRecentProject); // // btnUpgradeProject @@ -127,7 +128,7 @@ private void InitializeComponent() this.btnUpgradeProject.Location = new System.Drawing.Point(3, 511); this.btnUpgradeProject.Name = "btnUpgradeProject"; this.btnUpgradeProject.Size = new System.Drawing.Size(98, 35); - this.btnUpgradeProject.TabIndex = 16; + this.btnUpgradeProject.TabIndex = 4; this.btnUpgradeProject.Text = "Upgrade Project"; this.toolTip1.SetToolTip(this.btnUpgradeProject, "Open File Explorer"); this.btnUpgradeProject.UseVisualStyleBackColor = true; @@ -138,7 +139,7 @@ private void InitializeComponent() this.btnRunUnityOnly.Location = new System.Drawing.Point(105, 511); this.btnRunUnityOnly.Name = "btnRunUnityOnly"; this.btnRunUnityOnly.Size = new System.Drawing.Size(67, 35); - this.btnRunUnityOnly.TabIndex = 15; + this.btnRunUnityOnly.TabIndex = 5; this.btnRunUnityOnly.Text = "Run Unity"; this.toolTip1.SetToolTip(this.btnRunUnityOnly, "Open File Explorer"); this.btnRunUnityOnly.UseVisualStyleBackColor = true; @@ -149,7 +150,7 @@ private void InitializeComponent() this.btnOpenUnityFolder.Location = new System.Drawing.Point(510, 511); this.btnOpenUnityFolder.Name = "btnOpenUnityFolder"; this.btnOpenUnityFolder.Size = new System.Drawing.Size(67, 35); - this.btnOpenUnityFolder.TabIndex = 14; + this.btnOpenUnityFolder.TabIndex = 3; this.btnOpenUnityFolder.Text = "Explore"; this.toolTip1.SetToolTip(this.btnOpenUnityFolder, "Open File Explorer"); this.btnOpenUnityFolder.UseVisualStyleBackColor = true; @@ -161,7 +162,7 @@ private void InitializeComponent() this.btnLaunch.Location = new System.Drawing.Point(176, 511); this.btnLaunch.Name = "btnLaunch"; this.btnLaunch.Size = new System.Drawing.Size(330, 35); - this.btnLaunch.TabIndex = 10; + this.btnLaunch.TabIndex = 2; this.btnLaunch.Text = "Launch Project"; this.toolTip1.SetToolTip(this.btnLaunch, "Launch selected project"); this.btnLaunch.UseVisualStyleBackColor = true; @@ -184,18 +185,51 @@ private void InitializeComponent() this.gridRecent.MultiSelect = false; this.gridRecent.Name = "gridRecent"; this.gridRecent.ReadOnly = true; + this.gridRecent.RowHeadersWidth = 18; this.gridRecent.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.gridRecent.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; this.gridRecent.ShowCellErrors = false; this.gridRecent.ShowCellToolTips = false; this.gridRecent.ShowEditingIcon = false; this.gridRecent.Size = new System.Drawing.Size(574, 475); - this.gridRecent.TabIndex = 0; + this.gridRecent.TabIndex = 1; this.gridRecent.CellMouseDoubleClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.GridRecent_CellMouseDoubleClick); this.gridRecent.KeyDown += new System.Windows.Forms.KeyEventHandler(this.gridRecent_KeyDown); // + // _project + // + this._project.HeaderText = "Project"; + this._project.Name = "_project"; + this._project.ReadOnly = true; + this._project.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._project.Width = 150; + // + // _version + // + this._version.HeaderText = "Version"; + this._version.Name = "_version"; + this._version.ReadOnly = true; + this._version.Width = 72; + // + // _path + // + this._path.HeaderText = "Path"; + this._path.Name = "_path"; + this._path.ReadOnly = true; + this._path.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._path.Width = 185; + // + // _dateModified + // + this._dateModified.HeaderText = "Modified"; + this._dateModified.Name = "_dateModified"; + this._dateModified.ReadOnly = true; + this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._dateModified.Width = 120; + // // tabPage2 // + this.tabPage2.Controls.Add(this.btn_refreshUnityList); this.tabPage2.Controls.Add(this.btnOpenReleasePage); this.tabPage2.Controls.Add(this.btnExploreUnity); this.tabPage2.Controls.Add(this.btnLaunchUnity); @@ -207,6 +241,19 @@ private void InitializeComponent() this.tabPage2.Text = "Unity\'s"; this.tabPage2.UseVisualStyleBackColor = true; // + // btn_refreshUnityList + // + this.btn_refreshUnityList.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btn_refreshUnityList.Location = new System.Drawing.Point(555, 3); + this.btn_refreshUnityList.Name = "btn_refreshUnityList"; + this.btn_refreshUnityList.Size = new System.Drawing.Size(22, 23); + this.btn_refreshUnityList.TabIndex = 21; + this.btn_refreshUnityList.Text = "⟳"; + this.toolTip1.SetToolTip(this.btn_refreshUnityList, "Refresh Unity Installations List"); + this.btn_refreshUnityList.UseCompatibleTextRendering = true; + this.btn_refreshUnityList.UseVisualStyleBackColor = true; + this.btn_refreshUnityList.Click += new System.EventHandler(this.btnRefresh_Click); + // // btnOpenReleasePage // this.btnOpenReleasePage.Location = new System.Drawing.Point(411, 511); @@ -253,7 +300,7 @@ private void InitializeComponent() this._unityVersion, this._unityPath}); this.gridUnityList.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; - this.gridUnityList.Location = new System.Drawing.Point(3, 3); + this.gridUnityList.Location = new System.Drawing.Point(3, 27); this.gridUnityList.MultiSelect = false; this.gridUnityList.Name = "gridUnityList"; this.gridUnityList.ReadOnly = true; @@ -262,7 +309,7 @@ private void InitializeComponent() this.gridUnityList.ShowCellErrors = false; this.gridUnityList.ShowCellToolTips = false; this.gridUnityList.ShowEditingIcon = false; - this.gridUnityList.Size = new System.Drawing.Size(574, 502); + this.gridUnityList.Size = new System.Drawing.Size(574, 478); this.gridUnityList.TabIndex = 10; this.gridUnityList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.unityGridView_KeyDown); // @@ -559,37 +606,6 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // - // _project - // - this._project.HeaderText = "Project"; - this._project.Name = "_project"; - this._project.ReadOnly = true; - this._project.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this._project.Width = 150; - // - // _version - // - this._version.HeaderText = "Version"; - this._version.Name = "_version"; - this._version.ReadOnly = true; - this._version.Width = 72; - // - // _path - // - this._path.HeaderText = "Path"; - this._path.Name = "_path"; - this._path.ReadOnly = true; - this._path.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this._path.Width = 185; - // - // _dateModified - // - this._dateModified.HeaderText = "Modified"; - this._dateModified.Name = "_dateModified"; - this._dateModified.ReadOnly = true; - this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this._dateModified.Width = 120; - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -603,7 +619,7 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - HODL Edition 13"; + this.Text = "UnityLauncher - Mining Edition 14"; this.Load += new System.EventHandler(this.Form1_Load); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); @@ -672,6 +688,7 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn _version; private System.Windows.Forms.DataGridViewTextBoxColumn _path; private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; + private System.Windows.Forms.Button btn_refreshUnityList; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 7045b4a..e8dba52 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -758,23 +758,24 @@ private void unityGridView_KeyDown(object sender, KeyEventArgs e) /// private void Form1_KeyPress(object sender, KeyPressEventArgs e) { - switch (e.KeyChar) + //Console.WriteLine((int)e.KeyChar); + switch ((int)e.KeyChar) { - case '1': - tabControl1.SelectedIndex = 0; - break; - case '2': - tabControl1.SelectedIndex = 1; - break; - case '3': - tabControl1.SelectedIndex = 2; - break; - case '4': - tabControl1.SelectedIndex = 3; + case 27: // ESC - clear search + if (tabControl1.SelectedIndex == 0 && tbSearchBar.Text != "") + { + tbSearchBar.Text = ""; + } break; - default: - if (!tbSearchBar.Focused) + default: // any key + // activate searchbar if not active and we are in tab#1 + if (tabControl1.SelectedIndex == 0 && tbSearchBar.Focused == false) { + // skip tab key on search field + if ((int)e.KeyChar == 9) + { + break; + } tbSearchBar.Focus(); tbSearchBar.Text += e.KeyChar; tbSearchBar.Select(tbSearchBar.Text.Length, 0); @@ -783,6 +784,8 @@ private void Form1_KeyPress(object sender, KeyPressEventArgs e) } } + + /// /// grid keys /// @@ -1039,6 +1042,6 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch upgradeDialog.Close(); } - + } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 37f8bf3..d033fdb 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -1033,6 +1033,9 @@ 374, 17 + + 37 + AAABAA0AICAQAAEABADoAgAA1gAAABAQEAABAAQAKAEAAL4DAAAwMAAAAQAIAKgOAADmBAAAICAAAAEA From 10ccaf6f18a195fe13e5c5e6e17b7ac4c28ecc9e Mon Sep 17 00:00:00 2001 From: geo Date: Sat, 27 Jan 2018 11:47:48 +0100 Subject: [PATCH 22/81] Grid columns width changes are now saved in user settings. --- UnityLauncher/App.config | 7 +++++ UnityLauncher/Form1.cs | 30 +++++++++++++++++++ UnityLauncher/Properties/Settings.Designer.cs | 19 +++++++++++- UnityLauncher/Properties/Settings.settings | 6 ++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index 276d37d..6be7e45 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -33,6 +33,13 @@ True + + + + + + \ No newline at end of file diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 7045b4a..0b9003d 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -88,6 +88,8 @@ void Start() // preselect grid gridRecent.Select(); + + this.gridRecent.ColumnWidthChanged += new System.Windows.Forms.DataGridViewColumnEventHandler(this.gridRecent_ColumnWidthChanged); } void LoadSettings() @@ -101,6 +103,13 @@ void LoadSettings() lstRootFolders.Items.AddRange(Properties.Settings.Default.rootFolders.Cast().ToArray()); // update packages folder listbox lstPackageFolders.Items.AddRange(Properties.Settings.Default.packageFolders.Cast().ToArray()); + + // restore data grid view widths + int[] gridColumnWidths = Properties.Settings.Default.gridColumnWidths; + for ( int i=0; i< gridColumnWidths.Length; ++i ) + { + gridRecent.Columns[i].Width = gridColumnWidths[i]; + } } /// @@ -923,6 +932,27 @@ private void btnOpenLogFolder_Click(object sender, EventArgs e) LaunchExplorer(logfolder); } } + + private void gridRecent_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e) + { + List gridWidths = new List(Properties.Settings.Default.gridColumnWidths); + // restore data grid view widths + var colum = gridRecent.Columns[0]; + int a = Properties.Settings.Default.gridColumnWidths.Length; + for (int i = 0; i < gridRecent.Columns.Count; ++i) + { + if (Properties.Settings.Default.gridColumnWidths.Length > i) + { + gridWidths[i] = gridRecent.Columns[i].Width; + } + else + { + gridWidths.Add(gridRecent.Columns[i].Width); + } + } + Properties.Settings.Default.gridColumnWidths = gridWidths.ToArray(); + Properties.Settings.Default.Save(); + } #endregion UI events void OpenReleaseNotes(string version) diff --git a/UnityLauncher/Properties/Settings.Designer.cs b/UnityLauncher/Properties/Settings.Designer.cs index 78dd54b..7566ab4 100644 --- a/UnityLauncher/Properties/Settings.Designer.cs +++ b/UnityLauncher/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace UnityLauncher.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -85,5 +85,22 @@ public bool closeAfterProject { this["closeAfterProject"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("\r\n\r\n 100\r\n")] + public int[] gridColumnWidths + { + get + { + return ((int[])(this["gridColumnWidths"])); + } + set + { + this["gridColumnWidths"] = value; + } + } } } diff --git a/UnityLauncher/Properties/Settings.settings b/UnityLauncher/Properties/Settings.settings index c70e9e9..e37ba75 100644 --- a/UnityLauncher/Properties/Settings.settings +++ b/UnityLauncher/Properties/Settings.settings @@ -21,5 +21,11 @@ True + + + <ArrayOfInt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + </ArrayOfInt> + + \ No newline at end of file From 8737e73a7213f724f394edc3a47d2bd24fdf02a5 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sun, 4 Feb 2018 14:18:27 +0800 Subject: [PATCH 23/81] add 4.x project support, add Updates tab, --- UnityLauncher/Form1.Designer.cs | 212 ++++++++++++++++++++++---------- UnityLauncher/Form1.cs | 188 +++++++++++++++++++--------- UnityLauncher/Form1.resx | 33 +++++ 3 files changed, 310 insertions(+), 123 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index a799056..0252419 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -31,7 +31,7 @@ private void InitializeComponent() this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); this.tabControl1 = new System.Windows.Forms.TabControl(); - this.tabPage1 = new System.Windows.Forms.TabPage(); + this.tabProjects = new System.Windows.Forms.TabPage(); this.tbSearchBar = new System.Windows.Forms.TextBox(); this.btnUpgradeProject = new System.Windows.Forms.Button(); this.btnRunUnityOnly = new System.Windows.Forms.Button(); @@ -42,7 +42,7 @@ private void InitializeComponent() this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.tabPage2 = new System.Windows.Forms.TabPage(); + this.tabUnitys = new System.Windows.Forms.TabPage(); this.btn_refreshUnityList = new System.Windows.Forms.Button(); this.btnOpenReleasePage = new System.Windows.Forms.Button(); this.btnExploreUnity = new System.Windows.Forms.Button(); @@ -57,7 +57,8 @@ private void InitializeComponent() this.btnRemovePackFolder = new System.Windows.Forms.Button(); this.label3 = new System.Windows.Forms.Label(); this.lstPackageFolders = new System.Windows.Forms.ListBox(); - this.tabPage3 = new System.Windows.Forms.TabPage(); + this.tabUpdates = new System.Windows.Forms.TabPage(); + this.tabSettings = new System.Windows.Forms.TabPage(); this.ChkQuitAfterOpen = new System.Windows.Forms.CheckBox(); this.btnOpenLogFolder = new System.Windows.Forms.Button(); this.chkQuitAfterCommandline = new System.Windows.Forms.CheckBox(); @@ -78,42 +79,49 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.btnFetchUnityVersions = new System.Windows.Forms.Button(); + this.gridUnityUpdates = new System.Windows.Forms.DataGridView(); + this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.dataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabControl1.SuspendLayout(); - this.tabPage1.SuspendLayout(); + this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); - this.tabPage2.SuspendLayout(); + this.tabUnitys.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridUnityList)).BeginInit(); this.tabPackages.SuspendLayout(); - this.tabPage3.SuspendLayout(); + this.tabUpdates.SuspendLayout(); + this.tabSettings.SuspendLayout(); this.statusStrip1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).BeginInit(); this.SuspendLayout(); // // tabControl1 // - this.tabControl1.Controls.Add(this.tabPage1); - this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Controls.Add(this.tabProjects); + this.tabControl1.Controls.Add(this.tabUnitys); this.tabControl1.Controls.Add(this.tabPackages); - this.tabControl1.Controls.Add(this.tabPage3); + this.tabControl1.Controls.Add(this.tabUpdates); + this.tabControl1.Controls.Add(this.tabSettings); this.tabControl1.Location = new System.Drawing.Point(0, 12); this.tabControl1.Name = "tabControl1"; this.tabControl1.SelectedIndex = 0; this.tabControl1.Size = new System.Drawing.Size(588, 575); this.tabControl1.TabIndex = 6; // - // tabPage1 - // - this.tabPage1.Controls.Add(this.tbSearchBar); - this.tabPage1.Controls.Add(this.btnUpgradeProject); - this.tabPage1.Controls.Add(this.btnRunUnityOnly); - this.tabPage1.Controls.Add(this.btnOpenUnityFolder); - this.tabPage1.Controls.Add(this.btnLaunch); - this.tabPage1.Controls.Add(this.gridRecent); - this.tabPage1.Location = new System.Drawing.Point(4, 22); - this.tabPage1.Name = "tabPage1"; - this.tabPage1.Size = new System.Drawing.Size(580, 549); - this.tabPage1.TabIndex = 0; - this.tabPage1.Text = "Projects"; - this.tabPage1.UseVisualStyleBackColor = true; + // tabProjects + // + this.tabProjects.Controls.Add(this.tbSearchBar); + this.tabProjects.Controls.Add(this.btnUpgradeProject); + this.tabProjects.Controls.Add(this.btnRunUnityOnly); + this.tabProjects.Controls.Add(this.btnOpenUnityFolder); + this.tabProjects.Controls.Add(this.btnLaunch); + this.tabProjects.Controls.Add(this.gridRecent); + this.tabProjects.Location = new System.Drawing.Point(4, 22); + this.tabProjects.Name = "tabProjects"; + this.tabProjects.Size = new System.Drawing.Size(580, 549); + this.tabProjects.TabIndex = 0; + this.tabProjects.Text = "Projects"; + this.tabProjects.UseVisualStyleBackColor = true; // // tbSearchBar // @@ -227,19 +235,19 @@ private void InitializeComponent() this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.True; this._dateModified.Width = 120; // - // tabPage2 + // tabUnitys // - this.tabPage2.Controls.Add(this.btn_refreshUnityList); - this.tabPage2.Controls.Add(this.btnOpenReleasePage); - this.tabPage2.Controls.Add(this.btnExploreUnity); - this.tabPage2.Controls.Add(this.btnLaunchUnity); - this.tabPage2.Controls.Add(this.gridUnityList); - this.tabPage2.Location = new System.Drawing.Point(4, 22); - this.tabPage2.Name = "tabPage2"; - this.tabPage2.Size = new System.Drawing.Size(580, 549); - this.tabPage2.TabIndex = 1; - this.tabPage2.Text = "Unity\'s"; - this.tabPage2.UseVisualStyleBackColor = true; + this.tabUnitys.Controls.Add(this.btn_refreshUnityList); + this.tabUnitys.Controls.Add(this.btnOpenReleasePage); + this.tabUnitys.Controls.Add(this.btnExploreUnity); + this.tabUnitys.Controls.Add(this.btnLaunchUnity); + this.tabUnitys.Controls.Add(this.gridUnityList); + this.tabUnitys.Location = new System.Drawing.Point(4, 22); + this.tabUnitys.Name = "tabUnitys"; + this.tabUnitys.Size = new System.Drawing.Size(580, 549); + this.tabUnitys.TabIndex = 1; + this.tabUnitys.Text = "Unity\'s"; + this.tabUnitys.UseVisualStyleBackColor = true; // // btn_refreshUnityList // @@ -405,28 +413,39 @@ private void InitializeComponent() this.lstPackageFolders.Size = new System.Drawing.Size(539, 186); this.lstPackageFolders.TabIndex = 21; // - // tabPage3 - // - this.tabPage3.Controls.Add(this.ChkQuitAfterOpen); - this.tabPage3.Controls.Add(this.btnOpenLogFolder); - this.tabPage3.Controls.Add(this.chkQuitAfterCommandline); - this.tabPage3.Controls.Add(this.btnAddRegister); - this.tabPage3.Controls.Add(this.btnRemoveRegister); - this.tabPage3.Controls.Add(this.label4); - this.tabPage3.Controls.Add(this.label2); - this.tabPage3.Controls.Add(this.chkMinimizeToTaskbar); - this.tabPage3.Controls.Add(this.label1); - this.tabPage3.Controls.Add(this.btnAddUnityFolder); - this.tabPage3.Controls.Add(this.btnRemoveInstallFolder); - this.tabPage3.Controls.Add(this.lstRootFolders); - this.tabPage3.Controls.Add(this.lbl_unityCount); - this.tabPage3.Controls.Add(this.btnRefresh); - this.tabPage3.Location = new System.Drawing.Point(4, 22); - this.tabPage3.Name = "tabPage3"; - this.tabPage3.Size = new System.Drawing.Size(580, 549); - this.tabPage3.TabIndex = 3; - this.tabPage3.Text = "Settings"; - this.tabPage3.UseVisualStyleBackColor = true; + // tabUpdates + // + this.tabUpdates.Controls.Add(this.btnFetchUnityVersions); + this.tabUpdates.Controls.Add(this.gridUnityUpdates); + this.tabUpdates.Location = new System.Drawing.Point(4, 22); + this.tabUpdates.Name = "tabUpdates"; + this.tabUpdates.Size = new System.Drawing.Size(580, 549); + this.tabUpdates.TabIndex = 5; + this.tabUpdates.Text = "Updates"; + this.tabUpdates.UseVisualStyleBackColor = true; + // + // tabSettings + // + this.tabSettings.Controls.Add(this.ChkQuitAfterOpen); + this.tabSettings.Controls.Add(this.btnOpenLogFolder); + this.tabSettings.Controls.Add(this.chkQuitAfterCommandline); + this.tabSettings.Controls.Add(this.btnAddRegister); + this.tabSettings.Controls.Add(this.btnRemoveRegister); + this.tabSettings.Controls.Add(this.label4); + this.tabSettings.Controls.Add(this.label2); + this.tabSettings.Controls.Add(this.chkMinimizeToTaskbar); + this.tabSettings.Controls.Add(this.label1); + this.tabSettings.Controls.Add(this.btnAddUnityFolder); + this.tabSettings.Controls.Add(this.btnRemoveInstallFolder); + this.tabSettings.Controls.Add(this.lstRootFolders); + this.tabSettings.Controls.Add(this.lbl_unityCount); + this.tabSettings.Controls.Add(this.btnRefresh); + this.tabSettings.Location = new System.Drawing.Point(4, 22); + this.tabSettings.Name = "tabSettings"; + this.tabSettings.Size = new System.Drawing.Size(580, 549); + this.tabSettings.TabIndex = 3; + this.tabSettings.Text = "Settings"; + this.tabSettings.UseVisualStyleBackColor = true; // // ChkQuitAfterOpen // @@ -606,6 +625,60 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // + // btnFetchUnityVersions + // + this.btnFetchUnityVersions.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnFetchUnityVersions.Location = new System.Drawing.Point(555, 3); + this.btnFetchUnityVersions.Name = "btnFetchUnityVersions"; + this.btnFetchUnityVersions.Size = new System.Drawing.Size(22, 23); + this.btnFetchUnityVersions.TabIndex = 23; + this.btnFetchUnityVersions.Text = "⟳"; + this.toolTip1.SetToolTip(this.btnFetchUnityVersions, "Fetch list of Unity Updates"); + this.btnFetchUnityVersions.UseCompatibleTextRendering = true; + this.btnFetchUnityVersions.UseVisualStyleBackColor = true; + this.btnFetchUnityVersions.Click += new System.EventHandler(this.btnFetchUnityVersions_Click); + // + // gridUnityUpdates + // + this.gridUnityUpdates.AllowUserToAddRows = false; + this.gridUnityUpdates.AllowUserToDeleteRows = false; + this.gridUnityUpdates.AllowUserToResizeColumns = false; + this.gridUnityUpdates.AllowUserToResizeRows = false; + this.gridUnityUpdates.CausesValidation = false; + this.gridUnityUpdates.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.gridUnityUpdates.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.dataGridViewTextBoxColumn2, + this.dataGridViewTextBoxColumn1}); + this.gridUnityUpdates.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; + this.gridUnityUpdates.Location = new System.Drawing.Point(3, 27); + this.gridUnityUpdates.MultiSelect = false; + this.gridUnityUpdates.Name = "gridUnityUpdates"; + this.gridUnityUpdates.ReadOnly = true; + this.gridUnityUpdates.RowHeadersWidth = 18; + this.gridUnityUpdates.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.gridUnityUpdates.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.gridUnityUpdates.ShowCellErrors = false; + this.gridUnityUpdates.ShowCellToolTips = false; + this.gridUnityUpdates.ShowEditingIcon = false; + this.gridUnityUpdates.Size = new System.Drawing.Size(574, 478); + this.gridUnityUpdates.TabIndex = 22; + // + // dataGridViewTextBoxColumn2 + // + this.dataGridViewTextBoxColumn2.HeaderText = "Date"; + this.dataGridViewTextBoxColumn2.MinimumWidth = 100; + this.dataGridViewTextBoxColumn2.Name = "dataGridViewTextBoxColumn2"; + this.dataGridViewTextBoxColumn2.ReadOnly = true; + this.dataGridViewTextBoxColumn2.Resizable = System.Windows.Forms.DataGridViewTriState.False; + // + // dataGridViewTextBoxColumn1 + // + this.dataGridViewTextBoxColumn1.HeaderText = "Version"; + this.dataGridViewTextBoxColumn1.MinimumWidth = 350; + this.dataGridViewTextBoxColumn1.Name = "dataGridViewTextBoxColumn1"; + this.dataGridViewTextBoxColumn1.ReadOnly = true; + this.dataGridViewTextBoxColumn1.Width = 350; + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -619,22 +692,24 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Mining Edition 14"; + this.Text = "UnityLauncher - Flamethrower Edition 15"; this.Load += new System.EventHandler(this.Form1_Load); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); this.tabControl1.ResumeLayout(false); - this.tabPage1.ResumeLayout(false); - this.tabPage1.PerformLayout(); + this.tabProjects.ResumeLayout(false); + this.tabProjects.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).EndInit(); - this.tabPage2.ResumeLayout(false); + this.tabUnitys.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.gridUnityList)).EndInit(); this.tabPackages.ResumeLayout(false); this.tabPackages.PerformLayout(); - this.tabPage3.ResumeLayout(false); - this.tabPage3.PerformLayout(); + this.tabUpdates.ResumeLayout(false); + this.tabSettings.ResumeLayout(false); + this.tabSettings.PerformLayout(); this.statusStrip1.ResumeLayout(false); this.statusStrip1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -642,15 +717,15 @@ private void InitializeComponent() #endregion private System.Windows.Forms.TabControl tabControl1; - private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.TabPage tabProjects; private System.Windows.Forms.Button btnOpenUnityFolder; private System.Windows.Forms.ToolTip toolTip1; private System.Windows.Forms.Button btnLaunch; private System.Windows.Forms.DataGridView gridRecent; - private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.TabPage tabUnitys; private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1; private System.Windows.Forms.NotifyIcon notifyIcon; - private System.Windows.Forms.TabPage tabPage3; + private System.Windows.Forms.TabPage tabSettings; private System.Windows.Forms.Label lbl_unityCount; private System.Windows.Forms.Button btnRefresh; private System.Windows.Forms.DataGridView gridUnityList; @@ -689,6 +764,11 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn _path; private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; private System.Windows.Forms.Button btn_refreshUnityList; + private System.Windows.Forms.TabPage tabUpdates; + private System.Windows.Forms.Button btnFetchUnityVersions; + private System.Windows.Forms.DataGridView gridUnityUpdates; + private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn2; + private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn1; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index e8dba52..57d8dc8 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -14,11 +14,10 @@ namespace UnityLauncher { public partial class Form1 : Form { - // version,exe path (example: 5.6.1f1,c:\prog\unity561\editor\unity.exe) public static Dictionary unityList = new Dictionary(); - - const int settingsTabIndex = 3; const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; + bool isDownloadUnityList = false; + public Form1() { @@ -51,7 +50,7 @@ void Start() { SetStatus("Error> Did not found any Unity installations, try setting correct root folder.."); UpdateRecentProjectsList(); - tabControl1.SelectedIndex = settingsTabIndex; + tabControl1.SelectedIndex = tabControl1.TabCount - 1; // last tab is settings return; } @@ -117,14 +116,18 @@ bool HaveExactVersionInstalled(string version) } - // read and parse project settings file + /// + /// parse project version from ProjectSettings data + /// + /// project base path + /// string GetProjectVersion(string path) { var version = ""; if (Directory.Exists(Path.Combine(path, "ProjectSettings"))) { var versionPath = Path.Combine(path, "ProjectSettings", "ProjectVersion.txt"); - if (File.Exists(versionPath) == true) + if (File.Exists(versionPath) == true) // 5.x and later { var data = File.ReadAllLines(versionPath); @@ -154,6 +157,26 @@ string GetProjectVersion(string path) MessageBox.Show("Invalid projectversion data found in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); } } + else // maybe 4.x + { + versionPath = Path.Combine(path, "ProjectSettings", "ProjectSettings.asset"); + if (File.Exists(versionPath) == true) + { + // try to get version data out from binary asset + var data = File.ReadAllBytes(versionPath); + if (data != null && data.Length > 0) + { + int dataLen = 7; + int startIndex = 20; + var bytes = new byte[dataLen]; + for (int i = 0; i < dataLen; i++) + { + bytes[i] = data[startIndex + i]; + } + version = Encoding.UTF8.GetString(bytes); + } + } + } } return version; } @@ -240,77 +263,89 @@ void FilterRecentProject(object sender, EventArgs e) } } - // returns already sorted list of recent entries + /// + /// scans registry for recent projects and adds to project grid list + /// void UpdateRecentProjectsList() { SetStatus("Updating recent projects list.."); + gridRecent.Rows.Clear(); + var hklm = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); - RegistryKey key = hklm.OpenSubKey(@"SOFTWARE\Unity Technologies\Unity Editor 5.x"); + string[] registryPathsToCheck = new string[] { @"SOFTWARE\Unity Technologies\Unity Editor 5.x", @"SOFTWARE\Unity Technologies\Unity Editor 4.x" }; - if (key == null) + // check each version path + for (int i = 0, len = registryPathsToCheck.Length; i < len; i++) { - SetStatus("No recent projects list founded"); - return; - } + RegistryKey key = hklm.OpenSubKey(registryPathsToCheck[i]); - gridRecent.Rows.Clear(); + if (key == null) continue; - foreach (var valueName in key.GetValueNames()) - { - if (valueName.IndexOf("RecentlyUsedProjectPaths-") == 0) + // parse recent project path + foreach (var valueName in key.GetValueNames()) { - string projectPath = ""; - // check if binary or not - var valueKind = key.GetValueKind(valueName); - if (valueKind == RegistryValueKind.Binary) - { - byte[] projectPathBytes = (byte[])key.GetValue(valueName); - projectPath = Encoding.Default.GetString(projectPathBytes, 0, projectPathBytes.Length - 1); - } - else // should be string then + if (valueName.IndexOf("RecentlyUsedProjectPaths-") == 0) { - projectPath = (string)key.GetValue(valueName); - } + string projectPath = ""; + // check if binary or not + var valueKind = key.GetValueKind(valueName); + if (valueKind == RegistryValueKind.Binary) + { + byte[] projectPathBytes = (byte[])key.GetValue(valueName); + projectPath = Encoding.Default.GetString(projectPathBytes, 0, projectPathBytes.Length - 1); + } + else // should be string then + { + projectPath = (string)key.GetValue(valueName); + } - string projectName = ""; + string projectName = ""; - // get project name from full path - if (projectPath.IndexOf(Path.PathSeparator) > -1) - { - projectName = projectPath.Substring(projectPath.LastIndexOf(Path.PathSeparator) + 1); - } - else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) - { - projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); - } - else // no path separator founded - { - projectName = projectPath; - } + // get project name from full path + if (projectPath.IndexOf(Path.PathSeparator) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.PathSeparator) + 1); + } + else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); + } + else // no path separator founded + { + projectName = projectPath; + } - string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); + string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); - // editor only project - if (File.Exists(csprojFile) == false) - { - csprojFile = Path.Combine(projectPath, projectName + ".Editor.csproj"); - } + // editor only project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, projectName + ".Editor.csproj"); + } - DateTime? lastUpdated = GetLastUpdatedTime(csprojFile); + // maybe 4.x project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, "Assembly-CSharp.csproj"); + } - string projectVersion = GetProjectVersion(projectPath); - // TODO: could display "Today", "Yesterday", "Last week".. + // get last modified date + DateTime? lastUpdated = GetLastModifiedTime(csprojFile); - gridRecent.Rows.Add(projectName, projectVersion, projectPath, lastUpdated); - //gridRecent.Rows[gridRecent.Rows.Count-1].Cells[1].Style.BackColor = HaveExactVersionInstalled(projectVersion) ?Color.Green:Color.Red; - gridRecent.Rows[gridRecent.Rows.Count - 1].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; + // get project version + string projectVersion = GetProjectVersion(projectPath); + + gridRecent.Rows.Add(projectName, projectVersion, projectPath, lastUpdated); + gridRecent.Rows[gridRecent.Rows.Count - 1].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; + } } } + SetStatus("Ready"); } - DateTime? GetLastUpdatedTime(string path) + DateTime? GetLastModifiedTime(string path) { if (File.Exists(path) == true) { @@ -735,6 +770,11 @@ private void btnRemoveInstallFolder_Click(object sender, EventArgs e) } } + private void btnFetchUnityVersions_Click(object sender, EventArgs e) + { + FetchListOfUnityUpdates(); + } + private void unityGridView_KeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) @@ -784,8 +824,6 @@ private void Form1_KeyPress(object sender, KeyPressEventArgs e) } } - - /// /// grid keys /// @@ -928,6 +966,8 @@ private void btnOpenLogFolder_Click(object sender, EventArgs e) } #endregion UI events + + void OpenReleaseNotes(string version) { SetStatus("Opening release notes for version " + version); @@ -1042,6 +1082,40 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch upgradeDialog.Close(); } - + void FetchListOfUnityUpdates() + { + if (isDownloadUnityList == true) + { + SetStatus("We are already downloading.."); + return; + } + isDownloadUnityList = true; + SetStatus("Downloading list of unity versions.."); + + // download list of unity versions + using (WebClient webClient = new WebClient()) + { + webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(UnityVersionsListDownloaded); + var unityVersionsURL = @"http://symbolserver.unity3d.com/000Admin/history.txt"; + webClient.DownloadStringAsync(new Uri(unityVersionsURL)); + } + } + + private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedEventArgs e) + { + // TODO check for error.. + + SetStatus("Downloading list of unity versions..Done"); + isDownloadUnityList = false; + // parse to list + var unityList = e.Result.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + Array.Reverse(unityList); + gridUnityUpdates.Rows.Clear(); + for (int i = 0, len = unityList.Length; i < len; i++) + { + var row = unityList[i].Split(','); + gridUnityUpdates.Rows.Add(row[3], row[6].Trim('"')); + } + } } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index d033fdb..ef1c5c0 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -120,6 +120,15 @@ 14, 20 + + True + + + True + + + 14, 20 + True @@ -132,6 +141,24 @@ True + + True + + + True + + + True + + + True + + + True + + + True + True @@ -1033,6 +1060,12 @@ 374, 17 + + True + + + True + 37 From bab55fb92af41949bfb53b659b0a23ce5ab698c4 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sun, 4 Feb 2018 16:16:41 +0800 Subject: [PATCH 24/81] add visit website button to Updates tab --- UnityLauncher/Form1.Designer.cs | 139 ++++++++++++++++++-------------- UnityLauncher/Form1.cs | 14 +++- UnityLauncher/Form1.resx | 18 ++--- 3 files changed, 99 insertions(+), 72 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 0252419..1d48704 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -58,6 +58,11 @@ private void InitializeComponent() this.label3 = new System.Windows.Forms.Label(); this.lstPackageFolders = new System.Windows.Forms.ListBox(); this.tabUpdates = new System.Windows.Forms.TabPage(); + this.btnOpenUpdateWebsite = new System.Windows.Forms.Button(); + this.btnFetchUnityVersions = new System.Windows.Forms.Button(); + this.gridUnityUpdates = new System.Windows.Forms.DataGridView(); + this._Date = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._UnityUpdateVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabSettings = new System.Windows.Forms.TabPage(); this.ChkQuitAfterOpen = new System.Windows.Forms.CheckBox(); this.btnOpenLogFolder = new System.Windows.Forms.Button(); @@ -79,10 +84,6 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this.btnFetchUnityVersions = new System.Windows.Forms.Button(); - this.gridUnityUpdates = new System.Windows.Forms.DataGridView(); - this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.dataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -90,9 +91,9 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.gridUnityList)).BeginInit(); this.tabPackages.SuspendLayout(); this.tabUpdates.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).BeginInit(); this.tabSettings.SuspendLayout(); this.statusStrip1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).BeginInit(); this.SuspendLayout(); // // tabControl1 @@ -415,6 +416,7 @@ private void InitializeComponent() // // tabUpdates // + this.tabUpdates.Controls.Add(this.btnOpenUpdateWebsite); this.tabUpdates.Controls.Add(this.btnFetchUnityVersions); this.tabUpdates.Controls.Add(this.gridUnityUpdates); this.tabUpdates.Location = new System.Drawing.Point(4, 22); @@ -424,6 +426,72 @@ private void InitializeComponent() this.tabUpdates.Text = "Updates"; this.tabUpdates.UseVisualStyleBackColor = true; // + // btnOpenUpdateWebsite + // + this.btnOpenUpdateWebsite.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnOpenUpdateWebsite.Location = new System.Drawing.Point(5, 511); + this.btnOpenUpdateWebsite.Name = "btnOpenUpdateWebsite"; + this.btnOpenUpdateWebsite.Size = new System.Drawing.Size(572, 35); + this.btnOpenUpdateWebsite.TabIndex = 24; + this.btnOpenUpdateWebsite.Text = "Open Website"; + this.toolTip1.SetToolTip(this.btnOpenUpdateWebsite, "Launch selected project"); + this.btnOpenUpdateWebsite.UseVisualStyleBackColor = true; + this.btnOpenUpdateWebsite.Click += new System.EventHandler(this.btnOpenUpdateWebsite_Click); + // + // btnFetchUnityVersions + // + this.btnFetchUnityVersions.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnFetchUnityVersions.Location = new System.Drawing.Point(555, 3); + this.btnFetchUnityVersions.Name = "btnFetchUnityVersions"; + this.btnFetchUnityVersions.Size = new System.Drawing.Size(22, 23); + this.btnFetchUnityVersions.TabIndex = 23; + this.btnFetchUnityVersions.Text = "⟳"; + this.toolTip1.SetToolTip(this.btnFetchUnityVersions, "Fetch list of Unity Updates"); + this.btnFetchUnityVersions.UseCompatibleTextRendering = true; + this.btnFetchUnityVersions.UseVisualStyleBackColor = true; + this.btnFetchUnityVersions.Click += new System.EventHandler(this.btnFetchUnityVersions_Click); + // + // gridUnityUpdates + // + this.gridUnityUpdates.AllowUserToAddRows = false; + this.gridUnityUpdates.AllowUserToDeleteRows = false; + this.gridUnityUpdates.AllowUserToResizeColumns = false; + this.gridUnityUpdates.AllowUserToResizeRows = false; + this.gridUnityUpdates.CausesValidation = false; + this.gridUnityUpdates.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.gridUnityUpdates.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this._Date, + this._UnityUpdateVersion}); + this.gridUnityUpdates.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; + this.gridUnityUpdates.Location = new System.Drawing.Point(3, 27); + this.gridUnityUpdates.MultiSelect = false; + this.gridUnityUpdates.Name = "gridUnityUpdates"; + this.gridUnityUpdates.ReadOnly = true; + this.gridUnityUpdates.RowHeadersWidth = 18; + this.gridUnityUpdates.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.gridUnityUpdates.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.gridUnityUpdates.ShowCellErrors = false; + this.gridUnityUpdates.ShowCellToolTips = false; + this.gridUnityUpdates.ShowEditingIcon = false; + this.gridUnityUpdates.Size = new System.Drawing.Size(574, 478); + this.gridUnityUpdates.TabIndex = 22; + // + // _Date + // + this._Date.HeaderText = "Date"; + this._Date.MinimumWidth = 100; + this._Date.Name = "_Date"; + this._Date.ReadOnly = true; + this._Date.Resizable = System.Windows.Forms.DataGridViewTriState.False; + // + // _UnityUpdateVersion + // + this._UnityUpdateVersion.HeaderText = "Version"; + this._UnityUpdateVersion.MinimumWidth = 350; + this._UnityUpdateVersion.Name = "_UnityUpdateVersion"; + this._UnityUpdateVersion.ReadOnly = true; + this._UnityUpdateVersion.Width = 350; + // // tabSettings // this.tabSettings.Controls.Add(this.ChkQuitAfterOpen); @@ -625,60 +693,6 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // - // btnFetchUnityVersions - // - this.btnFetchUnityVersions.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnFetchUnityVersions.Location = new System.Drawing.Point(555, 3); - this.btnFetchUnityVersions.Name = "btnFetchUnityVersions"; - this.btnFetchUnityVersions.Size = new System.Drawing.Size(22, 23); - this.btnFetchUnityVersions.TabIndex = 23; - this.btnFetchUnityVersions.Text = "⟳"; - this.toolTip1.SetToolTip(this.btnFetchUnityVersions, "Fetch list of Unity Updates"); - this.btnFetchUnityVersions.UseCompatibleTextRendering = true; - this.btnFetchUnityVersions.UseVisualStyleBackColor = true; - this.btnFetchUnityVersions.Click += new System.EventHandler(this.btnFetchUnityVersions_Click); - // - // gridUnityUpdates - // - this.gridUnityUpdates.AllowUserToAddRows = false; - this.gridUnityUpdates.AllowUserToDeleteRows = false; - this.gridUnityUpdates.AllowUserToResizeColumns = false; - this.gridUnityUpdates.AllowUserToResizeRows = false; - this.gridUnityUpdates.CausesValidation = false; - this.gridUnityUpdates.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.gridUnityUpdates.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { - this.dataGridViewTextBoxColumn2, - this.dataGridViewTextBoxColumn1}); - this.gridUnityUpdates.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; - this.gridUnityUpdates.Location = new System.Drawing.Point(3, 27); - this.gridUnityUpdates.MultiSelect = false; - this.gridUnityUpdates.Name = "gridUnityUpdates"; - this.gridUnityUpdates.ReadOnly = true; - this.gridUnityUpdates.RowHeadersWidth = 18; - this.gridUnityUpdates.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.gridUnityUpdates.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; - this.gridUnityUpdates.ShowCellErrors = false; - this.gridUnityUpdates.ShowCellToolTips = false; - this.gridUnityUpdates.ShowEditingIcon = false; - this.gridUnityUpdates.Size = new System.Drawing.Size(574, 478); - this.gridUnityUpdates.TabIndex = 22; - // - // dataGridViewTextBoxColumn2 - // - this.dataGridViewTextBoxColumn2.HeaderText = "Date"; - this.dataGridViewTextBoxColumn2.MinimumWidth = 100; - this.dataGridViewTextBoxColumn2.Name = "dataGridViewTextBoxColumn2"; - this.dataGridViewTextBoxColumn2.ReadOnly = true; - this.dataGridViewTextBoxColumn2.Resizable = System.Windows.Forms.DataGridViewTriState.False; - // - // dataGridViewTextBoxColumn1 - // - this.dataGridViewTextBoxColumn1.HeaderText = "Version"; - this.dataGridViewTextBoxColumn1.MinimumWidth = 350; - this.dataGridViewTextBoxColumn1.Name = "dataGridViewTextBoxColumn1"; - this.dataGridViewTextBoxColumn1.ReadOnly = true; - this.dataGridViewTextBoxColumn1.Width = 350; - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -705,11 +719,11 @@ private void InitializeComponent() this.tabPackages.ResumeLayout(false); this.tabPackages.PerformLayout(); this.tabUpdates.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).EndInit(); this.tabSettings.ResumeLayout(false); this.tabSettings.PerformLayout(); this.statusStrip1.ResumeLayout(false); this.statusStrip1.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -767,8 +781,9 @@ private void InitializeComponent() private System.Windows.Forms.TabPage tabUpdates; private System.Windows.Forms.Button btnFetchUnityVersions; private System.Windows.Forms.DataGridView gridUnityUpdates; - private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn2; - private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn1; + private System.Windows.Forms.Button btnOpenUpdateWebsite; + private System.Windows.Forms.DataGridViewTextBoxColumn _Date; + private System.Windows.Forms.DataGridViewTextBoxColumn _UnityUpdateVersion; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index ccb4423..49dca53 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -105,7 +105,7 @@ void LoadSettings() // restore data grid view widths int[] gridColumnWidths = Properties.Settings.Default.gridColumnWidths; - for ( int i=0; i< gridColumnWidths.Length; ++i ) + for (int i = 0; i < gridColumnWidths.Length; ++i) { gridRecent.Columns[i].Width = gridColumnWidths[i]; } @@ -994,6 +994,18 @@ private void gridRecent_ColumnWidthChanged(object sender, DataGridViewColumnEven Properties.Settings.Default.gridColumnWidths = gridWidths.ToArray(); Properties.Settings.Default.Save(); } + + private void btnOpenUpdateWebsite_Click(object sender, EventArgs e) + { + var selected = gridUnityUpdates?.CurrentCell?.RowIndex; + if (selected != null && selected > -1) + { + var version = gridUnityUpdates.Rows[(int)selected].Cells["_UnityUpdateVersion"].Value.ToString(); + OpenReleaseNotes(version); + } + } + + #endregion UI events diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index ef1c5c0..bbfaf8d 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -120,10 +120,10 @@ 14, 20 - + True - + True @@ -165,6 +165,12 @@ True + + True + + + True + 111, 20 @@ -1060,14 +1066,8 @@ 374, 17 - - True - - - True - - 37 + 25 From c743a0f21f1196b06506f865401dae0dd7a89a92 Mon Sep 17 00:00:00 2001 From: mika Date: Sun, 4 Feb 2018 18:52:51 +0800 Subject: [PATCH 25/81] Update README.md --- README.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c4768a5..9439b52 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ # UnityLauncher -Tool for automatically launching specific unity versions for each project (Windows only) +Autotically launch projects with correct Unity versions and some extra features to manager your projects and Unity versions! # Features -- Launch correct Unity version for your recent projects -- Option to download missing unity version installation or open webpage -- Display Recent projects list with project version, last modified date -- Highlight project version with green if correct unity is installed -- Easily open project folder in explorer -- List of installed Unity versions, can easily run, explore, view release notes +- Automagically Open Projects with Correct Unity Version +- Display Recent Projects list with last modified date and Unity version info +- Quickly Explore Project Folder +- List installed Unity versions, can easily Run, Explore installation folder, View release notes +- Download Missing Unity Versions Easily - Can be used in commandline `UnityLauncher.exe -projectPath "c:/project/path/"` - Can add custom Explorer context menu item to launch folder as a project: https://github.com/unitycoder/UnityLauncher/wiki/Adding-Explorer-Context-Menu - List of custom package folders (quicly explore them and then can import packages) +- Show list of available Unity versions/updates # Instructions - Download, Run @@ -21,7 +21,7 @@ Tool for automatically launching specific unity versions for each project (Windo # Keyboard Shortcuts - When recent list is selected: Enter = Launch selected, F5 = refresh recent list -- 1,2,3 to switch tabs +- Project filter field: Esc - clear search # Download https://github.com/unitycoder/UnityLauncher/releases @@ -36,8 +36,14 @@ https://github.com/unitycoder/UnityLauncher/issues https://forum.unity3d.com/threads/unitylauncher-launch-correct-unity-versions-for-each-project-automatically.488718/ # Images -![unitylauncher-1](https://user-images.githubusercontent.com/5438317/29495593-0f2f1d54-85f5-11e7-929b-96fbe0147b2e.jpg) +![image](https://user-images.githubusercontent.com/5438317/35776535-65794550-09d9-11e8-925a-6b799d1a7b7f.png) -![unitylauncher-1b](https://user-images.githubusercontent.com/5438317/29495592-0f2bdf18-85f5-11e7-9d69-a29bf1f1b4f4.jpg) +![image](https://user-images.githubusercontent.com/5438317/35776559-d4ecb8ae-09d9-11e8-90e9-a01e662367f7.png) -![unitylauncher-1c](https://user-images.githubusercontent.com/5438317/29495591-0ee98ef6-85f5-11e7-849f-e78977f4f473.jpg) +![image](https://user-images.githubusercontent.com/5438317/35776539-7b5a63a4-09d9-11e8-825b-956110d98499.png) + +![image](https://user-images.githubusercontent.com/5438317/35776544-85f7c1f8-09d9-11e8-8ab7-ee08d01ebef3.png) + +![image](https://user-images.githubusercontent.com/5438317/35776558-d0692970-09d9-11e8-8191-f48da5d63ca8.png) + +![image](https://user-images.githubusercontent.com/5438317/35776575-01c720bc-09da-11e8-99d1-f6e4ad3c0fab.png) From fdc85fbaefb2652b587b5124642679ec14551f55 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Mon, 5 Feb 2018 21:18:19 +0800 Subject: [PATCH 26/81] check 4.x library file for version data, automatically fetch unity updates list if enter tab first time, --- UnityLauncher/Form1.Designer.cs | 3 ++- UnityLauncher/Form1.cs | 34 ++++++++++++++++++++++++++++----- UnityLauncher/Form1.resx | 18 ++++++++--------- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 1d48704..2e9a9d2 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -108,6 +108,7 @@ private void InitializeComponent() this.tabControl1.SelectedIndex = 0; this.tabControl1.Size = new System.Drawing.Size(588, 575); this.tabControl1.TabIndex = 6; + this.tabControl1.SelectedIndexChanged += new System.EventHandler(this.tabControl1_SelectedIndexChanged); // // tabProjects // @@ -706,7 +707,7 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Flamethrower Edition 15"; + this.Text = "UnityLauncher - BuyTheDip Edition 16"; this.Load += new System.EventHandler(this.Form1_Load); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 49dca53..d9f7b85 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -166,21 +166,33 @@ string GetProjectVersion(string path) MessageBox.Show("Invalid projectversion data found in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); } } - else // maybe 4.x + else // maybe its 4.x { versionPath = Path.Combine(path, "ProjectSettings", "ProjectSettings.asset"); if (File.Exists(versionPath) == true) { + // first try if its ascii format + var data = File.ReadAllLines(versionPath); + if (data != null && data.Length > 0 && data[0].IndexOf("YAML") > -1) + { + // in text format, then we need to try library file instead + var newVersionPath = Path.Combine(path, "Library", "AnnotationManager"); + if (File.Exists(versionPath) == true) + { + versionPath = newVersionPath; + } + } + // try to get version data out from binary asset - var data = File.ReadAllBytes(versionPath); - if (data != null && data.Length > 0) + var binData = File.ReadAllBytes(versionPath); + if (binData != null && binData.Length > 0) { int dataLen = 7; int startIndex = 20; var bytes = new byte[dataLen]; for (int i = 0; i < dataLen; i++) { - bytes[i] = data[startIndex + i]; + bytes[i] = binData[startIndex + i]; } version = Encoding.UTF8.GetString(bytes); } @@ -1005,6 +1017,19 @@ private void btnOpenUpdateWebsite_Click(object sender, EventArgs e) } } + private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) + { + // if enter Updates tab, then automatically fetch list of unity versions if list is empty (not fetched) + if (((TabControl)sender).SelectedIndex == 3) // FIXME: fixed index 3 for this tab.. + { + if (gridUnityUpdates.Rows.Count == 0) + { + FetchListOfUnityUpdates(); + } + } + } + + #endregion UI events @@ -1146,7 +1171,6 @@ void FetchListOfUnityUpdates() private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedEventArgs e) { // TODO check for error.. - SetStatus("Downloading list of unity versions..Done"); isDownloadUnityList = false; // parse to list diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index bbfaf8d..4902c55 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -120,15 +120,6 @@ 14, 20 - - True - - - True - - - 14, 20 - True @@ -171,6 +162,15 @@ True + + True + + + True + + + 14, 20 + 111, 20 From 2660ab9a59f93945a682756b1afc44819babad03 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Tue, 6 Feb 2018 20:36:25 +0800 Subject: [PATCH 27/81] resizable window, save/load form size, --- UnityLauncher/App.config | 90 ++++++++++--------- UnityLauncher/Form1.Designer.cs | 53 ++++++++++- UnityLauncher/Form1.cs | 20 ++++- UnityLauncher/Properties/Settings.Designer.cs | 45 +++++++--- UnityLauncher/Properties/Settings.settings | 16 ++-- 5 files changed, 158 insertions(+), 66 deletions(-) diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index 6be7e45..beb935b 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -1,45 +1,51 @@  - - -
- - - - - - - - - - - C:\Program Files\ - - - - - True - - - - - - - - True - - - True - - - - - - - - - + + +
+ + + + + + + + + + + C:\Program Files\ + + + + + True + + + + + + + + True + + + True + + + 600 + + + 650 + + + + + + + + + \ No newline at end of file diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 2e9a9d2..eecce41 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -98,6 +98,9 @@ private void InitializeComponent() // // tabControl1 // + this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.tabControl1.Controls.Add(this.tabProjects); this.tabControl1.Controls.Add(this.tabUnitys); this.tabControl1.Controls.Add(this.tabPackages); @@ -127,6 +130,8 @@ private void InitializeComponent() // // tbSearchBar // + this.tbSearchBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.tbSearchBar.Location = new System.Drawing.Point(9, 4); this.tbSearchBar.Name = "tbSearchBar"; this.tbSearchBar.Size = new System.Drawing.Size(563, 20); @@ -135,6 +140,7 @@ private void InitializeComponent() // // btnUpgradeProject // + this.btnUpgradeProject.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnUpgradeProject.Location = new System.Drawing.Point(3, 511); this.btnUpgradeProject.Name = "btnUpgradeProject"; this.btnUpgradeProject.Size = new System.Drawing.Size(98, 35); @@ -146,6 +152,7 @@ private void InitializeComponent() // // btnRunUnityOnly // + this.btnRunUnityOnly.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnRunUnityOnly.Location = new System.Drawing.Point(105, 511); this.btnRunUnityOnly.Name = "btnRunUnityOnly"; this.btnRunUnityOnly.Size = new System.Drawing.Size(67, 35); @@ -157,6 +164,7 @@ private void InitializeComponent() // // btnOpenUnityFolder // + this.btnOpenUnityFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnOpenUnityFolder.Location = new System.Drawing.Point(510, 511); this.btnOpenUnityFolder.Name = "btnOpenUnityFolder"; this.btnOpenUnityFolder.Size = new System.Drawing.Size(67, 35); @@ -168,6 +176,7 @@ private void InitializeComponent() // // btnLaunch // + this.btnLaunch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnLaunch.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.btnLaunch.Location = new System.Drawing.Point(176, 511); this.btnLaunch.Name = "btnLaunch"; @@ -183,6 +192,9 @@ private void InitializeComponent() this.gridRecent.AllowUserToAddRows = false; this.gridRecent.AllowUserToDeleteRows = false; this.gridRecent.AllowUserToResizeRows = false; + this.gridRecent.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.gridRecent.CausesValidation = false; this.gridRecent.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.gridRecent.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { @@ -253,6 +265,7 @@ private void InitializeComponent() // // btn_refreshUnityList // + this.btn_refreshUnityList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btn_refreshUnityList.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.btn_refreshUnityList.Location = new System.Drawing.Point(555, 3); this.btn_refreshUnityList.Name = "btn_refreshUnityList"; @@ -266,6 +279,7 @@ private void InitializeComponent() // // btnOpenReleasePage // + this.btnOpenReleasePage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnOpenReleasePage.Location = new System.Drawing.Point(411, 511); this.btnOpenReleasePage.Name = "btnOpenReleasePage"; this.btnOpenReleasePage.Size = new System.Drawing.Size(80, 35); @@ -277,6 +291,7 @@ private void InitializeComponent() // // btnExploreUnity // + this.btnExploreUnity.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnExploreUnity.Location = new System.Drawing.Point(497, 511); this.btnExploreUnity.Name = "btnExploreUnity"; this.btnExploreUnity.Size = new System.Drawing.Size(80, 35); @@ -288,6 +303,7 @@ private void InitializeComponent() // // btnLaunchUnity // + this.btnLaunchUnity.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnLaunchUnity.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.btnLaunchUnity.Location = new System.Drawing.Point(3, 511); this.btnLaunchUnity.Name = "btnLaunchUnity"; @@ -304,6 +320,9 @@ private void InitializeComponent() this.gridUnityList.AllowUserToDeleteRows = false; this.gridUnityList.AllowUserToResizeColumns = false; this.gridUnityList.AllowUserToResizeRows = false; + this.gridUnityList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.gridUnityList.CausesValidation = false; this.gridUnityList.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.gridUnityList.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { @@ -357,6 +376,7 @@ private void InitializeComponent() // // btnAddAssetStoreFolder // + this.btnAddAssetStoreFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnAddAssetStoreFolder.Location = new System.Drawing.Point(416, 232); this.btnAddAssetStoreFolder.Name = "btnAddAssetStoreFolder"; this.btnAddAssetStoreFolder.Size = new System.Drawing.Size(142, 23); @@ -367,6 +387,8 @@ private void InitializeComponent() // // btnExplorePackageFolder // + this.btnExplorePackageFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.btnExplorePackageFolder.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.btnExplorePackageFolder.Location = new System.Drawing.Point(3, 511); this.btnExplorePackageFolder.Name = "btnExplorePackageFolder"; @@ -409,6 +431,8 @@ private void InitializeComponent() // // lstPackageFolders // + this.lstPackageFolders.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.lstPackageFolders.FormattingEnabled = true; this.lstPackageFolders.Location = new System.Drawing.Point(19, 40); this.lstPackageFolders.Name = "lstPackageFolders"; @@ -429,6 +453,8 @@ private void InitializeComponent() // // btnOpenUpdateWebsite // + this.btnOpenUpdateWebsite.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.btnOpenUpdateWebsite.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.btnOpenUpdateWebsite.Location = new System.Drawing.Point(5, 511); this.btnOpenUpdateWebsite.Name = "btnOpenUpdateWebsite"; @@ -441,6 +467,7 @@ private void InitializeComponent() // // btnFetchUnityVersions // + this.btnFetchUnityVersions.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnFetchUnityVersions.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.btnFetchUnityVersions.Location = new System.Drawing.Point(555, 3); this.btnFetchUnityVersions.Name = "btnFetchUnityVersions"; @@ -458,6 +485,9 @@ private void InitializeComponent() this.gridUnityUpdates.AllowUserToDeleteRows = false; this.gridUnityUpdates.AllowUserToResizeColumns = false; this.gridUnityUpdates.AllowUserToResizeRows = false; + this.gridUnityUpdates.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.gridUnityUpdates.CausesValidation = false; this.gridUnityUpdates.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.gridUnityUpdates.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { @@ -518,6 +548,7 @@ private void InitializeComponent() // // ChkQuitAfterOpen // + this.ChkQuitAfterOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.ChkQuitAfterOpen.AutoSize = true; this.ChkQuitAfterOpen.Location = new System.Drawing.Point(20, 409); this.ChkQuitAfterOpen.Name = "ChkQuitAfterOpen"; @@ -529,6 +560,7 @@ private void InitializeComponent() // // btnOpenLogFolder // + this.btnOpenLogFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnOpenLogFolder.Location = new System.Drawing.Point(435, 380); this.btnOpenLogFolder.Name = "btnOpenLogFolder"; this.btnOpenLogFolder.Size = new System.Drawing.Size(137, 23); @@ -539,6 +571,7 @@ private void InitializeComponent() // // chkQuitAfterCommandline // + this.chkQuitAfterCommandline.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkQuitAfterCommandline.AutoSize = true; this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 432); this.chkQuitAfterCommandline.Name = "chkQuitAfterCommandline"; @@ -550,6 +583,7 @@ private void InitializeComponent() // // btnAddRegister // + this.btnAddRegister.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnAddRegister.Location = new System.Drawing.Point(139, 465); this.btnAddRegister.Name = "btnAddRegister"; this.btnAddRegister.Size = new System.Drawing.Size(64, 23); @@ -560,6 +594,7 @@ private void InitializeComponent() // // btnRemoveRegister // + this.btnRemoveRegister.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnRemoveRegister.Location = new System.Drawing.Point(209, 465); this.btnRemoveRegister.Name = "btnRemoveRegister"; this.btnRemoveRegister.Size = new System.Drawing.Size(64, 23); @@ -570,6 +605,7 @@ private void InitializeComponent() // // label4 // + this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.label4.AutoSize = true; this.label4.Location = new System.Drawing.Point(19, 470); this.label4.Name = "label4"; @@ -579,16 +615,19 @@ private void InitializeComponent() // // label2 // + this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.label2.AutoSize = true; this.label2.Enabled = false; + this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.label2.Location = new System.Drawing.Point(17, 361); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(74, 13); + this.label2.Size = new System.Drawing.Size(88, 13); this.label2.TabIndex = 26; this.label2.Text = "Other Settings"; // // chkMinimizeToTaskbar // + this.chkMinimizeToTaskbar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkMinimizeToTaskbar.AutoSize = true; this.chkMinimizeToTaskbar.Location = new System.Drawing.Point(20, 386); this.chkMinimizeToTaskbar.Name = "chkMinimizeToTaskbar"; @@ -630,6 +669,8 @@ private void InitializeComponent() // // lstRootFolders // + this.lstRootFolders.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.lstRootFolders.FormattingEnabled = true; this.lstRootFolders.Location = new System.Drawing.Point(20, 31); this.lstRootFolders.Name = "lstRootFolders"; @@ -638,6 +679,7 @@ private void InitializeComponent() // // lbl_unityCount // + this.lbl_unityCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.lbl_unityCount.AutoSize = true; this.lbl_unityCount.Enabled = false; this.lbl_unityCount.Location = new System.Drawing.Point(475, 15); @@ -648,6 +690,7 @@ private void InitializeComponent() // // btnRefresh // + this.btnRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnRefresh.Location = new System.Drawing.Point(435, 223); this.btnRefresh.Name = "btnRefresh"; this.btnRefresh.Size = new System.Drawing.Size(137, 23); @@ -680,11 +723,14 @@ private void InitializeComponent() // // statusStrip1 // + this.statusStrip1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(588, 22); + this.statusStrip1.Size = new System.Drawing.Size(166, 22); this.statusStrip1.TabIndex = 7; this.statusStrip1.Text = "statusStrip1"; // @@ -701,14 +747,15 @@ private void InitializeComponent() this.ClientSize = new System.Drawing.Size(588, 612); this.Controls.Add(this.statusStrip1); this.Controls.Add(this.tabControl1); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.KeyPreview = true; this.MaximizeBox = false; + this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.Text = "UnityLauncher - BuyTheDip Edition 16"; this.Load += new System.EventHandler(this.Form1_Load); + this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); this.Resize += new System.EventHandler(this.Form1_Resize); this.tabControl1.ResumeLayout(false); diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index d9f7b85..5071624 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -93,6 +93,10 @@ void Start() void LoadSettings() { + // form size + this.Width = Properties.Settings.Default.formWidth; + this.Height = Properties.Settings.Default.formHeight; + // update settings window chkMinimizeToTaskbar.Checked = Properties.Settings.Default.minimizeToTaskbar; chkQuitAfterCommandline.Checked = Properties.Settings.Default.closeAfterExplorer; @@ -105,9 +109,13 @@ void LoadSettings() // restore data grid view widths int[] gridColumnWidths = Properties.Settings.Default.gridColumnWidths; - for (int i = 0; i < gridColumnWidths.Length; ++i) + if (gridColumnWidths != null) { - gridRecent.Columns[i].Width = gridColumnWidths[i]; + + for (int i = 0; i < gridColumnWidths.Length; ++i) + { + gridRecent.Columns[i].Width = gridColumnWidths[i]; + } } } @@ -991,7 +999,6 @@ private void gridRecent_ColumnWidthChanged(object sender, DataGridViewColumnEven List gridWidths = new List(Properties.Settings.Default.gridColumnWidths); // restore data grid view widths var colum = gridRecent.Columns[0]; - int a = Properties.Settings.Default.gridColumnWidths.Length; for (int i = 0; i < gridRecent.Columns.Count; ++i) { if (Properties.Settings.Default.gridColumnWidths.Length > i) @@ -1029,6 +1036,13 @@ private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) } } + private void Form1_ResizeEnd(object sender, EventArgs e) + { + var form = (Form)sender; + Properties.Settings.Default.formWidth = form.Size.Width; + Properties.Settings.Default.formHeight = form.Size.Height; + Properties.Settings.Default.Save(); + } #endregion UI events diff --git a/UnityLauncher/Properties/Settings.Designer.cs b/UnityLauncher/Properties/Settings.Designer.cs index 7566ab4..5637586 100644 --- a/UnityLauncher/Properties/Settings.Designer.cs +++ b/UnityLauncher/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace UnityLauncher.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -85,20 +85,39 @@ public bool closeAfterProject { this["closeAfterProject"] = value; } } - + [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("\r\n\r\n 100\r\n")] - public int[] gridColumnWidths - { - get - { - return ((int[])(this["gridColumnWidths"])); - } - set - { + [global::System.Configuration.DefaultSettingValueAttribute("600")] + public int formWidth { + get { + return ((int)(this["formWidth"])); + } + set { + this["formWidth"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("650")] + public int formHeight { + get { + return ((int)(this["formHeight"])); + } + set { + this["formHeight"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public System.Int32[] gridColumnWidths { + get { + return (System.Int32[]) (this["gridColumnWidths"]); + } + set { this["gridColumnWidths"] = value; } } diff --git a/UnityLauncher/Properties/Settings.settings b/UnityLauncher/Properties/Settings.settings index e37ba75..ff93822 100644 --- a/UnityLauncher/Properties/Settings.settings +++ b/UnityLauncher/Properties/Settings.settings @@ -21,11 +21,17 @@ True - - - <ArrayOfInt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> - </ArrayOfInt> - + ++ ++ <ArrayOfInt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> ++ </ArrayOfInt> ++ ++ + + 600 + + + 650 \ No newline at end of file From 19ad6d71e9b0c65327d9d96bd7fe0374ed14ef52 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Wed, 7 Feb 2018 19:30:37 +0800 Subject: [PATCH 28/81] add extra columns (launch arguments, git branch), make custom arguments cell editable with F2, load/save custom launcher arguments, launch with custom arguments, display GIT branch info, gridviews disable TAB stop on cells --- UnityLauncher/Form1.Designer.cs | 109 +++++++++++++++++++------------- UnityLauncher/Form1.cs | 98 ++++++++++++++++++++++++++-- UnityLauncher/Form1.resx | 10 +-- 3 files changed, 159 insertions(+), 58 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index eecce41..c43c2ab 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -38,10 +38,6 @@ private void InitializeComponent() this.btnOpenUnityFolder = new System.Windows.Forms.Button(); this.btnLaunch = new System.Windows.Forms.Button(); this.gridRecent = new System.Windows.Forms.DataGridView(); - this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabUnitys = new System.Windows.Forms.TabPage(); this.btn_refreshUnityList = new System.Windows.Forms.Button(); this.btnOpenReleasePage = new System.Windows.Forms.Button(); @@ -84,6 +80,12 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._launchArguments = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._gitBranch = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -201,54 +203,25 @@ private void InitializeComponent() this._project, this._version, this._path, - this._dateModified}); - this.gridRecent.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; + this._dateModified, + this._launchArguments, + this._gitBranch}); + this.gridRecent.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnF2; this.gridRecent.Location = new System.Drawing.Point(3, 30); this.gridRecent.MultiSelect = false; this.gridRecent.Name = "gridRecent"; - this.gridRecent.ReadOnly = true; this.gridRecent.RowHeadersWidth = 18; this.gridRecent.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.gridRecent.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; this.gridRecent.ShowCellErrors = false; this.gridRecent.ShowCellToolTips = false; - this.gridRecent.ShowEditingIcon = false; this.gridRecent.Size = new System.Drawing.Size(574, 475); + this.gridRecent.StandardTab = true; this.gridRecent.TabIndex = 1; + this.gridRecent.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.gridRecent_CellEndEdit); this.gridRecent.CellMouseDoubleClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.GridRecent_CellMouseDoubleClick); this.gridRecent.KeyDown += new System.Windows.Forms.KeyEventHandler(this.gridRecent_KeyDown); // - // _project - // - this._project.HeaderText = "Project"; - this._project.Name = "_project"; - this._project.ReadOnly = true; - this._project.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this._project.Width = 150; - // - // _version - // - this._version.HeaderText = "Version"; - this._version.Name = "_version"; - this._version.ReadOnly = true; - this._version.Width = 72; - // - // _path - // - this._path.HeaderText = "Path"; - this._path.Name = "_path"; - this._path.ReadOnly = true; - this._path.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this._path.Width = 185; - // - // _dateModified - // - this._dateModified.HeaderText = "Modified"; - this._dateModified.Name = "_dateModified"; - this._dateModified.ReadOnly = true; - this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this._dateModified.Width = 120; - // // tabUnitys // this.tabUnitys.Controls.Add(this.btn_refreshUnityList); @@ -339,6 +312,7 @@ private void InitializeComponent() this.gridUnityList.ShowCellToolTips = false; this.gridUnityList.ShowEditingIcon = false; this.gridUnityList.Size = new System.Drawing.Size(574, 478); + this.gridUnityList.StandardTab = true; this.gridUnityList.TabIndex = 10; this.gridUnityList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.unityGridView_KeyDown); // @@ -505,6 +479,7 @@ private void InitializeComponent() this.gridUnityUpdates.ShowCellToolTips = false; this.gridUnityUpdates.ShowEditingIcon = false; this.gridUnityUpdates.Size = new System.Drawing.Size(574, 478); + this.gridUnityUpdates.StandardTab = true; this.gridUnityUpdates.TabIndex = 22; // // _Date @@ -730,7 +705,7 @@ private void InitializeComponent() this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(166, 22); + this.statusStrip1.Size = new System.Drawing.Size(135, 22); this.statusStrip1.TabIndex = 7; this.statusStrip1.Text = "statusStrip1"; // @@ -740,6 +715,48 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // + // _project + // + this._project.HeaderText = "Project"; + this._project.Name = "_project"; + this._project.ReadOnly = true; + this._project.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._project.Width = 150; + // + // _version + // + this._version.HeaderText = "Version"; + this._version.Name = "_version"; + this._version.ReadOnly = true; + this._version.Width = 72; + // + // _path + // + this._path.HeaderText = "Path"; + this._path.Name = "_path"; + this._path.ReadOnly = true; + this._path.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._path.Width = 185; + // + // _dateModified + // + this._dateModified.HeaderText = "Modified"; + this._dateModified.Name = "_dateModified"; + this._dateModified.ReadOnly = true; + this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._dateModified.Width = 120; + // + // _launchArguments + // + this._launchArguments.HeaderText = "Arguments"; + this._launchArguments.Name = "_launchArguments"; + // + // _gitBranch + // + this._gitBranch.HeaderText = "GITBranch"; + this._gitBranch.Name = "_gitBranch"; + this._gitBranch.ReadOnly = true; + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -753,7 +770,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - BuyTheDip Edition 16"; + this.Text = "UnityLauncher - FOMO Edition 17"; this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); @@ -821,10 +838,6 @@ private void InitializeComponent() private System.Windows.Forms.Button btnOpenLogFolder; private System.Windows.Forms.TextBox tbSearchBar; private System.Windows.Forms.CheckBox ChkQuitAfterOpen; - private System.Windows.Forms.DataGridViewTextBoxColumn _project; - private System.Windows.Forms.DataGridViewTextBoxColumn _version; - private System.Windows.Forms.DataGridViewTextBoxColumn _path; - private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; private System.Windows.Forms.Button btn_refreshUnityList; private System.Windows.Forms.TabPage tabUpdates; private System.Windows.Forms.Button btnFetchUnityVersions; @@ -832,6 +845,12 @@ private void InitializeComponent() private System.Windows.Forms.Button btnOpenUpdateWebsite; private System.Windows.Forms.DataGridViewTextBoxColumn _Date; private System.Windows.Forms.DataGridViewTextBoxColumn _UnityUpdateVersion; + private System.Windows.Forms.DataGridViewTextBoxColumn _project; + private System.Windows.Forms.DataGridViewTextBoxColumn _version; + private System.Windows.Forms.DataGridViewTextBoxColumn _path; + private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; + private System.Windows.Forms.DataGridViewTextBoxColumn _launchArguments; + private System.Windows.Forms.DataGridViewTextBoxColumn _gitBranch; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 5071624..2abcff2 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -17,6 +17,7 @@ public partial class Form1 : Form public static Dictionary unityList = new Dictionary(); const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; bool isDownloadUnityList = false; + const string launcherArgumentsFile = "LauncherArguments.txt"; public Form1() @@ -286,9 +287,14 @@ void FilterRecentProject(object sender, EventArgs e) SetStatus("Filtering recent projects list.."); foreach (DataGridViewRow recentProject in gridRecent.Rows) { - if (recentProject.Cells["_project"].Value.ToString().ToLower().Contains(tbSearchBar.Text.ToLower())) + if (recentProject.Cells["_project"].Value.ToString().IndexOf(tbSearchBar.Text, StringComparison.OrdinalIgnoreCase) > -1) + { recentProject.Visible = true; - else recentProject.Visible = false; + } + else + { + recentProject.Visible = false; + } } } @@ -365,7 +371,13 @@ void UpdateRecentProjectsList() // get project version string projectVersion = GetProjectVersion(projectPath); - gridRecent.Rows.Add(projectName, projectVersion, projectPath, lastUpdated); + // get custom launch arguments,TODO if enabled + string customArgs = ReadCustomLaunchArguments(projectPath); + + // get git branchinfo,TODO if enabled + string gitBranch = ReadGitBranchInfo(projectPath); + + gridRecent.Rows.Add(projectName, projectVersion, projectPath, lastUpdated, customArgs, gitBranch); gridRecent.Rows[gridRecent.Rows.Count - 1].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; } } @@ -420,6 +432,14 @@ void LaunchProject(string projectPath, string version, bool openProject = true) if (openProject == true) { var pars = " -projectPath " + "\"" + projectPath + "\""; + + // check for custom launch parameters and append them + string customArguments = GetSelectedRowData("_launchArguments"); + if (string.IsNullOrEmpty(customArguments) == false) + { + pars += " " + customArguments; + } + myProcess.StartInfo.Arguments = pars; } myProcess.Start(); @@ -627,6 +647,8 @@ void LaunchSelectedProject(bool openProject = true) } } + + void LaunchSelectedUnity() { var selected = gridUnityList.CurrentCell.RowIndex; @@ -827,7 +849,9 @@ private void unityGridView_KeyDown(object sender, KeyEventArgs e) /// private void Form1_KeyPress(object sender, KeyPressEventArgs e) { - //Console.WriteLine((int)e.KeyChar); + // if editing cells, dont focus on search + if (gridRecent.IsCurrentCellInEditMode == true) return; + switch ((int)e.KeyChar) { case 27: // ESC - clear search @@ -860,7 +884,9 @@ private void Form1_KeyPress(object sender, KeyPressEventArgs e) /// private void gridRecent_KeyDown(object sender, KeyEventArgs e) { - //Console.WriteLine(e.KeyValue); + // if editing cells, dont search or launch + if (gridRecent.IsCurrentCellInEditMode == true) return; + switch (e.KeyCode) { case Keys.Return: // launch selected project @@ -1197,5 +1223,67 @@ private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedE gridUnityUpdates.Rows.Add(row[3], row[6].Trim('"')); } } + + // after editing launch arguments cell + private void gridRecent_CellEndEdit(object sender, DataGridViewCellEventArgs e) + { + string path = GetSelectedRowData("_path"); + if (string.IsNullOrEmpty(path)) return; + + + string arguments = GetSelectedRowData("_launchArguments"); + + // save arguments to projectsettings folder + string outputFile = Path.Combine(path, "ProjectSettings", launcherArgumentsFile); + + try + { + StreamWriter sw = new StreamWriter(outputFile); + sw.WriteLine(arguments); + sw.Close(); + } + catch (Exception exception) + { + SetStatus("File error: " + exception.Message); + } + // TODO: keep current row selected + } + + // returns currently selected rows path string + string GetSelectedRowData(string key) + { + string path = null; + var selected = gridRecent.CurrentCell.RowIndex; + if (selected > -1) + { + path = gridRecent.Rows[selected].Cells[key].Value?.ToString(); + } + return path; + } + + string ReadCustomLaunchArguments(string projectPath) + { + string results = null; + string argumentsFile = Path.Combine(projectPath, "ProjectSettings", launcherArgumentsFile); + if (File.Exists(argumentsFile) == true) + { + results = File.ReadAllText(argumentsFile); + } + return results; + } + + string ReadGitBranchInfo(string projectPath) + { + string results = null; + string branchFile = Path.Combine(projectPath, ".git", "HEAD"); + if (File.Exists(branchFile) == true) + { + results = File.ReadAllText(branchFile); + // get branch only + int pos = results.LastIndexOf("/") + 1; + results = results.Substring(pos, results.Length - pos); + } + return results; + } } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 4902c55..8259f6b 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -132,16 +132,10 @@ True - - True - - + True - - True - - + True From b332def1d5d1f96d802e1bf0e7a7f8f694a6afdf Mon Sep 17 00:00:00 2001 From: unitycoder Date: Wed, 7 Feb 2018 19:39:38 +0800 Subject: [PATCH 29/81] create ProjectSettings folder if not exists (for launcherarguments file) --- UnityLauncher/Form1.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 2abcff2..768b8a3 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -1233,6 +1233,13 @@ private void gridRecent_CellEndEdit(object sender, DataGridViewCellEventArgs e) string arguments = GetSelectedRowData("_launchArguments"); + // check folder first + string outputFolder = Path.Combine(path, "ProjectSettings"); + if (Directory.Exists(outputFolder) == false) + { + Directory.CreateDirectory(outputFolder); + } + // save arguments to projectsettings folder string outputFile = Path.Combine(path, "ProjectSettings", launcherArgumentsFile); From dbf5a6879da0983ba084bc7eb544ef17495b528c Mon Sep 17 00:00:00 2001 From: unitycoder Date: Fri, 9 Feb 2018 21:22:18 +0800 Subject: [PATCH 30/81] Settings tab: Add toggles for launcher arguments and git branch columns visibility (optional columns). Change gridColumnsWidths to int32[] type (xml was causing issues when edit settings) --- UnityLauncher/App.config | 15 +- UnityLauncher/Form1.Designer.cs | 151 ++++++++++++------ UnityLauncher/Form1.cs | 22 +++ UnityLauncher/Form1.resx | 18 +++ UnityLauncher/Properties/Settings.Designer.cs | 29 +++- UnityLauncher/Properties/Settings.settings | 15 +- 6 files changed, 180 insertions(+), 70 deletions(-) diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index beb935b..18502f3 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -13,7 +13,7 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema"> C:\Program Files\ @@ -24,7 +24,7 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> @@ -39,12 +39,11 @@ 650 - - - - - + + False + + + False diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index c43c2ab..b05bc6f 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -38,6 +38,12 @@ private void InitializeComponent() this.btnOpenUnityFolder = new System.Windows.Forms.Button(); this.btnLaunch = new System.Windows.Forms.Button(); this.gridRecent = new System.Windows.Forms.DataGridView(); + this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._launchArguments = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._gitBranch = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabUnitys = new System.Windows.Forms.TabPage(); this.btn_refreshUnityList = new System.Windows.Forms.Button(); this.btnOpenReleasePage = new System.Windows.Forms.Button(); @@ -80,12 +86,9 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this._project = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._launchArguments = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._gitBranch = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.chkShowLauncherArgumentsColumn = new System.Windows.Forms.CheckBox(); + this.label5 = new System.Windows.Forms.Label(); + this.chkShowGitBranchColumn = new System.Windows.Forms.CheckBox(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -222,6 +225,48 @@ private void InitializeComponent() this.gridRecent.CellMouseDoubleClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.GridRecent_CellMouseDoubleClick); this.gridRecent.KeyDown += new System.Windows.Forms.KeyEventHandler(this.gridRecent_KeyDown); // + // _project + // + this._project.HeaderText = "Project"; + this._project.Name = "_project"; + this._project.ReadOnly = true; + this._project.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._project.Width = 150; + // + // _version + // + this._version.HeaderText = "Version"; + this._version.Name = "_version"; + this._version.ReadOnly = true; + this._version.Width = 72; + // + // _path + // + this._path.HeaderText = "Path"; + this._path.Name = "_path"; + this._path.ReadOnly = true; + this._path.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._path.Width = 185; + // + // _dateModified + // + this._dateModified.HeaderText = "Modified"; + this._dateModified.Name = "_dateModified"; + this._dateModified.ReadOnly = true; + this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this._dateModified.Width = 120; + // + // _launchArguments + // + this._launchArguments.HeaderText = "Arguments"; + this._launchArguments.Name = "_launchArguments"; + // + // _gitBranch + // + this._gitBranch.HeaderText = "GITBranch"; + this._gitBranch.Name = "_gitBranch"; + this._gitBranch.ReadOnly = true; + // // tabUnitys // this.tabUnitys.Controls.Add(this.btn_refreshUnityList); @@ -500,6 +545,9 @@ private void InitializeComponent() // // tabSettings // + this.tabSettings.Controls.Add(this.chkShowGitBranchColumn); + this.tabSettings.Controls.Add(this.label5); + this.tabSettings.Controls.Add(this.chkShowLauncherArgumentsColumn); this.tabSettings.Controls.Add(this.ChkQuitAfterOpen); this.tabSettings.Controls.Add(this.btnOpenLogFolder); this.tabSettings.Controls.Add(this.chkQuitAfterCommandline); @@ -536,7 +584,7 @@ private void InitializeComponent() // btnOpenLogFolder // this.btnOpenLogFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnOpenLogFolder.Location = new System.Drawing.Point(435, 380); + this.btnOpenLogFolder.Location = new System.Drawing.Point(432, 512); this.btnOpenLogFolder.Name = "btnOpenLogFolder"; this.btnOpenLogFolder.Size = new System.Drawing.Size(137, 23); this.btnOpenLogFolder.TabIndex = 32; @@ -559,7 +607,7 @@ private void InitializeComponent() // btnAddRegister // this.btnAddRegister.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.btnAddRegister.Location = new System.Drawing.Point(139, 465); + this.btnAddRegister.Location = new System.Drawing.Point(139, 512); this.btnAddRegister.Name = "btnAddRegister"; this.btnAddRegister.Size = new System.Drawing.Size(64, 23); this.btnAddRegister.TabIndex = 30; @@ -570,7 +618,7 @@ private void InitializeComponent() // btnRemoveRegister // this.btnRemoveRegister.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.btnRemoveRegister.Location = new System.Drawing.Point(209, 465); + this.btnRemoveRegister.Location = new System.Drawing.Point(209, 512); this.btnRemoveRegister.Name = "btnRemoveRegister"; this.btnRemoveRegister.Size = new System.Drawing.Size(64, 23); this.btnRemoveRegister.TabIndex = 29; @@ -582,7 +630,7 @@ private void InitializeComponent() // this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(19, 470); + this.label4.Location = new System.Drawing.Point(19, 517); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(117, 13); this.label4.TabIndex = 28; @@ -657,7 +705,7 @@ private void InitializeComponent() this.lbl_unityCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.lbl_unityCount.AutoSize = true; this.lbl_unityCount.Enabled = false; - this.lbl_unityCount.Location = new System.Drawing.Point(475, 15); + this.lbl_unityCount.Location = new System.Drawing.Point(472, 15); this.lbl_unityCount.Name = "lbl_unityCount"; this.lbl_unityCount.Size = new System.Drawing.Size(97, 13); this.lbl_unityCount.TabIndex = 18; @@ -715,47 +763,41 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // - // _project - // - this._project.HeaderText = "Project"; - this._project.Name = "_project"; - this._project.ReadOnly = true; - this._project.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this._project.Width = 150; - // - // _version - // - this._version.HeaderText = "Version"; - this._version.Name = "_version"; - this._version.ReadOnly = true; - this._version.Width = 72; - // - // _path - // - this._path.HeaderText = "Path"; - this._path.Name = "_path"; - this._path.ReadOnly = true; - this._path.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this._path.Width = 185; - // - // _dateModified - // - this._dateModified.HeaderText = "Modified"; - this._dateModified.Name = "_dateModified"; - this._dateModified.ReadOnly = true; - this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this._dateModified.Width = 120; - // - // _launchArguments - // - this._launchArguments.HeaderText = "Arguments"; - this._launchArguments.Name = "_launchArguments"; - // - // _gitBranch - // - this._gitBranch.HeaderText = "GITBranch"; - this._gitBranch.Name = "_gitBranch"; - this._gitBranch.ReadOnly = true; + // chkShowLauncherArgumentsColumn + // + this.chkShowLauncherArgumentsColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.chkShowLauncherArgumentsColumn.AutoSize = true; + this.chkShowLauncherArgumentsColumn.Location = new System.Drawing.Point(266, 386); + this.chkShowLauncherArgumentsColumn.Name = "chkShowLauncherArgumentsColumn"; + this.chkShowLauncherArgumentsColumn.Size = new System.Drawing.Size(124, 17); + this.chkShowLauncherArgumentsColumn.TabIndex = 34; + this.chkShowLauncherArgumentsColumn.Text = "Launcher Arguments"; + this.chkShowLauncherArgumentsColumn.UseVisualStyleBackColor = true; + this.chkShowLauncherArgumentsColumn.CheckedChanged += new System.EventHandler(this.checkShowLauncherArgumentsColumn_CheckedChanged); + // + // label5 + // + this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label5.AutoSize = true; + this.label5.Enabled = false; + this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label5.Location = new System.Drawing.Point(263, 361); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(105, 13); + this.label5.TabIndex = 35; + this.label5.Text = "Optional Columns"; + // + // chkShowGitBranchColumn + // + this.chkShowGitBranchColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.chkShowGitBranchColumn.AutoSize = true; + this.chkShowGitBranchColumn.Location = new System.Drawing.Point(266, 409); + this.chkShowGitBranchColumn.Name = "chkShowGitBranchColumn"; + this.chkShowGitBranchColumn.Size = new System.Drawing.Size(76, 17); + this.chkShowGitBranchColumn.TabIndex = 36; + this.chkShowGitBranchColumn.Text = "Git Branch"; + this.chkShowGitBranchColumn.UseVisualStyleBackColor = true; + this.chkShowGitBranchColumn.CheckedChanged += new System.EventHandler(this.checkShowGitBranchColumn_CheckedChanged); // // Form1 // @@ -770,7 +812,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - FOMO Edition 17"; + this.Text = "UnityLauncher - Hub Edition 18"; this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); @@ -851,6 +893,9 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; private System.Windows.Forms.DataGridViewTextBoxColumn _launchArguments; private System.Windows.Forms.DataGridViewTextBoxColumn _gitBranch; + private System.Windows.Forms.CheckBox chkShowGitBranchColumn; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.CheckBox chkShowLauncherArgumentsColumn; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 768b8a3..8b17ce8 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -102,6 +102,12 @@ void LoadSettings() chkMinimizeToTaskbar.Checked = Properties.Settings.Default.minimizeToTaskbar; chkQuitAfterCommandline.Checked = Properties.Settings.Default.closeAfterExplorer; ChkQuitAfterOpen.Checked = Properties.Settings.Default.closeAfterProject; + chkShowLauncherArgumentsColumn.Checked = Properties.Settings.Default.showArgumentsColumn; + chkShowGitBranchColumn.Checked = Properties.Settings.Default.showGitBranchColumn; + + // update optional grid columns, hidden or visible + gridRecent.Columns["_launchArguments"].Visible = chkShowLauncherArgumentsColumn.Checked; + gridRecent.Columns["_gitBranch"].Visible = chkShowGitBranchColumn.Checked; // update installations folder listbox lstRootFolders.Items.AddRange(Properties.Settings.Default.rootFolders.Cast().ToArray()); @@ -766,6 +772,8 @@ private void chkMinimizeToTaskbar_CheckedChanged(object sender, EventArgs e) Properties.Settings.Default.Save(); } + + private void btnAddPackageFolder_Click(object sender, EventArgs e) { AddPackageFolder(); @@ -1292,5 +1300,19 @@ string ReadGitBranchInfo(string projectPath) } return results; } + + private void checkShowLauncherArgumentsColumn_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.showArgumentsColumn = chkShowLauncherArgumentsColumn.Checked; + Properties.Settings.Default.Save(); + gridRecent.Columns["_launchArguments"].Visible = chkShowLauncherArgumentsColumn.Checked; + } + + private void checkShowGitBranchColumn_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.showGitBranchColumn = chkShowGitBranchColumn.Checked; + Properties.Settings.Default.Save(); + gridRecent.Columns["_gitBranch"].Visible = chkShowGitBranchColumn.Checked; + } } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 8259f6b..8992051 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -138,6 +138,24 @@ True + + True + + + True + + + True + + + True + + + True + + + True + True diff --git a/UnityLauncher/Properties/Settings.Designer.cs b/UnityLauncher/Properties/Settings.Designer.cs index 5637586..e25de41 100644 --- a/UnityLauncher/Properties/Settings.Designer.cs +++ b/UnityLauncher/Properties/Settings.Designer.cs @@ -112,14 +112,37 @@ public int formHeight { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public System.Int32[] gridColumnWidths { + public int[] gridColumnWidths { get { - return (System.Int32[]) (this["gridColumnWidths"]); + return ((int[])(this["gridColumnWidths"])); } set { this["gridColumnWidths"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool showArgumentsColumn { + get { + return ((bool)(this["showArgumentsColumn"])); + } + set { + this["showArgumentsColumn"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool showGitBranchColumn { + get { + return ((bool)(this["showGitBranchColumn"])); + } + set { + this["showGitBranchColumn"] = value; + } + } } } diff --git a/UnityLauncher/Properties/Settings.settings b/UnityLauncher/Properties/Settings.settings index ff93822..bca9a0e 100644 --- a/UnityLauncher/Properties/Settings.settings +++ b/UnityLauncher/Properties/Settings.settings @@ -21,17 +21,20 @@ True - -+ -+ <ArrayOfInt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> -+ </ArrayOfInt> -+ -+ 600 650 + + + + + False + + + False + \ No newline at end of file From 469e14c8b584fc1874b8dc1b2ef1e74ab4eb7a3c Mon Sep 17 00:00:00 2001 From: unitycoder Date: Fri, 9 Feb 2018 21:53:57 +0800 Subject: [PATCH 31/81] add link to unity commandline docs, add link to unitylauncher releases page --- UnityLauncher/Form1.Designer.cs | 120 +++++++++++++++++++++----------- UnityLauncher/Form1.cs | 57 ++++++++++----- 2 files changed, 119 insertions(+), 58 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index b05bc6f..6f11534 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -66,6 +66,9 @@ private void InitializeComponent() this._Date = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._UnityUpdateVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabSettings = new System.Windows.Forms.TabPage(); + this.chkShowGitBranchColumn = new System.Windows.Forms.CheckBox(); + this.label5 = new System.Windows.Forms.Label(); + this.chkShowLauncherArgumentsColumn = new System.Windows.Forms.CheckBox(); this.ChkQuitAfterOpen = new System.Windows.Forms.CheckBox(); this.btnOpenLogFolder = new System.Windows.Forms.Button(); this.chkQuitAfterCommandline = new System.Windows.Forms.CheckBox(); @@ -86,9 +89,8 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this.chkShowLauncherArgumentsColumn = new System.Windows.Forms.CheckBox(); - this.label5 = new System.Windows.Forms.Label(); - this.chkShowGitBranchColumn = new System.Windows.Forms.CheckBox(); + this.linkArgumentsDocs = new System.Windows.Forms.LinkLabel(); + this.linkProjectGithub = new System.Windows.Forms.LinkLabel(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -545,6 +547,8 @@ private void InitializeComponent() // // tabSettings // + this.tabSettings.Controls.Add(this.linkProjectGithub); + this.tabSettings.Controls.Add(this.linkArgumentsDocs); this.tabSettings.Controls.Add(this.chkShowGitBranchColumn); this.tabSettings.Controls.Add(this.label5); this.tabSettings.Controls.Add(this.chkShowLauncherArgumentsColumn); @@ -569,6 +573,42 @@ private void InitializeComponent() this.tabSettings.Text = "Settings"; this.tabSettings.UseVisualStyleBackColor = true; // + // chkShowGitBranchColumn + // + this.chkShowGitBranchColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.chkShowGitBranchColumn.AutoSize = true; + this.chkShowGitBranchColumn.Location = new System.Drawing.Point(266, 409); + this.chkShowGitBranchColumn.Name = "chkShowGitBranchColumn"; + this.chkShowGitBranchColumn.Size = new System.Drawing.Size(76, 17); + this.chkShowGitBranchColumn.TabIndex = 36; + this.chkShowGitBranchColumn.Text = "Git Branch"; + this.chkShowGitBranchColumn.UseVisualStyleBackColor = true; + this.chkShowGitBranchColumn.CheckedChanged += new System.EventHandler(this.checkShowGitBranchColumn_CheckedChanged); + // + // label5 + // + this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label5.AutoSize = true; + this.label5.Enabled = false; + this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label5.Location = new System.Drawing.Point(263, 361); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(105, 13); + this.label5.TabIndex = 35; + this.label5.Text = "Optional Columns"; + // + // chkShowLauncherArgumentsColumn + // + this.chkShowLauncherArgumentsColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.chkShowLauncherArgumentsColumn.AutoSize = true; + this.chkShowLauncherArgumentsColumn.Location = new System.Drawing.Point(266, 386); + this.chkShowLauncherArgumentsColumn.Name = "chkShowLauncherArgumentsColumn"; + this.chkShowLauncherArgumentsColumn.Size = new System.Drawing.Size(124, 17); + this.chkShowLauncherArgumentsColumn.TabIndex = 34; + this.chkShowLauncherArgumentsColumn.Text = "Launcher Arguments"; + this.chkShowLauncherArgumentsColumn.UseVisualStyleBackColor = true; + this.chkShowLauncherArgumentsColumn.CheckedChanged += new System.EventHandler(this.checkShowLauncherArgumentsColumn_CheckedChanged); + // // ChkQuitAfterOpen // this.ChkQuitAfterOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); @@ -584,7 +624,7 @@ private void InitializeComponent() // btnOpenLogFolder // this.btnOpenLogFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnOpenLogFolder.Location = new System.Drawing.Point(432, 512); + this.btnOpenLogFolder.Location = new System.Drawing.Point(435, 285); this.btnOpenLogFolder.Name = "btnOpenLogFolder"; this.btnOpenLogFolder.Size = new System.Drawing.Size(137, 23); this.btnOpenLogFolder.TabIndex = 32; @@ -607,7 +647,7 @@ private void InitializeComponent() // btnAddRegister // this.btnAddRegister.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.btnAddRegister.Location = new System.Drawing.Point(139, 512); + this.btnAddRegister.Location = new System.Drawing.Point(139, 481); this.btnAddRegister.Name = "btnAddRegister"; this.btnAddRegister.Size = new System.Drawing.Size(64, 23); this.btnAddRegister.TabIndex = 30; @@ -618,7 +658,7 @@ private void InitializeComponent() // btnRemoveRegister // this.btnRemoveRegister.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.btnRemoveRegister.Location = new System.Drawing.Point(209, 512); + this.btnRemoveRegister.Location = new System.Drawing.Point(209, 481); this.btnRemoveRegister.Name = "btnRemoveRegister"; this.btnRemoveRegister.Size = new System.Drawing.Size(64, 23); this.btnRemoveRegister.TabIndex = 29; @@ -630,7 +670,7 @@ private void InitializeComponent() // this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(19, 517); + this.label4.Location = new System.Drawing.Point(19, 486); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(117, 13); this.label4.TabIndex = 28; @@ -763,41 +803,35 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // - // chkShowLauncherArgumentsColumn - // - this.chkShowLauncherArgumentsColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.chkShowLauncherArgumentsColumn.AutoSize = true; - this.chkShowLauncherArgumentsColumn.Location = new System.Drawing.Point(266, 386); - this.chkShowLauncherArgumentsColumn.Name = "chkShowLauncherArgumentsColumn"; - this.chkShowLauncherArgumentsColumn.Size = new System.Drawing.Size(124, 17); - this.chkShowLauncherArgumentsColumn.TabIndex = 34; - this.chkShowLauncherArgumentsColumn.Text = "Launcher Arguments"; - this.chkShowLauncherArgumentsColumn.UseVisualStyleBackColor = true; - this.chkShowLauncherArgumentsColumn.CheckedChanged += new System.EventHandler(this.checkShowLauncherArgumentsColumn_CheckedChanged); - // - // label5 - // - this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.label5.AutoSize = true; - this.label5.Enabled = false; - this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label5.Location = new System.Drawing.Point(263, 361); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(105, 13); - this.label5.TabIndex = 35; - this.label5.Text = "Optional Columns"; - // - // chkShowGitBranchColumn - // - this.chkShowGitBranchColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.chkShowGitBranchColumn.AutoSize = true; - this.chkShowGitBranchColumn.Location = new System.Drawing.Point(266, 409); - this.chkShowGitBranchColumn.Name = "chkShowGitBranchColumn"; - this.chkShowGitBranchColumn.Size = new System.Drawing.Size(76, 17); - this.chkShowGitBranchColumn.TabIndex = 36; - this.chkShowGitBranchColumn.Text = "Git Branch"; - this.chkShowGitBranchColumn.UseVisualStyleBackColor = true; - this.chkShowGitBranchColumn.CheckedChanged += new System.EventHandler(this.checkShowGitBranchColumn_CheckedChanged); + // linkArgumentsDocs + // + this.linkArgumentsDocs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.linkArgumentsDocs.AutoSize = true; + this.linkArgumentsDocs.LinkArea = new System.Windows.Forms.LinkArea(1, 4); + this.linkArgumentsDocs.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline; + this.linkArgumentsDocs.Location = new System.Drawing.Point(385, 387); + this.linkArgumentsDocs.Name = "linkArgumentsDocs"; + this.linkArgumentsDocs.Size = new System.Drawing.Size(36, 17); + this.linkArgumentsDocs.TabIndex = 38; + this.linkArgumentsDocs.TabStop = true; + this.linkArgumentsDocs.Text = "(docs)"; + this.linkArgumentsDocs.UseCompatibleTextRendering = true; + this.linkArgumentsDocs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkArgumentsDocs_LinkClicked); + // + // linkProjectGithub + // + this.linkProjectGithub.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.linkProjectGithub.AutoSize = true; + this.linkProjectGithub.LinkArea = new System.Windows.Forms.LinkArea(20, 6); + this.linkProjectGithub.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline; + this.linkProjectGithub.Location = new System.Drawing.Point(439, 532); + this.linkProjectGithub.Name = "linkProjectGithub"; + this.linkProjectGithub.Size = new System.Drawing.Size(138, 17); + this.linkProjectGithub.TabIndex = 39; + this.linkProjectGithub.TabStop = true; + this.linkProjectGithub.Text = "Visit UnityLauncher Github"; + this.linkProjectGithub.UseCompatibleTextRendering = true; + this.linkProjectGithub.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkProjectGithub_LinkClicked); // // Form1 // @@ -896,6 +930,8 @@ private void InitializeComponent() private System.Windows.Forms.CheckBox chkShowGitBranchColumn; private System.Windows.Forms.Label label5; private System.Windows.Forms.CheckBox chkShowLauncherArgumentsColumn; + private System.Windows.Forms.LinkLabel linkArgumentsDocs; + private System.Windows.Forms.LinkLabel linkProjectGithub; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 8b17ce8..2351638 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -377,18 +377,25 @@ void UpdateRecentProjectsList() // get project version string projectVersion = GetProjectVersion(projectPath); - // get custom launch arguments,TODO if enabled - string customArgs = ReadCustomLaunchArguments(projectPath); + // get custom launch arguments, only if column in enabled + string customArgs = ""; + if (chkShowLauncherArgumentsColumn.Checked == true) + { + customArgs = ReadCustomLaunchArguments(projectPath); + } - // get git branchinfo,TODO if enabled - string gitBranch = ReadGitBranchInfo(projectPath); + // get git branchinfo, only if column in enabled + string gitBranch = ""; + if (chkShowGitBranchColumn.Checked == true) + { + gitBranch = ReadGitBranchInfo(projectPath); + } gridRecent.Rows.Add(projectName, projectVersion, projectPath, lastUpdated, customArgs, gitBranch); gridRecent.Rows[gridRecent.Rows.Count - 1].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; } } } - SetStatus("Ready"); } @@ -1078,6 +1085,33 @@ private void Form1_ResizeEnd(object sender, EventArgs e) Properties.Settings.Default.Save(); } + private void checkShowLauncherArgumentsColumn_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.showArgumentsColumn = chkShowLauncherArgumentsColumn.Checked; + Properties.Settings.Default.Save(); + gridRecent.Columns["_launchArguments"].Visible = chkShowLauncherArgumentsColumn.Checked; + // reload list data, if enabled (otherwise missing data) + if (chkShowLauncherArgumentsColumn.Checked == true) UpdateRecentProjectsList(); + } + + private void checkShowGitBranchColumn_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.showGitBranchColumn = chkShowGitBranchColumn.Checked; + Properties.Settings.Default.Save(); + gridRecent.Columns["_gitBranch"].Visible = chkShowGitBranchColumn.Checked; + // reload list data, if enabled (otherwise missing data) + if (chkShowGitBranchColumn.Checked == true) UpdateRecentProjectsList(); + } + + private void linkArgumentsDocs_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + OpenURL("https://docs.unity3d.com/Manual/CommandLineArguments.html"); + } + + private void linkProjectGithub_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + OpenURL("https://github.com/unitycoder/UnityLauncher/releases"); + } #endregion UI events @@ -1301,18 +1335,9 @@ string ReadGitBranchInfo(string projectPath) return results; } - private void checkShowLauncherArgumentsColumn_CheckedChanged(object sender, EventArgs e) + private void OpenURL(string url) { - Properties.Settings.Default.showArgumentsColumn = chkShowLauncherArgumentsColumn.Checked; - Properties.Settings.Default.Save(); - gridRecent.Columns["_launchArguments"].Visible = chkShowLauncherArgumentsColumn.Checked; - } - - private void checkShowGitBranchColumn_CheckedChanged(object sender, EventArgs e) - { - Properties.Settings.Default.showGitBranchColumn = chkShowGitBranchColumn.Checked; - Properties.Settings.Default.Save(); - gridRecent.Columns["_gitBranch"].Visible = chkShowGitBranchColumn.Checked; + Process.Start(url); } } } From bd0f7098c0b4805f51b53ed0849354aca2137ff5 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Fri, 16 Feb 2018 10:33:50 +0800 Subject: [PATCH 32/81] don't check backup file if running unity only (fixes #35), check unity install date (fixes #34), fix unity tab tooltip text --- UnityLauncher/Form1.Designer.cs | 117 +++++++++++++++++--------------- UnityLauncher/Form1.cs | 24 ++++--- UnityLauncher/Form1.resx | 14 ++-- 3 files changed, 88 insertions(+), 67 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 6f11534..b74977c 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -50,8 +50,6 @@ private void InitializeComponent() this.btnExploreUnity = new System.Windows.Forms.Button(); this.btnLaunchUnity = new System.Windows.Forms.Button(); this.gridUnityList = new System.Windows.Forms.DataGridView(); - this._unityVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._unityPath = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabPackages = new System.Windows.Forms.TabPage(); this.btnAddAssetStoreFolder = new System.Windows.Forms.Button(); this.btnExplorePackageFolder = new System.Windows.Forms.Button(); @@ -66,6 +64,8 @@ private void InitializeComponent() this._Date = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._UnityUpdateVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabSettings = new System.Windows.Forms.TabPage(); + this.linkProjectGithub = new System.Windows.Forms.LinkLabel(); + this.linkArgumentsDocs = new System.Windows.Forms.LinkLabel(); this.chkShowGitBranchColumn = new System.Windows.Forms.CheckBox(); this.label5 = new System.Windows.Forms.Label(); this.chkShowLauncherArgumentsColumn = new System.Windows.Forms.CheckBox(); @@ -89,8 +89,9 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this.linkArgumentsDocs = new System.Windows.Forms.LinkLabel(); - this.linkProjectGithub = new System.Windows.Forms.LinkLabel(); + this._unityVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._unityPath = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._unityInstallDate = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -347,12 +348,14 @@ private void InitializeComponent() this.gridUnityList.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.gridUnityList.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this._unityVersion, - this._unityPath}); + this._unityPath, + this._unityInstallDate}); this.gridUnityList.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; this.gridUnityList.Location = new System.Drawing.Point(3, 27); this.gridUnityList.MultiSelect = false; this.gridUnityList.Name = "gridUnityList"; this.gridUnityList.ReadOnly = true; + this.gridUnityList.RowHeadersWidth = 18; this.gridUnityList.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.gridUnityList.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; this.gridUnityList.ShowCellErrors = false; @@ -363,23 +366,6 @@ private void InitializeComponent() this.gridUnityList.TabIndex = 10; this.gridUnityList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.unityGridView_KeyDown); // - // _unityVersion - // - this._unityVersion.HeaderText = "Version"; - this._unityVersion.MinimumWidth = 150; - this._unityVersion.Name = "_unityVersion"; - this._unityVersion.ReadOnly = true; - this._unityVersion.Width = 150; - // - // _unityPath - // - this._unityPath.HeaderText = "Path"; - this._unityPath.MinimumWidth = 300; - this._unityPath.Name = "_unityPath"; - this._unityPath.ReadOnly = true; - this._unityPath.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._unityPath.Width = 300; - // // tabPackages // this.tabPackages.Controls.Add(this.btnAddAssetStoreFolder); @@ -482,7 +468,7 @@ private void InitializeComponent() this.btnOpenUpdateWebsite.Size = new System.Drawing.Size(572, 35); this.btnOpenUpdateWebsite.TabIndex = 24; this.btnOpenUpdateWebsite.Text = "Open Website"; - this.toolTip1.SetToolTip(this.btnOpenUpdateWebsite, "Launch selected project"); + this.toolTip1.SetToolTip(this.btnOpenUpdateWebsite, "Open Release Page"); this.btnOpenUpdateWebsite.UseVisualStyleBackColor = true; this.btnOpenUpdateWebsite.Click += new System.EventHandler(this.btnOpenUpdateWebsite_Click); // @@ -573,6 +559,36 @@ private void InitializeComponent() this.tabSettings.Text = "Settings"; this.tabSettings.UseVisualStyleBackColor = true; // + // linkProjectGithub + // + this.linkProjectGithub.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.linkProjectGithub.AutoSize = true; + this.linkProjectGithub.LinkArea = new System.Windows.Forms.LinkArea(20, 6); + this.linkProjectGithub.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline; + this.linkProjectGithub.Location = new System.Drawing.Point(439, 532); + this.linkProjectGithub.Name = "linkProjectGithub"; + this.linkProjectGithub.Size = new System.Drawing.Size(138, 17); + this.linkProjectGithub.TabIndex = 39; + this.linkProjectGithub.TabStop = true; + this.linkProjectGithub.Text = "Visit UnityLauncher Github"; + this.linkProjectGithub.UseCompatibleTextRendering = true; + this.linkProjectGithub.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkProjectGithub_LinkClicked); + // + // linkArgumentsDocs + // + this.linkArgumentsDocs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.linkArgumentsDocs.AutoSize = true; + this.linkArgumentsDocs.LinkArea = new System.Windows.Forms.LinkArea(1, 4); + this.linkArgumentsDocs.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline; + this.linkArgumentsDocs.Location = new System.Drawing.Point(385, 387); + this.linkArgumentsDocs.Name = "linkArgumentsDocs"; + this.linkArgumentsDocs.Size = new System.Drawing.Size(36, 17); + this.linkArgumentsDocs.TabIndex = 38; + this.linkArgumentsDocs.TabStop = true; + this.linkArgumentsDocs.Text = "(docs)"; + this.linkArgumentsDocs.UseCompatibleTextRendering = true; + this.linkArgumentsDocs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkArgumentsDocs_LinkClicked); + // // chkShowGitBranchColumn // this.chkShowGitBranchColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); @@ -789,8 +805,6 @@ private void InitializeComponent() this.statusStrip1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(135, 22); @@ -803,35 +817,29 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // - // linkArgumentsDocs + // _unityVersion // - this.linkArgumentsDocs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.linkArgumentsDocs.AutoSize = true; - this.linkArgumentsDocs.LinkArea = new System.Windows.Forms.LinkArea(1, 4); - this.linkArgumentsDocs.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline; - this.linkArgumentsDocs.Location = new System.Drawing.Point(385, 387); - this.linkArgumentsDocs.Name = "linkArgumentsDocs"; - this.linkArgumentsDocs.Size = new System.Drawing.Size(36, 17); - this.linkArgumentsDocs.TabIndex = 38; - this.linkArgumentsDocs.TabStop = true; - this.linkArgumentsDocs.Text = "(docs)"; - this.linkArgumentsDocs.UseCompatibleTextRendering = true; - this.linkArgumentsDocs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkArgumentsDocs_LinkClicked); + this._unityVersion.HeaderText = "Version"; + this._unityVersion.MinimumWidth = 150; + this._unityVersion.Name = "_unityVersion"; + this._unityVersion.ReadOnly = true; + this._unityVersion.Width = 150; // - // linkProjectGithub + // _unityPath // - this.linkProjectGithub.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.linkProjectGithub.AutoSize = true; - this.linkProjectGithub.LinkArea = new System.Windows.Forms.LinkArea(20, 6); - this.linkProjectGithub.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline; - this.linkProjectGithub.Location = new System.Drawing.Point(439, 532); - this.linkProjectGithub.Name = "linkProjectGithub"; - this.linkProjectGithub.Size = new System.Drawing.Size(138, 17); - this.linkProjectGithub.TabIndex = 39; - this.linkProjectGithub.TabStop = true; - this.linkProjectGithub.Text = "Visit UnityLauncher Github"; - this.linkProjectGithub.UseCompatibleTextRendering = true; - this.linkProjectGithub.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkProjectGithub_LinkClicked); + this._unityPath.HeaderText = "Path"; + this._unityPath.MinimumWidth = 300; + this._unityPath.Name = "_unityPath"; + this._unityPath.ReadOnly = true; + this._unityPath.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this._unityPath.Width = 300; + // + // _unityInstallDate + // + this._unityInstallDate.HeaderText = "Installed"; + this._unityInstallDate.Name = "_unityInstallDate"; + this._unityInstallDate.ReadOnly = true; + this._unityInstallDate.Width = 150; // // Form1 // @@ -846,7 +854,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Hub Edition 18"; + this.Text = "UnityLauncher - Hubs Edition 18"; this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); @@ -886,8 +894,6 @@ private void InitializeComponent() private System.Windows.Forms.DataGridView gridUnityList; private System.Windows.Forms.Button btnExploreUnity; private System.Windows.Forms.Button btnLaunchUnity; - private System.Windows.Forms.DataGridViewTextBoxColumn _unityVersion; - private System.Windows.Forms.DataGridViewTextBoxColumn _unityPath; private System.Windows.Forms.ListBox lstRootFolders; private System.Windows.Forms.Button btnAddUnityFolder; private System.Windows.Forms.Button btnRemoveInstallFolder; @@ -932,6 +938,9 @@ private void InitializeComponent() private System.Windows.Forms.CheckBox chkShowLauncherArgumentsColumn; private System.Windows.Forms.LinkLabel linkArgumentsDocs; private System.Windows.Forms.LinkLabel linkProjectGithub; + private System.Windows.Forms.DataGridViewTextBoxColumn _unityVersion; + private System.Windows.Forms.DataGridViewTextBoxColumn _unityPath; + private System.Windows.Forms.DataGridViewTextBoxColumn _unityInstallDate; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 2351638..9f32c4f 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -262,9 +262,10 @@ bool ScanUnityInstallations() if (unityList.ContainsKey(unityVersion) == false) { unityList.Add(unityVersion, unityExe); - gridUnityList.Rows.Add(unityVersion, unityExe); + var dataFolder = Path.Combine(directories[i], "Editor", "Data"); + DateTime? installDate = GetLastModifiedTime(dataFolder); + gridUnityList.Rows.Add(unityVersion, unityExe, installDate); } - //Console.WriteLine(unityVersion); } // have unity.exe } // have uninstaller.exe } // got folders @@ -401,7 +402,7 @@ void UpdateRecentProjectsList() DateTime? GetLastModifiedTime(string path) { - if (File.Exists(path) == true) + if (File.Exists(path) == true || Directory.Exists(path) == true) { DateTime modification = File.GetLastWriteTime(path); //return modification.ToShortDateString(); @@ -425,11 +426,14 @@ void LaunchProject(string projectPath, string version, bool openProject = true) Directory.CreateDirectory(assetsFolder); } - // check for crashed backup scene first - var cancelLaunch = CheckCrashBackupScene(projectPath); - if (cancelLaunch == true) + // when opening project, check for crashed backup scene first + if (openProject == true) { - return; + var cancelLaunch = CheckCrashBackupScene(projectPath); + if (cancelLaunch == true) + { + return; + } } if (HaveExactVersionInstalled(version) == true) @@ -1272,7 +1276,6 @@ private void gridRecent_CellEndEdit(object sender, DataGridViewCellEventArgs e) string path = GetSelectedRowData("_path"); if (string.IsNullOrEmpty(path)) return; - string arguments = GetSelectedRowData("_launchArguments"); // check folder first @@ -1295,7 +1298,10 @@ private void gridRecent_CellEndEdit(object sender, DataGridViewCellEventArgs e) { SetStatus("File error: " + exception.Message); } - // TODO: keep current row selected + + // select the same row again (dont move to next), doesnt work here + // var previousRow = gridRecent.CurrentCell.RowIndex; + // gridRecent.Rows[previousRow].Selected = true; } // returns currently selected rows path string diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 8992051..c8f85ab 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -162,10 +162,7 @@ True - - True - - + True @@ -1078,6 +1075,15 @@ 374, 17 + + True + + + True + + + True + 25 From 43afba0399ea3f05893080c3aaeb4d0f724198d4 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sat, 17 Feb 2018 15:04:15 +0800 Subject: [PATCH 33/81] moving helper methods to separate class, remove unity installer file download (open in browser instead) --- UnityLauncher/Form1.Designer.cs | 61 ++-- UnityLauncher/Form1.cs | 441 ++++++----------------------- UnityLauncher/Form1.resx | 18 +- UnityLauncher/Form2.Designer.cs | 2 +- UnityLauncher/Form2.cs | 3 +- UnityLauncher/Tools.cs | 328 +++++++++++++++++++++ UnityLauncher/UnityLauncher.csproj | 1 + 7 files changed, 452 insertions(+), 402 deletions(-) create mode 100644 UnityLauncher/Tools.cs diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index b74977c..808eaf8 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -50,6 +50,9 @@ private void InitializeComponent() this.btnExploreUnity = new System.Windows.Forms.Button(); this.btnLaunchUnity = new System.Windows.Forms.Button(); this.gridUnityList = new System.Windows.Forms.DataGridView(); + this._unityVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._unityPath = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._unityInstallDate = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabPackages = new System.Windows.Forms.TabPage(); this.btnAddAssetStoreFolder = new System.Windows.Forms.Button(); this.btnExplorePackageFolder = new System.Windows.Forms.Button(); @@ -89,9 +92,6 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this._unityVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._unityPath = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._unityInstallDate = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -101,7 +101,6 @@ private void InitializeComponent() this.tabUpdates.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).BeginInit(); this.tabSettings.SuspendLayout(); - this.statusStrip1.SuspendLayout(); this.SuspendLayout(); // // tabControl1 @@ -366,6 +365,30 @@ private void InitializeComponent() this.gridUnityList.TabIndex = 10; this.gridUnityList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.unityGridView_KeyDown); // + // _unityVersion + // + this._unityVersion.HeaderText = "Version"; + this._unityVersion.MinimumWidth = 150; + this._unityVersion.Name = "_unityVersion"; + this._unityVersion.ReadOnly = true; + this._unityVersion.Width = 150; + // + // _unityPath + // + this._unityPath.HeaderText = "Path"; + this._unityPath.MinimumWidth = 300; + this._unityPath.Name = "_unityPath"; + this._unityPath.ReadOnly = true; + this._unityPath.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this._unityPath.Width = 300; + // + // _unityInstallDate + // + this._unityInstallDate.HeaderText = "Installed"; + this._unityInstallDate.Name = "_unityInstallDate"; + this._unityInstallDate.ReadOnly = true; + this._unityInstallDate.Width = 150; + // // tabPackages // this.tabPackages.Controls.Add(this.btnAddAssetStoreFolder); @@ -807,7 +830,7 @@ private void InitializeComponent() this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(135, 22); + this.statusStrip1.Size = new System.Drawing.Size(150, 22); this.statusStrip1.TabIndex = 7; this.statusStrip1.Text = "statusStrip1"; // @@ -817,30 +840,6 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // - // _unityVersion - // - this._unityVersion.HeaderText = "Version"; - this._unityVersion.MinimumWidth = 150; - this._unityVersion.Name = "_unityVersion"; - this._unityVersion.ReadOnly = true; - this._unityVersion.Width = 150; - // - // _unityPath - // - this._unityPath.HeaderText = "Path"; - this._unityPath.MinimumWidth = 300; - this._unityPath.Name = "_unityPath"; - this._unityPath.ReadOnly = true; - this._unityPath.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._unityPath.Width = 300; - // - // _unityInstallDate - // - this._unityInstallDate.HeaderText = "Installed"; - this._unityInstallDate.Name = "_unityInstallDate"; - this._unityInstallDate.ReadOnly = true; - this._unityInstallDate.Width = 150; - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -854,7 +853,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Hubs Edition 18"; + this.Text = "UnityLauncher - Too Sunny Edition 19"; this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); @@ -871,8 +870,6 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).EndInit(); this.tabSettings.ResumeLayout(false); this.tabSettings.PerformLayout(); - this.statusStrip1.ResumeLayout(false); - this.statusStrip1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 9f32c4f..211478a 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -9,6 +9,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; +using UnityLauncherTools; namespace UnityLauncher { @@ -33,19 +34,18 @@ private void Form1_Load(object sender, EventArgs e) void Start() { SetStatus("Initializing.."); - // check installations folder - var root = GetRootFolder(); + var root = GetUnityInstallationsRootFolder(); if (root == null || root.Length == 0) { SetStatus("Missing root folder.."); - AddRootFolder(); + AddUnityInstallationRootFolder(); SetStatus("Ready"); } LoadSettings(); - // scan installed unitys, TODO: could cache results, at least fileinfo's + // scan installed unitys bool foundedUnitys = ScanUnityInstallations(); if (foundedUnitys == false) { @@ -65,7 +65,7 @@ void Start() SetStatus("Launching from commandline.."); var projectPathArgument = args[2]; - var version = GetProjectVersion(projectPathArgument); + var version = Tools.GetProjectVersion(projectPathArgument); // try launching it LaunchProject(projectPathArgument, version, true); @@ -89,6 +89,7 @@ void Start() // preselect grid gridRecent.Select(); + // subscribe to columnwidthchange event, so that can save column sizes this.gridRecent.ColumnWidthChanged += new System.Windows.Forms.DataGridViewColumnEventHandler(this.gridRecent_ColumnWidthChanged); } @@ -140,85 +141,7 @@ bool HaveExactVersionInstalled(string version) } - /// - /// parse project version from ProjectSettings data - /// - /// project base path - /// - string GetProjectVersion(string path) - { - var version = ""; - if (Directory.Exists(Path.Combine(path, "ProjectSettings"))) - { - var versionPath = Path.Combine(path, "ProjectSettings", "ProjectVersion.txt"); - if (File.Exists(versionPath) == true) // 5.x and later - { - var data = File.ReadAllLines(versionPath); - - if (data != null && data.Length > 0) - { - var dd = data[0]; - // check first line - if (dd.Contains("m_EditorVersion")) - { - var t = dd.Split(new string[] { "m_EditorVersion: " }, StringSplitOptions.None); - if (t != null && t.Length > 0) - { - version = t[1].Trim(); - } - else - { - throw new InvalidDataException("invalid version data:" + data); - } - } - else - { - MessageBox.Show("Cannot find m_EditorVersion in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); - } - } - else - { - MessageBox.Show("Invalid projectversion data found in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); - } - } - else // maybe its 4.x - { - versionPath = Path.Combine(path, "ProjectSettings", "ProjectSettings.asset"); - if (File.Exists(versionPath) == true) - { - // first try if its ascii format - var data = File.ReadAllLines(versionPath); - if (data != null && data.Length > 0 && data[0].IndexOf("YAML") > -1) - { - // in text format, then we need to try library file instead - var newVersionPath = Path.Combine(path, "Library", "AnnotationManager"); - if (File.Exists(versionPath) == true) - { - versionPath = newVersionPath; - } - } - - // try to get version data out from binary asset - var binData = File.ReadAllBytes(versionPath); - if (binData != null && binData.Length > 0) - { - int dataLen = 7; - int startIndex = 20; - var bytes = new byte[dataLen]; - for (int i = 0; i < dataLen; i++) - { - bytes[i] = binData[startIndex + i]; - } - version = Encoding.UTF8.GetString(bytes); - } - } - } - } - return version; - } - - - void AddRootFolder() + void AddUnityInstallationRootFolder() { folderBrowserDialog1.Description = "Select root folder"; var d = folderBrowserDialog1.ShowDialog(); @@ -245,7 +168,6 @@ bool ScanUnityInstallations() // iterate all root folders foreach (string root in lstRootFolders.Items) { - // var root = GetRootFolder(); if (String.IsNullOrWhiteSpace(root) == false && Directory.Exists(root) == true) { // parse all folders here, and search for unity editor files @@ -258,12 +180,12 @@ bool ScanUnityInstallations() var unityExe = Path.Combine(directories[i], "Editor", "Unity.exe"); if (File.Exists(uninstallExe) == true) { - var unityVersion = GetUnityVersion(uninstallExe).Replace("Unity", "").Trim(); + var unityVersion = Tools.GetFileVersionData(uninstallExe).Replace("Unity", "").Trim(); if (unityList.ContainsKey(unityVersion) == false) { unityList.Add(unityVersion, unityExe); var dataFolder = Path.Combine(directories[i], "Editor", "Data"); - DateTime? installDate = GetLastModifiedTime(dataFolder); + DateTime? installDate = Tools.GetLastModifiedTime(dataFolder); gridUnityList.Rows.Add(unityVersion, unityExe, installDate); } } // have unity.exe @@ -282,13 +204,6 @@ bool ScanUnityInstallations() } - private string GetUnityVersion(string path) - { - // todo check path - FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(path); - return fvi.ProductName.Replace("(64-bit)", "").Trim(); - } - void FilterRecentProject(object sender, EventArgs e) { SetStatus("Filtering recent projects list.."); @@ -373,23 +288,23 @@ void UpdateRecentProjectsList() } // get last modified date - DateTime? lastUpdated = GetLastModifiedTime(csprojFile); + DateTime? lastUpdated = Tools.GetLastModifiedTime(csprojFile); // get project version - string projectVersion = GetProjectVersion(projectPath); + string projectVersion = Tools.GetProjectVersion(projectPath); // get custom launch arguments, only if column in enabled string customArgs = ""; if (chkShowLauncherArgumentsColumn.Checked == true) { - customArgs = ReadCustomLaunchArguments(projectPath); + customArgs = Tools.ReadCustomLaunchArguments(projectPath, launcherArgumentsFile); } // get git branchinfo, only if column in enabled string gitBranch = ""; if (chkShowGitBranchColumn.Checked == true) { - gitBranch = ReadGitBranchInfo(projectPath); + gitBranch = Tools.ReadGitBranchInfo(projectPath); } gridRecent.Rows.Add(projectName, projectVersion, projectPath, lastUpdated, customArgs, gitBranch); @@ -400,20 +315,6 @@ void UpdateRecentProjectsList() SetStatus("Ready"); } - DateTime? GetLastModifiedTime(string path) - { - if (File.Exists(path) == true || Directory.Exists(path) == true) - { - DateTime modification = File.GetLastWriteTime(path); - //return modification.ToShortDateString(); - return modification; - } - else - { - return null; - } - } - void LaunchProject(string projectPath, string version, bool openProject = true) { if (Directory.Exists(projectPath) == true) @@ -543,41 +444,16 @@ string GetDownloadUrlForUnityVersion(string releaseUrl) } /// - /// downloads unity installer and launches it + /// launches browser to download installer /// - /// - void DownloadAndRun(string url) + /// full url to installer + void DownloadInBrowser(string url) { string exeURL = GetDownloadUrlForUnityVersion(url); - if (string.IsNullOrEmpty(exeURL) == false) { - SetStatus("Download installer: " + exeURL); - // download temp file - using (WebClient downloader = new WebClient()) - { - var f = GetFileNameFromUrl(exeURL); - FileInfo fileInfo = new FileInfo(f); - downloader.DownloadFile(exeURL, f); - if (File.Exists(fileInfo.FullName)) - { - SetStatus("Running installer"); - try - { - Process myProcess = new Process(); - myProcess.StartInfo.FileName = fileInfo.FullName; - myProcess.Start(); - myProcess.WaitForExit(); - } - catch (Exception ex) - { - Console.WriteLine(ex); - SetStatus("Failed running installer"); - } - - } - } - SetStatus("Finished Running installer"); + SetStatus("Download installer in browser: " + exeURL); + Process.Start(exeURL); } else // not found { @@ -586,23 +462,11 @@ void DownloadAndRun(string url) } } - /// - /// parse unity installer filename from url - /// - /// - /// - string GetFileNameFromUrl(string url) - { - var uri = new Uri(url); - var filename = uri.Segments.Last(); - return filename; - } - /// /// get rootfolder from settings, default is c:\program files\ /// /// - string[] GetRootFolder() + string[] GetUnityInstallationsRootFolder() { string[] rootFolders = null; try @@ -613,7 +477,6 @@ string[] GetRootFolder() } catch (Exception e) { - Console.WriteLine(e); // this doesnt work? Properties.Settings.Default.Reset(); Properties.Settings.Default.Save(); @@ -621,22 +484,6 @@ string[] GetRootFolder() return rootFolders; } - /// - /// launch windows explorer to selected project folder - /// - /// - void LaunchExplorer(string folder) - { - if (Directory.Exists(folder) == true) - { - Process.Start(folder); - } - else - { - SetStatus("Error> Directory not found: " + folder); - } - } - void SetStatus(string msg) { toolStripStatusLabel1.Text = msg; @@ -658,7 +505,7 @@ void LaunchSelectedProject(bool openProject = true) { SetStatus("Launching project.."); var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); - var version = GetProjectVersion(projectPath); + var version = Tools.GetProjectVersion(projectPath); LaunchProject(projectPath, version, openProject); SetStatus("Ready"); } @@ -688,26 +535,6 @@ void LaunchSelectedUnity() } } - - string GetUnityReleaseURL(string version) - { - string url = ""; - if (version.Contains("f")) // archived - { - version = Regex.Replace(version, @"f.", "", RegexOptions.IgnoreCase); - url = "https://unity3d.com/unity/whats-new/unity-" + version; - } - if (version.Contains("p")) // patch version - { - url = "https://unity3d.com/unity/qa/patch-releases/" + version; - } - if (version.Contains("b")) // beta version - { - url = "https://unity3d.com/unity/beta/unity" + version; - } - return url; - } - void AddPackageFolder() { folderBrowserDialog1.Description = "Select package folder"; @@ -722,59 +549,12 @@ void AddPackageFolder() } } - void AddContextMenuRegistry() - { - RegistryKey key = Registry.CurrentUser.OpenSubKey(contextRegRoot, true); - if (key != null) - { - var appName = "UnityLauncher"; - key.CreateSubKey(appName); - - key = key.OpenSubKey(appName, true); - key.SetValue("", "Open with UnityLauncher"); - key.SetValue("Icon", "\"" + Application.ExecutablePath + "\""); - - key.CreateSubKey("command"); - key = key.OpenSubKey("command", true); - var executeString = "\"" + Application.ExecutablePath + "\""; - executeString += " -projectPath \"%V\""; - key.SetValue("", executeString); - SetStatus("Added context menu registry items"); - } - else - { - SetStatus("Error> Cannot find registry key: " + contextRegRoot); - } - } - - void RemoveContextMenuRegistry() - { - RegistryKey key = Registry.CurrentUser.OpenSubKey(contextRegRoot, true); - if (key != null) - { - var appName = "UnityLauncher"; - RegistryKey appKey = Registry.CurrentUser.OpenSubKey(contextRegRoot + "\\" + appName, false); - if (appKey != null) - { - key.DeleteSubKeyTree(appName); - SetStatus("Removed context menu registry items"); - } - else - { - SetStatus("Nothing to uninstall.."); - } - } - else - { - SetStatus("Error> Cannot find registry key: " + contextRegRoot); - } - } #region Buttons and UI events private void btnRemoveRegister_Click(object sender, EventArgs e) { - RemoveContextMenuRegistry(); + Tools.RemoveContextMenuRegistry(contextRegRoot); } private void chkMinimizeToTaskbar_CheckedChanged(object sender, EventArgs e) @@ -804,7 +584,14 @@ private void btnOpenReleasePage_Click(object sender, EventArgs e) if (selected > -1) { var version = gridUnityList.Rows[selected].Cells["_unityVersion"].Value.ToString(); - OpenReleaseNotes(version); + if (Tools.OpenReleaseNotes(version) == true) + { + SetStatus("Opening release notes for version " + version); + } + else + { + SetStatus("Failed opening Release Notes URL for version " + version); + } } } @@ -819,13 +606,16 @@ private void btnExploreUnity_Click(object sender, EventArgs e) if (selected > -1) { var unityPath = Path.GetDirectoryName(gridUnityList.Rows[selected].Cells["_unityPath"].Value.ToString()); - LaunchExplorer(unityPath); + if (Tools.LaunchExplorer(unityPath) == false) + { + SetStatus("Error> Directory not found: " + unityPath); + } } } private void btnAddUnityFolder_Click(object sender, EventArgs e) { - AddRootFolder(); + AddUnityInstallationRootFolder(); ScanUnityInstallations(); } @@ -932,7 +722,7 @@ private void GridRecent_CellMouseDoubleClick(object sender, DataGridViewCellMous // set basefolder of all unity installations private void btn_setinstallfolder_Click(object sender, EventArgs e) { - AddRootFolder(); + AddUnityInstallationRootFolder(); ScanUnityInstallations(); UpdateRecentProjectsList(); } @@ -973,7 +763,11 @@ private void btn_openFolder_Click(object sender, EventArgs e) var selected = gridRecent.CurrentCell.RowIndex; if (selected > -1) { - LaunchExplorer(gridRecent.Rows[selected].Cells["_path"].Value.ToString()); + string folder = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); + if (Tools.LaunchExplorer(folder) == false) + { + SetStatus("Error> Directory not found: " + folder); + } } } @@ -983,8 +777,11 @@ private void btnExplorePackageFolder_Click(object sender, EventArgs e) //Console.WriteLine(lstPackageFolders.Items[selected].ToString()); if (selected > -1) { - var path = lstPackageFolders.Items[selected].ToString(); - LaunchExplorer(path); + string folder = lstPackageFolders.Items[selected].ToString(); + if (Tools.LaunchExplorer(folder) == false) + { + SetStatus("Error> Directory not found: " + folder); + } } } @@ -1004,7 +801,7 @@ private void btnAddAssetStoreFolder_Click(object sender, EventArgs e) private void btnAddRegister_Click(object sender, EventArgs e) { - AddContextMenuRegistry(); + Tools.AddContextMenuRegistry(contextRegRoot); } private void ChkQuitAfterOpen_CheckedChanged(object sender, EventArgs e) @@ -1032,10 +829,12 @@ private void btnUpgradeProject_Click(object sender, EventArgs e) private void btnOpenLogFolder_Click(object sender, EventArgs e) { var logfolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Unity", "Editor"); - //Console.WriteLine(logfolder); if (Directory.Exists(logfolder) == true) { - LaunchExplorer(logfolder); + if (Tools.LaunchExplorer(logfolder) == false) + { + SetStatus("Error> Directory not found: " + logfolder); + } } } @@ -1065,7 +864,7 @@ private void btnOpenUpdateWebsite_Click(object sender, EventArgs e) if (selected != null && selected > -1) { var version = gridUnityUpdates.Rows[(int)selected].Cells["_UnityUpdateVersion"].Value.ToString(); - OpenReleaseNotes(version); + Tools.OpenReleaseNotes(version); } } @@ -1107,66 +906,54 @@ private void checkShowGitBranchColumn_CheckedChanged(object sender, EventArgs e) if (chkShowGitBranchColumn.Checked == true) UpdateRecentProjectsList(); } + private void linkArgumentsDocs_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - OpenURL("https://docs.unity3d.com/Manual/CommandLineArguments.html"); + Tools.OpenURL("https://docs.unity3d.com/Manual/CommandLineArguments.html"); } private void linkProjectGithub_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - OpenURL("https://github.com/unitycoder/UnityLauncher/releases"); + Tools.OpenURL("https://github.com/unitycoder/UnityLauncher/releases"); } - #endregion UI events - - - void OpenReleaseNotes(string version) + // after editing launch arguments cell + private void gridRecent_CellEndEdit(object sender, DataGridViewCellEventArgs e) { - SetStatus("Opening release notes for version " + version); - var url = GetUnityReleaseURL(version); - if (string.IsNullOrEmpty(url) == false) - { - Process.Start(url); - } - else - { - SetStatus("Failed opening Release Notes URL for version " + version); - } - } + string path = GetSelectedRowData("_path"); + if (string.IsNullOrEmpty(path)) return; - public static string FindNearestVersion(string version, List allAvailable) - { - if (version.Contains("2017")) + string arguments = GetSelectedRowData("_launchArguments"); + + // check folder first + string outputFolder = Path.Combine(path, "ProjectSettings"); + if (Directory.Exists(outputFolder) == false) { - return FindNearestVersionFromSimilarVersions(version, allAvailable.Where(x => x.Contains("2017"))); + Directory.CreateDirectory(outputFolder); } - return FindNearestVersionFromSimilarVersions(version, allAvailable.Where(x => !x.Contains("2017"))); - } - private static string FindNearestVersionFromSimilarVersions(string version, IEnumerable allAvailable) - { - Dictionary stripped = new Dictionary(); - var enumerable = allAvailable as string[] ?? allAvailable.ToArray(); + // save arguments to projectsettings folder + string outputFile = Path.Combine(path, "ProjectSettings", launcherArgumentsFile); - foreach (var t in enumerable) + try { - stripped.Add(new Regex("[a-zA-z]").Replace(t, "."), t); + StreamWriter sw = new StreamWriter(outputFile); + sw.WriteLine(arguments); + sw.Close(); } - - var comparableVersion = new Regex("[a-zA-z]").Replace(version, "."); - if (!stripped.ContainsKey(comparableVersion)) + catch (Exception exception) { - stripped.Add(comparableVersion, version); + SetStatus("File error: " + exception.Message); } - var comparables = stripped.Keys.OrderBy(x => x).ToList(); - var actualIndex = comparables.IndexOf(comparableVersion); - - if (actualIndex < stripped.Count - 1) return stripped[comparables[actualIndex + 1]]; - return null; + // select the same row again (dont move to next), doesnt work here + // var previousRow = gridRecent.CurrentCell.RowIndex; + // gridRecent.Rows[previousRow].Selected = true; } + #endregion UI events + // displays version selector to upgrade project void UpgradeProject() { @@ -1176,7 +963,7 @@ void UpgradeProject() SetStatus("Upgrading project.."); var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); - var currentVersion = GetProjectVersion(projectPath); + var currentVersion = Tools.GetProjectVersion(projectPath); if (string.IsNullOrEmpty(currentVersion) == true) { @@ -1205,7 +992,7 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch switch (results) { case DialogResult.Ignore: // view release notes page - OpenReleaseNotes(currentVersion); + Tools.OpenReleaseNotes(currentVersion); // display window again for now.. DisplayUpgradeDialog(currentVersion, projectPath, launchProject); break; @@ -1214,10 +1001,10 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch break; case DialogResult.Retry: // download and install missing version SetStatus("Download and Install missing version " + currentVersion); - string url = GetUnityReleaseURL(currentVersion); + string url = Tools.GetUnityReleaseURL(currentVersion); if (string.IsNullOrEmpty(url) == false) { - DownloadAndRun(url); + DownloadInBrowser(url); } else { @@ -1235,7 +1022,7 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch upgradeDialog.Close(); } - void FetchListOfUnityUpdates() + private void FetchListOfUnityUpdates() { if (isDownloadUnityList == true) { @@ -1270,40 +1057,6 @@ private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedE } } - // after editing launch arguments cell - private void gridRecent_CellEndEdit(object sender, DataGridViewCellEventArgs e) - { - string path = GetSelectedRowData("_path"); - if (string.IsNullOrEmpty(path)) return; - - string arguments = GetSelectedRowData("_launchArguments"); - - // check folder first - string outputFolder = Path.Combine(path, "ProjectSettings"); - if (Directory.Exists(outputFolder) == false) - { - Directory.CreateDirectory(outputFolder); - } - - // save arguments to projectsettings folder - string outputFile = Path.Combine(path, "ProjectSettings", launcherArgumentsFile); - - try - { - StreamWriter sw = new StreamWriter(outputFile); - sw.WriteLine(arguments); - sw.Close(); - } - catch (Exception exception) - { - SetStatus("File error: " + exception.Message); - } - - // select the same row again (dont move to next), doesnt work here - // var previousRow = gridRecent.CurrentCell.RowIndex; - // gridRecent.Rows[previousRow].Selected = true; - } - // returns currently selected rows path string string GetSelectedRowData(string key) { @@ -1315,35 +1068,5 @@ string GetSelectedRowData(string key) } return path; } - - string ReadCustomLaunchArguments(string projectPath) - { - string results = null; - string argumentsFile = Path.Combine(projectPath, "ProjectSettings", launcherArgumentsFile); - if (File.Exists(argumentsFile) == true) - { - results = File.ReadAllText(argumentsFile); - } - return results; - } - - string ReadGitBranchInfo(string projectPath) - { - string results = null; - string branchFile = Path.Combine(projectPath, ".git", "HEAD"); - if (File.Exists(branchFile) == true) - { - results = File.ReadAllText(branchFile); - // get branch only - int pos = results.LastIndexOf("/") + 1; - results = results.Substring(pos, results.Length - pos); - } - return results; - } - - private void OpenURL(string url) - { - Process.Start(url); - } } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index c8f85ab..1124349 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -165,6 +165,15 @@ True + + True + + + True + + + True + True @@ -1075,15 +1084,6 @@ 374, 17 - - True - - - True - - - True - 25 diff --git a/UnityLauncher/Form2.Designer.cs b/UnityLauncher/Form2.Designer.cs index ce7d9fe..344580b 100644 --- a/UnityLauncher/Form2.Designer.cs +++ b/UnityLauncher/Form2.Designer.cs @@ -99,7 +99,7 @@ private void InitializeComponent() this.btn_GoInstallMissingVersion.Name = "btn_GoInstallMissingVersion"; this.btn_GoInstallMissingVersion.Size = new System.Drawing.Size(111, 22); this.btn_GoInstallMissingVersion.TabIndex = 6; - this.btn_GoInstallMissingVersion.Text = "Download && Install"; + this.btn_GoInstallMissingVersion.Text = "Download"; this.btn_GoInstallMissingVersion.UseVisualStyleBackColor = true; this.btn_GoInstallMissingVersion.Click += new System.EventHandler(this.btn_GoInstallMissingVersion_Click); // diff --git a/UnityLauncher/Form2.cs b/UnityLauncher/Form2.cs index 4d5e919..00ef5e4 100644 --- a/UnityLauncher/Form2.cs +++ b/UnityLauncher/Form2.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using UnityLauncherTools; namespace UnityLauncher { @@ -32,7 +33,7 @@ void Start() // show available versions, autoselect nearest one if (string.IsNullOrEmpty(currentVersion) == false) { - string nearestVersion = Form1.FindNearestVersion(currentVersion, Form1.unityList.Keys.ToList()); + string nearestVersion = Tools.FindNearestVersion(currentVersion, Form1.unityList.Keys.ToList()); //Console.WriteLine("nearest:" + nearestVersion); // preselect most likely version diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs new file mode 100644 index 0000000..c91852a --- /dev/null +++ b/UnityLauncher/Tools.cs @@ -0,0 +1,328 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace UnityLauncherTools +{ + public static class Tools + { + /// + /// open url with default browser + /// + /// + public static void OpenURL(string url) + { + Process.Start(url); + } + + /// + /// reads .git/HEAD file from the project to get current branch name + /// + /// + /// + public static string ReadGitBranchInfo(string projectPath) + { + string results = null; + string branchFile = Path.Combine(projectPath, ".git", "HEAD"); + if (File.Exists(branchFile) == true) + { + results = File.ReadAllText(branchFile); + // get branch only + int pos = results.LastIndexOf("/") + 1; + results = results.Substring(pos, results.Length - pos); + } + return results; + } + + /// + /// returns last-write-time for a file or folder + /// + /// full path to file or folder + /// + public static DateTime? GetLastModifiedTime(string path) + { + if (File.Exists(path) == true || Directory.Exists(path) == true) + { + DateTime modification = File.GetLastWriteTime(path); + return modification; + } + else + { + return null; + } + } + + /// + /// reads LauncherArguments.txt file from ProjectSettings-folder + /// + /// full project root path + /// default filename is "LauncherArguments.txt" + /// + public static string ReadCustomLaunchArguments(string projectPath, string launcherArgumentsFile) + { + string results = null; + string argumentsFile = Path.Combine(projectPath, "ProjectSettings", launcherArgumentsFile); + if (File.Exists(argumentsFile) == true) + { + results = File.ReadAllText(argumentsFile); + } + return results; + } + + /// + /// tries to find next higher version + /// + /// + /// + /// + public static string FindNearestVersion(string currentVersion, List allAvailable) + { + if (currentVersion.Contains("2017")) + { + return FindNearestVersionFromSimilarVersions(currentVersion, allAvailable.Where(x => x.Contains("2017"))); + } + return FindNearestVersionFromSimilarVersions(currentVersion, allAvailable.Where(x => !x.Contains("2017"))); + } + + private static string FindNearestVersionFromSimilarVersions(string version, IEnumerable allAvailable) + { + Dictionary stripped = new Dictionary(); + var enumerable = allAvailable as string[] ?? allAvailable.ToArray(); + + foreach (var t in enumerable) + { + stripped.Add(new Regex("[a-zA-z]").Replace(t, "."), t); + } + + var comparableVersion = new Regex("[a-zA-z]").Replace(version, "."); + if (!stripped.ContainsKey(comparableVersion)) + { + stripped.Add(comparableVersion, version); + } + + var comparables = stripped.Keys.OrderBy(x => x).ToList(); + var actualIndex = comparables.IndexOf(comparableVersion); + + if (actualIndex < stripped.Count - 1) return stripped[comparables[actualIndex + 1]]; + return null; + } + + /// + /// opens release notes url in default browser + /// + /// + /// + public static bool OpenReleaseNotes(string version) + { + bool result = false; + var url = GetUnityReleaseURL(version); + if (string.IsNullOrEmpty(url) == false) + { + Process.Start(url); + result = true; + } + else + { + } + return result; + } + + /// + /// returns release page URL to given version + /// NOTE: doesnt parse alpha versions, since they are not visible + /// + /// + /// + public static string GetUnityReleaseURL(string version) + { + string url = ""; + if (version.Contains("f")) // archived + { + version = Regex.Replace(version, @"f.", "", RegexOptions.IgnoreCase); + url = "https://unity3d.com/unity/whats-new/unity-" + version; + } + if (version.Contains("p")) // patch version + { + url = "https://unity3d.com/unity/qa/patch-releases/" + version; + } + if (version.Contains("b")) // beta version + { + url = "https://unity3d.com/unity/beta/unity" + version; + } + return url; + } + + /// + /// uninstall context menu item from registry + /// + /// + public static void RemoveContextMenuRegistry(string contextRegRoot) + { + RegistryKey key = Registry.CurrentUser.OpenSubKey(contextRegRoot, true); + if (key != null) + { + var appName = "UnityLauncher"; + RegistryKey appKey = Registry.CurrentUser.OpenSubKey(contextRegRoot + "\\" + appName, false); + if (appKey != null) + { + key.DeleteSubKeyTree(appName); + //SetStatus("Removed context menu registry items"); + } + else + { + //SetStatus("Nothing to uninstall.."); + } + } + else + { + //SetStatus("Error> Cannot find registry key: " + contextRegRoot); + } + } + + /// + /// install context menu item to registry + /// + /// + public static void AddContextMenuRegistry(string contextRegRoot) + { + RegistryKey key = Registry.CurrentUser.OpenSubKey(contextRegRoot, true); + if (key != null) + { + var appName = "UnityLauncher"; + key.CreateSubKey(appName); + + key = key.OpenSubKey(appName, true); + key.SetValue("", "Open with UnityLauncher"); + key.SetValue("Icon", "\"" + Application.ExecutablePath + "\""); + + key.CreateSubKey("command"); + key = key.OpenSubKey("command", true); + var executeString = "\"" + Application.ExecutablePath + "\""; + executeString += " -projectPath \"%V\""; + key.SetValue("", executeString); + //SetStatus("Added context menu registry items"); + } + else + { + //SetStatus("Error> Cannot find registry key: " + contextRegRoot); + } + } + + + /// + /// parse project version from ProjectSettings/ data + /// + /// project base path + /// + public static string GetProjectVersion(string path) + { + var version = ""; + if (Directory.Exists(Path.Combine(path, "ProjectSettings"))) + { + var versionPath = Path.Combine(path, "ProjectSettings", "ProjectVersion.txt"); + if (File.Exists(versionPath) == true) // 5.x and later + { + var data = File.ReadAllLines(versionPath); + + if (data != null && data.Length > 0) + { + var dd = data[0]; + // check first line + if (dd.Contains("m_EditorVersion")) + { + var t = dd.Split(new string[] { "m_EditorVersion: " }, StringSplitOptions.None); + if (t != null && t.Length > 0) + { + version = t[1].Trim(); + } + else + { + throw new InvalidDataException("invalid version data:" + data); + } + } + else + { + MessageBox.Show("Cannot find m_EditorVersion in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); + } + } + else + { + MessageBox.Show("Invalid projectversion data found in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); + } + } + else // maybe its 4.x + { + versionPath = Path.Combine(path, "ProjectSettings", "ProjectSettings.asset"); + if (File.Exists(versionPath) == true) + { + // first try if its ascii format + var data = File.ReadAllLines(versionPath); + if (data != null && data.Length > 0 && data[0].IndexOf("YAML") > -1) + { + // in text format, then we need to try library file instead + var newVersionPath = Path.Combine(path, "Library", "AnnotationManager"); + if (File.Exists(versionPath) == true) + { + versionPath = newVersionPath; + } + } + + // try to get version data out from binary asset + var binData = File.ReadAllBytes(versionPath); + if (binData != null && binData.Length > 0) + { + int dataLen = 7; + int startIndex = 20; + var bytes = new byte[dataLen]; + for (int i = 0; i < dataLen; i++) + { + bytes[i] = binData[startIndex + i]; + } + version = Encoding.UTF8.GetString(bytes); + } + } + } + } + return version; + } + + /// + /// checks file version info + /// + /// + /// + public static string GetFileVersionData(string path) + { + // TODO check if path exists + FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(path); + return fvi.ProductName.Replace("(64-bit)", "").Trim(); + } + + /// + /// launch windows explorer to selected project folder + /// + /// + public static bool LaunchExplorer(string folder) + { + bool result = false; + if (Directory.Exists(folder) == true) + { + Process.Start(folder); + result = true; + } + else + { + result = false; + } + return result; + } + + } +} diff --git a/UnityLauncher/UnityLauncher.csproj b/UnityLauncher/UnityLauncher.csproj index 890845b..e00f106 100644 --- a/UnityLauncher/UnityLauncher.csproj +++ b/UnityLauncher/UnityLauncher.csproj @@ -75,6 +75,7 @@ + Form From 3591453fddc995d4f4e5459811e7b141f46576fe Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sat, 17 Feb 2018 18:12:32 +0800 Subject: [PATCH 34/81] add update checker (from Settings tab, Check Updates button), add prebuild event script to fetch latest release into PreviousVersion.txt file, fix missing status label --- UnityLauncher/Form1.Designer.cs | 31 ++++++++++++++++------ UnityLauncher/Form1.cs | 41 +++++++++++++++++++++++++++-- UnityLauncher/PreviousVersion.txt | Bin 0 -> 14 bytes UnityLauncher/Tools.cs | 35 ++++++++++++++++++++++++ UnityLauncher/UnityLauncher.csproj | 4 +++ 5 files changed, 101 insertions(+), 10 deletions(-) create mode 100644 UnityLauncher/PreviousVersion.txt diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 808eaf8..f24ae44 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -92,6 +92,7 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.btnCheckUpdates = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -556,6 +557,7 @@ private void InitializeComponent() // // tabSettings // + this.tabSettings.Controls.Add(this.btnCheckUpdates); this.tabSettings.Controls.Add(this.linkProjectGithub); this.tabSettings.Controls.Add(this.linkArgumentsDocs); this.tabSettings.Controls.Add(this.chkShowGitBranchColumn); @@ -588,7 +590,7 @@ private void InitializeComponent() this.linkProjectGithub.AutoSize = true; this.linkProjectGithub.LinkArea = new System.Windows.Forms.LinkArea(20, 6); this.linkProjectGithub.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline; - this.linkProjectGithub.Location = new System.Drawing.Point(439, 532); + this.linkProjectGithub.Location = new System.Drawing.Point(434, 532); this.linkProjectGithub.Name = "linkProjectGithub"; this.linkProjectGithub.Size = new System.Drawing.Size(138, 17); this.linkProjectGithub.TabIndex = 39; @@ -663,9 +665,9 @@ private void InitializeComponent() // btnOpenLogFolder // this.btnOpenLogFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnOpenLogFolder.Location = new System.Drawing.Point(435, 285); + this.btnOpenLogFolder.Location = new System.Drawing.Point(453, 285); this.btnOpenLogFolder.Name = "btnOpenLogFolder"; - this.btnOpenLogFolder.Size = new System.Drawing.Size(137, 23); + this.btnOpenLogFolder.Size = new System.Drawing.Size(119, 23); this.btnOpenLogFolder.TabIndex = 32; this.btnOpenLogFolder.Text = "Open Editor Log Folder"; this.btnOpenLogFolder.UseVisualStyleBackColor = true; @@ -776,7 +778,7 @@ private void InitializeComponent() this.lstRootFolders.FormattingEnabled = true; this.lstRootFolders.Location = new System.Drawing.Point(20, 31); this.lstRootFolders.Name = "lstRootFolders"; - this.lstRootFolders.Size = new System.Drawing.Size(552, 186); + this.lstRootFolders.Size = new System.Drawing.Size(563, 186); this.lstRootFolders.TabIndex = 20; // // lbl_unityCount @@ -784,7 +786,7 @@ private void InitializeComponent() this.lbl_unityCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.lbl_unityCount.AutoSize = true; this.lbl_unityCount.Enabled = false; - this.lbl_unityCount.Location = new System.Drawing.Point(472, 15); + this.lbl_unityCount.Location = new System.Drawing.Point(483, 15); this.lbl_unityCount.Name = "lbl_unityCount"; this.lbl_unityCount.Size = new System.Drawing.Size(97, 13); this.lbl_unityCount.TabIndex = 18; @@ -793,9 +795,9 @@ private void InitializeComponent() // btnRefresh // this.btnRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnRefresh.Location = new System.Drawing.Point(435, 223); + this.btnRefresh.Location = new System.Drawing.Point(453, 223); this.btnRefresh.Name = "btnRefresh"; - this.btnRefresh.Size = new System.Drawing.Size(137, 23); + this.btnRefresh.Size = new System.Drawing.Size(119, 23); this.btnRefresh.TabIndex = 19; this.btnRefresh.Text = "Refresh Unity List"; this.toolTip1.SetToolTip(this.btnRefresh, "Refresh Unity Installations List"); @@ -825,12 +827,13 @@ private void InitializeComponent() // // statusStrip1 // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.toolStripStatusLabel1}); this.statusStrip1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(150, 22); + this.statusStrip1.Size = new System.Drawing.Size(202, 22); this.statusStrip1.TabIndex = 7; this.statusStrip1.Text = "statusStrip1"; // @@ -840,6 +843,17 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // + // btnCheckUpdates + // + this.btnCheckUpdates.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnCheckUpdates.Location = new System.Drawing.Point(434, 495); + this.btnCheckUpdates.Name = "btnCheckUpdates"; + this.btnCheckUpdates.Size = new System.Drawing.Size(138, 23); + this.btnCheckUpdates.TabIndex = 40; + this.btnCheckUpdates.Text = "Check Updates"; + this.btnCheckUpdates.UseVisualStyleBackColor = true; + this.btnCheckUpdates.Click += new System.EventHandler(this.btnCheckUpdates_Click); + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -938,6 +952,7 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn _unityVersion; private System.Windows.Forms.DataGridViewTextBoxColumn _unityPath; private System.Windows.Forms.DataGridViewTextBoxColumn _unityInstallDate; + private System.Windows.Forms.Button btnCheckUpdates; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 211478a..80a0614 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Net; +using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; @@ -17,8 +18,12 @@ public partial class Form1 : Form { public static Dictionary unityList = new Dictionary(); const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; - bool isDownloadUnityList = false; const string launcherArgumentsFile = "LauncherArguments.txt"; + const string githubReleaseCheckURL = "https://api.github.com/repos/unitycoder/unitylauncher/releases/latest"; + const string githubReleasesURL = "https://github.com/unitycoder/UnityLauncher/releases"; + + bool isDownloadUnityList = false; + string previousGitRelease = null; public Form1() @@ -91,6 +96,15 @@ void Start() // subscribe to columnwidthchange event, so that can save column sizes this.gridRecent.ColumnWidthChanged += new System.Windows.Forms.DataGridViewColumnEventHandler(this.gridRecent_ColumnWidthChanged); + + + // get previous version build info string + // this string is release tag for latest release when this app was compiled + using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("UnityLauncher." + "PreviousVersion.txt")) + using (StreamReader reader = new StreamReader(stream)) + { + previousGitRelease = reader.ReadToEnd().Trim(); + } } void LoadSettings() @@ -952,6 +966,11 @@ private void gridRecent_CellEndEdit(object sender, DataGridViewCellEventArgs e) // gridRecent.Rows[previousRow].Selected = true; } + private void btnCheckUpdates_Click(object sender, EventArgs e) + { + CheckUpdates(); + } + #endregion UI events // displays version selector to upgrade project @@ -1068,5 +1087,23 @@ string GetSelectedRowData(string key) } return path; } + + void CheckUpdates() + { + var result = Tools.CheckUpdates(githubReleaseCheckURL, previousGitRelease); + if (string.IsNullOrEmpty(result) == false) + { + SetStatus("Update available: " + result); + DialogResult dialogResult = MessageBox.Show("Update " + result + " is available, open download page?", "UnityLauncher - Check Update", MessageBoxButtons.YesNo); + if (dialogResult == DialogResult.Yes) // open download page + { + Tools.OpenURL(githubReleasesURL); + } + } + else + { + SetStatus("No updates available.."); + } + } } -} +} \ No newline at end of file diff --git a/UnityLauncher/PreviousVersion.txt b/UnityLauncher/PreviousVersion.txt new file mode 100644 index 0000000000000000000000000000000000000000..05bfbacb238bae1999d50e661a812838b225ed70 GIT binary patch literal 14 VcmezW&yYcn!H~g%ftP`c0RSQ%0^I-r literal 0 HcmV?d00001 diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index c91852a..2db0222 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -324,5 +325,39 @@ public static bool LaunchExplorer(string folder) return result; } + public static string CheckUpdates(string githubReleaseURL, string previousGitRelease) + { + string result = null; + using (WebClient client = new WebClient()) + { + client.Headers.Add("user-agent", "MuskBrowser"); + string json = client.DownloadString(githubReleaseURL); + var arr = json.Split(new string[] { "\"tag_name\":" }, StringSplitOptions.None); + + // have tagname + if (arr.Length > 1) + { + var arr2 = arr[1].Trim().Split('"'); + // have " + if (arr2.Length > 1) + { + var currentlyAvailableLatestReleaseTag = arr2[1]; + // compare with this build release version + if (currentlyAvailableLatestReleaseTag != previousGitRelease) + { + result = currentlyAvailableLatestReleaseTag; + Console.WriteLine("update available: [" + currentlyAvailableLatestReleaseTag + "] / [" + previousGitRelease + "]"); + } + else + { + Console.WriteLine("no update available: [" + currentlyAvailableLatestReleaseTag + "] / [" + previousGitRelease + "]"); + } + } + } + } + return result; + } + + } } diff --git a/UnityLauncher/UnityLauncher.csproj b/UnityLauncher/UnityLauncher.csproj index e00f106..b2b7a49 100644 --- a/UnityLauncher/UnityLauncher.csproj +++ b/UnityLauncher/UnityLauncher.csproj @@ -127,7 +127,11 @@ + + + powershell.exe -command "$web = New-Object System.Net.WebClient;$web.Headers['User-Agent'] = 'DefinitelyBrowser';$results = $web.DownloadString('https://api.github.com/repos/unitycoder/unitylauncher/releases/latest');$results = $results | ConvertFrom-Json;$results = $results | select -expand tag_name;echo $results | Out-File $(ProjectDir)PreviousVersion.txt;" + \ No newline at end of file From e51c8155cc1a5835f128aa7307154a86671ea5c0 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sat, 17 Feb 2018 22:44:46 +0800 Subject: [PATCH 35/81] pass all arguments to launcher when running from commandline --- UnityLauncher/Form1.cs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 80a0614..4add1a0 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -64,24 +64,34 @@ void Start() string[] args = Environment.GetCommandLineArgs(); if (args != null && args.Length > 2) { + // first argument needs to be -projectPath var commandLineArgs = args[1]; if (commandLineArgs == "-projectPath") { SetStatus("Launching from commandline.."); + // path var projectPathArgument = args[2]; + var version = Tools.GetProjectVersion(projectPathArgument); - // try launching it - LaunchProject(projectPathArgument, version, true); + // take extra arguments also + var commandLineArguments = ""; + for (int i = 3, len = args.Length; i < len; i++) + { + commandLineArguments += " " + args[i]; + } - SetStatus("Ready"); + // try launching it + LaunchProject(projectPathArgument, version, openProject: true, commandLineArguments: commandLineArguments); // quit after launch if enabled in settings if (Properties.Settings.Default.closeAfterExplorer == true) { Application.Exit(); } + + SetStatus("Ready"); } else { @@ -329,7 +339,7 @@ void UpdateRecentProjectsList() SetStatus("Ready"); } - void LaunchProject(string projectPath, string version, bool openProject = true) + void LaunchProject(string projectPath, string version, bool openProject = true, string commandLineArguments = "") { if (Directory.Exists(projectPath) == true) { @@ -372,7 +382,7 @@ void LaunchProject(string projectPath, string version, bool openProject = true) pars += " " + customArguments; } - myProcess.StartInfo.Arguments = pars; + myProcess.StartInfo.Arguments = pars + commandLineArguments; } myProcess.Start(); From a5731f8b794e2105421cf681802717c4ca690098 Mon Sep 17 00:00:00 2001 From: mika Date: Sun, 18 Feb 2018 14:07:41 +0800 Subject: [PATCH 36/81] Update README.md --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9439b52..5160a27 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,17 @@ # UnityLauncher -Autotically launch projects with correct Unity versions and some extra features to manager your projects and Unity versions! +Handle all your Unity versions and Projects easily! # Features - Automagically Open Projects with Correct Unity Version -- Display Recent Projects list with last modified date and Unity version info +- Display Recent Projects list with last modified date and project version info - Quickly Explore Project Folder - List installed Unity versions, can easily Run, Explore installation folder, View release notes - Download Missing Unity Versions Easily -- Can be used in commandline `UnityLauncher.exe -projectPath "c:/project/path/"` +- Can be used from commandline `UnityLauncher.exe -projectPath "c:/project/path/"` - Can add custom Explorer context menu item to launch folder as a project: https://github.com/unitycoder/UnityLauncher/wiki/Adding-Explorer-Context-Menu +- Use custom launcher arguments per project! +- Show project git branch info - List of custom package folders (quicly explore them and then can import packages) - Show list of available Unity versions/updates From 96b1a3815e655e96371ee9649851793c12c9a26d Mon Sep 17 00:00:00 2001 From: unitycoder Date: Wed, 21 Feb 2018 20:49:59 +0800 Subject: [PATCH 37/81] adjust statusbar texts fixes #37, compare version numbers, if difference is more than 0.1 then show update available fixes #38, clear folder list when loading settings fixes#39 --- UnityLauncher/Form1.cs | 22 ++++++++++++++-------- UnityLauncher/PreviousVersion.txt | Bin 14 -> 14 bytes UnityLauncher/Tools.cs | 12 ++++++++++-- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 4add1a0..da10141 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -19,7 +19,7 @@ public partial class Form1 : Form public static Dictionary unityList = new Dictionary(); const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; const string launcherArgumentsFile = "LauncherArguments.txt"; - const string githubReleaseCheckURL = "https://api.github.com/repos/unitycoder/unitylauncher/releases/latest"; + const string githubReleaseAPICheckURL = "https://api.github.com/repos/unitycoder/unitylauncher/releases/latest"; const string githubReleasesURL = "https://github.com/unitycoder/UnityLauncher/releases"; bool isDownloadUnityList = false; @@ -135,6 +135,7 @@ void LoadSettings() gridRecent.Columns["_gitBranch"].Visible = chkShowGitBranchColumn.Checked; // update installations folder listbox + lstRootFolders.Items.Clear(); lstRootFolders.Items.AddRange(Properties.Settings.Default.rootFolders.Cast().ToArray()); // update packages folder listbox lstPackageFolders.Items.AddRange(Properties.Settings.Default.packageFolders.Cast().ToArray()); @@ -167,7 +168,7 @@ bool HaveExactVersionInstalled(string version) void AddUnityInstallationRootFolder() { - folderBrowserDialog1.Description = "Select root folder"; + folderBrowserDialog1.Description = "Select Unity installations root folder"; var d = folderBrowserDialog1.ShowDialog(); var newRoot = folderBrowserDialog1.SelectedPath; @@ -363,8 +364,14 @@ void LaunchProject(string projectPath, string version, bool openProject = true, if (HaveExactVersionInstalled(version) == true) { - //Console.WriteLine("Opening unity version " + version); - SetStatus("Launching project in unity " + version); + if (openProject == true) + { + SetStatus("Launching project in Unity " + version); + } + else + { + SetStatus("Launching Unity " + version); + } try { @@ -527,7 +534,6 @@ void LaunchSelectedProject(bool openProject = true) var selected = gridRecent.CurrentCell.RowIndex; if (selected > -1) { - SetStatus("Launching project.."); var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); var version = Tools.GetProjectVersion(projectPath); LaunchProject(projectPath, version, openProject); @@ -1100,10 +1106,10 @@ string GetSelectedRowData(string key) void CheckUpdates() { - var result = Tools.CheckUpdates(githubReleaseCheckURL, previousGitRelease); + var result = Tools.CheckUpdates(githubReleaseAPICheckURL, previousGitRelease); if (string.IsNullOrEmpty(result) == false) { - SetStatus("Update available: " + result); + SetStatus("Update available: " + result + " - Previous release was:" + previousGitRelease); DialogResult dialogResult = MessageBox.Show("Update " + result + " is available, open download page?", "UnityLauncher - Check Update", MessageBoxButtons.YesNo); if (dialogResult == DialogResult.Yes) // open download page { @@ -1112,7 +1118,7 @@ void CheckUpdates() } else { - SetStatus("No updates available.."); + SetStatus("No updates available. Current release is " + previousGitRelease); } } } diff --git a/UnityLauncher/PreviousVersion.txt b/UnityLauncher/PreviousVersion.txt index 05bfbacb238bae1999d50e661a812838b225ed70..38f4de6527cc9870d524596a07ea91fcd73ff27e 100644 GIT binary patch literal 14 VcmezW&yYcn!H~g{ftP`c0RSQ-0^R@s literal 14 VcmezW&yYcn!H~g%ftP`c0RSQ%0^I-r diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index 2db0222..ae95aed 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -325,11 +325,18 @@ public static bool LaunchExplorer(string folder) return result; } + /// + /// + /// + /// api to check releases + /// embedded previous release version + /// null if no info available, otherwise returns current github release number public static string CheckUpdates(string githubReleaseURL, string previousGitRelease) { string result = null; using (WebClient client = new WebClient()) { + // fetch current release info client.Headers.Add("user-agent", "MuskBrowser"); string json = client.DownloadString(githubReleaseURL); var arr = json.Split(new string[] { "\"tag_name\":" }, StringSplitOptions.None); @@ -342,8 +349,9 @@ public static string CheckUpdates(string githubReleaseURL, string previousGitRel if (arr2.Length > 1) { var currentlyAvailableLatestReleaseTag = arr2[1]; - // compare with this build release version - if (currentlyAvailableLatestReleaseTag != previousGitRelease) + // compare online version with build in release version, return github version if different from embedded version + if (Math.Abs(float.Parse(currentlyAvailableLatestReleaseTag)-float.Parse(previousGitRelease))>0.1f) +// if (currentlyAvailableLatestReleaseTag != previousGitRelease) { result = currentlyAvailableLatestReleaseTag; Console.WriteLine("update available: [" + currentlyAvailableLatestReleaseTag + "] / [" + previousGitRelease + "]"); From 953ecf7a07b7fc81b37be9780f3ba1911cbd6a1a Mon Sep 17 00:00:00 2001 From: unitycoder Date: Fri, 23 Feb 2018 20:25:32 +0800 Subject: [PATCH 38/81] add more error checking to update checker, use TLS12 (suddenly windows requires it), update powershell script to use TLS12 also, --- UnityLauncher/Form1.Designer.cs | 29 ++++++++++++++++------------- UnityLauncher/Form1.cs | 7 +++---- UnityLauncher/Tools.cs | 20 +++++++++++++++++--- UnityLauncher/UnityLauncher.csproj | 2 +- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index f24ae44..0df5225 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -67,6 +67,7 @@ private void InitializeComponent() this._Date = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._UnityUpdateVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabSettings = new System.Windows.Forms.TabPage(); + this.btnCheckUpdates = new System.Windows.Forms.Button(); this.linkProjectGithub = new System.Windows.Forms.LinkLabel(); this.linkArgumentsDocs = new System.Windows.Forms.LinkLabel(); this.chkShowGitBranchColumn = new System.Windows.Forms.CheckBox(); @@ -92,7 +93,6 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this.btnCheckUpdates = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -102,6 +102,7 @@ private void InitializeComponent() this.tabUpdates.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).BeginInit(); this.tabSettings.SuspendLayout(); + this.statusStrip1.SuspendLayout(); this.SuspendLayout(); // // tabControl1 @@ -584,6 +585,17 @@ private void InitializeComponent() this.tabSettings.Text = "Settings"; this.tabSettings.UseVisualStyleBackColor = true; // + // btnCheckUpdates + // + this.btnCheckUpdates.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnCheckUpdates.Location = new System.Drawing.Point(434, 495); + this.btnCheckUpdates.Name = "btnCheckUpdates"; + this.btnCheckUpdates.Size = new System.Drawing.Size(138, 23); + this.btnCheckUpdates.TabIndex = 40; + this.btnCheckUpdates.Text = "Check Updates"; + this.btnCheckUpdates.UseVisualStyleBackColor = true; + this.btnCheckUpdates.Click += new System.EventHandler(this.btnCheckUpdates_Click); + // // linkProjectGithub // this.linkProjectGithub.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); @@ -843,17 +855,6 @@ private void InitializeComponent() this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; // - // btnCheckUpdates - // - this.btnCheckUpdates.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnCheckUpdates.Location = new System.Drawing.Point(434, 495); - this.btnCheckUpdates.Name = "btnCheckUpdates"; - this.btnCheckUpdates.Size = new System.Drawing.Size(138, 23); - this.btnCheckUpdates.TabIndex = 40; - this.btnCheckUpdates.Text = "Check Updates"; - this.btnCheckUpdates.UseVisualStyleBackColor = true; - this.btnCheckUpdates.Click += new System.EventHandler(this.btnCheckUpdates_Click); - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -867,7 +868,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Too Sunny Edition 19"; + this.Text = "UnityLauncher - \'4 Months To Go\' Edition 20"; this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); @@ -884,6 +885,8 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).EndInit(); this.tabSettings.ResumeLayout(false); this.tabSettings.PerformLayout(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index da10141..fb6a33c 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -20,10 +20,10 @@ public partial class Form1 : Form const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; const string launcherArgumentsFile = "LauncherArguments.txt"; const string githubReleaseAPICheckURL = "https://api.github.com/repos/unitycoder/unitylauncher/releases/latest"; - const string githubReleasesURL = "https://github.com/unitycoder/UnityLauncher/releases"; + const string githubReleasesLinkURL = "https://github.com/unitycoder/UnityLauncher/releases"; bool isDownloadUnityList = false; - string previousGitRelease = null; + string previousGitRelease = "0"; public Form1() @@ -107,7 +107,6 @@ void Start() // subscribe to columnwidthchange event, so that can save column sizes this.gridRecent.ColumnWidthChanged += new System.Windows.Forms.DataGridViewColumnEventHandler(this.gridRecent_ColumnWidthChanged); - // get previous version build info string // this string is release tag for latest release when this app was compiled using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("UnityLauncher." + "PreviousVersion.txt")) @@ -1113,7 +1112,7 @@ void CheckUpdates() DialogResult dialogResult = MessageBox.Show("Update " + result + " is available, open download page?", "UnityLauncher - Check Update", MessageBoxButtons.YesNo); if (dialogResult == DialogResult.Yes) // open download page { - Tools.OpenURL(githubReleasesURL); + Tools.OpenURL(githubReleasesLinkURL); } } else diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index ae95aed..931f203 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -7,7 +7,6 @@ using System.Net; using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; using System.Windows.Forms; namespace UnityLauncherTools @@ -336,9 +335,19 @@ public static string CheckUpdates(string githubReleaseURL, string previousGitRel string result = null; using (WebClient client = new WebClient()) { + // apparently this is now required..otherwise: "The request was aborted: Could not create SSL/TLS secure channel" + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + // fetch current release info client.Headers.Add("user-agent", "MuskBrowser"); string json = client.DownloadString(githubReleaseURL); + + if (json.IndexOf('{') != 0) + { + // invalid json + return result; + } + var arr = json.Split(new string[] { "\"tag_name\":" }, StringSplitOptions.None); // have tagname @@ -349,9 +358,14 @@ public static string CheckUpdates(string githubReleaseURL, string previousGitRel if (arr2.Length > 1) { var currentlyAvailableLatestReleaseTag = arr2[1]; + // compare online version with build in release version, return github version if different from embedded version - if (Math.Abs(float.Parse(currentlyAvailableLatestReleaseTag)-float.Parse(previousGitRelease))>0.1f) -// if (currentlyAvailableLatestReleaseTag != previousGitRelease) + float previous = 0; + float current = 0; + if (float.TryParse(previousGitRelease, out previous) == false) return result; + if (float.TryParse(currentlyAvailableLatestReleaseTag, out current) == false) return result; + + if (Math.Abs(previous - current) > 0.1f) { result = currentlyAvailableLatestReleaseTag; Console.WriteLine("update available: [" + currentlyAvailableLatestReleaseTag + "] / [" + previousGitRelease + "]"); diff --git a/UnityLauncher/UnityLauncher.csproj b/UnityLauncher/UnityLauncher.csproj index b2b7a49..927e3a4 100644 --- a/UnityLauncher/UnityLauncher.csproj +++ b/UnityLauncher/UnityLauncher.csproj @@ -132,6 +132,6 @@ - powershell.exe -command "$web = New-Object System.Net.WebClient;$web.Headers['User-Agent'] = 'DefinitelyBrowser';$results = $web.DownloadString('https://api.github.com/repos/unitycoder/unitylauncher/releases/latest');$results = $results | ConvertFrom-Json;$results = $results | select -expand tag_name;echo $results | Out-File $(ProjectDir)PreviousVersion.txt;" + powershell.exe -command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;$web = New-Object System.Net.WebClient;$web.Headers['User-Agent'] = 'DefinitelyBrowser';$results = $web.DownloadString('https://api.github.com/repos/unitycoder/unitylauncher/releases/latest');$results = $results | ConvertFrom-Json;$results = $results | select -expand tag_name;echo $results | Out-File $(ProjectDir)PreviousVersion.txt;" \ No newline at end of file From 4a243b9caa33167ee70382308c31741352849d76 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sun, 25 Feb 2018 12:01:45 +0800 Subject: [PATCH 39/81] add msgbox in case of rare settings error --- UnityLauncher/Form1.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index fb6a33c..e101e61 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -507,6 +507,8 @@ string[] GetUnityInstallationsRootFolder() } catch (Exception e) { + MessageBox.Show("Rare Error while checking unity installation folder settings: " + e.Message, "UnityLauncher", MessageBoxButtons.OK); + // this doesnt work? Properties.Settings.Default.Reset(); Properties.Settings.Default.Save(); From 1c8e5b8ba6b04d6d535154ea30809945c7050adc Mon Sep 17 00:00:00 2001 From: geo Date: Sat, 3 Mar 2018 12:57:30 +0100 Subject: [PATCH 40/81] Fix for NullPointer Exception after column resize. --- UnityLauncher/App.config | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index 18502f3..f9f5fbc 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -45,6 +45,13 @@ False + + + + + + \ No newline at end of file From 89b87b0a44864d9ac7f57ce2392999c8ee5bdcce Mon Sep 17 00:00:00 2001 From: geo Date: Sat, 3 Mar 2018 17:55:43 +0100 Subject: [PATCH 41/81] Revert "Fix for NullPointer Exception after column resize." This reverts commit 1c8e5b8ba6b04d6d535154ea30809945c7050adc. Add new fix. --- UnityLauncher/App.config | 7 ------- UnityLauncher/Form1.cs | 13 +++++++++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index f9f5fbc..18502f3 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -45,13 +45,6 @@ False - - - - - - \ No newline at end of file diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index e101e61..02d8339 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -871,12 +871,21 @@ private void btnOpenLogFolder_Click(object sender, EventArgs e) private void gridRecent_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e) { - List gridWidths = new List(Properties.Settings.Default.gridColumnWidths); + List gridWidths; + if (Properties.Settings.Default.gridColumnWidths != null ) + { + gridWidths = new List(Properties.Settings.Default.gridColumnWidths); + } + else + { + gridWidths = new List(); + } + // restore data grid view widths var colum = gridRecent.Columns[0]; for (int i = 0; i < gridRecent.Columns.Count; ++i) { - if (Properties.Settings.Default.gridColumnWidths.Length > i) + if (Properties.Settings.Default.gridColumnWidths != null && Properties.Settings.Default.gridColumnWidths.Length > i) { gridWidths[i] = gridRecent.Columns[i].Width; } From 17815f7beb48f256d1954c672981d4b23f07ede4 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sun, 4 Mar 2018 14:28:41 +0800 Subject: [PATCH 42/81] fix prebuild event output path for special characters --- UnityLauncher/Form1.Designer.cs | 2 +- UnityLauncher/PreviousVersion.txt | Bin 14 -> 14 bytes UnityLauncher/UnityLauncher.csproj | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 0df5225..4293f0d 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -868,7 +868,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - \'4 Months To Go\' Edition 20"; + this.Text = "UnityLauncher - Fixed Edition 21"; this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); diff --git a/UnityLauncher/PreviousVersion.txt b/UnityLauncher/PreviousVersion.txt index 38f4de6527cc9870d524596a07ea91fcd73ff27e..77560dab84bb247ae3f9dc22c9645656342a5f4d 100644 GIT binary patch literal 14 VcmezW&yYcn!HB_tftP`c0RSQP0@eTk literal 14 VcmezW&yYcn!H~g{ftP`c0RSQ-0^R@s diff --git a/UnityLauncher/UnityLauncher.csproj b/UnityLauncher/UnityLauncher.csproj index 927e3a4..ec7571b 100644 --- a/UnityLauncher/UnityLauncher.csproj +++ b/UnityLauncher/UnityLauncher.csproj @@ -132,6 +132,6 @@ - powershell.exe -command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;$web = New-Object System.Net.WebClient;$web.Headers['User-Agent'] = 'DefinitelyBrowser';$results = $web.DownloadString('https://api.github.com/repos/unitycoder/unitylauncher/releases/latest');$results = $results | ConvertFrom-Json;$results = $results | select -expand tag_name;echo $results | Out-File $(ProjectDir)PreviousVersion.txt;" + powershell.exe -command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;$web = New-Object System.Net.WebClient;$web.Headers['User-Agent'] = 'DefinitelyBrowser';$results = $web.DownloadString('https://api.github.com/repos/unitycoder/unitylauncher/releases/latest');$results = $results | ConvertFrom-Json;$results = $results | select -expand tag_name;echo $results | Out-File \"$(ProjectDir)PreviousVersion.txt\";" \ No newline at end of file From 4a143d68b81a044fa30a69ab65f8510e65633f59 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sun, 4 Mar 2018 15:12:01 +0800 Subject: [PATCH 43/81] adjust statusbar width --- UnityLauncher/Form1.Designer.cs | 13 +++++++++---- UnityLauncher/PreviousVersion.txt | Bin 14 -> 14 bytes 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 4293f0d..51979c6 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -842,18 +842,24 @@ private void InitializeComponent() this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.toolStripStatusLabel1}); this.statusStrip1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.statusStrip1.AutoSize = false; this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(202, 22); + this.statusStrip1.Size = new System.Drawing.Size(579, 22); + this.statusStrip1.SizingGrip = false; this.statusStrip1.TabIndex = 7; this.statusStrip1.Text = "statusStrip1"; // // toolStripStatusLabel1 // + this.toolStripStatusLabel1.AutoSize = false; this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; - this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); + this.toolStripStatusLabel1.Size = new System.Drawing.Size(550, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // Form1 // @@ -868,7 +874,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Fixed Edition 21"; + this.Text = "UnityLauncher - Fixed Edition 22"; this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); @@ -888,7 +894,6 @@ private void InitializeComponent() this.statusStrip1.ResumeLayout(false); this.statusStrip1.PerformLayout(); this.ResumeLayout(false); - this.PerformLayout(); } diff --git a/UnityLauncher/PreviousVersion.txt b/UnityLauncher/PreviousVersion.txt index 77560dab84bb247ae3f9dc22c9645656342a5f4d..91931c01d870238456743963b34243b92f796463 100644 GIT binary patch literal 14 VcmezW&yYcn!HB_-ftP`c0RSQV0@nZl literal 14 VcmezW&yYcn!HB_tftP`c0RSQP0@eTk From 29c12a36ad1c00e1058566c9929adbb2993b905f Mon Sep 17 00:00:00 2001 From: geo Date: Sun, 4 Mar 2018 10:12:13 +0100 Subject: [PATCH 44/81] Improved GitBranch detection robusness. It now searches all folders up to root for .git infos. --- UnityLauncher/Tools.cs | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index 931f203..9310842 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -30,17 +30,44 @@ public static void OpenURL(string url) public static string ReadGitBranchInfo(string projectPath) { string results = null; - string branchFile = Path.Combine(projectPath, ".git", "HEAD"); - if (File.Exists(branchFile) == true) + DirectoryInfo gitDirectory = FindDir(".git", projectPath); + if (gitDirectory != null ) { - results = File.ReadAllText(branchFile); - // get branch only - int pos = results.LastIndexOf("/") + 1; - results = results.Substring(pos, results.Length - pos); + string branchFile = Path.Combine(gitDirectory.FullName, "HEAD"); + if (File.Exists(branchFile)) + { + results = File.ReadAllText(branchFile); + // get branch only + int pos = results.LastIndexOf("/") + 1; + results = results.Substring(pos, results.Length - pos); + } } return results; } + /// + /// Searches for a directory beginning with "startPath". + /// If the directory is not found, then parent folders are searched until + /// either it is found or the root folder has been reached. + /// Null is returned if the directory was not found. + /// + /// + /// + /// + public static DirectoryInfo FindDir(string dirName, string startPath) + { + DirectoryInfo dirInfo = new DirectoryInfo(Path.Combine(startPath, dirName)); + while ( !dirInfo.Exists ) + { + if(dirInfo.Parent.Parent == null ) + { + return null; + } + dirInfo = new DirectoryInfo(Path.Combine(dirInfo.Parent.Parent.FullName, dirName)); + } + return dirInfo; + } + /// /// returns last-write-time for a file or folder /// From 56b68ac79100a24f7046cec6334580f9e78bae09 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Fri, 16 Mar 2018 21:02:03 +0800 Subject: [PATCH 45/81] add refresh recent projects button, add Add Project button, show correct current version on update check statusbar, fix path parsing (was Path.PathSeparator, correct one is Path.DirectorySeparatorChar) --- UnityLauncher/Form1.Designer.cs | 41 +++++++++++-- UnityLauncher/Form1.cs | 94 +++++++++++++++++++++++++++++- UnityLauncher/Form1.resx | 3 - UnityLauncher/PreviousVersion.txt | Bin 14 -> 14 bytes 4 files changed, 126 insertions(+), 12 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 51979c6..2b88b93 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -93,6 +93,8 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.btnRefreshProjectList = new System.Windows.Forms.Button(); + this.btnBrowseForProject = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -124,6 +126,8 @@ private void InitializeComponent() // // tabProjects // + this.tabProjects.Controls.Add(this.btnBrowseForProject); + this.tabProjects.Controls.Add(this.btnRefreshProjectList); this.tabProjects.Controls.Add(this.tbSearchBar); this.tabProjects.Controls.Add(this.btnUpgradeProject); this.tabProjects.Controls.Add(this.btnRunUnityOnly); @@ -139,11 +143,9 @@ private void InitializeComponent() // // tbSearchBar // - this.tbSearchBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.tbSearchBar.Location = new System.Drawing.Point(9, 4); + this.tbSearchBar.Location = new System.Drawing.Point(3, 5); this.tbSearchBar.Name = "tbSearchBar"; - this.tbSearchBar.Size = new System.Drawing.Size(563, 20); + this.tbSearchBar.Size = new System.Drawing.Size(460, 20); this.tbSearchBar.TabIndex = 0; this.tbSearchBar.TextChanged += new System.EventHandler(this.FilterRecentProject); // @@ -839,7 +841,6 @@ private void InitializeComponent() // // statusStrip1 // - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.toolStripStatusLabel1}); this.statusStrip1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.statusStrip1.AutoSize = false; @@ -861,6 +862,32 @@ private void InitializeComponent() this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // + // btnRefreshProjectList + // + this.btnRefreshProjectList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnRefreshProjectList.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnRefreshProjectList.Location = new System.Drawing.Point(555, 3); + this.btnRefreshProjectList.Name = "btnRefreshProjectList"; + this.btnRefreshProjectList.Size = new System.Drawing.Size(22, 23); + this.btnRefreshProjectList.TabIndex = 22; + this.btnRefreshProjectList.Text = "⟳"; + this.toolTip1.SetToolTip(this.btnRefreshProjectList, "Refresh Unity Installations List"); + this.btnRefreshProjectList.UseCompatibleTextRendering = true; + this.btnRefreshProjectList.UseVisualStyleBackColor = true; + this.btnRefreshProjectList.Click += new System.EventHandler(this.btnRefreshProjectList_Click); + // + // btnBrowseForProject + // + this.btnBrowseForProject.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnBrowseForProject.Location = new System.Drawing.Point(469, 3); + this.btnBrowseForProject.Name = "btnBrowseForProject"; + this.btnBrowseForProject.Size = new System.Drawing.Size(80, 23); + this.btnBrowseForProject.TabIndex = 23; + this.btnBrowseForProject.Text = "+ Add Project"; + this.toolTip1.SetToolTip(this.btnBrowseForProject, "Open File Explorer"); + this.btnBrowseForProject.UseVisualStyleBackColor = true; + this.btnBrowseForProject.Click += new System.EventHandler(this.btnBrowseForProject_Click); + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -874,7 +901,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Fixed Edition 22"; + this.Text = "UnityLauncher - 2018 Edition 23"; this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); @@ -961,6 +988,8 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn _unityPath; private System.Windows.Forms.DataGridViewTextBoxColumn _unityInstallDate; private System.Windows.Forms.Button btnCheckUpdates; + private System.Windows.Forms.Button btnRefreshProjectList; + private System.Windows.Forms.Button btnBrowseForProject; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 02d8339..ff888d7 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -284,9 +284,9 @@ void UpdateRecentProjectsList() string projectName = ""; // get project name from full path - if (projectPath.IndexOf(Path.PathSeparator) > -1) + if (projectPath.IndexOf(Path.DirectorySeparatorChar) > -1) { - projectName = projectPath.Substring(projectPath.LastIndexOf(Path.PathSeparator) + 1); + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); } else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) { @@ -997,6 +997,16 @@ private void btnCheckUpdates_Click(object sender, EventArgs e) CheckUpdates(); } + private void btnRefreshProjectList_Click(object sender, EventArgs e) + { + UpdateRecentProjectsList(); + } + + private void btnBrowseForProject_Click(object sender, EventArgs e) + { + BrowseForExistingProjectFolder(); + } + #endregion UI events // displays version selector to upgrade project @@ -1128,7 +1138,85 @@ void CheckUpdates() } else { - SetStatus("No updates available. Current release is " + previousGitRelease); + SetStatus("No updates available. Current release is " + (float.Parse(previousGitRelease)+0.01f)); + } + } + + + + void BrowseForExistingProjectFolder() + { + folderBrowserDialog1.Description = "Select Existing Project Folder"; + var d = folderBrowserDialog1.ShowDialog(); + var projectPath = folderBrowserDialog1.SelectedPath; + if (String.IsNullOrWhiteSpace(projectPath) == false && Directory.Exists(projectPath) == true) + { + + // TODO: remove duplicate code (from UpdateRecentList()) + + string projectName = ""; + + Console.WriteLine(Path.DirectorySeparatorChar); + Console.WriteLine(Path.AltDirectorySeparatorChar); + + // get project name from full path + if (projectPath.IndexOf(Path.DirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); + Console.WriteLine("1"); + } + else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); + Console.WriteLine("2"); + } + else // no path separator founded + { + projectName = projectPath; + Console.WriteLine("3"); + } + + string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); + + // editor only project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, projectName + ".Editor.csproj"); + } + + // maybe 4.x project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, "Assembly-CSharp.csproj"); + } + + // get last modified date + DateTime? lastUpdated = Tools.GetLastModifiedTime(csprojFile); + + // get project version + string projectVersion = Tools.GetProjectVersion(projectPath); + + // get custom launch arguments, only if column in enabled + string customArgs = ""; + if (chkShowLauncherArgumentsColumn.Checked == true) + { + customArgs = Tools.ReadCustomLaunchArguments(projectPath, launcherArgumentsFile); + } + + // get git branchinfo, only if column in enabled + string gitBranch = ""; + if (chkShowGitBranchColumn.Checked == true) + { + gitBranch = Tools.ReadGitBranchInfo(projectPath); + } + + // NOTE: list item will disappear if you dont open the project once.. + + // TODO: dont add if not a project?? + + gridRecent.Rows.Insert(0, projectName, projectVersion, projectPath, lastUpdated, customArgs, gitBranch); + gridRecent.Rows[0].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; + gridRecent.Rows[0].Selected = true; } } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 1124349..820ca22 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -186,9 +186,6 @@ True - - 14, 20 - 111, 20 diff --git a/UnityLauncher/PreviousVersion.txt b/UnityLauncher/PreviousVersion.txt index 91931c01d870238456743963b34243b92f796463..aadc1faaea7864daa27b9808c707026fb28ab97d 100644 GIT binary patch literal 14 TcmezW&yYcn!3YR>8Mqh#A_4-~ literal 14 VcmezW&yYcn!HB_-ftP`c0RSQV0@nZl From f8c7063552a4f73b517addcde5f778493cca8a01 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sat, 17 Mar 2018 22:39:18 +0800 Subject: [PATCH 46/81] skip project if directory missing fixes #44 --- UnityLauncher/Form1.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index ff888d7..828a45f 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -281,6 +281,12 @@ void UpdateRecentProjectsList() projectPath = (string)key.GetValue(valueName); } + // first check if whole folder exists, if not, skip + if (Directory.Exists(projectPath)==false) + { + continue; + } + string projectName = ""; // get project name from full path From 3caec9d2d87184de0ff66b3165413a874dc0ca9d Mon Sep 17 00:00:00 2001 From: unitycoder Date: Thu, 22 Mar 2018 19:28:48 +0800 Subject: [PATCH 47/81] check .sln file for modified date, fixes #46 --- UnityLauncher/Form1.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 828a45f..9ce950e 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -282,7 +282,7 @@ void UpdateRecentProjectsList() } // first check if whole folder exists, if not, skip - if (Directory.Exists(projectPath)==false) + if (Directory.Exists(projectPath) == false) { continue; } @@ -305,6 +305,12 @@ void UpdateRecentProjectsList() string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); + // solution only + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, projectName + ".sln"); + } + // editor only project if (File.Exists(csprojFile) == false) { @@ -878,7 +884,7 @@ private void btnOpenLogFolder_Click(object sender, EventArgs e) private void gridRecent_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e) { List gridWidths; - if (Properties.Settings.Default.gridColumnWidths != null ) + if (Properties.Settings.Default.gridColumnWidths != null) { gridWidths = new List(Properties.Settings.Default.gridColumnWidths); } @@ -886,7 +892,7 @@ private void gridRecent_ColumnWidthChanged(object sender, DataGridViewColumnEven { gridWidths = new List(); } - + // restore data grid view widths var colum = gridRecent.Columns[0]; for (int i = 0; i < gridRecent.Columns.Count; ++i) @@ -1144,7 +1150,7 @@ void CheckUpdates() } else { - SetStatus("No updates available. Current release is " + (float.Parse(previousGitRelease)+0.01f)); + SetStatus("No updates available. Current release is " + (float.Parse(previousGitRelease) + 0.01f)); } } From 2b64aa35de89f130c7cd5e31968a541a95cfa447 Mon Sep 17 00:00:00 2001 From: Quorra Date: Tue, 27 Mar 2018 20:45:47 +0200 Subject: [PATCH 48/81] Type error corrections in various strings. --- UnityLauncher/Form1.cs | 64 +++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 9ce950e..1943037 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -38,12 +38,12 @@ private void Form1_Load(object sender, EventArgs e) void Start() { - SetStatus("Initializing.."); + SetStatus("Initializing ..."); // check installations folder var root = GetUnityInstallationsRootFolder(); if (root == null || root.Length == 0) { - SetStatus("Missing root folder.."); + SetStatus("Missing root folder ..."); AddUnityInstallationRootFolder(); SetStatus("Ready"); } @@ -51,10 +51,10 @@ void Start() LoadSettings(); // scan installed unitys - bool foundedUnitys = ScanUnityInstallations(); - if (foundedUnitys == false) + bool foundUnitys = ScanUnityInstallations(); + if (foundUnitys == false) { - SetStatus("Error> Did not found any Unity installations, try setting correct root folder.."); + SetStatus("Error> Did not find any Unity installations, try setting correct root folder ..."); UpdateRecentProjectsList(); tabControl1.SelectedIndex = tabControl1.TabCount - 1; // last tab is settings return; @@ -68,7 +68,7 @@ void Start() var commandLineArgs = args[1]; if (commandLineArgs == "-projectPath") { - SetStatus("Launching from commandline.."); + SetStatus("Launching from commandline ..."); // path var projectPathArgument = args[2]; @@ -181,7 +181,7 @@ void AddUnityInstallationRootFolder() bool ScanUnityInstallations() { - SetStatus("Scanning unity installations.."); + SetStatus("Scanning Unity installations ..."); // dictionary to keep version and path unityList.Clear(); @@ -219,18 +219,18 @@ bool ScanUnityInstallations() } // all root folders - lbl_unityCount.Text = "Founded " + unityList.Count.ToString() + " versions"; + lbl_unityCount.Text = "Found " + unityList.Count.ToString() + " versions"; SetStatus("Finished scanning"); - // founded any unity installations? + // found any Unity installations? return unityList.Count > 0; } void FilterRecentProject(object sender, EventArgs e) { - SetStatus("Filtering recent projects list.."); + SetStatus("Filtering recent projects list ..."); foreach (DataGridViewRow recentProject in gridRecent.Rows) { if (recentProject.Cells["_project"].Value.ToString().IndexOf(tbSearchBar.Text, StringComparison.OrdinalIgnoreCase) > -1) @@ -249,7 +249,7 @@ void FilterRecentProject(object sender, EventArgs e) ///
void UpdateRecentProjectsList() { - SetStatus("Updating recent projects list.."); + SetStatus("Updating recent projects list ..."); gridRecent.Rows.Clear(); @@ -298,7 +298,7 @@ void UpdateRecentProjectsList() { projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); } - else // no path separator founded + else // no path separator found { projectName = projectPath; } @@ -416,13 +416,13 @@ void LaunchProject(string projectPath, string version, bool openProject = true, } else // we dont have this version installed (or no version info available) { - SetStatus("Missing unity version: " + version); + SetStatus("Missing Unity version: " + version); DisplayUpgradeDialog(version, projectPath); } } else // given path doesnt exists, strange { - SetStatus("Invalid Path: " + projectPath); + SetStatus("Invalid path: " + projectPath); } } @@ -432,7 +432,7 @@ bool CheckCrashBackupScene(string projectPath) var recoveryFile = Path.Combine(projectPath, "Temp", "__Backupscenes", "0.backup"); if (File.Exists(recoveryFile)) { - DialogResult dialogResult = MessageBox.Show("Crash recovery scene founded, do you want to copy it into Assets/_Recovery/-folder?", "UnityLauncher - Scene Recovery", MessageBoxButtons.YesNoCancel); + DialogResult dialogResult = MessageBox.Show("Crash recovery scene found, do you want to copy it into Assets/_Recovery/-folder?", "UnityLauncher - Scene Recovery", MessageBoxButtons.YesNoCancel); if (dialogResult == DialogResult.Yes) // restore { var restoreFolder = Path.Combine(projectPath, "Assets", "_Recovery"); @@ -453,7 +453,7 @@ bool CheckCrashBackupScene(string projectPath) cancelRunningUnity = true; } } - else if (dialogResult == DialogResult.Cancel) // dont do restore, but run unity + else if (dialogResult == DialogResult.Cancel) // dont do restore, but run Unity { cancelRunningUnity = true; } @@ -461,7 +461,7 @@ bool CheckCrashBackupScene(string projectPath) return cancelRunningUnity; } - // parse unity installer exe from release page + // parse Unity installer exe from release page // thanks to https://github.com/softfruit string GetDownloadUrlForUnityVersion(string releaseUrl) { @@ -479,7 +479,7 @@ string GetDownloadUrlForUnityVersion(string releaseUrl) } else { - SetStatus("Cannot find UnityDownloadAssistant.exe for this version.."); + SetStatus("Cannot find UnityDownloadAssistant.exe for this version."); } } return url; @@ -499,7 +499,7 @@ void DownloadInBrowser(string url) } else // not found { - SetStatus("Error> Cannot find installer exe.. opening website instead"); + SetStatus("Error> Cannot find installer executable ... opening website instead"); Process.Start(url + "#installer-exe-not-found"); } } @@ -519,7 +519,7 @@ string[] GetUnityInstallationsRootFolder() } catch (Exception e) { - MessageBox.Show("Rare Error while checking unity installation folder settings: " + e.Message, "UnityLauncher", MessageBoxButtons.OK); + MessageBox.Show("Rare error while checking Unity installation folder settings: " + e.Message, "UnityLauncher", MessageBoxButtons.OK); // this doesnt work? Properties.Settings.Default.Reset(); @@ -682,11 +682,11 @@ private void unityGridView_KeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) { - case Keys.Return: // launch selected unity + case Keys.Return: // launch selected Unity e.SuppressKeyPress = true; LaunchSelectedUnity(); break; - case Keys.F5: // refresh installed unitys list + case Keys.F5: // refresh installed Unity versions list ScanUnityInstallations(); break; default: @@ -762,7 +762,7 @@ private void GridRecent_CellMouseDoubleClick(object sender, DataGridViewCellMous } } - // set basefolder of all unity installations + // set basefolder of all Unity installations private void btn_setinstallfolder_Click(object sender, EventArgs e) { AddUnityInstallationRootFolder(); @@ -922,7 +922,7 @@ private void btnOpenUpdateWebsite_Click(object sender, EventArgs e) private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) { - // if enter Updates tab, then automatically fetch list of unity versions if list is empty (not fetched) + // if enter Updates tab, then automatically fetch list of Unity versions if list is empty (not fetched) if (((TabControl)sender).SelectedIndex == 3) // FIXME: fixed index 3 for this tab.. { if (gridUnityUpdates.Rows.Count == 0) @@ -1027,7 +1027,7 @@ void UpgradeProject() var selected = gridRecent.CurrentCell.RowIndex; if (selected > -1) { - SetStatus("Upgrading project.."); + SetStatus("Upgrading project ..."); var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); var currentVersion = Tools.GetProjectVersion(projectPath); @@ -1067,7 +1067,7 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch SetStatus("Cancelled project upgrade"); break; case DialogResult.Retry: // download and install missing version - SetStatus("Download and Install missing version " + currentVersion); + SetStatus("Download and install missing version " + currentVersion); string url = Tools.GetUnityReleaseURL(currentVersion); if (string.IsNullOrEmpty(url) == false) { @@ -1093,13 +1093,13 @@ private void FetchListOfUnityUpdates() { if (isDownloadUnityList == true) { - SetStatus("We are already downloading.."); + SetStatus("We are already downloading ..."); return; } isDownloadUnityList = true; - SetStatus("Downloading list of unity versions.."); + SetStatus("Downloading list of Unity versions ..."); - // download list of unity versions + // download list of Unity versions using (WebClient webClient = new WebClient()) { webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(UnityVersionsListDownloaded); @@ -1111,7 +1111,7 @@ private void FetchListOfUnityUpdates() private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedEventArgs e) { // TODO check for error.. - SetStatus("Downloading list of unity versions..Done"); + SetStatus("Downloading list of Unity versions ... done"); isDownloadUnityList = false; // parse to list var unityList = e.Result.Split(new[] { Environment.NewLine }, StringSplitOptions.None); @@ -1158,7 +1158,7 @@ void CheckUpdates() void BrowseForExistingProjectFolder() { - folderBrowserDialog1.Description = "Select Existing Project Folder"; + folderBrowserDialog1.Description = "Select existing project folder"; var d = folderBrowserDialog1.ShowDialog(); var projectPath = folderBrowserDialog1.SelectedPath; if (String.IsNullOrWhiteSpace(projectPath) == false && Directory.Exists(projectPath) == true) @@ -1182,7 +1182,7 @@ void BrowseForExistingProjectFolder() projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); Console.WriteLine("2"); } - else // no path separator founded + else // no path separator found { projectName = projectPath; Console.WriteLine("3"); From d768e6054579b542d6899b8a4080a33e3a73cf16 Mon Sep 17 00:00:00 2001 From: Ville Tuhkanen Date: Wed, 28 Mar 2018 23:03:50 +0300 Subject: [PATCH 49/81] Support relative paths from command line Add support for providing product path argument as relative path. This makes it easier to open projects from command line as user doesn't need to provide full path to project directory. It also allows opening the project from current directory by providing . as path argument. Check for relative path was done with just checking if the path isn't a rooted path. If more thorough checks are needed, this StackOverflow thread has discussion on how the current check could be extended. https://stackoverflow.com/questions/5565029/check-if-full-path-given/35046453 --- UnityLauncher/Form1.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 9ce950e..a4c34f3 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -73,6 +73,12 @@ void Start() // path var projectPathArgument = args[2]; + // resolve full path if path parameter isn't a rooted path + if (!Path.IsPathRooted(projectPathArgument)) + { + projectPathArgument = Directory.GetCurrentDirectory() + projectPathArgument; + } + var version = Tools.GetProjectVersion(projectPathArgument); // take extra arguments also From 07b522b94221a699f07318affa16ed23525ccc81 Mon Sep 17 00:00:00 2001 From: Ville Tuhkanen Date: Wed, 28 Mar 2018 23:38:02 +0300 Subject: [PATCH 50/81] Fix exception thrown when run from command line Opening project from command line doesn't work because exception is thrown when trying to launch the application. Exception occurs because application is trying to retrieve _launchArguments for the row of the currently selected cell. When running from command line currently selected cell is null and that causes a null reference exception to occur. Issue is fixed by checking the current grid and cell for null and handling the situation like no row has been selected. --- UnityLauncher/Form1.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 9ce950e..c1036c6 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -1128,10 +1128,10 @@ private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedE string GetSelectedRowData(string key) { string path = null; - var selected = gridRecent.CurrentCell.RowIndex; - if (selected > -1) + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) { - path = gridRecent.Rows[selected].Cells[key].Value?.ToString(); + path = gridRecent.Rows[selected.Value].Cells[key].Value?.ToString(); } return path; } From 0eb982bc97658880f4774d18bb823c8083814aa4 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Thu, 29 Mar 2018 17:34:52 +0800 Subject: [PATCH 51/81] adjust button/tab names --- UnityLauncher/Form1.Designer.cs | 62 ++++++++++++++++----------------- UnityLauncher/Form1.resx | 33 ------------------ 2 files changed, 31 insertions(+), 64 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 2b88b93..0e4f433 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -32,6 +32,8 @@ private void InitializeComponent() System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabProjects = new System.Windows.Forms.TabPage(); + this.btnBrowseForProject = new System.Windows.Forms.Button(); + this.btnRefreshProjectList = new System.Windows.Forms.Button(); this.tbSearchBar = new System.Windows.Forms.TextBox(); this.btnUpgradeProject = new System.Windows.Forms.Button(); this.btnRunUnityOnly = new System.Windows.Forms.Button(); @@ -93,8 +95,6 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this.btnRefreshProjectList = new System.Windows.Forms.Button(); - this.btnBrowseForProject = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -141,6 +141,32 @@ private void InitializeComponent() this.tabProjects.Text = "Projects"; this.tabProjects.UseVisualStyleBackColor = true; // + // btnBrowseForProject + // + this.btnBrowseForProject.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnBrowseForProject.Location = new System.Drawing.Point(469, 3); + this.btnBrowseForProject.Name = "btnBrowseForProject"; + this.btnBrowseForProject.Size = new System.Drawing.Size(80, 23); + this.btnBrowseForProject.TabIndex = 23; + this.btnBrowseForProject.Text = "+ Add Project"; + this.toolTip1.SetToolTip(this.btnBrowseForProject, "Browse for a Project"); + this.btnBrowseForProject.UseVisualStyleBackColor = true; + this.btnBrowseForProject.Click += new System.EventHandler(this.btnBrowseForProject_Click); + // + // btnRefreshProjectList + // + this.btnRefreshProjectList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnRefreshProjectList.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnRefreshProjectList.Location = new System.Drawing.Point(555, 3); + this.btnRefreshProjectList.Name = "btnRefreshProjectList"; + this.btnRefreshProjectList.Size = new System.Drawing.Size(22, 23); + this.btnRefreshProjectList.TabIndex = 22; + this.btnRefreshProjectList.Text = "⟳"; + this.toolTip1.SetToolTip(this.btnRefreshProjectList, "Refresh Unity Installations List"); + this.btnRefreshProjectList.UseCompatibleTextRendering = true; + this.btnRefreshProjectList.UseVisualStyleBackColor = true; + this.btnRefreshProjectList.Click += new System.EventHandler(this.btnRefreshProjectList_Click); + // // tbSearchBar // this.tbSearchBar.Location = new System.Drawing.Point(3, 5); @@ -284,7 +310,7 @@ private void InitializeComponent() this.tabUnitys.Name = "tabUnitys"; this.tabUnitys.Size = new System.Drawing.Size(580, 549); this.tabUnitys.TabIndex = 1; - this.tabUnitys.Text = "Unity\'s"; + this.tabUnitys.Text = "Unitys"; this.tabUnitys.UseVisualStyleBackColor = true; // // btn_refreshUnityList @@ -594,7 +620,7 @@ private void InitializeComponent() this.btnCheckUpdates.Name = "btnCheckUpdates"; this.btnCheckUpdates.Size = new System.Drawing.Size(138, 23); this.btnCheckUpdates.TabIndex = 40; - this.btnCheckUpdates.Text = "Check Updates"; + this.btnCheckUpdates.Text = "Check for Updates"; this.btnCheckUpdates.UseVisualStyleBackColor = true; this.btnCheckUpdates.Click += new System.EventHandler(this.btnCheckUpdates_Click); // @@ -717,7 +743,7 @@ private void InitializeComponent() this.btnRemoveRegister.Name = "btnRemoveRegister"; this.btnRemoveRegister.Size = new System.Drawing.Size(64, 23); this.btnRemoveRegister.TabIndex = 29; - this.btnRemoveRegister.Text = "uninstall"; + this.btnRemoveRegister.Text = "Uninstall"; this.btnRemoveRegister.UseVisualStyleBackColor = true; this.btnRemoveRegister.Click += new System.EventHandler(this.btnRemoveRegister_Click); // @@ -862,32 +888,6 @@ private void InitializeComponent() this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // - // btnRefreshProjectList - // - this.btnRefreshProjectList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnRefreshProjectList.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnRefreshProjectList.Location = new System.Drawing.Point(555, 3); - this.btnRefreshProjectList.Name = "btnRefreshProjectList"; - this.btnRefreshProjectList.Size = new System.Drawing.Size(22, 23); - this.btnRefreshProjectList.TabIndex = 22; - this.btnRefreshProjectList.Text = "⟳"; - this.toolTip1.SetToolTip(this.btnRefreshProjectList, "Refresh Unity Installations List"); - this.btnRefreshProjectList.UseCompatibleTextRendering = true; - this.btnRefreshProjectList.UseVisualStyleBackColor = true; - this.btnRefreshProjectList.Click += new System.EventHandler(this.btnRefreshProjectList_Click); - // - // btnBrowseForProject - // - this.btnBrowseForProject.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.btnBrowseForProject.Location = new System.Drawing.Point(469, 3); - this.btnBrowseForProject.Name = "btnBrowseForProject"; - this.btnBrowseForProject.Size = new System.Drawing.Size(80, 23); - this.btnBrowseForProject.TabIndex = 23; - this.btnBrowseForProject.Text = "+ Add Project"; - this.toolTip1.SetToolTip(this.btnBrowseForProject, "Open File Explorer"); - this.btnBrowseForProject.UseVisualStyleBackColor = true; - this.btnBrowseForProject.Click += new System.EventHandler(this.btnBrowseForProject_Click); - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 820ca22..259ed12 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -138,33 +138,6 @@ True - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - True - True @@ -180,12 +153,6 @@ True - - True - - - True - 111, 20 From 5ff3947902e9c13d3adf362da34085d26692aab4 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Tue, 3 Apr 2018 20:21:53 +0800 Subject: [PATCH 52/81] anchor add-project button --- UnityLauncher/Form1.Designer.cs | 4 ++-- UnityLauncher/Form1.resx | 36 ++++++++++++++++++++++++++++++ UnityLauncher/PreviousVersion.txt | Bin 14 -> 14 bytes 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 0e4f433..57626d3 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -143,7 +143,7 @@ private void InitializeComponent() // // btnBrowseForProject // - this.btnBrowseForProject.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnBrowseForProject.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnBrowseForProject.Location = new System.Drawing.Point(469, 3); this.btnBrowseForProject.Name = "btnBrowseForProject"; this.btnBrowseForProject.Size = new System.Drawing.Size(80, 23); @@ -901,7 +901,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - 2018 Edition 23"; + this.Text = "UnityLauncher - 2018 Super Edition 24"; this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 259ed12..1124349 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -138,6 +138,33 @@ True + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + True @@ -153,6 +180,15 @@ True + + True + + + True + + + 14, 20 + 111, 20 diff --git a/UnityLauncher/PreviousVersion.txt b/UnityLauncher/PreviousVersion.txt index aadc1faaea7864daa27b9808c707026fb28ab97d..f94c56c34bf714d0b3d3b427d76f8b2cbaf8b471 100644 GIT binary patch literal 14 VcmezW&yYcn!HB__ftP`c0RSQh0@(ln literal 14 TcmezW&yYcn!3YR>8Mqh#A_4-~ From 36e68d8cfa31a08079c2ce01265dbc10caf98c27 Mon Sep 17 00:00:00 2001 From: Kyle Orth Date: Thu, 5 Apr 2018 04:22:21 +1000 Subject: [PATCH 53/81] Adding support for loading a project's version from a ProjectVersionOverride.txt file in the root directory --- UnityLauncher/Tools.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index 9310842..0c8dec8 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -251,7 +251,12 @@ public static void AddContextMenuRegistry(string contextRegRoot) public static string GetProjectVersion(string path) { var version = ""; - if (Directory.Exists(Path.Combine(path, "ProjectSettings"))) + + if(File.Exists(Path.Combine(path, "ProjectVersionOverride.txt"))) + { + version = File.ReadAllText(Path.Combine(path, "ProjectVersionOverride.txt")); + } + else if (Directory.Exists(Path.Combine(path, "ProjectSettings"))) { var versionPath = Path.Combine(path, "ProjectSettings", "ProjectVersion.txt"); if (File.Exists(versionPath) == true) // 5.x and later From f2d633982a011bb02567dfd810fd8262bcaa593c Mon Sep 17 00:00:00 2001 From: unitycoder Date: Fri, 6 Apr 2018 20:14:57 +0800 Subject: [PATCH 54/81] save settings on form close only fixes #53 --- UnityLauncher/Form1.Designer.cs | 6 +-- UnityLauncher/Form1.cs | 78 +++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 57626d3..8708904 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -104,7 +104,6 @@ private void InitializeComponent() this.tabUpdates.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).BeginInit(); this.tabSettings.SuspendLayout(); - this.statusStrip1.SuspendLayout(); this.SuspendLayout(); // // tabControl1 @@ -901,7 +900,8 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - 2018 Super Edition 24"; + this.Text = "UnityLauncher - Spring Edition 25"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); @@ -918,8 +918,6 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).EndInit(); this.tabSettings.ResumeLayout(false); this.tabSettings.PerformLayout(); - this.statusStrip1.ResumeLayout(false); - this.statusStrip1.PerformLayout(); this.ResumeLayout(false); } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index d22a035..b06c2af 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -36,6 +36,8 @@ private void Form1_Load(object sender, EventArgs e) Start(); } + + void Start() { SetStatus("Initializing ..."); @@ -110,9 +112,6 @@ void Start() // preselect grid gridRecent.Select(); - // subscribe to columnwidthchange event, so that can save column sizes - this.gridRecent.ColumnWidthChanged += new System.Windows.Forms.DataGridViewColumnEventHandler(this.gridRecent_ColumnWidthChanged); - // get previous version build info string // this string is release tag for latest release when this app was compiled using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("UnityLauncher." + "PreviousVersion.txt")) @@ -887,35 +886,6 @@ private void btnOpenLogFolder_Click(object sender, EventArgs e) } } - private void gridRecent_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e) - { - List gridWidths; - if (Properties.Settings.Default.gridColumnWidths != null) - { - gridWidths = new List(Properties.Settings.Default.gridColumnWidths); - } - else - { - gridWidths = new List(); - } - - // restore data grid view widths - var colum = gridRecent.Columns[0]; - for (int i = 0; i < gridRecent.Columns.Count; ++i) - { - if (Properties.Settings.Default.gridColumnWidths != null && Properties.Settings.Default.gridColumnWidths.Length > i) - { - gridWidths[i] = gridRecent.Columns[i].Width; - } - else - { - gridWidths.Add(gridRecent.Columns[i].Width); - } - } - Properties.Settings.Default.gridColumnWidths = gridWidths.ToArray(); - Properties.Settings.Default.Save(); - } - private void btnOpenUpdateWebsite_Click(object sender, EventArgs e) { var selected = gridUnityUpdates?.CurrentCell?.RowIndex; @@ -1025,8 +995,16 @@ private void btnBrowseForProject_Click(object sender, EventArgs e) BrowseForExistingProjectFolder(); } + private void Form1_FormClosing(object sender, FormClosingEventArgs e) + { + SaveSettingsOnExit(); + } + #endregion UI events + + + // displays version selector to upgrade project void UpgradeProject() { @@ -1237,5 +1215,37 @@ void BrowseForExistingProjectFolder() gridRecent.Rows[0].Selected = true; } } - } -} \ No newline at end of file + + private void SaveSettingsOnExit() + { + // save list column widths + List gridWidths; + if (Properties.Settings.Default.gridColumnWidths != null) + { + gridWidths = new List(Properties.Settings.Default.gridColumnWidths); + } + else + { + gridWidths = new List(); + } + + // restore data grid view widths + var colum = gridRecent.Columns[0]; + for (int i = 0; i < gridRecent.Columns.Count; ++i) + { + if (Properties.Settings.Default.gridColumnWidths != null && Properties.Settings.Default.gridColumnWidths.Length > i) + { + gridWidths[i] = gridRecent.Columns[i].Width; + } + else + { + gridWidths.Add(gridRecent.Columns[i].Width); + } + } + Properties.Settings.Default.gridColumnWidths = gridWidths.ToArray(); + Properties.Settings.Default.Save(); + } + + + } // class Form +} // namespace \ No newline at end of file From 66a423145ff30416045b973eebcd27ee7a7408c2 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Thu, 10 May 2018 20:55:38 +0800 Subject: [PATCH 55/81] set selectedindex after inserting new project fixes #58 --- UnityLauncher/Form1.Designer.cs | 76 +++++++++++++++++++-------------- UnityLauncher/Form1.cs | 2 + UnityLauncher/Form1.resx | 30 ++++++------- 3 files changed, 58 insertions(+), 50 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 8708904..8a2c0a9 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -52,9 +52,6 @@ private void InitializeComponent() this.btnExploreUnity = new System.Windows.Forms.Button(); this.btnLaunchUnity = new System.Windows.Forms.Button(); this.gridUnityList = new System.Windows.Forms.DataGridView(); - this._unityVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._unityPath = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._unityInstallDate = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabPackages = new System.Windows.Forms.TabPage(); this.btnAddAssetStoreFolder = new System.Windows.Forms.Button(); this.btnExplorePackageFolder = new System.Windows.Forms.Button(); @@ -95,6 +92,10 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this._unityVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._unityPath = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._unityInstallDate = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._Platforms = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -104,6 +105,7 @@ private void InitializeComponent() this.tabUpdates.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).BeginInit(); this.tabSettings.SuspendLayout(); + this.statusStrip1.SuspendLayout(); this.SuspendLayout(); // // tabControl1 @@ -377,13 +379,14 @@ private void InitializeComponent() this.gridUnityList.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this._unityVersion, this._unityPath, - this._unityInstallDate}); + this._unityInstallDate, + this._Platforms}); this.gridUnityList.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; this.gridUnityList.Location = new System.Drawing.Point(3, 27); this.gridUnityList.MultiSelect = false; this.gridUnityList.Name = "gridUnityList"; this.gridUnityList.ReadOnly = true; - this.gridUnityList.RowHeadersWidth = 18; + this.gridUnityList.RowHeadersWidth = 15; this.gridUnityList.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.gridUnityList.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; this.gridUnityList.ShowCellErrors = false; @@ -394,30 +397,6 @@ private void InitializeComponent() this.gridUnityList.TabIndex = 10; this.gridUnityList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.unityGridView_KeyDown); // - // _unityVersion - // - this._unityVersion.HeaderText = "Version"; - this._unityVersion.MinimumWidth = 150; - this._unityVersion.Name = "_unityVersion"; - this._unityVersion.ReadOnly = true; - this._unityVersion.Width = 150; - // - // _unityPath - // - this._unityPath.HeaderText = "Path"; - this._unityPath.MinimumWidth = 300; - this._unityPath.Name = "_unityPath"; - this._unityPath.ReadOnly = true; - this._unityPath.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._unityPath.Width = 300; - // - // _unityInstallDate - // - this._unityInstallDate.HeaderText = "Installed"; - this._unityInstallDate.Name = "_unityInstallDate"; - this._unityInstallDate.ReadOnly = true; - this._unityInstallDate.Width = 150; - // // tabPackages // this.tabPackages.Controls.Add(this.btnAddAssetStoreFolder); @@ -887,6 +866,36 @@ private void InitializeComponent() this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // + // _unityVersion + // + this._unityVersion.HeaderText = "Version"; + this._unityVersion.MinimumWidth = 120; + this._unityVersion.Name = "_unityVersion"; + this._unityVersion.ReadOnly = true; + this._unityVersion.Width = 120; + // + // _unityPath + // + this._unityPath.HeaderText = "Path"; + this._unityPath.MinimumWidth = 300; + this._unityPath.Name = "_unityPath"; + this._unityPath.ReadOnly = true; + this._unityPath.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this._unityPath.Width = 300; + // + // _unityInstallDate + // + this._unityInstallDate.HeaderText = "Installed"; + this._unityInstallDate.Name = "_unityInstallDate"; + this._unityInstallDate.ReadOnly = true; + this._unityInstallDate.Width = 120; + // + // _Platforms + // + this._Platforms.HeaderText = "Platforms"; + this._Platforms.Name = "_Platforms"; + this._Platforms.ReadOnly = true; + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -918,6 +927,8 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).EndInit(); this.tabSettings.ResumeLayout(false); this.tabSettings.PerformLayout(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); this.ResumeLayout(false); } @@ -982,12 +993,13 @@ private void InitializeComponent() private System.Windows.Forms.CheckBox chkShowLauncherArgumentsColumn; private System.Windows.Forms.LinkLabel linkArgumentsDocs; private System.Windows.Forms.LinkLabel linkProjectGithub; - private System.Windows.Forms.DataGridViewTextBoxColumn _unityVersion; - private System.Windows.Forms.DataGridViewTextBoxColumn _unityPath; - private System.Windows.Forms.DataGridViewTextBoxColumn _unityInstallDate; private System.Windows.Forms.Button btnCheckUpdates; private System.Windows.Forms.Button btnRefreshProjectList; private System.Windows.Forms.Button btnBrowseForProject; + private System.Windows.Forms.DataGridViewTextBoxColumn _unityVersion; + private System.Windows.Forms.DataGridViewTextBoxColumn _unityPath; + private System.Windows.Forms.DataGridViewTextBoxColumn _unityInstallDate; + private System.Windows.Forms.DataGridViewTextBoxColumn _Platforms; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index b06c2af..0dc56b4 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -215,6 +215,7 @@ bool ScanUnityInstallations() unityList.Add(unityVersion, unityExe); var dataFolder = Path.Combine(directories[i], "Editor", "Data"); DateTime? installDate = Tools.GetLastModifiedTime(dataFolder); + // TODO add platforms: PC|iOS|tvOS|Android|UWP|WebGL|Facebook|XBox|PSVita|PS4 gridUnityList.Rows.Add(unityVersion, unityExe, installDate); } } // have unity.exe @@ -1213,6 +1214,7 @@ void BrowseForExistingProjectFolder() gridRecent.Rows.Insert(0, projectName, projectVersion, projectPath, lastUpdated, customArgs, gitBranch); gridRecent.Rows[0].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; gridRecent.Rows[0].Selected = true; + gridRecent.CurrentCell = gridRecent[0, 0]; // reset position to first item } } diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 1124349..cb55b8b 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -117,26 +117,20 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 14, 20 - - - True - - + True - + True - + True - + True - - True + + 14, 20 True @@ -156,22 +150,22 @@ True - + True - + True - + True - + True - + True - + True From 87e7ad788746e6870be792c0170da2099d793ca4 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Thu, 31 May 2018 22:13:13 +0800 Subject: [PATCH 56/81] fix version detector crash fixes #64 --- UnityLauncher/Tools.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index 0c8dec8..729fce1 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -300,7 +300,7 @@ public static string GetProjectVersion(string path) { // in text format, then we need to try library file instead var newVersionPath = Path.Combine(path, "Library", "AnnotationManager"); - if (File.Exists(versionPath) == true) + if (File.Exists(newVersionPath) == true) { versionPath = newVersionPath; } From 84b424290e63c6134f5d268d8c0015ebb73c5f63 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Tue, 11 Sep 2018 15:13:46 +0800 Subject: [PATCH 57/81] add searchbox in updates tab (to filter unity versions), update release url fixes #66, project list is refreshed after unity list is refreshed manually closes issue #19 --- UnityLauncher/Form1.Designer.cs | 84 +++++++++++++++++------------ UnityLauncher/Form1.cs | 35 ++++++++++-- UnityLauncher/Form1.resx | 35 ++++++++---- UnityLauncher/PreviousVersion.txt | Bin 14 -> 14 bytes UnityLauncher/Tools.cs | 14 +++-- UnityLauncher/UnityLauncher.csproj | 2 +- 6 files changed, 114 insertions(+), 56 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 8a2c0a9..6e4ac0a 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -52,6 +52,10 @@ private void InitializeComponent() this.btnExploreUnity = new System.Windows.Forms.Button(); this.btnLaunchUnity = new System.Windows.Forms.Button(); this.gridUnityList = new System.Windows.Forms.DataGridView(); + this._unityVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._unityPath = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._unityInstallDate = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._Platforms = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabPackages = new System.Windows.Forms.TabPage(); this.btnAddAssetStoreFolder = new System.Windows.Forms.Button(); this.btnExplorePackageFolder = new System.Windows.Forms.Button(); @@ -92,10 +96,8 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this._unityVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._unityPath = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._unityInstallDate = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this._Platforms = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker(); + this.tbSearchUpdates = new System.Windows.Forms.TextBox(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -397,6 +399,36 @@ private void InitializeComponent() this.gridUnityList.TabIndex = 10; this.gridUnityList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.unityGridView_KeyDown); // + // _unityVersion + // + this._unityVersion.HeaderText = "Version"; + this._unityVersion.MinimumWidth = 120; + this._unityVersion.Name = "_unityVersion"; + this._unityVersion.ReadOnly = true; + this._unityVersion.Width = 120; + // + // _unityPath + // + this._unityPath.HeaderText = "Path"; + this._unityPath.MinimumWidth = 300; + this._unityPath.Name = "_unityPath"; + this._unityPath.ReadOnly = true; + this._unityPath.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this._unityPath.Width = 300; + // + // _unityInstallDate + // + this._unityInstallDate.HeaderText = "Installed"; + this._unityInstallDate.Name = "_unityInstallDate"; + this._unityInstallDate.ReadOnly = true; + this._unityInstallDate.Width = 120; + // + // _Platforms + // + this._Platforms.HeaderText = "Platforms"; + this._Platforms.Name = "_Platforms"; + this._Platforms.ReadOnly = true; + // // tabPackages // this.tabPackages.Controls.Add(this.btnAddAssetStoreFolder); @@ -479,6 +511,7 @@ private void InitializeComponent() // // tabUpdates // + this.tabUpdates.Controls.Add(this.tbSearchUpdates); this.tabUpdates.Controls.Add(this.btnOpenUpdateWebsite); this.tabUpdates.Controls.Add(this.btnFetchUnityVersions); this.tabUpdates.Controls.Add(this.gridUnityUpdates); @@ -532,7 +565,7 @@ private void InitializeComponent() this._Date, this._UnityUpdateVersion}); this.gridUnityUpdates.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; - this.gridUnityUpdates.Location = new System.Drawing.Point(3, 27); + this.gridUnityUpdates.Location = new System.Drawing.Point(3, 30); this.gridUnityUpdates.MultiSelect = false; this.gridUnityUpdates.Name = "gridUnityUpdates"; this.gridUnityUpdates.ReadOnly = true; @@ -542,7 +575,7 @@ private void InitializeComponent() this.gridUnityUpdates.ShowCellErrors = false; this.gridUnityUpdates.ShowCellToolTips = false; this.gridUnityUpdates.ShowEditingIcon = false; - this.gridUnityUpdates.Size = new System.Drawing.Size(574, 478); + this.gridUnityUpdates.Size = new System.Drawing.Size(574, 475); this.gridUnityUpdates.StandardTab = true; this.gridUnityUpdates.TabIndex = 22; // @@ -866,35 +899,13 @@ private void InitializeComponent() this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // - // _unityVersion + // tbSearchUpdates // - this._unityVersion.HeaderText = "Version"; - this._unityVersion.MinimumWidth = 120; - this._unityVersion.Name = "_unityVersion"; - this._unityVersion.ReadOnly = true; - this._unityVersion.Width = 120; - // - // _unityPath - // - this._unityPath.HeaderText = "Path"; - this._unityPath.MinimumWidth = 300; - this._unityPath.Name = "_unityPath"; - this._unityPath.ReadOnly = true; - this._unityPath.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this._unityPath.Width = 300; - // - // _unityInstallDate - // - this._unityInstallDate.HeaderText = "Installed"; - this._unityInstallDate.Name = "_unityInstallDate"; - this._unityInstallDate.ReadOnly = true; - this._unityInstallDate.Width = 120; - // - // _Platforms - // - this._Platforms.HeaderText = "Platforms"; - this._Platforms.Name = "_Platforms"; - this._Platforms.ReadOnly = true; + this.tbSearchUpdates.Location = new System.Drawing.Point(3, 5); + this.tbSearchUpdates.Name = "tbSearchUpdates"; + this.tbSearchUpdates.Size = new System.Drawing.Size(460, 20); + this.tbSearchUpdates.TabIndex = 8; + this.tbSearchUpdates.TextChanged += new System.EventHandler(this.FilterUnityUpdates); // // Form1 // @@ -909,7 +920,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Spring Edition 25"; + this.Text = "UnityLauncher - Getting Darker Edition 26"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); @@ -924,6 +935,7 @@ private void InitializeComponent() this.tabPackages.ResumeLayout(false); this.tabPackages.PerformLayout(); this.tabUpdates.ResumeLayout(false); + this.tabUpdates.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).EndInit(); this.tabSettings.ResumeLayout(false); this.tabSettings.PerformLayout(); @@ -1000,6 +1012,8 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn _unityPath; private System.Windows.Forms.DataGridViewTextBoxColumn _unityInstallDate; private System.Windows.Forms.DataGridViewTextBoxColumn _Platforms; + private System.Windows.Forms.TextBox tbSearchUpdates; + private System.ComponentModel.BackgroundWorker backgroundWorker1; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 0dc56b4..fb71d92 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -237,15 +237,33 @@ bool ScanUnityInstallations() void FilterRecentProject(object sender, EventArgs e) { SetStatus("Filtering recent projects list ..."); - foreach (DataGridViewRow recentProject in gridRecent.Rows) + string searchString = tbSearchBar.Text; + foreach (DataGridViewRow row in gridRecent.Rows) { - if (recentProject.Cells["_project"].Value.ToString().IndexOf(tbSearchBar.Text, StringComparison.OrdinalIgnoreCase) > -1) + if (row.Cells["_project"].Value.ToString().IndexOf(searchString, StringComparison.OrdinalIgnoreCase) > -1) { - recentProject.Visible = true; + row.Visible = true; } else { - recentProject.Visible = false; + row.Visible = false; + } + } + } + + void FilterUnityUpdates(object sender, EventArgs e) + { + SetStatus("Filtering Unity updates list ..."); + string searchString = tbSearchUpdates.Text; + foreach (DataGridViewRow row in gridUnityUpdates.Rows) + { + if (row.Cells["_UnityUpdateVersion"].Value.ToString().IndexOf(searchString, StringComparison.OrdinalIgnoreCase) > -1) + { + row.Visible = true; + } + else + { + row.Visible = false; } } } @@ -666,6 +684,7 @@ private void btnAddUnityFolder_Click(object sender, EventArgs e) { AddUnityInstallationRootFolder(); ScanUnityInstallations(); + UpdateRecentProjectsList(); } private void btnRemoveInstallFolder_Click(object sender, EventArgs e) @@ -694,6 +713,7 @@ private void unityGridView_KeyDown(object sender, KeyEventArgs e) break; case Keys.F5: // refresh installed Unity versions list ScanUnityInstallations(); + UpdateRecentProjectsList(); break; default: break; @@ -712,11 +732,15 @@ private void Form1_KeyPress(object sender, KeyPressEventArgs e) switch ((int)e.KeyChar) { - case 27: // ESC - clear search + case 27: // ESCAPE - clear search if (tabControl1.SelectedIndex == 0 && tbSearchBar.Text != "") { tbSearchBar.Text = ""; } + else if (tabControl1.SelectedIndex == 3 && tbSearchUpdates.Text != "") + { + tbSearchUpdates.Text = ""; + } break; default: // any key // activate searchbar if not active and we are in tab#1 @@ -800,6 +824,7 @@ private void Form1_Resize(object sender, EventArgs e) private void btnRefresh_Click(object sender, EventArgs e) { ScanUnityInstallations(); + UpdateRecentProjectsList(); } private void notifyIcon_MouseClick(object sender, MouseEventArgs e) diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index cb55b8b..fe59a50 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -117,16 +117,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - True - - - True - - + True - + True @@ -168,10 +162,28 @@ True - + True - + + True + + + True + + + True + + + True + + + True + + + True + + True @@ -1078,6 +1090,9 @@ 374, 17 + + 17, 56 + 25 diff --git a/UnityLauncher/PreviousVersion.txt b/UnityLauncher/PreviousVersion.txt index f94c56c34bf714d0b3d3b427d76f8b2cbaf8b471..2a14793eee5de70158767545a91716e559f22acb 100644 GIT binary patch literal 14 VcmezW&yYcn!HB_>ftP`c0RSQt0^0xp literal 14 VcmezW&yYcn!HB__ftP`c0RSQh0@(ln diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index 729fce1..9309f56 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -31,7 +31,7 @@ public static string ReadGitBranchInfo(string projectPath) { string results = null; DirectoryInfo gitDirectory = FindDir(".git", projectPath); - if (gitDirectory != null ) + if (gitDirectory != null) { string branchFile = Path.Combine(gitDirectory.FullName, "HEAD"); if (File.Exists(branchFile)) @@ -57,9 +57,9 @@ public static string ReadGitBranchInfo(string projectPath) public static DirectoryInfo FindDir(string dirName, string startPath) { DirectoryInfo dirInfo = new DirectoryInfo(Path.Combine(startPath, dirName)); - while ( !dirInfo.Exists ) + while (!dirInfo.Exists) { - if(dirInfo.Parent.Parent == null ) + if (dirInfo.Parent.Parent == null) { return null; } @@ -111,6 +111,10 @@ public static string ReadCustomLaunchArguments(string projectPath, string launch /// public static string FindNearestVersion(string currentVersion, List allAvailable) { + if (currentVersion.Contains("2018")) + { + return FindNearestVersionFromSimilarVersions(currentVersion, allAvailable.Where(x => x.Contains("2018"))); + } if (currentVersion.Contains("2017")) { return FindNearestVersionFromSimilarVersions(currentVersion, allAvailable.Where(x => x.Contains("2017"))); @@ -173,7 +177,7 @@ public static string GetUnityReleaseURL(string version) if (version.Contains("f")) // archived { version = Regex.Replace(version, @"f.", "", RegexOptions.IgnoreCase); - url = "https://unity3d.com/unity/whats-new/unity-" + version; + url = "https://unity3d.com/unity/whatsnew/unity-" + version; } if (version.Contains("p")) // patch version { @@ -252,7 +256,7 @@ public static string GetProjectVersion(string path) { var version = ""; - if(File.Exists(Path.Combine(path, "ProjectVersionOverride.txt"))) + if (File.Exists(Path.Combine(path, "ProjectVersionOverride.txt"))) { version = File.ReadAllText(Path.Combine(path, "ProjectVersionOverride.txt")); } diff --git a/UnityLauncher/UnityLauncher.csproj b/UnityLauncher/UnityLauncher.csproj index ec7571b..bbd86b4 100644 --- a/UnityLauncher/UnityLauncher.csproj +++ b/UnityLauncher/UnityLauncher.csproj @@ -56,7 +56,7 @@ true - true + false unitylauncher.ico From 1c359528487e023ce8cf788343b5331132137f86 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Thu, 27 Sep 2018 13:54:58 +0800 Subject: [PATCH 58/81] add dark theme settings and checkbox --- UnityLauncher/App.config | 3 ++ UnityLauncher/Form1.Designer.cs | 49 ++++++++++++------- UnityLauncher/Form1.cs | 10 +++- UnityLauncher/Form1.resx | 39 --------------- UnityLauncher/Properties/Settings.Designer.cs | 12 +++++ UnityLauncher/Properties/Settings.settings | 3 ++ 6 files changed, 59 insertions(+), 57 deletions(-) diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index 18502f3..7d2fcca 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -45,6 +45,9 @@ False + + True + \ No newline at end of file diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 6e4ac0a..4249c40 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -64,12 +64,14 @@ private void InitializeComponent() this.label3 = new System.Windows.Forms.Label(); this.lstPackageFolders = new System.Windows.Forms.ListBox(); this.tabUpdates = new System.Windows.Forms.TabPage(); + this.tbSearchUpdates = new System.Windows.Forms.TextBox(); this.btnOpenUpdateWebsite = new System.Windows.Forms.Button(); this.btnFetchUnityVersions = new System.Windows.Forms.Button(); this.gridUnityUpdates = new System.Windows.Forms.DataGridView(); this._Date = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._UnityUpdateVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabSettings = new System.Windows.Forms.TabPage(); + this.chkDarkSkin = new System.Windows.Forms.CheckBox(); this.btnCheckUpdates = new System.Windows.Forms.Button(); this.linkProjectGithub = new System.Windows.Forms.LinkLabel(); this.linkArgumentsDocs = new System.Windows.Forms.LinkLabel(); @@ -97,7 +99,6 @@ private void InitializeComponent() this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker(); - this.tbSearchUpdates = new System.Windows.Forms.TextBox(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -522,6 +523,14 @@ private void InitializeComponent() this.tabUpdates.Text = "Updates"; this.tabUpdates.UseVisualStyleBackColor = true; // + // tbSearchUpdates + // + this.tbSearchUpdates.Location = new System.Drawing.Point(3, 5); + this.tbSearchUpdates.Name = "tbSearchUpdates"; + this.tbSearchUpdates.Size = new System.Drawing.Size(460, 20); + this.tbSearchUpdates.TabIndex = 8; + this.tbSearchUpdates.TextChanged += new System.EventHandler(this.FilterUnityUpdates); + // // btnOpenUpdateWebsite // this.btnOpenUpdateWebsite.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) @@ -597,6 +606,7 @@ private void InitializeComponent() // // tabSettings // + this.tabSettings.Controls.Add(this.chkDarkSkin); this.tabSettings.Controls.Add(this.btnCheckUpdates); this.tabSettings.Controls.Add(this.linkProjectGithub); this.tabSettings.Controls.Add(this.linkArgumentsDocs); @@ -624,6 +634,18 @@ private void InitializeComponent() this.tabSettings.Text = "Settings"; this.tabSettings.UseVisualStyleBackColor = true; // + // chkDarkSkin + // + this.chkDarkSkin.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.chkDarkSkin.AutoSize = true; + this.chkDarkSkin.Location = new System.Drawing.Point(20, 416); + this.chkDarkSkin.Name = "chkDarkSkin"; + this.chkDarkSkin.Size = new System.Drawing.Size(85, 17); + this.chkDarkSkin.TabIndex = 41; + this.chkDarkSkin.Text = "Dark Theme"; + this.chkDarkSkin.UseVisualStyleBackColor = true; + this.chkDarkSkin.CheckedChanged += new System.EventHandler(this.chkDarkSkin_CheckedChanged); + // // btnCheckUpdates // this.btnCheckUpdates.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); @@ -656,7 +678,7 @@ private void InitializeComponent() this.linkArgumentsDocs.AutoSize = true; this.linkArgumentsDocs.LinkArea = new System.Windows.Forms.LinkArea(1, 4); this.linkArgumentsDocs.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline; - this.linkArgumentsDocs.Location = new System.Drawing.Point(385, 387); + this.linkArgumentsDocs.Location = new System.Drawing.Point(385, 348); this.linkArgumentsDocs.Name = "linkArgumentsDocs"; this.linkArgumentsDocs.Size = new System.Drawing.Size(36, 17); this.linkArgumentsDocs.TabIndex = 38; @@ -669,7 +691,7 @@ private void InitializeComponent() // this.chkShowGitBranchColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkShowGitBranchColumn.AutoSize = true; - this.chkShowGitBranchColumn.Location = new System.Drawing.Point(266, 409); + this.chkShowGitBranchColumn.Location = new System.Drawing.Point(266, 370); this.chkShowGitBranchColumn.Name = "chkShowGitBranchColumn"; this.chkShowGitBranchColumn.Size = new System.Drawing.Size(76, 17); this.chkShowGitBranchColumn.TabIndex = 36; @@ -683,7 +705,7 @@ private void InitializeComponent() this.label5.AutoSize = true; this.label5.Enabled = false; this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label5.Location = new System.Drawing.Point(263, 361); + this.label5.Location = new System.Drawing.Point(263, 322); this.label5.Name = "label5"; this.label5.Size = new System.Drawing.Size(105, 13); this.label5.TabIndex = 35; @@ -693,7 +715,7 @@ private void InitializeComponent() // this.chkShowLauncherArgumentsColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkShowLauncherArgumentsColumn.AutoSize = true; - this.chkShowLauncherArgumentsColumn.Location = new System.Drawing.Point(266, 386); + this.chkShowLauncherArgumentsColumn.Location = new System.Drawing.Point(266, 347); this.chkShowLauncherArgumentsColumn.Name = "chkShowLauncherArgumentsColumn"; this.chkShowLauncherArgumentsColumn.Size = new System.Drawing.Size(124, 17); this.chkShowLauncherArgumentsColumn.TabIndex = 34; @@ -705,7 +727,7 @@ private void InitializeComponent() // this.ChkQuitAfterOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.ChkQuitAfterOpen.AutoSize = true; - this.ChkQuitAfterOpen.Location = new System.Drawing.Point(20, 409); + this.ChkQuitAfterOpen.Location = new System.Drawing.Point(20, 370); this.ChkQuitAfterOpen.Name = "ChkQuitAfterOpen"; this.ChkQuitAfterOpen.Size = new System.Drawing.Size(172, 17); this.ChkQuitAfterOpen.TabIndex = 33; @@ -728,7 +750,7 @@ private void InitializeComponent() // this.chkQuitAfterCommandline.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkQuitAfterCommandline.AutoSize = true; - this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 432); + this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 393); this.chkQuitAfterCommandline.Name = "chkQuitAfterCommandline"; this.chkQuitAfterCommandline.Size = new System.Drawing.Size(189, 17); this.chkQuitAfterCommandline.TabIndex = 31; @@ -774,7 +796,7 @@ private void InitializeComponent() this.label2.AutoSize = true; this.label2.Enabled = false; this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label2.Location = new System.Drawing.Point(17, 361); + this.label2.Location = new System.Drawing.Point(17, 322); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(88, 13); this.label2.TabIndex = 26; @@ -784,7 +806,7 @@ private void InitializeComponent() // this.chkMinimizeToTaskbar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkMinimizeToTaskbar.AutoSize = true; - this.chkMinimizeToTaskbar.Location = new System.Drawing.Point(20, 386); + this.chkMinimizeToTaskbar.Location = new System.Drawing.Point(20, 347); this.chkMinimizeToTaskbar.Name = "chkMinimizeToTaskbar"; this.chkMinimizeToTaskbar.Size = new System.Drawing.Size(116, 17); this.chkMinimizeToTaskbar.TabIndex = 25; @@ -899,14 +921,6 @@ private void InitializeComponent() this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // - // tbSearchUpdates - // - this.tbSearchUpdates.Location = new System.Drawing.Point(3, 5); - this.tbSearchUpdates.Name = "tbSearchUpdates"; - this.tbSearchUpdates.Size = new System.Drawing.Size(460, 20); - this.tbSearchUpdates.TabIndex = 8; - this.tbSearchUpdates.TextChanged += new System.EventHandler(this.FilterUnityUpdates); - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1014,6 +1028,7 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn _Platforms; private System.Windows.Forms.TextBox tbSearchUpdates; private System.ComponentModel.BackgroundWorker backgroundWorker1; + private System.Windows.Forms.CheckBox chkDarkSkin; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index fb71d92..bd82b2f 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -133,6 +133,7 @@ void LoadSettings() ChkQuitAfterOpen.Checked = Properties.Settings.Default.closeAfterProject; chkShowLauncherArgumentsColumn.Checked = Properties.Settings.Default.showArgumentsColumn; chkShowGitBranchColumn.Checked = Properties.Settings.Default.showGitBranchColumn; + chkDarkSkin.Checked = Properties.Settings.Default.useDarkSkin; // update optional grid columns, hidden or visible gridRecent.Columns["_launchArguments"].Visible = chkShowLauncherArgumentsColumn.Checked; @@ -154,6 +155,8 @@ void LoadSettings() gridRecent.Columns[i].Width = gridColumnWidths[i]; } } + + // TODO assign colors, if using dark/light theme } /// @@ -890,6 +893,12 @@ private void chkQuitAfterCommandline_CheckedChanged(object sender, EventArgs e) Properties.Settings.Default.Save(); } + private void chkDarkSkin_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.useDarkSkin = chkDarkSkin.Checked; + Properties.Settings.Default.Save(); + } + private void btnRunUnityOnly_Click(object sender, EventArgs e) { LaunchSelectedProject(openProject: false); @@ -1273,6 +1282,5 @@ private void SaveSettingsOnExit() Properties.Settings.Default.Save(); } - } // class Form } // namespace \ No newline at end of file diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index fe59a50..f629e1d 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -117,12 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - True - - - True - 14, 20 @@ -144,36 +138,6 @@ True - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - True - True @@ -192,9 +156,6 @@ True - - 14, 20 - 111, 20 diff --git a/UnityLauncher/Properties/Settings.Designer.cs b/UnityLauncher/Properties/Settings.Designer.cs index e25de41..c8b6fbd 100644 --- a/UnityLauncher/Properties/Settings.Designer.cs +++ b/UnityLauncher/Properties/Settings.Designer.cs @@ -144,5 +144,17 @@ public bool showGitBranchColumn { this["showGitBranchColumn"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool useDarkSkin { + get { + return ((bool)(this["useDarkSkin"])); + } + set { + this["useDarkSkin"] = value; + } + } } } diff --git a/UnityLauncher/Properties/Settings.settings b/UnityLauncher/Properties/Settings.settings index bca9a0e..1ca3140 100644 --- a/UnityLauncher/Properties/Settings.settings +++ b/UnityLauncher/Properties/Settings.settings @@ -36,5 +36,8 @@ False + + True + \ No newline at end of file From 394c1cddfb37d70a0f2137f9b248546432e4832a Mon Sep 17 00:00:00 2001 From: unitycoder Date: Thu, 27 Sep 2018 22:26:10 +0800 Subject: [PATCH 59/81] adding dark theme colors to controls (wip) --- UnityLauncher/Form1.cs | 21 ++++++++++++++++++++- UnityLauncher/Form1.resx | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index bd82b2f..ad71d5d 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -156,7 +156,26 @@ void LoadSettings() } } - // TODO assign colors, if using dark/light theme + // TODO assign colors for dark theme + if (chkDarkSkin.Checked == true) + { + var darkBg = Color.FromArgb(32, 37, 41); + var darkRaised = Color.FromArgb(50, 56, 61); + var darkBright = Color.FromArgb(161, 180, 196); + + + this.BackColor = darkBg; + tabProjects.BackColor = darkRaised; + gridRecent.BackgroundColor = darkRaised; + + gridRecent.GridColor = darkBg; + var dgs = new DataGridViewCellStyle(); + dgs.BackColor = darkRaised; + dgs.ForeColor = darkBright; + gridRecent.DefaultCellStyle = dgs; + + statusStrip1.BackColor = darkRaised; + } } /// diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index f629e1d..83ebd0f 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -138,6 +138,36 @@ True + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + True @@ -156,6 +186,15 @@ True + + True + + + True + + + 14, 20 + 111, 20 From f2ce747afaa11317706862e98dcaee1079ae8979 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Tue, 27 Nov 2018 11:00:25 +0200 Subject: [PATCH 60/81] add registry folder if missing fixes #65 --- UnityLauncher/Tools.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index 9309f56..c01f602 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -224,6 +224,13 @@ public static void RemoveContextMenuRegistry(string contextRegRoot) public static void AddContextMenuRegistry(string contextRegRoot) { RegistryKey key = Registry.CurrentUser.OpenSubKey(contextRegRoot, true); + + // add folder if missing + if (key == null) + { + key = Registry.CurrentUser.CreateSubKey(@"Software\Classes\Directory\Background\Shell"); + } + if (key != null) { var appName = "UnityLauncher"; @@ -238,11 +245,10 @@ public static void AddContextMenuRegistry(string contextRegRoot) var executeString = "\"" + Application.ExecutablePath + "\""; executeString += " -projectPath \"%V\""; key.SetValue("", executeString); - //SetStatus("Added context menu registry items"); } else { - //SetStatus("Error> Cannot find registry key: " + contextRegRoot); + Console.WriteLine("Error> Cannot find registry key: " + contextRegRoot); } } From fc22f90d3defb02d60d6e57e25ad74125f76a549 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Tue, 27 Nov 2018 11:09:01 +0200 Subject: [PATCH 61/81] update alpha, beta release note links fixes #61 --- UnityLauncher/Tools.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index c01f602..1c1076d 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -179,13 +179,20 @@ public static string GetUnityReleaseURL(string version) version = Regex.Replace(version, @"f.", "", RegexOptions.IgnoreCase); url = "https://unity3d.com/unity/whatsnew/unity-" + version; } + else if (version.Contains("p")) // patch version { url = "https://unity3d.com/unity/qa/patch-releases/" + version; } + else if (version.Contains("b")) // beta version { - url = "https://unity3d.com/unity/beta/unity" + version; + url = "https://unity3d.com/unity/beta/" + version; + } + else + if (version.Contains("a")) // alpha version + { + url = "https://unity3d.com/unity/alpha/" + version; } return url; } From bcefe976472c7ea4ddc3ca24fe3bd2b1c7e73fa7 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Tue, 27 Nov 2018 18:09:58 +0200 Subject: [PATCH 62/81] set darkskin disabled by default --- UnityLauncher/App.config | 2 +- UnityLauncher/Form1.cs | 2 +- UnityLauncher/Properties/Settings.Designer.cs | 4 ++-- UnityLauncher/Properties/Settings.settings | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index 7d2fcca..d120241 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -46,7 +46,7 @@ False - True + False diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index ad71d5d..d81d867 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -162,7 +162,7 @@ void LoadSettings() var darkBg = Color.FromArgb(32, 37, 41); var darkRaised = Color.FromArgb(50, 56, 61); var darkBright = Color.FromArgb(161, 180, 196); - + this.BackColor = darkBg; tabProjects.BackColor = darkRaised; diff --git a/UnityLauncher/Properties/Settings.Designer.cs b/UnityLauncher/Properties/Settings.Designer.cs index c8b6fbd..bfbc853 100644 --- a/UnityLauncher/Properties/Settings.Designer.cs +++ b/UnityLauncher/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace UnityLauncher.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -147,7 +147,7 @@ public bool showGitBranchColumn { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("True")] + [global::System.Configuration.DefaultSettingValueAttribute("False")] public bool useDarkSkin { get { return ((bool)(this["useDarkSkin"])); diff --git a/UnityLauncher/Properties/Settings.settings b/UnityLauncher/Properties/Settings.settings index 1ca3140..ebe4f8c 100644 --- a/UnityLauncher/Properties/Settings.settings +++ b/UnityLauncher/Properties/Settings.settings @@ -37,7 +37,7 @@ False - True + False \ No newline at end of file From 48c307516555bd03e5f7f07a991f2500b0292c84 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Wed, 5 Dec 2018 12:22:27 +0200 Subject: [PATCH 63/81] fix utf8 project path parsing fixes #72 --- UnityLauncher/Form1.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index d81d867..1d4d38b 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -307,7 +307,14 @@ void UpdateRecentProjectsList() { RegistryKey key = hklm.OpenSubKey(registryPathsToCheck[i]); - if (key == null) continue; + if (key == null) + { + continue; + } + else + { + Console.WriteLine("Null registry key at "+ registryPathsToCheck[i]); + } // parse recent project path foreach (var valueName in key.GetValueNames()) @@ -320,7 +327,7 @@ void UpdateRecentProjectsList() if (valueKind == RegistryValueKind.Binary) { byte[] projectPathBytes = (byte[])key.GetValue(valueName); - projectPath = Encoding.Default.GetString(projectPathBytes, 0, projectPathBytes.Length - 1); + projectPath = Encoding.UTF8.GetString(projectPathBytes, 0, projectPathBytes.Length - 1); } else // should be string then { @@ -330,6 +337,7 @@ void UpdateRecentProjectsList() // first check if whole folder exists, if not, skip if (Directory.Exists(projectPath) == false) { + Console.WriteLine("Recent project directory not found, skipping: "+ projectPath); continue; } From 4b0fee7ccfb07f07fc79e9559b00801d07dd0dec Mon Sep 17 00:00:00 2001 From: unitycoder Date: Wed, 2 Jan 2019 21:41:42 +0200 Subject: [PATCH 64/81] fixed #73, fixed #74 --- UnityLauncher/Form1.cs | 13 +++++++++++-- UnityLauncher/Tools.cs | 4 +++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 1d4d38b..6e6a229 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -313,7 +313,7 @@ void UpdateRecentProjectsList() } else { - Console.WriteLine("Null registry key at "+ registryPathsToCheck[i]); + Console.WriteLine("Null registry key at " + registryPathsToCheck[i]); } // parse recent project path @@ -337,7 +337,7 @@ void UpdateRecentProjectsList() // first check if whole folder exists, if not, skip if (Directory.Exists(projectPath) == false) { - Console.WriteLine("Recent project directory not found, skipping: "+ projectPath); + Console.WriteLine("Recent project directory not found, skipping: " + projectPath); continue; } @@ -598,7 +598,16 @@ private void ShowForm() void LaunchSelectedProject(bool openProject = true) { + if (gridRecent.CurrentCell == null) + { + if (gridRecent.SelectedRows.Count != 0) + { + DataGridViewRow row = gridRecent.SelectedRows[0]; + gridRecent.CurrentCell = row.Cells[0]; + } + } var selected = gridRecent.CurrentCell.RowIndex; + if (selected > -1) { var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index 1c1076d..07ca9fd 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -177,7 +177,9 @@ public static string GetUnityReleaseURL(string version) if (version.Contains("f")) // archived { version = Regex.Replace(version, @"f.", "", RegexOptions.IgnoreCase); - url = "https://unity3d.com/unity/whatsnew/unity-" + version; + string padding = "unity-"; + if (version.Contains("2018.2")) padding = ""; + url = "https://unity3d.com/unity/whats-new/" + padding + version; } else if (version.Contains("p")) // patch version From d6df0063e88ed3db5ae82c1d5bdab9c5ebb6035f Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sun, 13 Jan 2019 14:24:14 +0200 Subject: [PATCH 65/81] fix null selected rows after search --- UnityLauncher/Form1.cs | 68 ++++++++++++++++++------------ UnityLauncher/PreviousVersion.txt | Bin 14 -> 14 bytes 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 6e6a229..8842cc1 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -598,19 +598,12 @@ private void ShowForm() void LaunchSelectedProject(bool openProject = true) { - if (gridRecent.CurrentCell == null) - { - if (gridRecent.SelectedRows.Count != 0) - { - DataGridViewRow row = gridRecent.SelectedRows[0]; - gridRecent.CurrentCell = row.Cells[0]; - } - } - var selected = gridRecent.CurrentCell.RowIndex; + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; - if (selected > -1) + if (selected.HasValue && selected > -1) { - var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); + var projectPath = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); var version = Tools.GetProjectVersion(projectPath); LaunchProject(projectPath, version, openProject); SetStatus("Ready"); @@ -621,11 +614,12 @@ void LaunchSelectedProject(bool openProject = true) void LaunchSelectedUnity() { - var selected = gridUnityList.CurrentCell.RowIndex; - if (selected > -1) + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) { SetStatus("Launching Unity.."); - var version = gridUnityList.Rows[selected].Cells["_unityVersion"].Value.ToString(); + var version = gridUnityList.Rows[(int)selected].Cells["_unityVersion"].Value.ToString(); try { Process myProcess = new Process(); @@ -686,10 +680,11 @@ private void btnRemovePackFolder_Click(object sender, EventArgs e) private void btnOpenReleasePage_Click(object sender, EventArgs e) { - var selected = gridUnityList.CurrentCell.RowIndex; - if (selected > -1) + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) { - var version = gridUnityList.Rows[selected].Cells["_unityVersion"].Value.ToString(); + var version = gridUnityList.Rows[(int)selected].Cells["_unityVersion"].Value.ToString(); if (Tools.OpenReleaseNotes(version) == true) { SetStatus("Opening release notes for version " + version); @@ -708,10 +703,11 @@ private void btnLaunchUnity_Click(object sender, EventArgs e) private void btnExploreUnity_Click(object sender, EventArgs e) { - var selected = gridUnityList.CurrentCell.RowIndex; - if (selected > -1) + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) { - var unityPath = Path.GetDirectoryName(gridUnityList.Rows[selected].Cells["_unityPath"].Value.ToString()); + var unityPath = Path.GetDirectoryName(gridUnityList.Rows[(int)selected].Cells["_unityPath"].Value.ToString()); if (Tools.LaunchExplorer(unityPath) == false) { SetStatus("Error> Directory not found: " + unityPath); @@ -873,10 +869,11 @@ private void notifyIcon_MouseClick(object sender, MouseEventArgs e) private void btn_openFolder_Click(object sender, EventArgs e) { - var selected = gridRecent.CurrentCell.RowIndex; - if (selected > -1) + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) { - string folder = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); + string folder = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); if (Tools.LaunchExplorer(folder) == false) { SetStatus("Error> Directory not found: " + folder); @@ -959,8 +956,9 @@ private void btnOpenLogFolder_Click(object sender, EventArgs e) private void btnOpenUpdateWebsite_Click(object sender, EventArgs e) { + FixSelectedRow(); var selected = gridUnityUpdates?.CurrentCell?.RowIndex; - if (selected != null && selected > -1) + if (selected.HasValue && selected > -1) { var version = gridUnityUpdates.Rows[(int)selected].Cells["_UnityUpdateVersion"].Value.ToString(); Tools.OpenReleaseNotes(version); @@ -1079,12 +1077,13 @@ private void Form1_FormClosing(object sender, FormClosingEventArgs e) // displays version selector to upgrade project void UpgradeProject() { - var selected = gridRecent.CurrentCell.RowIndex; - if (selected > -1) + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) { SetStatus("Upgrading project ..."); - var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); + var projectPath = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); var currentVersion = Tools.GetProjectVersion(projectPath); if (string.IsNullOrEmpty(currentVersion) == true) @@ -1183,10 +1182,11 @@ private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedE string GetSelectedRowData(string key) { string path = null; + FixSelectedRow(); var selected = gridRecent?.CurrentCell?.RowIndex; if (selected.HasValue && selected > -1) { - path = gridRecent.Rows[selected.Value].Cells[key].Value?.ToString(); + path = gridRecent.Rows[(int)selected].Cells[key].Value?.ToString(); } return path; } @@ -1318,5 +1318,17 @@ private void SaveSettingsOnExit() Properties.Settings.Default.Save(); } + void FixSelectedRow() + { + if (gridRecent.CurrentCell == null) + { + if (gridRecent.SelectedRows.Count != 0) + { + DataGridViewRow row = gridRecent.SelectedRows[0]; + gridRecent.CurrentCell = row.Cells[0]; + } + } + } + } // class Form } // namespace \ No newline at end of file diff --git a/UnityLauncher/PreviousVersion.txt b/UnityLauncher/PreviousVersion.txt index 2a14793eee5de70158767545a91716e559f22acb..03acb06106898c45e721d14736087abde6f24ca9 100644 GIT binary patch literal 14 VcmezW&yYcn!HB_(ftP`c0RSQz0^9%q literal 14 VcmezW&yYcn!HB_>ftP`c0RSQt0^0xp From ec591c9eb3f0bd927f3b924893e6dae2bc069b60 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Thu, 24 Jan 2019 08:35:59 +0200 Subject: [PATCH 66/81] update lts version url, add colors to updates tab (non-installed versions as red) fixes #75 --- UnityLauncher/Form1.cs | 24 +++++++++++++++--------- UnityLauncher/Tools.cs | 5 ++++- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 8842cc1..0bdda62 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -22,7 +22,7 @@ public partial class Form1 : Form const string githubReleaseAPICheckURL = "https://api.github.com/repos/unitycoder/unitylauncher/releases/latest"; const string githubReleasesLinkURL = "https://github.com/unitycoder/UnityLauncher/releases"; - bool isDownloadUnityList = false; + bool isDownloadingUnityList = false; string previousGitRelease = "0"; @@ -1145,12 +1145,12 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch private void FetchListOfUnityUpdates() { - if (isDownloadUnityList == true) + if (isDownloadingUnityList == true) { SetStatus("We are already downloading ..."); return; } - isDownloadUnityList = true; + isDownloadingUnityList = true; SetStatus("Downloading list of Unity versions ..."); // download list of Unity versions @@ -1166,15 +1166,21 @@ private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedE { // TODO check for error.. SetStatus("Downloading list of Unity versions ... done"); - isDownloadUnityList = false; + isDownloadingUnityList = false; + // parse to list - var unityList = e.Result.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - Array.Reverse(unityList); + var receivedList = e.Result.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + Array.Reverse(receivedList); gridUnityUpdates.Rows.Clear(); - for (int i = 0, len = unityList.Length; i < len; i++) + // fill in, TODO: show only top 50 or so + for (int i = 0, len = receivedList.Length; i < len; i++) { - var row = unityList[i].Split(','); - gridUnityUpdates.Rows.Add(row[3], row[6].Trim('"')); + var row = receivedList[i].Split(','); + var versionTemp = row[6].Trim('"'); + gridUnityUpdates.Rows.Add(row[3], versionTemp); + + // set color if we already have it installed + gridUnityUpdates.Rows[i].Cells[1].Style.ForeColor = unityList.ContainsKey(versionTemp) ? Color.Black : Color.Red; } } diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index 07ca9fd..4205ed1 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -174,10 +174,12 @@ public static bool OpenReleaseNotes(string version) public static string GetUnityReleaseURL(string version) { string url = ""; + + if (version.Contains("f")) // archived { version = Regex.Replace(version, @"f.", "", RegexOptions.IgnoreCase); - string padding = "unity-"; + string padding = ""; if (version.Contains("2018.2")) padding = ""; url = "https://unity3d.com/unity/whats-new/" + padding + version; } @@ -196,6 +198,7 @@ public static string GetUnityReleaseURL(string version) { url = "https://unity3d.com/unity/alpha/" + version; } + return url; } From 30bd916808147cb6e2274925509876ad5cd7e637 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Thu, 24 Jan 2019 19:41:05 +0200 Subject: [PATCH 67/81] fix update tab buttons (referenced wrong gridlist), color installed updates as green --- UnityLauncher/Form1.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 0bdda62..b84489a 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -614,8 +614,8 @@ void LaunchSelectedProject(bool openProject = true) void LaunchSelectedUnity() { - FixSelectedRow(); - var selected = gridRecent?.CurrentCell?.RowIndex; + + var selected = gridUnityList?.CurrentCell?.RowIndex; if (selected.HasValue && selected > -1) { SetStatus("Launching Unity.."); @@ -680,8 +680,7 @@ private void btnRemovePackFolder_Click(object sender, EventArgs e) private void btnOpenReleasePage_Click(object sender, EventArgs e) { - FixSelectedRow(); - var selected = gridRecent?.CurrentCell?.RowIndex; + var selected = gridUnityList?.CurrentCell?.RowIndex; if (selected.HasValue && selected > -1) { var version = gridUnityList.Rows[(int)selected].Cells["_unityVersion"].Value.ToString(); @@ -703,8 +702,8 @@ private void btnLaunchUnity_Click(object sender, EventArgs e) private void btnExploreUnity_Click(object sender, EventArgs e) { - FixSelectedRow(); - var selected = gridRecent?.CurrentCell?.RowIndex; + + var selected = gridUnityList?.CurrentCell?.RowIndex; if (selected.HasValue && selected > -1) { var unityPath = Path.GetDirectoryName(gridUnityList.Rows[(int)selected].Cells["_unityPath"].Value.ToString()); @@ -1180,7 +1179,7 @@ private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedE gridUnityUpdates.Rows.Add(row[3], versionTemp); // set color if we already have it installed - gridUnityUpdates.Rows[i].Cells[1].Style.ForeColor = unityList.ContainsKey(versionTemp) ? Color.Black : Color.Red; + gridUnityUpdates.Rows[i].Cells[1].Style.ForeColor = unityList.ContainsKey(versionTemp) ? Color.Green : Color.Black; } } From e31a36427f5952573f8ab65fd526fc152de5f90c Mon Sep 17 00:00:00 2001 From: unitycoder Date: Wed, 27 Feb 2019 20:23:19 +0200 Subject: [PATCH 68/81] "set close after project: false" as default, remove update checker and build powershell script, add 2019 to nearest version search --- UnityLauncher/App.config | 2 +- UnityLauncher/Form1.Designer.cs | 8 +-- UnityLauncher/Form1.cs | 29 ++------- UnityLauncher/Properties/Settings.Designer.cs | 2 +- UnityLauncher/Properties/Settings.settings | 2 +- UnityLauncher/Tools.cs | 61 ++----------------- UnityLauncher/UnityLauncher.csproj | 3 +- 7 files changed, 16 insertions(+), 91 deletions(-) diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index d120241..498e2cf 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -31,7 +31,7 @@ True - True + False 600 diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 4249c40..81c3ce7 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -649,11 +649,11 @@ private void InitializeComponent() // btnCheckUpdates // this.btnCheckUpdates.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnCheckUpdates.Location = new System.Drawing.Point(434, 495); + this.btnCheckUpdates.Location = new System.Drawing.Point(415, 495); this.btnCheckUpdates.Name = "btnCheckUpdates"; - this.btnCheckUpdates.Size = new System.Drawing.Size(138, 23); + this.btnCheckUpdates.Size = new System.Drawing.Size(157, 23); this.btnCheckUpdates.TabIndex = 40; - this.btnCheckUpdates.Text = "Check for Updates"; + this.btnCheckUpdates.Text = "Open Github Releases Page"; this.btnCheckUpdates.UseVisualStyleBackColor = true; this.btnCheckUpdates.Click += new System.EventHandler(this.btnCheckUpdates_Click); // @@ -904,8 +904,6 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.statusStrip1.AutoSize = false; this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(579, 22); diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index b84489a..c211b89 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -19,7 +19,6 @@ public partial class Form1 : Form public static Dictionary unityList = new Dictionary(); const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; const string launcherArgumentsFile = "LauncherArguments.txt"; - const string githubReleaseAPICheckURL = "https://api.github.com/repos/unitycoder/unitylauncher/releases/latest"; const string githubReleasesLinkURL = "https://github.com/unitycoder/UnityLauncher/releases"; bool isDownloadingUnityList = false; @@ -229,8 +228,9 @@ bool ScanUnityInstallations() if (File.Exists(uninstallExe) == true) { var unityExe = Path.Combine(directories[i], "Editor", "Unity.exe"); - if (File.Exists(uninstallExe) == true) + if (File.Exists(unityExe) == true) { + // get full version number from uninstaller var unityVersion = Tools.GetFileVersionData(uninstallExe).Replace("Unity", "").Trim(); if (unityList.ContainsKey(unityVersion) == false) { @@ -246,7 +246,6 @@ bool ScanUnityInstallations() } // failed check } // all root folders - lbl_unityCount.Text = "Found " + unityList.Count.ToString() + " versions"; SetStatus("Finished scanning"); @@ -313,7 +312,7 @@ void UpdateRecentProjectsList() } else { - Console.WriteLine("Null registry key at " + registryPathsToCheck[i]); + //Console.WriteLine("Null registry key at " + registryPathsToCheck[i]); } // parse recent project path @@ -1050,7 +1049,7 @@ private void gridRecent_CellEndEdit(object sender, DataGridViewCellEventArgs e) private void btnCheckUpdates_Click(object sender, EventArgs e) { - CheckUpdates(); + Tools.OpenURL("https://github.com/unitycoder/UnityLauncher/releases"); } private void btnRefreshProjectList_Click(object sender, EventArgs e) @@ -1196,26 +1195,6 @@ string GetSelectedRowData(string key) return path; } - void CheckUpdates() - { - var result = Tools.CheckUpdates(githubReleaseAPICheckURL, previousGitRelease); - if (string.IsNullOrEmpty(result) == false) - { - SetStatus("Update available: " + result + " - Previous release was:" + previousGitRelease); - DialogResult dialogResult = MessageBox.Show("Update " + result + " is available, open download page?", "UnityLauncher - Check Update", MessageBoxButtons.YesNo); - if (dialogResult == DialogResult.Yes) // open download page - { - Tools.OpenURL(githubReleasesLinkURL); - } - } - else - { - SetStatus("No updates available. Current release is " + (float.Parse(previousGitRelease) + 0.01f)); - } - } - - - void BrowseForExistingProjectFolder() { folderBrowserDialog1.Description = "Select existing project folder"; diff --git a/UnityLauncher/Properties/Settings.Designer.cs b/UnityLauncher/Properties/Settings.Designer.cs index bfbc853..89b70cd 100644 --- a/UnityLauncher/Properties/Settings.Designer.cs +++ b/UnityLauncher/Properties/Settings.Designer.cs @@ -76,7 +76,7 @@ public bool closeAfterExplorer { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("True")] + [global::System.Configuration.DefaultSettingValueAttribute("False")] public bool closeAfterProject { get { return ((bool)(this["closeAfterProject"])); diff --git a/UnityLauncher/Properties/Settings.settings b/UnityLauncher/Properties/Settings.settings index ebe4f8c..b18b7e0 100644 --- a/UnityLauncher/Properties/Settings.settings +++ b/UnityLauncher/Properties/Settings.settings @@ -19,7 +19,7 @@ True - True + False 600 diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index 4205ed1..ee80320 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -111,6 +111,10 @@ public static string ReadCustomLaunchArguments(string projectPath, string launch /// public static string FindNearestVersion(string currentVersion, List allAvailable) { + if (currentVersion.Contains("2019")) + { + return FindNearestVersionFromSimilarVersions(currentVersion, allAvailable.Where(x => x.Contains("2019"))); + } if (currentVersion.Contains("2018")) { return FindNearestVersionFromSimilarVersions(currentVersion, allAvailable.Where(x => x.Contains("2018"))); @@ -378,62 +382,5 @@ public static bool LaunchExplorer(string folder) return result; } - /// - /// - /// - /// api to check releases - /// embedded previous release version - /// null if no info available, otherwise returns current github release number - public static string CheckUpdates(string githubReleaseURL, string previousGitRelease) - { - string result = null; - using (WebClient client = new WebClient()) - { - // apparently this is now required..otherwise: "The request was aborted: Could not create SSL/TLS secure channel" - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - - // fetch current release info - client.Headers.Add("user-agent", "MuskBrowser"); - string json = client.DownloadString(githubReleaseURL); - - if (json.IndexOf('{') != 0) - { - // invalid json - return result; - } - - var arr = json.Split(new string[] { "\"tag_name\":" }, StringSplitOptions.None); - - // have tagname - if (arr.Length > 1) - { - var arr2 = arr[1].Trim().Split('"'); - // have " - if (arr2.Length > 1) - { - var currentlyAvailableLatestReleaseTag = arr2[1]; - - // compare online version with build in release version, return github version if different from embedded version - float previous = 0; - float current = 0; - if (float.TryParse(previousGitRelease, out previous) == false) return result; - if (float.TryParse(currentlyAvailableLatestReleaseTag, out current) == false) return result; - - if (Math.Abs(previous - current) > 0.1f) - { - result = currentlyAvailableLatestReleaseTag; - Console.WriteLine("update available: [" + currentlyAvailableLatestReleaseTag + "] / [" + previousGitRelease + "]"); - } - else - { - Console.WriteLine("no update available: [" + currentlyAvailableLatestReleaseTag + "] / [" + previousGitRelease + "]"); - } - } - } - } - return result; - } - - } } diff --git a/UnityLauncher/UnityLauncher.csproj b/UnityLauncher/UnityLauncher.csproj index bbd86b4..8bd73a9 100644 --- a/UnityLauncher/UnityLauncher.csproj +++ b/UnityLauncher/UnityLauncher.csproj @@ -132,6 +132,7 @@ - powershell.exe -command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;$web = New-Object System.Net.WebClient;$web.Headers['User-Agent'] = 'DefinitelyBrowser';$results = $web.DownloadString('https://api.github.com/repos/unitycoder/unitylauncher/releases/latest');$results = $results | ConvertFrom-Json;$results = $results | select -expand tag_name;echo $results | Out-File \"$(ProjectDir)PreviousVersion.txt\";" + + \ No newline at end of file From 610e9615085b808cb470e1ac8f257dc35273800f Mon Sep 17 00:00:00 2001 From: mika Date: Tue, 16 Apr 2019 22:57:15 +0300 Subject: [PATCH 69/81] fix release note urls, add unity to list even without uninstaller.exe (but missing version info) --- UnityLauncher/Form1.cs | 17 +++++++++++++++++ UnityLauncher/Tools.cs | 13 +++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index c211b89..1219323 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -242,6 +242,23 @@ bool ScanUnityInstallations() } } // have unity.exe } // have uninstaller.exe + else // no uninstaller, probably preview builds + { + var unityExe = Path.Combine(directories[i], "Editor", "Unity.exe"); + if (File.Exists(unityExe) == true) + { + // get full version number from uninstaller + var unityVersion = Tools.GetFileVersionData(unityExe).Replace("Unity", "").Trim(); + if (unityList.ContainsKey(unityVersion) == false) + { + unityList.Add(unityVersion, unityExe); + var dataFolder = Path.Combine(directories[i], "Editor", "Data"); + DateTime? installDate = Tools.GetLastModifiedTime(dataFolder); + // TODO add platforms: PC|iOS|tvOS|Android|UWP|WebGL|Facebook|XBox|PSVita|PS4 + gridUnityList.Rows.Add(unityVersion, unityExe, installDate); + } + } // have unity.exe + } } // got folders } // failed check } // all root folders diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index ee80320..daf15d6 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -183,9 +183,14 @@ public static string GetUnityReleaseURL(string version) if (version.Contains("f")) // archived { version = Regex.Replace(version, @"f.", "", RegexOptions.IgnoreCase); - string padding = ""; - if (version.Contains("2018.2")) padding = ""; - url = "https://unity3d.com/unity/whats-new/" + padding + version; + string padding = "unity-"; + string whatsnew = "whats-new"; + if (version.Contains("5.6")) padding = ""; + if (version.Contains("2017.1")) whatsnew = "whatsnew"; + if (version.Contains("2017.4")) padding = ""; + if (version.Contains("2018")) padding = ""; + if (version.Contains("2019")) padding = ""; + url = "https://unity3d.com/unity/"+ whatsnew +"/" + padding + version; } else if (version.Contains("p")) // patch version @@ -358,9 +363,9 @@ public static string GetProjectVersion(string path) /// public static string GetFileVersionData(string path) { - // TODO check if path exists FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(path); return fvi.ProductName.Replace("(64-bit)", "").Trim(); + //return fvi.FileVersion.Replace("(64-bit)", "").Trim(); } /// From 772a085c16c798c85d814a128058e10e5ce52087 Mon Sep 17 00:00:00 2001 From: mika Date: Tue, 16 Apr 2019 23:04:12 +0300 Subject: [PATCH 70/81] fix release note urls, go to archives page from download button if no exe download available --- UnityLauncher/Form1.cs | 1 + UnityLauncher/Tools.cs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 1219323..40bf7c9 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -570,6 +570,7 @@ void DownloadInBrowser(string url) else // not found { SetStatus("Error> Cannot find installer executable ... opening website instead"); + url = "https://unity3d.com/get-unity/download/archive"; Process.Start(url + "#installer-exe-not-found"); } } diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index daf15d6..4b3c198 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -188,9 +188,10 @@ public static string GetUnityReleaseURL(string version) if (version.Contains("5.6")) padding = ""; if (version.Contains("2017.1")) whatsnew = "whatsnew"; if (version.Contains("2017.4")) padding = ""; - if (version.Contains("2018")) padding = ""; + if (version.Contains("2018.2")) whatsnew = "whatsnew"; + if (version.Contains("2018.3")) padding = ""; if (version.Contains("2019")) padding = ""; - url = "https://unity3d.com/unity/"+ whatsnew +"/" + padding + version; + url = "https://unity3d.com/unity/" + whatsnew + "/" + padding + version; } else if (version.Contains("p")) // patch version From 42f645a2d6cfd97842cbeeb262d30b8017bc8c89 Mon Sep 17 00:00:00 2001 From: mika Date: Fri, 26 Apr 2019 09:58:38 +0300 Subject: [PATCH 71/81] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5160a27..35ed757 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,6 @@ https://forum.unity3d.com/threads/unitylauncher-launch-correct-unity-versions-fo ![image](https://user-images.githubusercontent.com/5438317/35776544-85f7c1f8-09d9-11e8-8ab7-ee08d01ebef3.png) -![image](https://user-images.githubusercontent.com/5438317/35776558-d0692970-09d9-11e8-8191-f48da5d63ca8.png) +![image](https://user-images.githubusercontent.com/5438317/56789044-ac867c80-6809-11e9-9187-b998dbed0d0d.png) ![image](https://user-images.githubusercontent.com/5438317/35776575-01c720bc-09da-11e8-99d1-f6e4ad3c0fab.png) From 5e08a5bb44721b6d2468f15fa246c924816e24f8 Mon Sep 17 00:00:00 2001 From: mika Date: Fri, 26 Apr 2019 22:40:41 +0300 Subject: [PATCH 72/81] add enter and esc keys to upgrade dialog #fixes 80, fix release note urls fixes #73, if no matching upgrade version set first row selected, fix HaveExactVersionInstalled (returned true for null version), download missing version button now shows version number in target url, fix missing statuslabel, add button to launch adb logcat fixes #62, release 28 --- UnityLauncher/Form1.Designer.cs | 48 ++++++++++++++++++++------------ UnityLauncher/Form1.cs | 49 ++++++++++++++++++++------------- UnityLauncher/Form2.Designer.cs | 1 + UnityLauncher/Form2.cs | 43 ++++++++++++++++++++++------- 4 files changed, 95 insertions(+), 46 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 81c3ce7..af7b7ab 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -71,6 +71,7 @@ private void InitializeComponent() this._Date = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._UnityUpdateVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabSettings = new System.Windows.Forms.TabPage(); + this.btnOpenLogcatCmd = new System.Windows.Forms.Button(); this.chkDarkSkin = new System.Windows.Forms.CheckBox(); this.btnCheckUpdates = new System.Windows.Forms.Button(); this.linkProjectGithub = new System.Windows.Forms.LinkLabel(); @@ -108,7 +109,6 @@ private void InitializeComponent() this.tabUpdates.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).BeginInit(); this.tabSettings.SuspendLayout(); - this.statusStrip1.SuspendLayout(); this.SuspendLayout(); // // tabControl1 @@ -606,6 +606,7 @@ private void InitializeComponent() // // tabSettings // + this.tabSettings.Controls.Add(this.btnOpenLogcatCmd); this.tabSettings.Controls.Add(this.chkDarkSkin); this.tabSettings.Controls.Add(this.btnCheckUpdates); this.tabSettings.Controls.Add(this.linkProjectGithub); @@ -634,11 +635,23 @@ private void InitializeComponent() this.tabSettings.Text = "Settings"; this.tabSettings.UseVisualStyleBackColor = true; // + // btnOpenLogcatCmd + // + this.btnOpenLogcatCmd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnOpenLogcatCmd.Location = new System.Drawing.Point(453, 311); + this.btnOpenLogcatCmd.Name = "btnOpenLogcatCmd"; + this.btnOpenLogcatCmd.Size = new System.Drawing.Size(119, 23); + this.btnOpenLogcatCmd.TabIndex = 42; + this.btnOpenLogcatCmd.Text = "ADB logcat (cmd)"; + this.toolTip1.SetToolTip(this.btnOpenLogcatCmd, "adb logcat -s Unity ActivityManager PackageManager dalvikvm DEBUG -v color"); + this.btnOpenLogcatCmd.UseVisualStyleBackColor = true; + this.btnOpenLogcatCmd.Click += new System.EventHandler(this.btnOpenLogcatCmd_Click); + // // chkDarkSkin // this.chkDarkSkin.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkDarkSkin.AutoSize = true; - this.chkDarkSkin.Location = new System.Drawing.Point(20, 416); + this.chkDarkSkin.Location = new System.Drawing.Point(20, 443); this.chkDarkSkin.Name = "chkDarkSkin"; this.chkDarkSkin.Size = new System.Drawing.Size(85, 17); this.chkDarkSkin.TabIndex = 41; @@ -678,7 +691,7 @@ private void InitializeComponent() this.linkArgumentsDocs.AutoSize = true; this.linkArgumentsDocs.LinkArea = new System.Windows.Forms.LinkArea(1, 4); this.linkArgumentsDocs.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline; - this.linkArgumentsDocs.Location = new System.Drawing.Point(385, 348); + this.linkArgumentsDocs.Location = new System.Drawing.Point(385, 375); this.linkArgumentsDocs.Name = "linkArgumentsDocs"; this.linkArgumentsDocs.Size = new System.Drawing.Size(36, 17); this.linkArgumentsDocs.TabIndex = 38; @@ -691,7 +704,7 @@ private void InitializeComponent() // this.chkShowGitBranchColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkShowGitBranchColumn.AutoSize = true; - this.chkShowGitBranchColumn.Location = new System.Drawing.Point(266, 370); + this.chkShowGitBranchColumn.Location = new System.Drawing.Point(266, 397); this.chkShowGitBranchColumn.Name = "chkShowGitBranchColumn"; this.chkShowGitBranchColumn.Size = new System.Drawing.Size(76, 17); this.chkShowGitBranchColumn.TabIndex = 36; @@ -705,7 +718,7 @@ private void InitializeComponent() this.label5.AutoSize = true; this.label5.Enabled = false; this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label5.Location = new System.Drawing.Point(263, 322); + this.label5.Location = new System.Drawing.Point(263, 349); this.label5.Name = "label5"; this.label5.Size = new System.Drawing.Size(105, 13); this.label5.TabIndex = 35; @@ -715,7 +728,7 @@ private void InitializeComponent() // this.chkShowLauncherArgumentsColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkShowLauncherArgumentsColumn.AutoSize = true; - this.chkShowLauncherArgumentsColumn.Location = new System.Drawing.Point(266, 347); + this.chkShowLauncherArgumentsColumn.Location = new System.Drawing.Point(266, 374); this.chkShowLauncherArgumentsColumn.Name = "chkShowLauncherArgumentsColumn"; this.chkShowLauncherArgumentsColumn.Size = new System.Drawing.Size(124, 17); this.chkShowLauncherArgumentsColumn.TabIndex = 34; @@ -727,7 +740,7 @@ private void InitializeComponent() // this.ChkQuitAfterOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.ChkQuitAfterOpen.AutoSize = true; - this.ChkQuitAfterOpen.Location = new System.Drawing.Point(20, 370); + this.ChkQuitAfterOpen.Location = new System.Drawing.Point(20, 397); this.ChkQuitAfterOpen.Name = "ChkQuitAfterOpen"; this.ChkQuitAfterOpen.Size = new System.Drawing.Size(172, 17); this.ChkQuitAfterOpen.TabIndex = 33; @@ -738,7 +751,7 @@ private void InitializeComponent() // btnOpenLogFolder // this.btnOpenLogFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnOpenLogFolder.Location = new System.Drawing.Point(453, 285); + this.btnOpenLogFolder.Location = new System.Drawing.Point(453, 273); this.btnOpenLogFolder.Name = "btnOpenLogFolder"; this.btnOpenLogFolder.Size = new System.Drawing.Size(119, 23); this.btnOpenLogFolder.TabIndex = 32; @@ -750,7 +763,7 @@ private void InitializeComponent() // this.chkQuitAfterCommandline.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkQuitAfterCommandline.AutoSize = true; - this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 393); + this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 420); this.chkQuitAfterCommandline.Name = "chkQuitAfterCommandline"; this.chkQuitAfterCommandline.Size = new System.Drawing.Size(189, 17); this.chkQuitAfterCommandline.TabIndex = 31; @@ -761,7 +774,7 @@ private void InitializeComponent() // btnAddRegister // this.btnAddRegister.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.btnAddRegister.Location = new System.Drawing.Point(139, 481); + this.btnAddRegister.Location = new System.Drawing.Point(139, 493); this.btnAddRegister.Name = "btnAddRegister"; this.btnAddRegister.Size = new System.Drawing.Size(64, 23); this.btnAddRegister.TabIndex = 30; @@ -772,7 +785,7 @@ private void InitializeComponent() // btnRemoveRegister // this.btnRemoveRegister.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.btnRemoveRegister.Location = new System.Drawing.Point(209, 481); + this.btnRemoveRegister.Location = new System.Drawing.Point(209, 493); this.btnRemoveRegister.Name = "btnRemoveRegister"; this.btnRemoveRegister.Size = new System.Drawing.Size(64, 23); this.btnRemoveRegister.TabIndex = 29; @@ -784,7 +797,7 @@ private void InitializeComponent() // this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(19, 486); + this.label4.Location = new System.Drawing.Point(19, 498); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(117, 13); this.label4.TabIndex = 28; @@ -796,7 +809,7 @@ private void InitializeComponent() this.label2.AutoSize = true; this.label2.Enabled = false; this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label2.Location = new System.Drawing.Point(17, 322); + this.label2.Location = new System.Drawing.Point(17, 349); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(88, 13); this.label2.TabIndex = 26; @@ -806,7 +819,7 @@ private void InitializeComponent() // this.chkMinimizeToTaskbar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkMinimizeToTaskbar.AutoSize = true; - this.chkMinimizeToTaskbar.Location = new System.Drawing.Point(20, 347); + this.chkMinimizeToTaskbar.Location = new System.Drawing.Point(20, 374); this.chkMinimizeToTaskbar.Name = "chkMinimizeToTaskbar"; this.chkMinimizeToTaskbar.Size = new System.Drawing.Size(116, 17); this.chkMinimizeToTaskbar.TabIndex = 25; @@ -900,6 +913,8 @@ private void InitializeComponent() // // statusStrip1 // + // this next line keeps disappearing : this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.toolStripStatusLabel1}); + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.toolStripStatusLabel1}); this.statusStrip1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.statusStrip1.AutoSize = false; @@ -932,7 +947,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - Getting Darker Edition 26"; + this.Text = "UnityLauncher - SummerEdition 28"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); @@ -951,8 +966,6 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).EndInit(); this.tabSettings.ResumeLayout(false); this.tabSettings.PerformLayout(); - this.statusStrip1.ResumeLayout(false); - this.statusStrip1.PerformLayout(); this.ResumeLayout(false); } @@ -1027,6 +1040,7 @@ private void InitializeComponent() private System.Windows.Forms.TextBox tbSearchUpdates; private System.ComponentModel.BackgroundWorker backgroundWorker1; private System.Windows.Forms.CheckBox chkDarkSkin; + private System.Windows.Forms.Button btnOpenLogcatCmd; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 40bf7c9..5aab7a6 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -184,10 +184,7 @@ void LoadSettings() /// bool HaveExactVersionInstalled(string version) { - //Console.WriteLine("checking: '" + version + "'"); - var installedExact = unityList.ContainsKey(version); - //Console.WriteLine("have exact:" + installedExact); - return installedExact; + return string.IsNullOrEmpty(version) == false && unityList.ContainsKey(version); } @@ -545,7 +542,6 @@ string GetDownloadUrlForUnityVersion(string releaseUrl) if (match.Success == true) { url = match.Groups[0].Captures[0].Value; - // Console.WriteLine(url); } else { @@ -559,7 +555,7 @@ string GetDownloadUrlForUnityVersion(string releaseUrl) /// launches browser to download installer /// /// full url to installer - void DownloadInBrowser(string url) + void DownloadInBrowser(string url, string version) { string exeURL = GetDownloadUrlForUnityVersion(url); if (string.IsNullOrEmpty(exeURL) == false) @@ -571,7 +567,7 @@ void DownloadInBrowser(string url) { SetStatus("Error> Cannot find installer executable ... opening website instead"); url = "https://unity3d.com/get-unity/download/archive"; - Process.Start(url + "#installer-exe-not-found"); + Process.Start(url + "#installer-not-found---version-" + version); } } @@ -584,7 +580,7 @@ string[] GetUnityInstallationsRootFolder() string[] rootFolders = null; try { - // if settings exists, use that + // if settings exists, use that value rootFolders = new string[Properties.Settings.Default.rootFolders.Count]; Properties.Settings.Default.rootFolders.CopyTo(rootFolders, 0); } @@ -622,6 +618,7 @@ void LaunchSelectedProject(bool openProject = true) { var projectPath = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); var version = Tools.GetProjectVersion(projectPath); + Console.WriteLine("version: '" + version + "'"); LaunchProject(projectPath, version, openProject); SetStatus("Ready"); } @@ -631,7 +628,7 @@ void LaunchSelectedProject(bool openProject = true) void LaunchSelectedUnity() { - + var selected = gridUnityList?.CurrentCell?.RowIndex; if (selected.HasValue && selected > -1) { @@ -719,7 +716,7 @@ private void btnLaunchUnity_Click(object sender, EventArgs e) private void btnExploreUnity_Click(object sender, EventArgs e) { - + var selected = gridUnityList?.CurrentCell?.RowIndex; if (selected.HasValue && selected > -1) { @@ -1141,7 +1138,7 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch string url = Tools.GetUnityReleaseURL(currentVersion); if (string.IsNullOrEmpty(url) == false) { - DownloadInBrowser(url); + DownloadInBrowser(url, currentVersion); } else { @@ -1218,31 +1215,27 @@ void BrowseForExistingProjectFolder() folderBrowserDialog1.Description = "Select existing project folder"; var d = folderBrowserDialog1.ShowDialog(); var projectPath = folderBrowserDialog1.SelectedPath; + + // NOTE: if user didnt click enter or deselect-select newly created folder, this fails as it returns "new folder" instead of actual name + // https://social.msdn.microsoft.com/Forums/vstudio/en-US/cc7f1d54-c1a0-45de-9611-7f69873f32df/folderbrowserdialog-bug-when-click-ok-while-modify-new-folders-name?forum=netfxbcl + if (String.IsNullOrWhiteSpace(projectPath) == false && Directory.Exists(projectPath) == true) { - // TODO: remove duplicate code (from UpdateRecentList()) - string projectName = ""; - Console.WriteLine(Path.DirectorySeparatorChar); - Console.WriteLine(Path.AltDirectorySeparatorChar); - // get project name from full path if (projectPath.IndexOf(Path.DirectorySeparatorChar) > -1) { projectName = projectPath.Substring(projectPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); - Console.WriteLine("1"); } else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) { projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); - Console.WriteLine("2"); } else // no path separator found { projectName = projectPath; - Console.WriteLine("3"); } string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); @@ -1332,5 +1325,23 @@ void FixSelectedRow() } } + private void btnOpenLogcatCmd_Click(object sender, EventArgs e) + { + try + { + Process myProcess = new Process(); + var cmd = "cmd.exe"; + myProcess.StartInfo.FileName = cmd; + // NOTE windows 10 cmd line supports ansi colors, otherwise remove -v color + var pars = " /c adb logcat -s Unity ActivityManager PackageManager dalvikvm DEBUG -v color"; + myProcess.StartInfo.Arguments = pars; + myProcess.Start(); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + } // class Form } // namespace \ No newline at end of file diff --git a/UnityLauncher/Form2.Designer.cs b/UnityLauncher/Form2.Designer.cs index 344580b..6293ff1 100644 --- a/UnityLauncher/Form2.Designer.cs +++ b/UnityLauncher/Form2.Designer.cs @@ -54,6 +54,7 @@ private void InitializeComponent() this.lstUnityVersions.Name = "lstUnityVersions"; this.lstUnityVersions.Size = new System.Drawing.Size(235, 303); this.lstUnityVersions.TabIndex = 1; + this.lstUnityVersions.KeyDown += new System.Windows.Forms.KeyEventHandler(this.lstUnityVersions_KeyDown); // // btnCancelUpgrade // diff --git a/UnityLauncher/Form2.cs b/UnityLauncher/Form2.cs index 00ef5e4..d8df7aa 100644 --- a/UnityLauncher/Form2.cs +++ b/UnityLauncher/Form2.cs @@ -34,7 +34,6 @@ void Start() if (string.IsNullOrEmpty(currentVersion) == false) { string nearestVersion = Tools.FindNearestVersion(currentVersion, Form1.unityList.Keys.ToList()); - //Console.WriteLine("nearest:" + nearestVersion); // preselect most likely version int likelyIndex = lstUnityVersions.FindString(nearestVersion); @@ -42,6 +41,11 @@ void Start() { lstUnityVersions.SetSelected(likelyIndex, true); } + else + { + // just select first item then + lstUnityVersions.SetSelected(0, true); + } // enable release and dl buttons btn_GoInstallMissingVersion.Enabled = true; @@ -54,6 +58,8 @@ void Start() btn_OpenMissingVersionReleasePage.Enabled = false; currentVersion = "None"; + // just select first item then + if (lstUnityVersions != null && lstUnityVersions.Items.Count > 0) lstUnityVersions.SetSelected(0, true); } // fill textbox @@ -64,15 +70,7 @@ void Start() private void btnConfirmUpgrade_Click(object sender, EventArgs e) { - if (lstUnityVersions.SelectedIndex > -1) - { - currentVersion = lstUnityVersions.Items[lstUnityVersions.SelectedIndex].ToString(); - DialogResult = DialogResult.Yes; - } - else - { - // no version selected - } + UpgradeToSelected(); } private void btnCancelUpgrade_Click(object sender, EventArgs e) @@ -91,5 +89,30 @@ private void btn_GoInstallMissingVersion_Click(object sender, EventArgs e) } #endregion + + private void lstUnityVersions_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Return) + { + UpgradeToSelected(); + } + else if (e.KeyCode == Keys.Escape) + { + DialogResult = DialogResult.Cancel; + } + } + + void UpgradeToSelected() + { + if (lstUnityVersions.SelectedIndex > -1) + { + currentVersion = lstUnityVersions.Items[lstUnityVersions.SelectedIndex].ToString(); + DialogResult = DialogResult.Yes; + } + else + { + // no version selected + } + } } } From 726fe87d382839e13742e1638d730e449346e3d1 Mon Sep 17 00:00:00 2001 From: 851marc Date: Thu, 2 May 2019 12:38:58 -0400 Subject: [PATCH 73/81] Add files via upload --- UnityLauncher/Form1.cs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 5aab7a6..462d559 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -530,24 +530,31 @@ bool CheckCrashBackupScene(string projectPath) // parse Unity installer exe from release page // thanks to https://github.com/softfruit - string GetDownloadUrlForUnityVersion(string releaseUrl) + string GetDownloadUrlForUnityVersion(string version) { string url = ""; - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - using (WebClient client = new WebClient()) - { - string html = client.DownloadString(releaseUrl); - Regex regex = new Regex(@"(http).+(UnityDownloadAssistant)+[^\s*]*(.exe)"); - Match match = regex.Match(html); - if (match.Success == true) - { - url = match.Groups[0].Captures[0].Value; - } - else - { - SetStatus("Cannot find UnityDownloadAssistant.exe for this version."); - } + + using (WebClient client = new WebClient()) + { + string htmlCode = client.DownloadString("https://unity3d.com/get-unity/download/archive"); + string[] lines = htmlCode.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); + + for (int i = 0; i < lines.Length; i++) + { + if (lines[i].Contains("UnitySetup64-" + version)) + { + string line = lines[i-1]; + int start = line.IndexOf('"') + 1; + int end = line.IndexOf('"', start); + url = @"https://unity3d.com" + line.Substring(start, end - start); + break; + } + } } + + if(string.IsNullOrEmpty(url)) + SetStatus("Cannot find UnityDownloadAssistant.exe for this version."); + return url; } @@ -557,7 +564,7 @@ string GetDownloadUrlForUnityVersion(string releaseUrl) /// full url to installer void DownloadInBrowser(string url, string version) { - string exeURL = GetDownloadUrlForUnityVersion(url); + string exeURL = GetDownloadUrlForUnityVersion(version); if (string.IsNullOrEmpty(exeURL) == false) { SetStatus("Download installer in browser: " + exeURL); From 76213b46c0101b2ae8b32fd27e4ab7361f1adbeb Mon Sep 17 00:00:00 2001 From: mika Date: Sun, 12 May 2019 00:14:01 +0300 Subject: [PATCH 74/81] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 35ed757..a7a96cc 100644 --- a/README.md +++ b/README.md @@ -49,3 +49,11 @@ https://forum.unity3d.com/threads/unitylauncher-launch-correct-unity-versions-fo ![image](https://user-images.githubusercontent.com/5438317/56789044-ac867c80-6809-11e9-9187-b998dbed0d0d.png) ![image](https://user-images.githubusercontent.com/5438317/35776575-01c720bc-09da-11e8-99d1-f6e4ad3c0fab.png) + +# Special Thanks (for fixes, updates, pull requests) +- https://github.com/851marc +- https://github.com/KyleOrth +- https://github.com/Raebyn +- Ville Tuhkanen +- https://github.com/geo-at-github +- https://github.com/yschuurmans From 9b08737d288e08fda425f339710f674ad1a42b7c Mon Sep 17 00:00:00 2001 From: mika Date: Sat, 3 Aug 2019 13:55:04 +0300 Subject: [PATCH 75/81] keep selected row after refresh project list fixes #86, fixed some release note urls from #73, remove excess "Ready" status messages, dont show upgrade dialog if only running unity fixes #45, add download in browser button for unity updates, --- UnityLauncher/Form1.Designer.cs | 30 +- UnityLauncher/Form1.cs | 2718 ++++++++++++++++--------------- UnityLauncher/Form1.resx | 39 - UnityLauncher/Tools.cs | 7 +- 4 files changed, 1408 insertions(+), 1386 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index af7b7ab..7f38ec3 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -100,6 +100,7 @@ private void InitializeComponent() this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker(); + this.btnDownloadNewUnity = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -109,6 +110,7 @@ private void InitializeComponent() this.tabUpdates.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).BeginInit(); this.tabSettings.SuspendLayout(); + this.statusStrip1.SuspendLayout(); this.SuspendLayout(); // // tabControl1 @@ -512,6 +514,7 @@ private void InitializeComponent() // // tabUpdates // + this.tabUpdates.Controls.Add(this.btnDownloadNewUnity); this.tabUpdates.Controls.Add(this.tbSearchUpdates); this.tabUpdates.Controls.Add(this.btnOpenUpdateWebsite); this.tabUpdates.Controls.Add(this.btnFetchUnityVersions); @@ -536,9 +539,9 @@ private void InitializeComponent() this.btnOpenUpdateWebsite.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.btnOpenUpdateWebsite.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnOpenUpdateWebsite.Location = new System.Drawing.Point(5, 511); + this.btnOpenUpdateWebsite.Location = new System.Drawing.Point(248, 511); this.btnOpenUpdateWebsite.Name = "btnOpenUpdateWebsite"; - this.btnOpenUpdateWebsite.Size = new System.Drawing.Size(572, 35); + this.btnOpenUpdateWebsite.Size = new System.Drawing.Size(329, 35); this.btnOpenUpdateWebsite.TabIndex = 24; this.btnOpenUpdateWebsite.Text = "Open Website"; this.toolTip1.SetToolTip(this.btnOpenUpdateWebsite, "Open Release Page"); @@ -913,12 +916,12 @@ private void InitializeComponent() // // statusStrip1 // - // this next line keeps disappearing : this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.toolStripStatusLabel1}); - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.toolStripStatusLabel1}); this.statusStrip1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.statusStrip1.AutoSize = false; this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(579, 22); @@ -934,6 +937,20 @@ private void InitializeComponent() this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // + // btnDownloadNewUnity + // + this.btnDownloadNewUnity.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.btnDownloadNewUnity.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnDownloadNewUnity.Location = new System.Drawing.Point(3, 511); + this.btnDownloadNewUnity.Name = "btnDownloadNewUnity"; + this.btnDownloadNewUnity.Size = new System.Drawing.Size(239, 35); + this.btnDownloadNewUnity.TabIndex = 25; + this.btnDownloadNewUnity.Text = "Download in Browser"; + this.toolTip1.SetToolTip(this.btnDownloadNewUnity, "Open Release Page"); + this.btnDownloadNewUnity.UseVisualStyleBackColor = true; + this.btnDownloadNewUnity.Click += new System.EventHandler(this.btnDownloadNewUnity_Click); + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -947,7 +964,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - SummerEdition 28"; + this.Text = "UnityLauncher - AutumnEdition 29"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); @@ -966,6 +983,8 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).EndInit(); this.tabSettings.ResumeLayout(false); this.tabSettings.PerformLayout(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); this.ResumeLayout(false); } @@ -1041,6 +1060,7 @@ private void InitializeComponent() private System.ComponentModel.BackgroundWorker backgroundWorker1; private System.Windows.Forms.CheckBox chkDarkSkin; private System.Windows.Forms.Button btnOpenLogcatCmd; + private System.Windows.Forms.Button btnDownloadNewUnity; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 462d559..6d5ebfa 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -1,1354 +1,1390 @@ -using Microsoft.Win32; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Windows.Forms; -using UnityLauncherTools; - -namespace UnityLauncher -{ - public partial class Form1 : Form - { - public static Dictionary unityList = new Dictionary(); - const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; - const string launcherArgumentsFile = "LauncherArguments.txt"; - const string githubReleasesLinkURL = "https://github.com/unitycoder/UnityLauncher/releases"; - - bool isDownloadingUnityList = false; - string previousGitRelease = "0"; - - - public Form1() - { - InitializeComponent(); - } - - private void Form1_Load(object sender, EventArgs e) - { - Start(); - } - - - - void Start() - { - SetStatus("Initializing ..."); - // check installations folder - var root = GetUnityInstallationsRootFolder(); - if (root == null || root.Length == 0) - { - SetStatus("Missing root folder ..."); - AddUnityInstallationRootFolder(); - SetStatus("Ready"); - } - - LoadSettings(); - - // scan installed unitys - bool foundUnitys = ScanUnityInstallations(); - if (foundUnitys == false) - { - SetStatus("Error> Did not find any Unity installations, try setting correct root folder ..."); - UpdateRecentProjectsList(); - tabControl1.SelectedIndex = tabControl1.TabCount - 1; // last tab is settings - return; - } - - // check if received -projectPath argument (that means opening from explorer / cmdline) - string[] args = Environment.GetCommandLineArgs(); - if (args != null && args.Length > 2) - { - // first argument needs to be -projectPath - var commandLineArgs = args[1]; - if (commandLineArgs == "-projectPath") - { - SetStatus("Launching from commandline ..."); - - // path - var projectPathArgument = args[2]; - - // resolve full path if path parameter isn't a rooted path - if (!Path.IsPathRooted(projectPathArgument)) - { - projectPathArgument = Directory.GetCurrentDirectory() + projectPathArgument; - } - - var version = Tools.GetProjectVersion(projectPathArgument); - - // take extra arguments also - var commandLineArguments = ""; - for (int i = 3, len = args.Length; i < len; i++) - { - commandLineArguments += " " + args[i]; - } - - // try launching it - LaunchProject(projectPathArgument, version, openProject: true, commandLineArguments: commandLineArguments); - - // quit after launch if enabled in settings - if (Properties.Settings.Default.closeAfterExplorer == true) - { - Application.Exit(); - } - - SetStatus("Ready"); - } - else - { - SetStatus("Error> Invalid arguments:" + args[1]); - } - } - - UpdateRecentProjectsList(); - - // preselect grid - gridRecent.Select(); - - // get previous version build info string - // this string is release tag for latest release when this app was compiled - using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("UnityLauncher." + "PreviousVersion.txt")) - using (StreamReader reader = new StreamReader(stream)) - { - previousGitRelease = reader.ReadToEnd().Trim(); - } - } - - void LoadSettings() - { - // form size - this.Width = Properties.Settings.Default.formWidth; - this.Height = Properties.Settings.Default.formHeight; - - // update settings window - chkMinimizeToTaskbar.Checked = Properties.Settings.Default.minimizeToTaskbar; - chkQuitAfterCommandline.Checked = Properties.Settings.Default.closeAfterExplorer; - ChkQuitAfterOpen.Checked = Properties.Settings.Default.closeAfterProject; - chkShowLauncherArgumentsColumn.Checked = Properties.Settings.Default.showArgumentsColumn; - chkShowGitBranchColumn.Checked = Properties.Settings.Default.showGitBranchColumn; - chkDarkSkin.Checked = Properties.Settings.Default.useDarkSkin; - - // update optional grid columns, hidden or visible - gridRecent.Columns["_launchArguments"].Visible = chkShowLauncherArgumentsColumn.Checked; - gridRecent.Columns["_gitBranch"].Visible = chkShowGitBranchColumn.Checked; - - // update installations folder listbox - lstRootFolders.Items.Clear(); - lstRootFolders.Items.AddRange(Properties.Settings.Default.rootFolders.Cast().ToArray()); - // update packages folder listbox - lstPackageFolders.Items.AddRange(Properties.Settings.Default.packageFolders.Cast().ToArray()); - - // restore data grid view widths - int[] gridColumnWidths = Properties.Settings.Default.gridColumnWidths; - if (gridColumnWidths != null) - { - - for (int i = 0; i < gridColumnWidths.Length; ++i) - { - gridRecent.Columns[i].Width = gridColumnWidths[i]; - } - } - - // TODO assign colors for dark theme - if (chkDarkSkin.Checked == true) - { - var darkBg = Color.FromArgb(32, 37, 41); - var darkRaised = Color.FromArgb(50, 56, 61); - var darkBright = Color.FromArgb(161, 180, 196); - - - this.BackColor = darkBg; - tabProjects.BackColor = darkRaised; - gridRecent.BackgroundColor = darkRaised; - - gridRecent.GridColor = darkBg; - var dgs = new DataGridViewCellStyle(); - dgs.BackColor = darkRaised; - dgs.ForeColor = darkBright; - gridRecent.DefaultCellStyle = dgs; - - statusStrip1.BackColor = darkRaised; - } - } - - /// - /// returns true if we have exact version installed - /// - /// - /// - bool HaveExactVersionInstalled(string version) - { - return string.IsNullOrEmpty(version) == false && unityList.ContainsKey(version); - } - - - void AddUnityInstallationRootFolder() - { - folderBrowserDialog1.Description = "Select Unity installations root folder"; - var d = folderBrowserDialog1.ShowDialog(); - var newRoot = folderBrowserDialog1.SelectedPath; - - if (String.IsNullOrWhiteSpace(newRoot) == false && Directory.Exists(newRoot) == true) - { - lstRootFolders.Items.Add(newRoot); - Properties.Settings.Default.rootFolders.Add(newRoot); - Properties.Settings.Default.Save(); - } - } - - bool ScanUnityInstallations() - { - SetStatus("Scanning Unity installations ..."); - - // dictionary to keep version and path - unityList.Clear(); - - // installed unitys list in other tab - gridUnityList.Rows.Clear(); - - // iterate all root folders - foreach (string root in lstRootFolders.Items) - { - if (String.IsNullOrWhiteSpace(root) == false && Directory.Exists(root) == true) - { - // parse all folders here, and search for unity editor files - var directories = Directory.GetDirectories(root); - for (int i = 0, length = directories.Length; i < length; i++) - { - var uninstallExe = Path.Combine(directories[i], "Editor", "Uninstall.exe"); - if (File.Exists(uninstallExe) == true) - { - var unityExe = Path.Combine(directories[i], "Editor", "Unity.exe"); - if (File.Exists(unityExe) == true) - { - // get full version number from uninstaller - var unityVersion = Tools.GetFileVersionData(uninstallExe).Replace("Unity", "").Trim(); - if (unityList.ContainsKey(unityVersion) == false) - { - unityList.Add(unityVersion, unityExe); - var dataFolder = Path.Combine(directories[i], "Editor", "Data"); - DateTime? installDate = Tools.GetLastModifiedTime(dataFolder); - // TODO add platforms: PC|iOS|tvOS|Android|UWP|WebGL|Facebook|XBox|PSVita|PS4 - gridUnityList.Rows.Add(unityVersion, unityExe, installDate); - } - } // have unity.exe - } // have uninstaller.exe - else // no uninstaller, probably preview builds - { - var unityExe = Path.Combine(directories[i], "Editor", "Unity.exe"); - if (File.Exists(unityExe) == true) - { - // get full version number from uninstaller - var unityVersion = Tools.GetFileVersionData(unityExe).Replace("Unity", "").Trim(); - if (unityList.ContainsKey(unityVersion) == false) - { - unityList.Add(unityVersion, unityExe); - var dataFolder = Path.Combine(directories[i], "Editor", "Data"); - DateTime? installDate = Tools.GetLastModifiedTime(dataFolder); - // TODO add platforms: PC|iOS|tvOS|Android|UWP|WebGL|Facebook|XBox|PSVita|PS4 - gridUnityList.Rows.Add(unityVersion, unityExe, installDate); - } - } // have unity.exe - } - } // got folders - } // failed check - } // all root folders - - lbl_unityCount.Text = "Found " + unityList.Count.ToString() + " versions"; - - SetStatus("Finished scanning"); - - // found any Unity installations? - return unityList.Count > 0; - } - - - void FilterRecentProject(object sender, EventArgs e) - { - SetStatus("Filtering recent projects list ..."); - string searchString = tbSearchBar.Text; - foreach (DataGridViewRow row in gridRecent.Rows) - { - if (row.Cells["_project"].Value.ToString().IndexOf(searchString, StringComparison.OrdinalIgnoreCase) > -1) - { - row.Visible = true; - } - else - { - row.Visible = false; - } - } - } - - void FilterUnityUpdates(object sender, EventArgs e) - { - SetStatus("Filtering Unity updates list ..."); - string searchString = tbSearchUpdates.Text; - foreach (DataGridViewRow row in gridUnityUpdates.Rows) - { - if (row.Cells["_UnityUpdateVersion"].Value.ToString().IndexOf(searchString, StringComparison.OrdinalIgnoreCase) > -1) - { - row.Visible = true; - } - else - { - row.Visible = false; - } - } - } - - /// - /// scans registry for recent projects and adds to project grid list - /// - void UpdateRecentProjectsList() - { - SetStatus("Updating recent projects list ..."); - - gridRecent.Rows.Clear(); - - var hklm = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); - string[] registryPathsToCheck = new string[] { @"SOFTWARE\Unity Technologies\Unity Editor 5.x", @"SOFTWARE\Unity Technologies\Unity Editor 4.x" }; - - // check each version path - for (int i = 0, len = registryPathsToCheck.Length; i < len; i++) - { - RegistryKey key = hklm.OpenSubKey(registryPathsToCheck[i]); - - if (key == null) - { - continue; - } - else - { - //Console.WriteLine("Null registry key at " + registryPathsToCheck[i]); - } - - // parse recent project path - foreach (var valueName in key.GetValueNames()) - { - if (valueName.IndexOf("RecentlyUsedProjectPaths-") == 0) - { - string projectPath = ""; - // check if binary or not - var valueKind = key.GetValueKind(valueName); - if (valueKind == RegistryValueKind.Binary) - { - byte[] projectPathBytes = (byte[])key.GetValue(valueName); - projectPath = Encoding.UTF8.GetString(projectPathBytes, 0, projectPathBytes.Length - 1); - } - else // should be string then - { - projectPath = (string)key.GetValue(valueName); - } - - // first check if whole folder exists, if not, skip - if (Directory.Exists(projectPath) == false) - { - Console.WriteLine("Recent project directory not found, skipping: " + projectPath); - continue; - } - - string projectName = ""; - - // get project name from full path - if (projectPath.IndexOf(Path.DirectorySeparatorChar) > -1) - { - projectName = projectPath.Substring(projectPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); - } - else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) - { - projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); - } - else // no path separator found - { - projectName = projectPath; - } - - string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); - - // solution only - if (File.Exists(csprojFile) == false) - { - csprojFile = Path.Combine(projectPath, projectName + ".sln"); - } - - // editor only project - if (File.Exists(csprojFile) == false) - { - csprojFile = Path.Combine(projectPath, projectName + ".Editor.csproj"); - } - - // maybe 4.x project - if (File.Exists(csprojFile) == false) - { - csprojFile = Path.Combine(projectPath, "Assembly-CSharp.csproj"); - } - - // get last modified date - DateTime? lastUpdated = Tools.GetLastModifiedTime(csprojFile); - - // get project version - string projectVersion = Tools.GetProjectVersion(projectPath); - - // get custom launch arguments, only if column in enabled - string customArgs = ""; - if (chkShowLauncherArgumentsColumn.Checked == true) - { - customArgs = Tools.ReadCustomLaunchArguments(projectPath, launcherArgumentsFile); - } - - // get git branchinfo, only if column in enabled - string gitBranch = ""; - if (chkShowGitBranchColumn.Checked == true) - { - gitBranch = Tools.ReadGitBranchInfo(projectPath); - } - - gridRecent.Rows.Add(projectName, projectVersion, projectPath, lastUpdated, customArgs, gitBranch); - gridRecent.Rows[gridRecent.Rows.Count - 1].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; - } - } - } - SetStatus("Ready"); - } - - void LaunchProject(string projectPath, string version, bool openProject = true, string commandLineArguments = "") - { - if (Directory.Exists(projectPath) == true) - { - // no assets path, probably we want to create new project then - var assetsFolder = Path.Combine(projectPath, "Assets"); - if (Directory.Exists(assetsFolder) == false) - { - // TODO could ask if want to create project.. - Directory.CreateDirectory(assetsFolder); - } - - // when opening project, check for crashed backup scene first - if (openProject == true) - { - var cancelLaunch = CheckCrashBackupScene(projectPath); - if (cancelLaunch == true) - { - return; - } - } - - if (HaveExactVersionInstalled(version) == true) - { - if (openProject == true) - { - SetStatus("Launching project in Unity " + version); - } - else - { - SetStatus("Launching Unity " + version); - } - - try - { - Process myProcess = new Process(); - var cmd = "\"" + unityList[version] + "\""; - myProcess.StartInfo.FileName = cmd; - if (openProject == true) - { - var pars = " -projectPath " + "\"" + projectPath + "\""; - - // check for custom launch parameters and append them - string customArguments = GetSelectedRowData("_launchArguments"); - if (string.IsNullOrEmpty(customArguments) == false) - { - pars += " " + customArguments; - } - - myProcess.StartInfo.Arguments = pars + commandLineArguments; - } - myProcess.Start(); - - if (Properties.Settings.Default.closeAfterProject) - { - Environment.Exit(0); - } - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - } - else // we dont have this version installed (or no version info available) - { - SetStatus("Missing Unity version: " + version); - DisplayUpgradeDialog(version, projectPath); - } - } - else // given path doesnt exists, strange - { - SetStatus("Invalid path: " + projectPath); - } - } - - bool CheckCrashBackupScene(string projectPath) - { - var cancelRunningUnity = false; - var recoveryFile = Path.Combine(projectPath, "Temp", "__Backupscenes", "0.backup"); - if (File.Exists(recoveryFile)) - { - DialogResult dialogResult = MessageBox.Show("Crash recovery scene found, do you want to copy it into Assets/_Recovery/-folder?", "UnityLauncher - Scene Recovery", MessageBoxButtons.YesNoCancel); - if (dialogResult == DialogResult.Yes) // restore - { - var restoreFolder = Path.Combine(projectPath, "Assets", "_Recovery"); - if (Directory.Exists(restoreFolder) == false) - { - Directory.CreateDirectory(restoreFolder); - } - if (Directory.Exists(restoreFolder) == true) - { - Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; - var uniqueFileName = "Recovered_Scene" + unixTimestamp + ".unity"; - File.Copy(recoveryFile, Path.Combine(restoreFolder, uniqueFileName)); - SetStatus("Recovered crashed scene into: " + restoreFolder); - } - else - { - SetStatus("Error: Failed to create restore folder: " + restoreFolder); - cancelRunningUnity = true; - } - } - else if (dialogResult == DialogResult.Cancel) // dont do restore, but run Unity - { - cancelRunningUnity = true; - } - } - return cancelRunningUnity; - } - - // parse Unity installer exe from release page - // thanks to https://github.com/softfruit - string GetDownloadUrlForUnityVersion(string version) - { - string url = ""; - +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using UnityLauncherTools; + +namespace UnityLauncher +{ + public partial class Form1 : Form + { + public static Dictionary unityList = new Dictionary(); + const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; + const string launcherArgumentsFile = "LauncherArguments.txt"; + const string githubReleasesLinkURL = "https://github.com/unitycoder/UnityLauncher/releases"; + + bool isDownloadingUnityList = false; + string previousGitRelease = "0"; + + + public Form1() + { + InitializeComponent(); + } + + private void Form1_Load(object sender, EventArgs e) + { + Start(); + } + + + + void Start() + { + SetStatus("Initializing ..."); + // check installations folder + var root = GetUnityInstallationsRootFolder(); + if (root == null || root.Length == 0) + { + SetStatus("Missing root folder ..."); + AddUnityInstallationRootFolder(); + SetStatus("Ready"); + } + + LoadSettings(); + + // scan installed unitys + bool foundUnitys = ScanUnityInstallations(); + if (foundUnitys == false) + { + SetStatus("Error> Did not find any Unity installations, try setting correct root folder ..."); + UpdateRecentProjectsList(); + tabControl1.SelectedIndex = tabControl1.TabCount - 1; // last tab is settings + return; + } + + // check if received -projectPath argument (that means opening from explorer / cmdline) + string[] args = Environment.GetCommandLineArgs(); + if (args != null && args.Length > 2) + { + // first argument needs to be -projectPath + var commandLineArgs = args[1]; + if (commandLineArgs == "-projectPath") + { + SetStatus("Launching from commandline ..."); + + // path + var projectPathArgument = args[2]; + + // resolve full path if path parameter isn't a rooted path + if (!Path.IsPathRooted(projectPathArgument)) + { + projectPathArgument = Directory.GetCurrentDirectory() + projectPathArgument; + } + + var version = Tools.GetProjectVersion(projectPathArgument); + + // take extra arguments also + var commandLineArguments = ""; + for (int i = 3, len = args.Length; i < len; i++) + { + commandLineArguments += " " + args[i]; + } + + // try launching it + LaunchProject(projectPathArgument, version, openProject: true, commandLineArguments: commandLineArguments); + + // quit after launch if enabled in settings + if (Properties.Settings.Default.closeAfterExplorer == true) + { + Application.Exit(); + } + + //SetStatus("Ready"); + } + else + { + SetStatus("Error> Invalid arguments:" + args[1]); + } + } + + UpdateRecentProjectsList(); + + // preselect grid + gridRecent.Select(); + + // get previous version build info string + // this string is release tag for latest release when this app was compiled + using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("UnityLauncher." + "PreviousVersion.txt")) + using (StreamReader reader = new StreamReader(stream)) + { + previousGitRelease = reader.ReadToEnd().Trim(); + } + } + + void LoadSettings() + { + // form size + this.Width = Properties.Settings.Default.formWidth; + this.Height = Properties.Settings.Default.formHeight; + + // update settings window + chkMinimizeToTaskbar.Checked = Properties.Settings.Default.minimizeToTaskbar; + chkQuitAfterCommandline.Checked = Properties.Settings.Default.closeAfterExplorer; + ChkQuitAfterOpen.Checked = Properties.Settings.Default.closeAfterProject; + chkShowLauncherArgumentsColumn.Checked = Properties.Settings.Default.showArgumentsColumn; + chkShowGitBranchColumn.Checked = Properties.Settings.Default.showGitBranchColumn; + chkDarkSkin.Checked = Properties.Settings.Default.useDarkSkin; + + // update optional grid columns, hidden or visible + gridRecent.Columns["_launchArguments"].Visible = chkShowLauncherArgumentsColumn.Checked; + gridRecent.Columns["_gitBranch"].Visible = chkShowGitBranchColumn.Checked; + + // update installations folder listbox + lstRootFolders.Items.Clear(); + lstRootFolders.Items.AddRange(Properties.Settings.Default.rootFolders.Cast().ToArray()); + // update packages folder listbox + lstPackageFolders.Items.AddRange(Properties.Settings.Default.packageFolders.Cast().ToArray()); + + // restore data grid view widths + int[] gridColumnWidths = Properties.Settings.Default.gridColumnWidths; + if (gridColumnWidths != null) + { + + for (int i = 0; i < gridColumnWidths.Length; ++i) + { + gridRecent.Columns[i].Width = gridColumnWidths[i]; + } + } + + // TODO assign colors for dark theme + if (chkDarkSkin.Checked == true) + { + var darkBg = Color.FromArgb(32, 37, 41); + var darkRaised = Color.FromArgb(50, 56, 61); + var darkBright = Color.FromArgb(161, 180, 196); + + + this.BackColor = darkBg; + tabProjects.BackColor = darkRaised; + gridRecent.BackgroundColor = darkRaised; + + gridRecent.GridColor = darkBg; + var dgs = new DataGridViewCellStyle(); + dgs.BackColor = darkRaised; + dgs.ForeColor = darkBright; + gridRecent.DefaultCellStyle = dgs; + + statusStrip1.BackColor = darkRaised; + } + } + + /// + /// returns true if we have exact version installed + /// + /// + /// + bool HaveExactVersionInstalled(string version) + { + return string.IsNullOrEmpty(version) == false && unityList.ContainsKey(version); + } + + + void AddUnityInstallationRootFolder() + { + folderBrowserDialog1.Description = "Select Unity installations root folder"; + var d = folderBrowserDialog1.ShowDialog(); + var newRoot = folderBrowserDialog1.SelectedPath; + + if (String.IsNullOrWhiteSpace(newRoot) == false && Directory.Exists(newRoot) == true) + { + lstRootFolders.Items.Add(newRoot); + Properties.Settings.Default.rootFolders.Add(newRoot); + Properties.Settings.Default.Save(); + } + } + + bool ScanUnityInstallations() + { + SetStatus("Scanning Unity installations ..."); + + // dictionary to keep version and path + unityList.Clear(); + + // installed unitys list in other tab + gridUnityList.Rows.Clear(); + + // iterate all root folders + foreach (string root in lstRootFolders.Items) + { + if (String.IsNullOrWhiteSpace(root) == false && Directory.Exists(root) == true) + { + // parse all folders here, and search for unity editor files + var directories = Directory.GetDirectories(root); + for (int i = 0, length = directories.Length; i < length; i++) + { + var uninstallExe = Path.Combine(directories[i], "Editor", "Uninstall.exe"); + if (File.Exists(uninstallExe) == true) + { + var unityExe = Path.Combine(directories[i], "Editor", "Unity.exe"); + if (File.Exists(unityExe) == true) + { + // get full version number from uninstaller + var unityVersion = Tools.GetFileVersionData(uninstallExe).Replace("Unity", "").Trim(); + if (unityList.ContainsKey(unityVersion) == false) + { + unityList.Add(unityVersion, unityExe); + var dataFolder = Path.Combine(directories[i], "Editor", "Data"); + DateTime? installDate = Tools.GetLastModifiedTime(dataFolder); + // TODO add platforms: PC|iOS|tvOS|Android|UWP|WebGL|Facebook|XBox|PSVita|PS4 + gridUnityList.Rows.Add(unityVersion, unityExe, installDate); + } + } // have unity.exe + } // have uninstaller.exe + else // no uninstaller, probably preview builds + { + var unityExe = Path.Combine(directories[i], "Editor", "Unity.exe"); + if (File.Exists(unityExe) == true) + { + // get full version number from uninstaller + var unityVersion = Tools.GetFileVersionData(unityExe).Replace("Unity", "").Trim(); + if (unityList.ContainsKey(unityVersion) == false) + { + unityList.Add(unityVersion, unityExe); + var dataFolder = Path.Combine(directories[i], "Editor", "Data"); + DateTime? installDate = Tools.GetLastModifiedTime(dataFolder); + // TODO add platforms: PC|iOS|tvOS|Android|UWP|WebGL|Facebook|XBox|PSVita|PS4 + gridUnityList.Rows.Add(unityVersion, unityExe, installDate); + } + } // have unity.exe + } + } // got folders + } // failed check + } // all root folders + + lbl_unityCount.Text = "Found " + unityList.Count.ToString() + " versions"; + + SetStatus("Finished scanning"); + + // found any Unity installations? + return unityList.Count > 0; + } + + + void FilterRecentProject(object sender, EventArgs e) + { + SetStatus("Filtering recent projects list ..."); + string searchString = tbSearchBar.Text; + foreach (DataGridViewRow row in gridRecent.Rows) + { + if (row.Cells["_project"].Value.ToString().IndexOf(searchString, StringComparison.OrdinalIgnoreCase) > -1) + { + row.Visible = true; + } + else + { + row.Visible = false; + } + } + } + + void FilterUnityUpdates(object sender, EventArgs e) + { + SetStatus("Filtering Unity updates list ..."); + string searchString = tbSearchUpdates.Text; + foreach (DataGridViewRow row in gridUnityUpdates.Rows) + { + if (row.Cells["_UnityUpdateVersion"].Value.ToString().IndexOf(searchString, StringComparison.OrdinalIgnoreCase) > -1) + { + row.Visible = true; + } + else + { + row.Visible = false; + } + } + } + + /// + /// scans registry for recent projects and adds to project grid list + /// + void UpdateRecentProjectsList() + { + SetStatus("Updating recent projects list ..."); + + gridRecent.Rows.Clear(); + + var hklm = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); + string[] registryPathsToCheck = new string[] { @"SOFTWARE\Unity Technologies\Unity Editor 5.x", @"SOFTWARE\Unity Technologies\Unity Editor 4.x" }; + + // check each version path + for (int i = 0, len = registryPathsToCheck.Length; i < len; i++) + { + RegistryKey key = hklm.OpenSubKey(registryPathsToCheck[i]); + + if (key == null) + { + continue; + } + else + { + //Console.WriteLine("Null registry key at " + registryPathsToCheck[i]); + } + + // parse recent project path + foreach (var valueName in key.GetValueNames()) + { + if (valueName.IndexOf("RecentlyUsedProjectPaths-") == 0) + { + string projectPath = ""; + // check if binary or not + var valueKind = key.GetValueKind(valueName); + if (valueKind == RegistryValueKind.Binary) + { + byte[] projectPathBytes = (byte[])key.GetValue(valueName); + projectPath = Encoding.UTF8.GetString(projectPathBytes, 0, projectPathBytes.Length - 1); + } + else // should be string then + { + projectPath = (string)key.GetValue(valueName); + } + + // first check if whole folder exists, if not, skip + if (Directory.Exists(projectPath) == false) + { + //Console.WriteLine("Recent project directory not found, skipping: " + projectPath); + continue; + } + + string projectName = ""; + + // get project name from full path + if (projectPath.IndexOf(Path.DirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); + } + else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); + } + else // no path separator found + { + projectName = projectPath; + } + + string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); + + // solution only + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, projectName + ".sln"); + } + + // editor only project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, projectName + ".Editor.csproj"); + } + + // maybe 4.x project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, "Assembly-CSharp.csproj"); + } + + // get last modified date + DateTime? lastUpdated = Tools.GetLastModifiedTime(csprojFile); + + // get project version + string projectVersion = Tools.GetProjectVersion(projectPath); + + // get custom launch arguments, only if column in enabled + string customArgs = ""; + if (chkShowLauncherArgumentsColumn.Checked == true) + { + customArgs = Tools.ReadCustomLaunchArguments(projectPath, launcherArgumentsFile); + } + + // get git branchinfo, only if column in enabled + string gitBranch = ""; + if (chkShowGitBranchColumn.Checked == true) + { + gitBranch = Tools.ReadGitBranchInfo(projectPath); + } + + gridRecent.Rows.Add(projectName, projectVersion, projectPath, lastUpdated, customArgs, gitBranch); + gridRecent.Rows[gridRecent.Rows.Count - 1].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; + } + } + } + //SetStatus("Ready"); + } + + void LaunchProject(string projectPath, string version, bool openProject = true, string commandLineArguments = "") + { + if (Directory.Exists(projectPath) == true) + { + // no assets path, probably we want to create new project then + var assetsFolder = Path.Combine(projectPath, "Assets"); + if (Directory.Exists(assetsFolder) == false) + { + // TODO could ask if want to create project.. + Directory.CreateDirectory(assetsFolder); + } + + // when opening project, check for crashed backup scene first + if (openProject == true) + { + var cancelLaunch = CheckCrashBackupScene(projectPath); + if (cancelLaunch == true) + { + return; + } + } + + if (HaveExactVersionInstalled(version) == true) + { + if (openProject == true) + { + SetStatus("Launching project in Unity " + version); + } + else + { + SetStatus("Launching Unity " + version); + } + + try + { + Process myProcess = new Process(); + var cmd = "\"" + unityList[version] + "\""; + myProcess.StartInfo.FileName = cmd; + if (openProject == true) + { + var pars = " -projectPath " + "\"" + projectPath + "\""; + + // check for custom launch parameters and append them + string customArguments = GetSelectedRowData("_launchArguments"); + if (string.IsNullOrEmpty(customArguments) == false) + { + pars += " " + customArguments; + } + + myProcess.StartInfo.Arguments = pars + commandLineArguments; + } + myProcess.Start(); + + if (Properties.Settings.Default.closeAfterProject) + { + Environment.Exit(0); + } + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + else // we dont have this version installed (or no version info available) + { + SetStatus("Missing Unity version: " + version); + // if only running only, stop here + if (openProject == true) DisplayUpgradeDialog(version, projectPath); + } + } + else // given path doesnt exists, strange + { + SetStatus("Invalid path: " + projectPath); + } + } + + bool CheckCrashBackupScene(string projectPath) + { + var cancelRunningUnity = false; + var recoveryFile = Path.Combine(projectPath, "Temp", "__Backupscenes", "0.backup"); + if (File.Exists(recoveryFile)) + { + DialogResult dialogResult = MessageBox.Show("Crash recovery scene found, do you want to copy it into Assets/_Recovery/-folder?", "UnityLauncher - Scene Recovery", MessageBoxButtons.YesNoCancel); + if (dialogResult == DialogResult.Yes) // restore + { + var restoreFolder = Path.Combine(projectPath, "Assets", "_Recovery"); + if (Directory.Exists(restoreFolder) == false) + { + Directory.CreateDirectory(restoreFolder); + } + if (Directory.Exists(restoreFolder) == true) + { + Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; + var uniqueFileName = "Recovered_Scene" + unixTimestamp + ".unity"; + File.Copy(recoveryFile, Path.Combine(restoreFolder, uniqueFileName)); + SetStatus("Recovered crashed scene into: " + restoreFolder); + } + else + { + SetStatus("Error: Failed to create restore folder: " + restoreFolder); + cancelRunningUnity = true; + } + } + else if (dialogResult == DialogResult.Cancel) // dont do restore, but run Unity + { + cancelRunningUnity = true; + } + } + return cancelRunningUnity; + } + + // parse Unity installer exe from release page + // thanks to https://github.com/softfruit + string GetDownloadUrlForUnityVersion(string version) + { + string url = ""; + using (WebClient client = new WebClient()) { string htmlCode = client.DownloadString("https://unity3d.com/get-unity/download/archive"); string[] lines = htmlCode.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); - + for (int i = 0; i < lines.Length; i++) { if (lines[i].Contains("UnitySetup64-" + version)) - { - string line = lines[i-1]; + { + string line = lines[i - 1]; int start = line.IndexOf('"') + 1; int end = line.IndexOf('"', start); url = @"https://unity3d.com" + line.Substring(start, end - start); break; } - } - } - - if(string.IsNullOrEmpty(url)) - SetStatus("Cannot find UnityDownloadAssistant.exe for this version."); - - return url; - } - - /// - /// launches browser to download installer - /// - /// full url to installer - void DownloadInBrowser(string url, string version) - { - string exeURL = GetDownloadUrlForUnityVersion(version); - if (string.IsNullOrEmpty(exeURL) == false) - { - SetStatus("Download installer in browser: " + exeURL); - Process.Start(exeURL); - } - else // not found - { - SetStatus("Error> Cannot find installer executable ... opening website instead"); - url = "https://unity3d.com/get-unity/download/archive"; - Process.Start(url + "#installer-not-found---version-" + version); - } - } - - /// - /// get rootfolder from settings, default is c:\program files\ - /// - /// - string[] GetUnityInstallationsRootFolder() - { - string[] rootFolders = null; - try - { - // if settings exists, use that value - rootFolders = new string[Properties.Settings.Default.rootFolders.Count]; - Properties.Settings.Default.rootFolders.CopyTo(rootFolders, 0); - } - catch (Exception e) - { - MessageBox.Show("Rare error while checking Unity installation folder settings: " + e.Message, "UnityLauncher", MessageBoxButtons.OK); - - // this doesnt work? - Properties.Settings.Default.Reset(); - Properties.Settings.Default.Save(); - } - return rootFolders; - } - - void SetStatus(string msg) - { - toolStripStatusLabel1.Text = msg; - this.Refresh(); - } - - private void ShowForm() - { - this.WindowState = FormWindowState.Minimized; - this.Show(); - this.WindowState = FormWindowState.Normal; - notifyIcon.Visible = false; - } - - void LaunchSelectedProject(bool openProject = true) - { - FixSelectedRow(); - var selected = gridRecent?.CurrentCell?.RowIndex; - - if (selected.HasValue && selected > -1) - { - var projectPath = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); - var version = Tools.GetProjectVersion(projectPath); - Console.WriteLine("version: '" + version + "'"); - LaunchProject(projectPath, version, openProject); - SetStatus("Ready"); - } - } - - - - void LaunchSelectedUnity() - { - - var selected = gridUnityList?.CurrentCell?.RowIndex; - if (selected.HasValue && selected > -1) - { - SetStatus("Launching Unity.."); - var version = gridUnityList.Rows[(int)selected].Cells["_unityVersion"].Value.ToString(); - try - { - Process myProcess = new Process(); - var cmd = "\"" + unityList[version] + "\""; - myProcess.StartInfo.FileName = cmd; - myProcess.Start(); - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - SetStatus("Ready"); - } - } - - void AddPackageFolder() - { - folderBrowserDialog1.Description = "Select package folder"; - var d = folderBrowserDialog1.ShowDialog(); - var newPackageFolder = folderBrowserDialog1.SelectedPath; - - if (String.IsNullOrWhiteSpace(newPackageFolder) == false && Directory.Exists(newPackageFolder) == true) - { - lstPackageFolders.Items.Add(newPackageFolder); - Properties.Settings.Default.packageFolders.Add(newPackageFolder); - Properties.Settings.Default.Save(); - } - } - - - #region Buttons and UI events - - private void btnRemoveRegister_Click(object sender, EventArgs e) - { - Tools.RemoveContextMenuRegistry(contextRegRoot); - } - - private void chkMinimizeToTaskbar_CheckedChanged(object sender, EventArgs e) - { - Properties.Settings.Default.minimizeToTaskbar = chkMinimizeToTaskbar.Checked; - Properties.Settings.Default.Save(); - } - - - - private void btnAddPackageFolder_Click(object sender, EventArgs e) - { - AddPackageFolder(); - } - - private void btnRemovePackFolder_Click(object sender, EventArgs e) - { - if (lstPackageFolders.SelectedIndex > -1) - { - lstPackageFolders.Items.RemoveAt(lstPackageFolders.SelectedIndex); - } - } - - private void btnOpenReleasePage_Click(object sender, EventArgs e) - { - var selected = gridUnityList?.CurrentCell?.RowIndex; - if (selected.HasValue && selected > -1) - { - var version = gridUnityList.Rows[(int)selected].Cells["_unityVersion"].Value.ToString(); - if (Tools.OpenReleaseNotes(version) == true) - { - SetStatus("Opening release notes for version " + version); - } - else - { - SetStatus("Failed opening Release Notes URL for version " + version); - } - } - } - - private void btnLaunchUnity_Click(object sender, EventArgs e) - { - LaunchSelectedUnity(); - } - - private void btnExploreUnity_Click(object sender, EventArgs e) - { - - var selected = gridUnityList?.CurrentCell?.RowIndex; - if (selected.HasValue && selected > -1) - { - var unityPath = Path.GetDirectoryName(gridUnityList.Rows[(int)selected].Cells["_unityPath"].Value.ToString()); - if (Tools.LaunchExplorer(unityPath) == false) - { - SetStatus("Error> Directory not found: " + unityPath); - } - } - } - - private void btnAddUnityFolder_Click(object sender, EventArgs e) - { - AddUnityInstallationRootFolder(); - ScanUnityInstallations(); - UpdateRecentProjectsList(); - } - - private void btnRemoveInstallFolder_Click(object sender, EventArgs e) - { - if (lstRootFolders.SelectedIndex > -1) - { - Properties.Settings.Default.rootFolders.Remove(lstRootFolders.Items[lstRootFolders.SelectedIndex].ToString()); - Properties.Settings.Default.Save(); - lstRootFolders.Items.RemoveAt(lstRootFolders.SelectedIndex); - ScanUnityInstallations(); - } - } - - private void btnFetchUnityVersions_Click(object sender, EventArgs e) - { - FetchListOfUnityUpdates(); - } - - private void unityGridView_KeyDown(object sender, KeyEventArgs e) - { - switch (e.KeyCode) - { - case Keys.Return: // launch selected Unity - e.SuppressKeyPress = true; - LaunchSelectedUnity(); - break; - case Keys.F5: // refresh installed Unity versions list - ScanUnityInstallations(); - UpdateRecentProjectsList(); - break; - default: - break; - } - } - - /// - /// global keys - /// - /// - /// - private void Form1_KeyPress(object sender, KeyPressEventArgs e) - { - // if editing cells, dont focus on search - if (gridRecent.IsCurrentCellInEditMode == true) return; - - switch ((int)e.KeyChar) - { - case 27: // ESCAPE - clear search - if (tabControl1.SelectedIndex == 0 && tbSearchBar.Text != "") - { - tbSearchBar.Text = ""; - } - else if (tabControl1.SelectedIndex == 3 && tbSearchUpdates.Text != "") - { - tbSearchUpdates.Text = ""; - } - break; - default: // any key - // activate searchbar if not active and we are in tab#1 - if (tabControl1.SelectedIndex == 0 && tbSearchBar.Focused == false) - { - // skip tab key on search field - if ((int)e.KeyChar == 9) - { - break; - } - tbSearchBar.Focus(); - tbSearchBar.Text += e.KeyChar; - tbSearchBar.Select(tbSearchBar.Text.Length, 0); - } - break; - } - } - - /// - /// grid keys - /// - /// - /// - private void gridRecent_KeyDown(object sender, KeyEventArgs e) - { - // if editing cells, dont search or launch - if (gridRecent.IsCurrentCellInEditMode == true) return; - - switch (e.KeyCode) - { - case Keys.Return: // launch selected project - e.SuppressKeyPress = true; - LaunchSelectedProject(); - break; - case Keys.F5: // refresh recent projects list - UpdateRecentProjectsList(); - break; - default: - break; - } - } - - //Checks if you are doubleclicking the current cell - private void GridRecent_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) - { - if (e.Button == MouseButtons.Left && e.RowIndex == gridRecent.CurrentCell.RowIndex) - { - LaunchSelectedProject(); - } - } - - // set basefolder of all Unity installations - private void btn_setinstallfolder_Click(object sender, EventArgs e) - { - AddUnityInstallationRootFolder(); - ScanUnityInstallations(); - UpdateRecentProjectsList(); - } - - private void btnLaunch_Click(object sender, EventArgs e) - { - LaunchSelectedProject(); - } - - private void Form1_Resize(object sender, EventArgs e) - { - if (chkMinimizeToTaskbar.Checked == true) - { - if (FormWindowState.Minimized == this.WindowState) - { - notifyIcon.Visible = true; - this.Hide(); - } - else if (FormWindowState.Normal == this.WindowState) - { - notifyIcon.Visible = false; - } - } - } - - private void btnRefresh_Click(object sender, EventArgs e) - { - ScanUnityInstallations(); - UpdateRecentProjectsList(); - } - - private void notifyIcon_MouseClick(object sender, MouseEventArgs e) - { - ShowForm(); - } - - private void btn_openFolder_Click(object sender, EventArgs e) - { - FixSelectedRow(); - var selected = gridRecent?.CurrentCell?.RowIndex; - if (selected.HasValue && selected > -1) - { - string folder = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); - if (Tools.LaunchExplorer(folder) == false) - { - SetStatus("Error> Directory not found: " + folder); - } - } - } - - private void btnExplorePackageFolder_Click(object sender, EventArgs e) - { - var selected = lstPackageFolders.SelectedIndex; - //Console.WriteLine(lstPackageFolders.Items[selected].ToString()); - if (selected > -1) - { - string folder = lstPackageFolders.Items[selected].ToString(); - if (Tools.LaunchExplorer(folder) == false) - { - SetStatus("Error> Directory not found: " + folder); - } - } - } - - private void btnAddAssetStoreFolder_Click(object sender, EventArgs e) - { - var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Unity", "Asset Store-5.x"); - if (Directory.Exists(path) == true) - { - if (lstPackageFolders.Items.Contains(path) == false) - { - lstPackageFolders.Items.Add(path); - Properties.Settings.Default.packageFolders.Add(path); - Properties.Settings.Default.Save(); - } - } - } - - private void btnAddRegister_Click(object sender, EventArgs e) - { - Tools.AddContextMenuRegistry(contextRegRoot); - } - - private void ChkQuitAfterOpen_CheckedChanged(object sender, EventArgs e) - { - Properties.Settings.Default.closeAfterProject = ChkQuitAfterOpen.Checked; - Properties.Settings.Default.Save(); - } - - private void chkQuitAfterCommandline_CheckedChanged(object sender, EventArgs e) - { - Properties.Settings.Default.closeAfterExplorer = chkQuitAfterCommandline.Checked; - Properties.Settings.Default.Save(); - } - - private void chkDarkSkin_CheckedChanged(object sender, EventArgs e) - { - Properties.Settings.Default.useDarkSkin = chkDarkSkin.Checked; - Properties.Settings.Default.Save(); - } - - private void btnRunUnityOnly_Click(object sender, EventArgs e) - { - LaunchSelectedProject(openProject: false); - } - - private void btnUpgradeProject_Click(object sender, EventArgs e) - { - UpgradeProject(); - } - - private void btnOpenLogFolder_Click(object sender, EventArgs e) - { - var logfolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Unity", "Editor"); - if (Directory.Exists(logfolder) == true) - { - if (Tools.LaunchExplorer(logfolder) == false) - { - SetStatus("Error> Directory not found: " + logfolder); - } - } - } - - private void btnOpenUpdateWebsite_Click(object sender, EventArgs e) - { - FixSelectedRow(); - var selected = gridUnityUpdates?.CurrentCell?.RowIndex; - if (selected.HasValue && selected > -1) - { - var version = gridUnityUpdates.Rows[(int)selected].Cells["_UnityUpdateVersion"].Value.ToString(); - Tools.OpenReleaseNotes(version); - } - } - - private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) - { - // if enter Updates tab, then automatically fetch list of Unity versions if list is empty (not fetched) - if (((TabControl)sender).SelectedIndex == 3) // FIXME: fixed index 3 for this tab.. - { - if (gridUnityUpdates.Rows.Count == 0) - { - FetchListOfUnityUpdates(); - } - } - } - - private void Form1_ResizeEnd(object sender, EventArgs e) - { - var form = (Form)sender; - Properties.Settings.Default.formWidth = form.Size.Width; - Properties.Settings.Default.formHeight = form.Size.Height; - Properties.Settings.Default.Save(); - } - - private void checkShowLauncherArgumentsColumn_CheckedChanged(object sender, EventArgs e) - { - Properties.Settings.Default.showArgumentsColumn = chkShowLauncherArgumentsColumn.Checked; - Properties.Settings.Default.Save(); - gridRecent.Columns["_launchArguments"].Visible = chkShowLauncherArgumentsColumn.Checked; - // reload list data, if enabled (otherwise missing data) - if (chkShowLauncherArgumentsColumn.Checked == true) UpdateRecentProjectsList(); - } - - private void checkShowGitBranchColumn_CheckedChanged(object sender, EventArgs e) - { - Properties.Settings.Default.showGitBranchColumn = chkShowGitBranchColumn.Checked; - Properties.Settings.Default.Save(); - gridRecent.Columns["_gitBranch"].Visible = chkShowGitBranchColumn.Checked; - // reload list data, if enabled (otherwise missing data) - if (chkShowGitBranchColumn.Checked == true) UpdateRecentProjectsList(); - } - - - private void linkArgumentsDocs_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - Tools.OpenURL("https://docs.unity3d.com/Manual/CommandLineArguments.html"); - } - - private void linkProjectGithub_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - Tools.OpenURL("https://github.com/unitycoder/UnityLauncher/releases"); - } - - - // after editing launch arguments cell - private void gridRecent_CellEndEdit(object sender, DataGridViewCellEventArgs e) - { - string path = GetSelectedRowData("_path"); - if (string.IsNullOrEmpty(path)) return; - - string arguments = GetSelectedRowData("_launchArguments"); - - // check folder first - string outputFolder = Path.Combine(path, "ProjectSettings"); - if (Directory.Exists(outputFolder) == false) - { - Directory.CreateDirectory(outputFolder); - } - - // save arguments to projectsettings folder - string outputFile = Path.Combine(path, "ProjectSettings", launcherArgumentsFile); - - try - { - StreamWriter sw = new StreamWriter(outputFile); - sw.WriteLine(arguments); - sw.Close(); - } - catch (Exception exception) - { - SetStatus("File error: " + exception.Message); - } - - // select the same row again (dont move to next), doesnt work here - // var previousRow = gridRecent.CurrentCell.RowIndex; - // gridRecent.Rows[previousRow].Selected = true; - } - - private void btnCheckUpdates_Click(object sender, EventArgs e) - { - Tools.OpenURL("https://github.com/unitycoder/UnityLauncher/releases"); - } - - private void btnRefreshProjectList_Click(object sender, EventArgs e) - { - UpdateRecentProjectsList(); - } - - private void btnBrowseForProject_Click(object sender, EventArgs e) - { - BrowseForExistingProjectFolder(); - } - - private void Form1_FormClosing(object sender, FormClosingEventArgs e) - { - SaveSettingsOnExit(); - } - - #endregion UI events - - - - - // displays version selector to upgrade project - void UpgradeProject() - { - FixSelectedRow(); - var selected = gridRecent?.CurrentCell?.RowIndex; - if (selected.HasValue && selected > -1) - { - SetStatus("Upgrading project ..."); - - var projectPath = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); - var currentVersion = Tools.GetProjectVersion(projectPath); - - if (string.IsNullOrEmpty(currentVersion) == true) - { - // TODO no version info available, should handle errors? - } - else // have version info - { - bool haveExactVersion = HaveExactVersionInstalled(currentVersion); - if (haveExactVersion == true) - { - // you already have exact version, are you sure about upgrade? - } - } - DisplayUpgradeDialog(currentVersion, projectPath, true); - } - } - - void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launchProject = true) - { - // display upgrade dialog (version selector) - Form2 upgradeDialog = new Form2(); - Form2.currentVersion = currentVersion; - - // check what user selected - var results = upgradeDialog.ShowDialog(this); - switch (results) - { - case DialogResult.Ignore: // view release notes page - Tools.OpenReleaseNotes(currentVersion); - // display window again for now.. - DisplayUpgradeDialog(currentVersion, projectPath, launchProject); - break; - case DialogResult.Cancel: // cancelled - SetStatus("Cancelled project upgrade"); - break; - case DialogResult.Retry: // download and install missing version - SetStatus("Download and install missing version " + currentVersion); - string url = Tools.GetUnityReleaseURL(currentVersion); - if (string.IsNullOrEmpty(url) == false) - { - DownloadInBrowser(url, currentVersion); - } - else - { - SetStatus("Failed getting Unity Installer URL"); - } - break; - case DialogResult.Yes: // upgrade - SetStatus("Upgrading project to " + Form2.currentVersion); - if (launchProject == true) LaunchProject(projectPath, Form2.currentVersion); - break; - default: - Console.WriteLine("Unknown DialogResult: " + results); - break; - } - upgradeDialog.Close(); - } - - private void FetchListOfUnityUpdates() - { - if (isDownloadingUnityList == true) - { - SetStatus("We are already downloading ..."); - return; - } - isDownloadingUnityList = true; - SetStatus("Downloading list of Unity versions ..."); - - // download list of Unity versions - using (WebClient webClient = new WebClient()) - { - webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(UnityVersionsListDownloaded); - var unityVersionsURL = @"http://symbolserver.unity3d.com/000Admin/history.txt"; - webClient.DownloadStringAsync(new Uri(unityVersionsURL)); - } - } - - private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedEventArgs e) - { - // TODO check for error.. - SetStatus("Downloading list of Unity versions ... done"); - isDownloadingUnityList = false; - - // parse to list - var receivedList = e.Result.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - Array.Reverse(receivedList); - gridUnityUpdates.Rows.Clear(); - // fill in, TODO: show only top 50 or so - for (int i = 0, len = receivedList.Length; i < len; i++) - { - var row = receivedList[i].Split(','); - var versionTemp = row[6].Trim('"'); - gridUnityUpdates.Rows.Add(row[3], versionTemp); - - // set color if we already have it installed - gridUnityUpdates.Rows[i].Cells[1].Style.ForeColor = unityList.ContainsKey(versionTemp) ? Color.Green : Color.Black; - } - } - - // returns currently selected rows path string - string GetSelectedRowData(string key) - { - string path = null; - FixSelectedRow(); - var selected = gridRecent?.CurrentCell?.RowIndex; - if (selected.HasValue && selected > -1) - { - path = gridRecent.Rows[(int)selected].Cells[key].Value?.ToString(); - } - return path; - } - - void BrowseForExistingProjectFolder() - { - folderBrowserDialog1.Description = "Select existing project folder"; - var d = folderBrowserDialog1.ShowDialog(); - var projectPath = folderBrowserDialog1.SelectedPath; - - // NOTE: if user didnt click enter or deselect-select newly created folder, this fails as it returns "new folder" instead of actual name - // https://social.msdn.microsoft.com/Forums/vstudio/en-US/cc7f1d54-c1a0-45de-9611-7f69873f32df/folderbrowserdialog-bug-when-click-ok-while-modify-new-folders-name?forum=netfxbcl - - if (String.IsNullOrWhiteSpace(projectPath) == false && Directory.Exists(projectPath) == true) - { - // TODO: remove duplicate code (from UpdateRecentList()) - string projectName = ""; - - // get project name from full path - if (projectPath.IndexOf(Path.DirectorySeparatorChar) > -1) - { - projectName = projectPath.Substring(projectPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); - } - else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) - { - projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); - } - else // no path separator found - { - projectName = projectPath; - } - - string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); - - // editor only project - if (File.Exists(csprojFile) == false) - { - csprojFile = Path.Combine(projectPath, projectName + ".Editor.csproj"); - } - - // maybe 4.x project - if (File.Exists(csprojFile) == false) - { - csprojFile = Path.Combine(projectPath, "Assembly-CSharp.csproj"); - } - - // get last modified date - DateTime? lastUpdated = Tools.GetLastModifiedTime(csprojFile); - - // get project version - string projectVersion = Tools.GetProjectVersion(projectPath); - - // get custom launch arguments, only if column in enabled - string customArgs = ""; - if (chkShowLauncherArgumentsColumn.Checked == true) - { - customArgs = Tools.ReadCustomLaunchArguments(projectPath, launcherArgumentsFile); - } - - // get git branchinfo, only if column in enabled - string gitBranch = ""; - if (chkShowGitBranchColumn.Checked == true) - { - gitBranch = Tools.ReadGitBranchInfo(projectPath); - } - - // NOTE: list item will disappear if you dont open the project once.. - - // TODO: dont add if not a project?? - - gridRecent.Rows.Insert(0, projectName, projectVersion, projectPath, lastUpdated, customArgs, gitBranch); - gridRecent.Rows[0].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; - gridRecent.Rows[0].Selected = true; - gridRecent.CurrentCell = gridRecent[0, 0]; // reset position to first item - } - } - - private void SaveSettingsOnExit() - { - // save list column widths - List gridWidths; - if (Properties.Settings.Default.gridColumnWidths != null) - { - gridWidths = new List(Properties.Settings.Default.gridColumnWidths); - } - else - { - gridWidths = new List(); - } - - // restore data grid view widths - var colum = gridRecent.Columns[0]; - for (int i = 0; i < gridRecent.Columns.Count; ++i) - { - if (Properties.Settings.Default.gridColumnWidths != null && Properties.Settings.Default.gridColumnWidths.Length > i) - { - gridWidths[i] = gridRecent.Columns[i].Width; - } - else - { - gridWidths.Add(gridRecent.Columns[i].Width); - } - } - Properties.Settings.Default.gridColumnWidths = gridWidths.ToArray(); - Properties.Settings.Default.Save(); - } - - void FixSelectedRow() - { - if (gridRecent.CurrentCell == null) - { - if (gridRecent.SelectedRows.Count != 0) - { - DataGridViewRow row = gridRecent.SelectedRows[0]; - gridRecent.CurrentCell = row.Cells[0]; - } - } - } - - private void btnOpenLogcatCmd_Click(object sender, EventArgs e) - { - try - { - Process myProcess = new Process(); - var cmd = "cmd.exe"; - myProcess.StartInfo.FileName = cmd; - // NOTE windows 10 cmd line supports ansi colors, otherwise remove -v color - var pars = " /c adb logcat -s Unity ActivityManager PackageManager dalvikvm DEBUG -v color"; - myProcess.StartInfo.Arguments = pars; - myProcess.Start(); - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - } - - } // class Form + } + } + + if (string.IsNullOrEmpty(url)) + SetStatus("Cannot find UnityDownloadAssistant.exe for this version."); + + return url; + } + + /// + /// launches browser to download installer + /// + /// full url to installer + void DownloadInBrowser(string url, string version) + { + string exeURL = GetDownloadUrlForUnityVersion(version); + if (string.IsNullOrEmpty(exeURL) == false) + { + SetStatus("Download installer in browser: " + exeURL); + Process.Start(exeURL); + } + else // not found + { + SetStatus("Error> Cannot find installer executable ... opening website instead"); + url = "https://unity3d.com/get-unity/download/archive"; + Process.Start(url + "#installer-not-found---version-" + version); + } + } + + /// + /// get rootfolder from settings, default is c:\program files\ + /// + /// + string[] GetUnityInstallationsRootFolder() + { + string[] rootFolders = null; + try + { + // if settings exists, use that value + rootFolders = new string[Properties.Settings.Default.rootFolders.Count]; + Properties.Settings.Default.rootFolders.CopyTo(rootFolders, 0); + } + catch (Exception e) + { + MessageBox.Show("Rare error while checking Unity installation folder settings: " + e.Message, "UnityLauncher", MessageBoxButtons.OK); + + // this doesnt work? + Properties.Settings.Default.Reset(); + Properties.Settings.Default.Save(); + } + return rootFolders; + } + + void SetStatus(string msg) + { + toolStripStatusLabel1.Text = msg; + this.Refresh(); + } + + private void ShowForm() + { + this.WindowState = FormWindowState.Minimized; + this.Show(); + this.WindowState = FormWindowState.Normal; + notifyIcon.Visible = false; + } + + void LaunchSelectedProject(bool openProject = true) + { + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + + if (selected.HasValue && selected > -1) + { + var projectPath = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); + var version = Tools.GetProjectVersion(projectPath); + Console.WriteLine("version: '" + version + "'"); + LaunchProject(projectPath, version, openProject); + //SetStatus("Ready"); + } + } + + void LaunchSelectedUnity() + { + + var selected = gridUnityList?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + var version = gridUnityList.Rows[(int)selected].Cells["_unityVersion"].Value.ToString(); + SetStatus("Launching Unity: " + version); + try + { + Process myProcess = new Process(); + var cmd = "\"" + unityList[version] + "\""; + myProcess.StartInfo.FileName = cmd; + myProcess.Start(); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + //SetStatus("Ready"); + } + } + + void AddPackageFolder() + { + folderBrowserDialog1.Description = "Select package folder"; + var d = folderBrowserDialog1.ShowDialog(); + var newPackageFolder = folderBrowserDialog1.SelectedPath; + + if (String.IsNullOrWhiteSpace(newPackageFolder) == false && Directory.Exists(newPackageFolder) == true) + { + lstPackageFolders.Items.Add(newPackageFolder); + Properties.Settings.Default.packageFolders.Add(newPackageFolder); + Properties.Settings.Default.Save(); + } + } + + + #region Buttons and UI events + + private void btnRemoveRegister_Click(object sender, EventArgs e) + { + Tools.RemoveContextMenuRegistry(contextRegRoot); + } + + private void chkMinimizeToTaskbar_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.minimizeToTaskbar = chkMinimizeToTaskbar.Checked; + Properties.Settings.Default.Save(); + } + + + + private void btnAddPackageFolder_Click(object sender, EventArgs e) + { + AddPackageFolder(); + } + + private void btnRemovePackFolder_Click(object sender, EventArgs e) + { + if (lstPackageFolders.SelectedIndex > -1) + { + lstPackageFolders.Items.RemoveAt(lstPackageFolders.SelectedIndex); + } + } + + private void btnOpenReleasePage_Click(object sender, EventArgs e) + { + var selected = gridUnityList?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + var version = gridUnityList.Rows[(int)selected].Cells["_unityVersion"].Value.ToString(); + if (Tools.OpenReleaseNotes(version) == true) + { + SetStatus("Opening release notes for version " + version); + } + else + { + SetStatus("Failed opening Release Notes URL for version " + version); + } + } + } + + private void btnLaunchUnity_Click(object sender, EventArgs e) + { + LaunchSelectedUnity(); + } + + private void btnExploreUnity_Click(object sender, EventArgs e) + { + + var selected = gridUnityList?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + var unityPath = Path.GetDirectoryName(gridUnityList.Rows[(int)selected].Cells["_unityPath"].Value.ToString()); + if (Tools.LaunchExplorer(unityPath) == false) + { + SetStatus("Error> Directory not found: " + unityPath); + } + } + } + + private void btnAddUnityFolder_Click(object sender, EventArgs e) + { + AddUnityInstallationRootFolder(); + ScanUnityInstallations(); + UpdateRecentProjectsList(); + } + + private void btnRemoveInstallFolder_Click(object sender, EventArgs e) + { + if (lstRootFolders.SelectedIndex > -1) + { + Properties.Settings.Default.rootFolders.Remove(lstRootFolders.Items[lstRootFolders.SelectedIndex].ToString()); + Properties.Settings.Default.Save(); + lstRootFolders.Items.RemoveAt(lstRootFolders.SelectedIndex); + ScanUnityInstallations(); + } + } + + private void btnFetchUnityVersions_Click(object sender, EventArgs e) + { + FetchListOfUnityUpdates(); + } + + int lastKnownSelectedRow = -1; + private void unityGridView_KeyDown(object sender, KeyEventArgs e) + { + switch (e.KeyCode) + { + case Keys.Return: // launch selected Unity + e.SuppressKeyPress = true; + LaunchSelectedUnity(); + break; + case Keys.F5: // refresh installed Unity versions list + ScanUnityInstallations(); + UpdateRecentProjectsList(); + break; + default: + break; + } + } + + /// + /// global keys + /// + /// + /// + private void Form1_KeyPress(object sender, KeyPressEventArgs e) + { + // if editing cells, dont focus on search + if (gridRecent.IsCurrentCellInEditMode == true) return; + + switch ((int)e.KeyChar) + { + case 27: // ESCAPE - clear search + if (tabControl1.SelectedIndex == 0 && tbSearchBar.Text != "") + { + tbSearchBar.Text = ""; + } + else if (tabControl1.SelectedIndex == 3 && tbSearchUpdates.Text != "") + { + tbSearchUpdates.Text = ""; + } + break; + default: // any key + // activate searchbar if not active and we are in tab#1 + if (tabControl1.SelectedIndex == 0 && tbSearchBar.Focused == false) + { + // skip tab key on search field + if ((int)e.KeyChar == 9) + { + break; + } + tbSearchBar.Focus(); + tbSearchBar.Text += e.KeyChar; + tbSearchBar.Select(tbSearchBar.Text.Length, 0); + } + break; + } + } + + /// + /// grid keys + /// + /// + /// + private void gridRecent_KeyDown(object sender, KeyEventArgs e) + { + // if editing cells, dont search or launch + if (gridRecent.IsCurrentCellInEditMode == true) return; + + switch (e.KeyCode) + { + case Keys.Return: // launch selected project + e.SuppressKeyPress = true; + LaunchSelectedProject(); + break; + case Keys.F5: // refresh recent projects list + lastKnownSelectedRow = GetSelectedRowIndex(); + Console.WriteLine(lastKnownSelectedRow); + UpdateRecentProjectsList(); + SetSelectedRowIndex(lastKnownSelectedRow); + break; + default: + break; + } + } + + //Checks if you are doubleclicking the current cell + private void GridRecent_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) + { + if (e.Button == MouseButtons.Left && e.RowIndex == gridRecent.CurrentCell.RowIndex) + { + LaunchSelectedProject(); + } + } + + // set basefolder of all Unity installations + private void btn_setinstallfolder_Click(object sender, EventArgs e) + { + AddUnityInstallationRootFolder(); + ScanUnityInstallations(); + UpdateRecentProjectsList(); + } + + private void btnLaunch_Click(object sender, EventArgs e) + { + LaunchSelectedProject(); + } + + private void Form1_Resize(object sender, EventArgs e) + { + if (chkMinimizeToTaskbar.Checked == true) + { + if (FormWindowState.Minimized == this.WindowState) + { + notifyIcon.Visible = true; + this.Hide(); + } + else if (FormWindowState.Normal == this.WindowState) + { + notifyIcon.Visible = false; + } + } + } + + private void btnRefresh_Click(object sender, EventArgs e) + { + ScanUnityInstallations(); + UpdateRecentProjectsList(); + } + + private void notifyIcon_MouseClick(object sender, MouseEventArgs e) + { + ShowForm(); + } + + private void btn_openFolder_Click(object sender, EventArgs e) + { + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + string folder = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); + if (Tools.LaunchExplorer(folder) == false) + { + SetStatus("Error> Directory not found: " + folder); + } + } + } + + private void btnExplorePackageFolder_Click(object sender, EventArgs e) + { + var selected = lstPackageFolders.SelectedIndex; + //Console.WriteLine(lstPackageFolders.Items[selected].ToString()); + if (selected > -1) + { + string folder = lstPackageFolders.Items[selected].ToString(); + if (Tools.LaunchExplorer(folder) == false) + { + SetStatus("Error> Directory not found: " + folder); + } + } + } + + private void btnAddAssetStoreFolder_Click(object sender, EventArgs e) + { + var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Unity", "Asset Store-5.x"); + if (Directory.Exists(path) == true) + { + if (lstPackageFolders.Items.Contains(path) == false) + { + lstPackageFolders.Items.Add(path); + Properties.Settings.Default.packageFolders.Add(path); + Properties.Settings.Default.Save(); + } + } + } + + private void btnAddRegister_Click(object sender, EventArgs e) + { + Tools.AddContextMenuRegistry(contextRegRoot); + } + + private void ChkQuitAfterOpen_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.closeAfterProject = ChkQuitAfterOpen.Checked; + Properties.Settings.Default.Save(); + } + + private void chkQuitAfterCommandline_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.closeAfterExplorer = chkQuitAfterCommandline.Checked; + Properties.Settings.Default.Save(); + } + + private void chkDarkSkin_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.useDarkSkin = chkDarkSkin.Checked; + Properties.Settings.Default.Save(); + } + + private void btnRunUnityOnly_Click(object sender, EventArgs e) + { + LaunchSelectedProject(openProject: false); + } + + private void btnUpgradeProject_Click(object sender, EventArgs e) + { + UpgradeProject(); + } + + private void btnOpenLogFolder_Click(object sender, EventArgs e) + { + var logfolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Unity", "Editor"); + if (Directory.Exists(logfolder) == true) + { + if (Tools.LaunchExplorer(logfolder) == false) + { + SetStatus("Error> Directory not found: " + logfolder); + } + } + } + + private void btnOpenUpdateWebsite_Click(object sender, EventArgs e) + { + FixSelectedRow(); + var selected = gridUnityUpdates?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + var version = gridUnityUpdates.Rows[(int)selected].Cells["_UnityUpdateVersion"].Value.ToString(); + Tools.OpenReleaseNotes(version); + } + } + + private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) + { + // if enter Updates tab, then automatically fetch list of Unity versions if list is empty (not fetched) + if (((TabControl)sender).SelectedIndex == 3) // FIXME: fixed index 3 for this tab.. + { + if (gridUnityUpdates.Rows.Count == 0) + { + FetchListOfUnityUpdates(); + } + } + } + + private void Form1_ResizeEnd(object sender, EventArgs e) + { + var form = (Form)sender; + Properties.Settings.Default.formWidth = form.Size.Width; + Properties.Settings.Default.formHeight = form.Size.Height; + Properties.Settings.Default.Save(); + } + + private void checkShowLauncherArgumentsColumn_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.showArgumentsColumn = chkShowLauncherArgumentsColumn.Checked; + Properties.Settings.Default.Save(); + gridRecent.Columns["_launchArguments"].Visible = chkShowLauncherArgumentsColumn.Checked; + // reload list data, if enabled (otherwise missing data) + if (chkShowLauncherArgumentsColumn.Checked == true) UpdateRecentProjectsList(); + } + + private void checkShowGitBranchColumn_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.showGitBranchColumn = chkShowGitBranchColumn.Checked; + Properties.Settings.Default.Save(); + gridRecent.Columns["_gitBranch"].Visible = chkShowGitBranchColumn.Checked; + // reload list data, if enabled (otherwise missing data) + if (chkShowGitBranchColumn.Checked == true) UpdateRecentProjectsList(); + } + + + private void linkArgumentsDocs_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Tools.OpenURL("https://docs.unity3d.com/Manual/CommandLineArguments.html"); + } + + private void linkProjectGithub_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Tools.OpenURL("https://github.com/unitycoder/UnityLauncher/releases"); + } + + + // after editing launch arguments cell + private void gridRecent_CellEndEdit(object sender, DataGridViewCellEventArgs e) + { + string path = GetSelectedRowData("_path"); + if (string.IsNullOrEmpty(path)) return; + + string arguments = GetSelectedRowData("_launchArguments"); + + // check folder first + string outputFolder = Path.Combine(path, "ProjectSettings"); + if (Directory.Exists(outputFolder) == false) + { + Directory.CreateDirectory(outputFolder); + } + + // save arguments to projectsettings folder + string outputFile = Path.Combine(path, "ProjectSettings", launcherArgumentsFile); + + try + { + StreamWriter sw = new StreamWriter(outputFile); + sw.WriteLine(arguments); + sw.Close(); + } + catch (Exception exception) + { + SetStatus("File error: " + exception.Message); + } + + // select the same row again (dont move to next), doesnt work here + // var previousRow = gridRecent.CurrentCell.RowIndex; + // gridRecent.Rows[previousRow].Selected = true; + } + + private void btnCheckUpdates_Click(object sender, EventArgs e) + { + Tools.OpenURL("https://github.com/unitycoder/UnityLauncher/releases"); + } + + private void btnRefreshProjectList_Click(object sender, EventArgs e) + { + UpdateRecentProjectsList(); + } + + private void btnBrowseForProject_Click(object sender, EventArgs e) + { + BrowseForExistingProjectFolder(); + } + + private void Form1_FormClosing(object sender, FormClosingEventArgs e) + { + SaveSettingsOnExit(); + } + + #endregion UI events + + + + + // displays version selector to upgrade project + void UpgradeProject() + { + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + SetStatus("Upgrading project ..."); + + var projectPath = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); + var currentVersion = Tools.GetProjectVersion(projectPath); + + if (string.IsNullOrEmpty(currentVersion) == true) + { + // TODO no version info available, should handle errors? + } + else // have version info + { + bool haveExactVersion = HaveExactVersionInstalled(currentVersion); + if (haveExactVersion == true) + { + // you already have exact version, are you sure about upgrade? + } + } + DisplayUpgradeDialog(currentVersion, projectPath, true); + } + } + + void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launchProject = true) + { + // display upgrade dialog (version selector) + Form2 upgradeDialog = new Form2(); + Form2.currentVersion = currentVersion; + + // check what user selected + var results = upgradeDialog.ShowDialog(this); + switch (results) + { + case DialogResult.Ignore: // view release notes page + Tools.OpenReleaseNotes(currentVersion); + // display window again for now.. + DisplayUpgradeDialog(currentVersion, projectPath, launchProject); + break; + case DialogResult.Cancel: // cancelled + SetStatus("Cancelled project upgrade"); + break; + case DialogResult.Retry: // download and install missing version + SetStatus("Download and install missing version " + currentVersion); + string url = Tools.GetUnityReleaseURL(currentVersion); + if (string.IsNullOrEmpty(url) == false) + { + DownloadInBrowser(url, currentVersion); + } + else + { + SetStatus("Failed getting Unity Installer URL"); + } + break; + case DialogResult.Yes: // upgrade + SetStatus("Upgrading project to " + Form2.currentVersion); + if (launchProject == true) LaunchProject(projectPath, Form2.currentVersion); + break; + default: + Console.WriteLine("Unknown DialogResult: " + results); + break; + } + upgradeDialog.Close(); + } + + private void FetchListOfUnityUpdates() + { + if (isDownloadingUnityList == true) + { + SetStatus("We are already downloading ..."); + return; + } + isDownloadingUnityList = true; + SetStatus("Downloading list of Unity versions ..."); + + // download list of Unity versions + using (WebClient webClient = new WebClient()) + { + webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(UnityVersionsListDownloaded); + var unityVersionsURL = @"http://symbolserver.unity3d.com/000Admin/history.txt"; + webClient.DownloadStringAsync(new Uri(unityVersionsURL)); + } + } + + private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedEventArgs e) + { + // TODO check for error.. + SetStatus("Downloading list of Unity versions ... done"); + isDownloadingUnityList = false; + + // parse to list + var receivedList = e.Result.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + Array.Reverse(receivedList); + gridUnityUpdates.Rows.Clear(); + // fill in, TODO: show only top 50 or so + for (int i = 0, len = receivedList.Length; i < len; i++) + { + var row = receivedList[i].Split(','); + var versionTemp = row[6].Trim('"'); + gridUnityUpdates.Rows.Add(row[3], versionTemp); + + // set color if we already have it installed + gridUnityUpdates.Rows[i].Cells[1].Style.ForeColor = unityList.ContainsKey(versionTemp) ? Color.Green : Color.Black; + } + } + + // returns currently selected rows path string + string GetSelectedRowData(string key) + { + string path = null; + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + path = gridRecent.Rows[(int)selected].Cells[key].Value?.ToString(); + } + return path; + } + + void BrowseForExistingProjectFolder() + { + folderBrowserDialog1.Description = "Select existing project folder"; + var d = folderBrowserDialog1.ShowDialog(); + var projectPath = folderBrowserDialog1.SelectedPath; + + // NOTE: if user didnt click enter or deselect-select newly created folder, this fails as it returns "new folder" instead of actual name + // https://social.msdn.microsoft.com/Forums/vstudio/en-US/cc7f1d54-c1a0-45de-9611-7f69873f32df/folderbrowserdialog-bug-when-click-ok-while-modify-new-folders-name?forum=netfxbcl + + if (String.IsNullOrWhiteSpace(projectPath) == false && Directory.Exists(projectPath) == true) + { + // TODO: remove duplicate code (from UpdateRecentList()) + string projectName = ""; + + // get project name from full path + if (projectPath.IndexOf(Path.DirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); + } + else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); + } + else // no path separator found + { + projectName = projectPath; + } + + string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); + + // editor only project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, projectName + ".Editor.csproj"); + } + + // maybe 4.x project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, "Assembly-CSharp.csproj"); + } + + // get last modified date + DateTime? lastUpdated = Tools.GetLastModifiedTime(csprojFile); + + // get project version + string projectVersion = Tools.GetProjectVersion(projectPath); + + // get custom launch arguments, only if column in enabled + string customArgs = ""; + if (chkShowLauncherArgumentsColumn.Checked == true) + { + customArgs = Tools.ReadCustomLaunchArguments(projectPath, launcherArgumentsFile); + } + + // get git branchinfo, only if column in enabled + string gitBranch = ""; + if (chkShowGitBranchColumn.Checked == true) + { + gitBranch = Tools.ReadGitBranchInfo(projectPath); + } + + // NOTE: list item will disappear if you dont open the project once.. + + // TODO: dont add if not a project?? + + gridRecent.Rows.Insert(0, projectName, projectVersion, projectPath, lastUpdated, customArgs, gitBranch); + gridRecent.Rows[0].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; + gridRecent.Rows[0].Selected = true; + gridRecent.CurrentCell = gridRecent[0, 0]; // reset position to first item + } + } + + private void SaveSettingsOnExit() + { + // save list column widths + List gridWidths; + if (Properties.Settings.Default.gridColumnWidths != null) + { + gridWidths = new List(Properties.Settings.Default.gridColumnWidths); + } + else + { + gridWidths = new List(); + } + + // restore data grid view widths + var colum = gridRecent.Columns[0]; + for (int i = 0; i < gridRecent.Columns.Count; ++i) + { + if (Properties.Settings.Default.gridColumnWidths != null && Properties.Settings.Default.gridColumnWidths.Length > i) + { + gridWidths[i] = gridRecent.Columns[i].Width; + } + else + { + gridWidths.Add(gridRecent.Columns[i].Width); + } + } + Properties.Settings.Default.gridColumnWidths = gridWidths.ToArray(); + Properties.Settings.Default.Save(); + } + + void FixSelectedRow() + { + if (gridRecent.CurrentCell == null) + { + if (gridRecent.SelectedRows.Count != 0) + { + DataGridViewRow row = gridRecent.SelectedRows[0]; + gridRecent.CurrentCell = row.Cells[0]; + } + } + } + + private void btnOpenLogcatCmd_Click(object sender, EventArgs e) + { + try + { + Process myProcess = new Process(); + var cmd = "cmd.exe"; + myProcess.StartInfo.FileName = cmd; + // NOTE windows 10 cmd line supports ansi colors, otherwise remove -v color + var pars = " /c adb logcat -s Unity ActivityManager PackageManager dalvikvm DEBUG -v color"; + myProcess.StartInfo.Arguments = pars; + myProcess.Start(); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + + int GetSelectedRowIndex() + { + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + return (int)selected; + } + else + { + return -1; + } + } + + void SetSelectedRowIndex(int index) + { + if (index > -1 && index < gridRecent.Rows.Count) gridRecent.Rows[index].Selected = true; + } + + private void btnDownloadNewUnity_Click(object sender, EventArgs e) + { + FixSelectedRow(); + var selected = gridUnityUpdates?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + var version = gridUnityUpdates.Rows[(int)selected].Cells["_UnityUpdateVersion"].Value.ToString(); + string url = Tools.GetUnityReleaseURL(version); + if (string.IsNullOrEmpty(url) == false) + { + DownloadInBrowser(url, version); + } + } + + } + } // class Form } // namespace \ No newline at end of file diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 83ebd0f..f629e1d 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -138,36 +138,6 @@ True - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - True - True @@ -186,15 +156,6 @@ True - - True - - - True - - - 14, 20 - 111, 20 diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index 4b3c198..0ac7e94 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -182,14 +182,19 @@ public static string GetUnityReleaseURL(string version) if (version.Contains("f")) // archived { + // remove f# version = Regex.Replace(version, @"f.", "", RegexOptions.IgnoreCase); + string padding = "unity-"; string whatsnew = "whats-new"; + if (version.Contains("5.6")) padding = ""; if (version.Contains("2017.1")) whatsnew = "whatsnew"; - if (version.Contains("2017.4")) padding = ""; if (version.Contains("2018.2")) whatsnew = "whatsnew"; if (version.Contains("2018.3")) padding = ""; + if (version.Contains("2018.1")) whatsnew = "whatsnew"; // doesnt work + if (version.Contains("2017.4.")) padding = ""; // doesnt work for all versions + if (version.Contains("2018.4.")) padding = ""; if (version.Contains("2019")) padding = ""; url = "https://unity3d.com/unity/" + whatsnew + "/" + padding + version; } From 718d0bc294fb3dd8fa634f40bbddaa73c28b9d3e Mon Sep 17 00:00:00 2001 From: mika Date: Fri, 23 Aug 2019 15:42:42 +0300 Subject: [PATCH 76/81] add force update key when launching project from explorer (hold shift key down) fixes #89, fix download button size in updates tab fixes #95, open update project form topmost --- UnityLauncher/Form1.Designer.cs | 36 ++++++++++++++---------------- UnityLauncher/Form1.cs | 19 ++++++++++++---- UnityLauncher/Form1.resx | 39 +++++++++++++++++++++++++++++++++ UnityLauncher/Form2.Designer.cs | 1 + 4 files changed, 72 insertions(+), 23 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 7f38ec3..322084d 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -64,6 +64,7 @@ private void InitializeComponent() this.label3 = new System.Windows.Forms.Label(); this.lstPackageFolders = new System.Windows.Forms.ListBox(); this.tabUpdates = new System.Windows.Forms.TabPage(); + this.btnDownloadNewUnity = new System.Windows.Forms.Button(); this.tbSearchUpdates = new System.Windows.Forms.TextBox(); this.btnOpenUpdateWebsite = new System.Windows.Forms.Button(); this.btnFetchUnityVersions = new System.Windows.Forms.Button(); @@ -100,7 +101,6 @@ private void InitializeComponent() this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker(); - this.btnDownloadNewUnity = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -526,6 +526,19 @@ private void InitializeComponent() this.tabUpdates.Text = "Updates"; this.tabUpdates.UseVisualStyleBackColor = true; // + // btnDownloadNewUnity + // + this.btnDownloadNewUnity.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnDownloadNewUnity.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnDownloadNewUnity.Location = new System.Drawing.Point(3, 511); + this.btnDownloadNewUnity.Name = "btnDownloadNewUnity"; + this.btnDownloadNewUnity.Size = new System.Drawing.Size(239, 35); + this.btnDownloadNewUnity.TabIndex = 25; + this.btnDownloadNewUnity.Text = "Download in Browser"; + this.toolTip1.SetToolTip(this.btnDownloadNewUnity, "Open Release Page"); + this.btnDownloadNewUnity.UseVisualStyleBackColor = true; + this.btnDownloadNewUnity.Click += new System.EventHandler(this.btnDownloadNewUnity_Click); + // // tbSearchUpdates // this.tbSearchUpdates.Location = new System.Drawing.Point(3, 5); @@ -536,8 +549,7 @@ private void InitializeComponent() // // btnOpenUpdateWebsite // - this.btnOpenUpdateWebsite.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); + this.btnOpenUpdateWebsite.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnOpenUpdateWebsite.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.btnOpenUpdateWebsite.Location = new System.Drawing.Point(248, 511); this.btnOpenUpdateWebsite.Name = "btnOpenUpdateWebsite"; @@ -916,12 +928,12 @@ private void InitializeComponent() // // statusStrip1 // + // this next line keeps disappearing : this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.toolStripStatusLabel1}); + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripStatusLabel1 }); this.statusStrip1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.statusStrip1.AutoSize = false; this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(579, 22); @@ -937,20 +949,6 @@ private void InitializeComponent() this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // - // btnDownloadNewUnity - // - this.btnDownloadNewUnity.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.btnDownloadNewUnity.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnDownloadNewUnity.Location = new System.Drawing.Point(3, 511); - this.btnDownloadNewUnity.Name = "btnDownloadNewUnity"; - this.btnDownloadNewUnity.Size = new System.Drawing.Size(239, 35); - this.btnDownloadNewUnity.TabIndex = 25; - this.btnDownloadNewUnity.Text = "Download in Browser"; - this.toolTip1.SetToolTip(this.btnDownloadNewUnity, "Open Release Page"); - this.btnDownloadNewUnity.UseVisualStyleBackColor = true; - this.btnDownloadNewUnity.Click += new System.EventHandler(this.btnDownloadNewUnity_Click); - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 6d5ebfa..dee7448 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -61,6 +61,8 @@ void Start() return; } + + // check if received -projectPath argument (that means opening from explorer / cmdline) string[] args = Environment.GetCommandLineArgs(); if (args != null && args.Length > 2) @@ -89,8 +91,17 @@ void Start() commandLineArguments += " " + args[i]; } - // try launching it - LaunchProject(projectPathArgument, version, openProject: true, commandLineArguments: commandLineArguments); + // check if force-update button is down + if ((Control.ModifierKeys & Keys.Shift) != 0) + { + DisplayUpgradeDialog(version, projectPathArgument, launchProject: true, commandLineArguments: commandLineArguments); + } + else + { + // try launching it + LaunchProject(projectPathArgument, version, openProject: true, commandLineArguments: commandLineArguments); + } + // quit after launch if enabled in settings if (Properties.Settings.Default.closeAfterExplorer == true) @@ -1125,7 +1136,7 @@ void UpgradeProject() } } - void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launchProject = true) + void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launchProject = true, string commandLineArguments = "") { // display upgrade dialog (version selector) Form2 upgradeDialog = new Form2(); @@ -1138,7 +1149,7 @@ void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launch case DialogResult.Ignore: // view release notes page Tools.OpenReleaseNotes(currentVersion); // display window again for now.. - DisplayUpgradeDialog(currentVersion, projectPath, launchProject); + DisplayUpgradeDialog(currentVersion, projectPath, launchProject, commandLineArguments); break; case DialogResult.Cancel: // cancelled SetStatus("Cancelled project upgrade"); diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index f629e1d..83ebd0f 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -138,6 +138,36 @@ True + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + True @@ -156,6 +186,15 @@ True + + True + + + True + + + 14, 20 + 111, 20 diff --git a/UnityLauncher/Form2.Designer.cs b/UnityLauncher/Form2.Designer.cs index 6293ff1..5f5e19c 100644 --- a/UnityLauncher/Form2.Designer.cs +++ b/UnityLauncher/Form2.Designer.cs @@ -133,6 +133,7 @@ private void InitializeComponent() this.Name = "Form2"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Missing Exact Unity Version"; + this.TopMost = true; this.Load += new System.EventHandler(this.Form2_Load); this.ResumeLayout(false); this.PerformLayout(); From d068675b412e9570f0b13d0929a293ed51e929ea Mon Sep 17 00:00:00 2001 From: mika Date: Wed, 28 Aug 2019 19:29:03 +0300 Subject: [PATCH 77/81] fix alpha, beta and patch release download in browser links fixes #93 --- UnityLauncher/Form1.cs | 68 ++++++++++++++++++++++++++++++++++-------- UnityLauncher/Tools.cs | 33 ++++++++++++++++---- 2 files changed, 83 insertions(+), 18 deletions(-) diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index dee7448..d4b22d4 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -542,30 +542,73 @@ bool CheckCrashBackupScene(string projectPath) // parse Unity installer exe from release page // thanks to https://github.com/softfruit - string GetDownloadUrlForUnityVersion(string version) + string ParseDownloadURLFromWebpage(string version) { string url = ""; using (WebClient client = new WebClient()) { - string htmlCode = client.DownloadString("https://unity3d.com/get-unity/download/archive"); - string[] lines = htmlCode.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); - - for (int i = 0; i < lines.Length; i++) + // get correct page url + string website = "https://unity3d.com/get-unity/download/archive"; + if (Tools.VersionIsPatch(version)) website = "https://unity3d.com/unity/qa/patch-releases"; + if (Tools.VersionIsBeta(version)) website = "https://unity3d.com/unity/beta/" + version; + if (Tools.VersionIsAlpha(version)) website = "https://unity3d.com/unity/alpha/" + version; + + // download html + string sourceHTML = client.DownloadString(website); + string[] lines = sourceHTML.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); + + // patch version download assistant finder + if (Tools.VersionIsPatch(version)) { - if (lines[i].Contains("UnitySetup64-" + version)) + for (int i = 0; i < lines.Length; i++) { - string line = lines[i - 1]; - int start = line.IndexOf('"') + 1; - int end = line.IndexOf('"', start); - url = @"https://unity3d.com" + line.Substring(start, end - start); - break; + if (lines[i].Contains("UnityDownloadAssistant-" + version + ".exe")) + { + int start = lines[i].IndexOf('"') + 1; + int end = lines[i].IndexOf('"', start); + url = lines[i].Substring(start, end - start); + break; + } + } + } + else if (Tools.VersionIsArchived(version)) + { + // archived version download assistant finder + for (int i = 0; i < lines.Length; i++) + { + // find line where full installer is (from archive page) + if (lines[i].Contains("UnitySetup64-" + version)) + { + // take previous line, which contains download assistant url + string line = lines[i - 1]; + int start = line.IndexOf('"') + 1; + int end = line.IndexOf('"', start); + url = @"https://unity3d.com" + line.Substring(start, end - start); + break; + } + } + } + else // alpha or beta version download assistant finder + { + for (int i = 0; i < lines.Length; i++) + { + if (lines[i].Contains("UnityDownloadAssistant.exe")) + { + int start = lines[i].IndexOf('"') + 1; + int end = lines[i].IndexOf('"', start); + url = lines[i].Substring(start, end - start) + "#version=" + version; + break; + } } } } + // didnt find installer if (string.IsNullOrEmpty(url)) + { SetStatus("Cannot find UnityDownloadAssistant.exe for this version."); + } return url; } @@ -576,7 +619,8 @@ string GetDownloadUrlForUnityVersion(string version) /// full url to installer void DownloadInBrowser(string url, string version) { - string exeURL = GetDownloadUrlForUnityVersion(version); + string exeURL = ParseDownloadURLFromWebpage(version); + if (string.IsNullOrEmpty(exeURL) == false) { SetStatus("Download installer in browser: " + exeURL); diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs index 0ac7e94..1dc5e63 100644 --- a/UnityLauncher/Tools.cs +++ b/UnityLauncher/Tools.cs @@ -178,9 +178,7 @@ public static bool OpenReleaseNotes(string version) public static string GetUnityReleaseURL(string version) { string url = ""; - - - if (version.Contains("f")) // archived + if (VersionIsArchived(version)) { // remove f# version = Regex.Replace(version, @"f.", "", RegexOptions.IgnoreCase); @@ -199,24 +197,47 @@ public static string GetUnityReleaseURL(string version) url = "https://unity3d.com/unity/" + whatsnew + "/" + padding + version; } else - if (version.Contains("p")) // patch version + if (VersionIsPatch(version)) { url = "https://unity3d.com/unity/qa/patch-releases/" + version; } else - if (version.Contains("b")) // beta version + if (VersionIsBeta(version)) { url = "https://unity3d.com/unity/beta/" + version; } else - if (version.Contains("a")) // alpha version + if (VersionIsAlpha(version)) { url = "https://unity3d.com/unity/alpha/" + version; } + Console.WriteLine(url); + return url; } + // if version contains *f* its archived version + public static bool VersionIsArchived(string version) + { + return version.Contains("f"); + } + + public static bool VersionIsPatch(string version) + { + return version.Contains("p"); + } + + public static bool VersionIsBeta(string version) + { + return version.Contains("b"); + } + + public static bool VersionIsAlpha(string version) + { + return version.Contains("a"); + } + /// /// uninstall context menu item from registry /// From 72134229ef23ee7d969d2663c8ad1d71ec4a72ce Mon Sep 17 00:00:00 2001 From: mika Date: Wed, 28 Aug 2019 20:54:43 +0300 Subject: [PATCH 78/81] add button to open AppData\LocalLow, fixes #92 --- UnityLauncher/Form1.Designer.cs | 18 ++++++++++++++++-- UnityLauncher/Form1.cs | 13 +++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 322084d..7c6a7ed 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -101,6 +101,7 @@ private void InitializeComponent() this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker(); + this.btnPlayerLogFolder = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -621,6 +622,7 @@ private void InitializeComponent() // // tabSettings // + this.tabSettings.Controls.Add(this.btnPlayerLogFolder); this.tabSettings.Controls.Add(this.btnOpenLogcatCmd); this.tabSettings.Controls.Add(this.chkDarkSkin); this.tabSettings.Controls.Add(this.btnCheckUpdates); @@ -653,7 +655,7 @@ private void InitializeComponent() // btnOpenLogcatCmd // this.btnOpenLogcatCmd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnOpenLogcatCmd.Location = new System.Drawing.Point(453, 311); + this.btnOpenLogcatCmd.Location = new System.Drawing.Point(453, 271); this.btnOpenLogcatCmd.Name = "btnOpenLogcatCmd"; this.btnOpenLogcatCmd.Size = new System.Drawing.Size(119, 23); this.btnOpenLogcatCmd.TabIndex = 42; @@ -766,7 +768,7 @@ private void InitializeComponent() // btnOpenLogFolder // this.btnOpenLogFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnOpenLogFolder.Location = new System.Drawing.Point(453, 273); + this.btnOpenLogFolder.Location = new System.Drawing.Point(328, 271); this.btnOpenLogFolder.Name = "btnOpenLogFolder"; this.btnOpenLogFolder.Size = new System.Drawing.Size(119, 23); this.btnOpenLogFolder.TabIndex = 32; @@ -949,6 +951,17 @@ private void InitializeComponent() this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // + // btnPlayerLogFolder + // + this.btnPlayerLogFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnPlayerLogFolder.Location = new System.Drawing.Point(328, 300); + this.btnPlayerLogFolder.Name = "btnPlayerLogFolder"; + this.btnPlayerLogFolder.Size = new System.Drawing.Size(119, 23); + this.btnPlayerLogFolder.TabIndex = 43; + this.btnPlayerLogFolder.Text = "Player.log Folder"; + this.btnPlayerLogFolder.UseVisualStyleBackColor = true; + this.btnPlayerLogFolder.Click += new System.EventHandler(this.btnPlayerLogFolder_Click); + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1059,6 +1072,7 @@ private void InitializeComponent() private System.Windows.Forms.CheckBox chkDarkSkin; private System.Windows.Forms.Button btnOpenLogcatCmd; private System.Windows.Forms.Button btnDownloadNewUnity; + private System.Windows.Forms.Button btnPlayerLogFolder; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index d4b22d4..bdbf983 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -1441,5 +1441,18 @@ private void btnDownloadNewUnity_Click(object sender, EventArgs e) } } + + // open LocalLow folder + private void btnPlayerLogFolder_Click(object sender, EventArgs e) + { + var logfolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "/../LocalLow"); + if (Directory.Exists(logfolder) == true) + { + if (Tools.LaunchExplorer(logfolder) == false) + { + SetStatus("Error> Directory not found: " + logfolder); + } + } + } } // class Form } // namespace \ No newline at end of file From 547a97741ea7c6d4f9ff8761b5c9ed3cd55f2ac2 Mon Sep 17 00:00:00 2001 From: mika Date: Sat, 31 Aug 2019 14:23:03 +0300 Subject: [PATCH 79/81] add clear button to search bar, fixes #90 --- UnityLauncher/Form1.Designer.cs | 41 +++++++++++++++++++++++---------- UnityLauncher/Form1.cs | 21 +++++++++++++++++ 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index 7c6a7ed..318d60b 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -32,6 +32,7 @@ private void InitializeComponent() System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabProjects = new System.Windows.Forms.TabPage(); + this.lblClearSearchField = new System.Windows.Forms.Label(); this.btnBrowseForProject = new System.Windows.Forms.Button(); this.btnRefreshProjectList = new System.Windows.Forms.Button(); this.tbSearchBar = new System.Windows.Forms.TextBox(); @@ -72,6 +73,7 @@ private void InitializeComponent() this._Date = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._UnityUpdateVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabSettings = new System.Windows.Forms.TabPage(); + this.btnPlayerLogFolder = new System.Windows.Forms.Button(); this.btnOpenLogcatCmd = new System.Windows.Forms.Button(); this.chkDarkSkin = new System.Windows.Forms.CheckBox(); this.btnCheckUpdates = new System.Windows.Forms.Button(); @@ -101,7 +103,6 @@ private void InitializeComponent() this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker(); - this.btnPlayerLogFolder = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -133,6 +134,7 @@ private void InitializeComponent() // // tabProjects // + this.tabProjects.Controls.Add(this.lblClearSearchField); this.tabProjects.Controls.Add(this.btnBrowseForProject); this.tabProjects.Controls.Add(this.btnRefreshProjectList); this.tabProjects.Controls.Add(this.tbSearchBar); @@ -148,6 +150,20 @@ private void InitializeComponent() this.tabProjects.Text = "Projects"; this.tabProjects.UseVisualStyleBackColor = true; // + // lblClearSearchField + // + this.lblClearSearchField.AutoSize = true; + this.lblClearSearchField.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblClearSearchField.ForeColor = System.Drawing.Color.DarkGray; + this.lblClearSearchField.Location = new System.Drawing.Point(448, 8); + this.lblClearSearchField.Name = "lblClearSearchField"; + this.lblClearSearchField.Size = new System.Drawing.Size(12, 13); + this.lblClearSearchField.TabIndex = 24; + this.lblClearSearchField.Text = "x"; + this.lblClearSearchField.Click += new System.EventHandler(this.lblClearSearchField_Click); + this.lblClearSearchField.MouseEnter += new System.EventHandler(this.lblClearSearchField_MouseEnter); + this.lblClearSearchField.MouseLeave += new System.EventHandler(this.lblClearSearchField_MouseLeave); + // // btnBrowseForProject // this.btnBrowseForProject.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); @@ -652,6 +668,17 @@ private void InitializeComponent() this.tabSettings.Text = "Settings"; this.tabSettings.UseVisualStyleBackColor = true; // + // btnPlayerLogFolder + // + this.btnPlayerLogFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnPlayerLogFolder.Location = new System.Drawing.Point(328, 300); + this.btnPlayerLogFolder.Name = "btnPlayerLogFolder"; + this.btnPlayerLogFolder.Size = new System.Drawing.Size(119, 23); + this.btnPlayerLogFolder.TabIndex = 43; + this.btnPlayerLogFolder.Text = "Player.log Folder"; + this.btnPlayerLogFolder.UseVisualStyleBackColor = true; + this.btnPlayerLogFolder.Click += new System.EventHandler(this.btnPlayerLogFolder_Click); + // // btnOpenLogcatCmd // this.btnOpenLogcatCmd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); @@ -951,17 +978,6 @@ private void InitializeComponent() this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // - // btnPlayerLogFolder - // - this.btnPlayerLogFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnPlayerLogFolder.Location = new System.Drawing.Point(328, 300); - this.btnPlayerLogFolder.Name = "btnPlayerLogFolder"; - this.btnPlayerLogFolder.Size = new System.Drawing.Size(119, 23); - this.btnPlayerLogFolder.TabIndex = 43; - this.btnPlayerLogFolder.Text = "Player.log Folder"; - this.btnPlayerLogFolder.UseVisualStyleBackColor = true; - this.btnPlayerLogFolder.Click += new System.EventHandler(this.btnPlayerLogFolder_Click); - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1073,6 +1089,7 @@ private void InitializeComponent() private System.Windows.Forms.Button btnOpenLogcatCmd; private System.Windows.Forms.Button btnDownloadNewUnity; private System.Windows.Forms.Button btnPlayerLogFolder; + private System.Windows.Forms.Label lblClearSearchField; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index bdbf983..456283e 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -284,6 +284,7 @@ void FilterRecentProject(object sender, EventArgs e) { SetStatus("Filtering recent projects list ..."); string searchString = tbSearchBar.Text; + foreach (DataGridViewRow row in gridRecent.Rows) { if (row.Cells["_project"].Value.ToString().IndexOf(searchString, StringComparison.OrdinalIgnoreCase) > -1) @@ -295,6 +296,9 @@ void FilterRecentProject(object sender, EventArgs e) row.Visible = false; } } + + lblClearSearchField.Visible = tbSearchBar.Text.Length > 0; + } void FilterUnityUpdates(object sender, EventArgs e) @@ -846,6 +850,7 @@ private void Form1_KeyPress(object sender, KeyPressEventArgs e) if (tabControl1.SelectedIndex == 0 && tbSearchBar.Text != "") { tbSearchBar.Text = ""; + lblClearSearchField.Visible = false; } else if (tabControl1.SelectedIndex == 3 && tbSearchUpdates.Text != "") { @@ -864,6 +869,7 @@ private void Form1_KeyPress(object sender, KeyPressEventArgs e) tbSearchBar.Focus(); tbSearchBar.Text += e.KeyChar; tbSearchBar.Select(tbSearchBar.Text.Length, 0); + lblClearSearchField.Visible = tbSearchBar.Text.Length > 0; } break; } @@ -1454,5 +1460,20 @@ private void btnPlayerLogFolder_Click(object sender, EventArgs e) } } } + + private void lblClearSearchField_Click(object sender, EventArgs e) + { + tbSearchBar.Text = ""; + } + + private void lblClearSearchField_MouseEnter(object sender, EventArgs e) + { + ((Label)sender).ForeColor = Color.FromArgb(255, 0, 0, 0); + } + + private void lblClearSearchField_MouseLeave(object sender, EventArgs e) + { + ((Label)sender).ForeColor = Color.FromArgb(128, 128, 128, 128); + } } // class Form } // namespace \ No newline at end of file From cb34a01f1ba61ba2c3825940859567aaea07ad5f Mon Sep 17 00:00:00 2001 From: mika Date: Sun, 29 Dec 2019 16:14:28 +0200 Subject: [PATCH 80/81] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a7a96cc..5103b05 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +** Note: New Dark Theme WPF version is coming up here, all new features will be available on that version only : https://github.com/unitycoder/UnityLauncherPro ** + # UnityLauncher Handle all your Unity versions and Projects easily! From 1b568e3f46bd9752e5bd41ba5b8386613b0d68d2 Mon Sep 17 00:00:00 2001 From: mika Date: Sat, 12 Sep 2020 14:12:22 +0300 Subject: [PATCH 81/81] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5103b05..d4b68b0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -** Note: New Dark Theme WPF version is coming up here, all new features will be available on that version only : https://github.com/unitycoder/UnityLauncherPro ** +# Note: New Dark Theme WPF version is here : https://github.com/unitycoder/UnityLauncherPro + +### this old winforms version is no longer updated! # UnityLauncher