diff --git a/FlashPatcher/DontTouchMyFlash.csproj b/FlashPatcher/DontTouchMyFlash.csproj deleted file mode 100644 index 0a262fb..0000000 --- a/FlashPatcher/DontTouchMyFlash.csproj +++ /dev/null @@ -1,99 +0,0 @@ - - - - - Debug - AnyCPU - {E986744D-FB17-40E9-83DC-6043995545D9} - WinExe - FlashPatcher - Flash Pwner - v4.0 - 512 - true - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - app.manifest - - - icon0.ico - - - - - - - - - - - - - - - - - Form - - - FlashPwner.cs - - - - - - FlashPwner.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - - - - - - - \ No newline at end of file diff --git a/FlashPatcher/FlashPatcher.csproj b/FlashPatcher/FlashPatcher.csproj index 231059f..3e2931f 100644 --- a/FlashPatcher/FlashPatcher.csproj +++ b/FlashPatcher/FlashPatcher.csproj @@ -30,6 +30,7 @@ false true true + 8.0 AnyCPU @@ -70,7 +71,8 @@ true - SilicaAndPina.pfx + + false @@ -90,6 +92,8 @@ + + @@ -110,6 +114,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + + + + + + FlashPatcherForm.cs @@ -123,8 +175,8 @@ Resources.resx True + - SettingsSingleFileGenerator Settings.Designer.cs @@ -134,13 +186,20 @@ Settings.settings True - + + + Designer + + + Designer + + diff --git a/FlashPatcher/FlashPatcherForm.Designer.cs b/FlashPatcher/FlashPatcherForm.Designer.cs index 5f7802a..f5d4b6e 100644 --- a/FlashPatcher/FlashPatcherForm.Designer.cs +++ b/FlashPatcher/FlashPatcherForm.Designer.cs @@ -38,6 +38,7 @@ this.deleteFile = new System.Windows.Forms.Button(); this.progressBar = new System.Windows.Forms.ProgressBar(); this.projectorPatch = new System.Windows.Forms.Button(); + this.UninstallNag = new System.Windows.Forms.CheckBox(); this.SuspendLayout(); // // label1 @@ -126,7 +127,7 @@ // projectorPatch // this.projectorPatch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.projectorPatch.Location = new System.Drawing.Point(422, 532); + this.projectorPatch.Location = new System.Drawing.Point(410, 528); this.projectorPatch.Name = "projectorPatch"; this.projectorPatch.Size = new System.Drawing.Size(63, 19); this.projectorPatch.TabIndex = 10; @@ -134,11 +135,22 @@ this.projectorPatch.UseVisualStyleBackColor = true; this.projectorPatch.Click += new System.EventHandler(this.projectorPatch_Click); // + // UninstallNag + // + this.UninstallNag.AutoSize = true; + this.UninstallNag.Location = new System.Drawing.Point(229, 530); + this.UninstallNag.Name = "UninstallNag"; + this.UninstallNag.Size = new System.Drawing.Size(178, 17); + this.UninstallNag.TabIndex = 11; + this.UninstallNag.Text = "\"Uninstall Flash\" Nag Messages"; + this.UninstallNag.UseVisualStyleBackColor = true; + // // FlashPatcherForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(486, 552); + this.Controls.Add(this.UninstallNag); this.Controls.Add(this.projectorPatch); this.Controls.Add(this.progressBar); this.Controls.Add(this.deleteFile); @@ -170,6 +182,7 @@ private System.Windows.Forms.Button deleteFile; private System.Windows.Forms.ProgressBar progressBar; private System.Windows.Forms.Button projectorPatch; + private System.Windows.Forms.CheckBox UninstallNag; } } diff --git a/FlashPatcher/FlashPatcherForm.cs b/FlashPatcher/FlashPatcherForm.cs index 1722949..b2f7e22 100644 --- a/FlashPatcher/FlashPatcherForm.cs +++ b/FlashPatcher/FlashPatcherForm.cs @@ -1,10 +1,11 @@ -using System; +using Microsoft.Win32.TaskScheduler; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Runtime.InteropServices; using System.Security.AccessControl; using System.Security.Principal; +using System.Text.RegularExpressions; using System.Windows.Forms; namespace FlashPatcher @@ -18,6 +19,14 @@ namespace FlashPatcher } public byte[] Timestamp = new byte[] { 0x00, 0x00, 0x40, 0x46, 0x3E, 0x6F, 0x77, 0x42 }; public byte[] Infintiy = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F }; + + /// + /// Locates a byte array inside a byte array, + /// used for finding the timestamp bytes + /// + /// data to search + /// bytes to find + /// Location of the found bytes, -1 if not found. public Int64 GetPositionAfterMatch(byte[] data, byte[] pattern) { @@ -40,7 +49,11 @@ namespace FlashPatcher return -1; } - + /// + /// Uses windows security api's to give program access to the files + /// this is required becuase by default the ActiveX controls are owned by TrustedInstaller. + /// + /// the file to get access to public void TakeOwn(string filepath) { FileSecurity fileS = File.GetAccessControl(filepath); @@ -73,6 +86,11 @@ namespace FlashPatcher File.SetAttributes(filepath, FileAttributes.Normal); } + /// + /// Checks if a given file contains a killswitch timestamp. + /// + /// File to check. + /// public bool CheckFileAndAdd(string filepath) { try @@ -92,6 +110,11 @@ namespace FlashPatcher return false; } } + + /// + /// Scans a folder for flash exectables, (OCX/DLL/EXE) + /// + /// Path to the folder public void ScanFolder(string path) { if(Directory.Exists(path)) @@ -107,6 +130,11 @@ namespace FlashPatcher } } + /// + /// Patches a given Portable Executable (PE) file + /// + /// The path to the executable. + /// public bool PatchExe(string filepath) { try @@ -143,26 +171,50 @@ namespace FlashPatcher return true; } } + /// + /// Locates Portable Executables (PE) files + /// of adobe flash player. + /// public void LocateExes() { string windir = Environment.GetEnvironmentVariable("WINDIR"); string localappdata = Environment.GetEnvironmentVariable("LOCALAPPDATA"); - string flashPath = Path.Combine(windir, "System32", "Macromed", "Flash"); + + // Firefox / Internet Explorer + + string flashPath = Path.Combine(windir, "System32", "Macromed", "Flash"); // Win64 in win64 mode, Win32 in win32 mode ScanFolder(flashPath); - flashPath = Path.Combine(windir, "SysWOW64", "Macromed", "Flash"); + flashPath = Path.Combine(windir, "Sysnative", "Macromed", "Flash"); // Win64 in win32 mode. ScanFolder(flashPath); + flashPath = Path.Combine(windir, "SysWOW64", "Macromed", "Flash"); // Win32 in win64 mode + ScanFolder(flashPath); + + // Chrome (<88) + flashPath = Path.Combine(localappdata, "Google", "Chrome", "User Data", "PepperFlash"); ScanFolder(flashPath); + // Edge + flashPath = Path.Combine(localappdata, "Microsoft", "Edge", "User Data", "PepperFlash"); ScanFolder(flashPath); + + // Opera + + flashPath = Path.Combine(localappdata, "Microsoft", "Opera Software", "Opera GX Stable", "User Data", "PepperFlash"); + ScanFolder(flashPath); + + flashPath = Path.Combine(localappdata, "Microsoft", "Opera Software", "Opera Stable", "User Data", "PepperFlash"); + ScanFolder(flashPath); + } private void FlashPwner_Load(object sender, EventArgs e) { LocateExes(); + ScheduledTasksCheck(); } private void defuseBomb_Click(object sender, EventArgs e) @@ -243,5 +295,36 @@ namespace FlashPatcher MessageBox.Show("Patched! Projector should no longer open the browser!!!", "SUCCESS", MessageBoxButtons.OK, MessageBoxIcon.Information); } } + + private void ScheduledTasksCheck() + { + TaskService service = new TaskService(); + TaskCollection collection = service.RootFolder.GetTasks(new Regex("Adobe Flash Player .* Notifier")); + foreach(Task task in collection) + { + if (task.Enabled) + { + UninstallNag.Checked = true; + break; + } + } + + this.UninstallNag.CheckedChanged += new EventHandler(this.UninstallNag_CheckedChanged); + } + + private void UninstallNag_CheckedChanged(object sender, EventArgs e) + { + TaskService service = new TaskService(); + TaskCollection collection = service.RootFolder.GetTasks(new Regex("Adobe Flash Player .* Notifier")); + foreach (Task task in collection) + task.Enabled = UninstallNag.Checked; + + if(!UninstallNag.Checked) + MessageBox.Show("\"Please Uninstall Flash\" Nag Messages DISABLED.", "Nag Messages",MessageBoxButtons.OK, MessageBoxIcon.Information); + else + MessageBox.Show("\"Please Uninstall Flash\" Nag Messages ENABLED.", "Nag Messages", MessageBoxButtons.OK, MessageBoxIcon.Information); + + } + } } diff --git a/FlashPatcher/FlashPatcher_TemporaryKey.pfx b/FlashPatcher/FlashPatcher_TemporaryKey.pfx deleted file mode 100644 index d5b6275..0000000 Binary files a/FlashPatcher/FlashPatcher_TemporaryKey.pfx and /dev/null differ diff --git a/FlashPatcher/FlashPwner.Designer.cs b/FlashPatcher/FlashPwner.Designer.cs deleted file mode 100644 index e683aef..0000000 --- a/FlashPatcher/FlashPwner.Designer.cs +++ /dev/null @@ -1,175 +0,0 @@ -namespace FlashPatcher -{ - partial class FlashPwner - { - /// - /// 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() - { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FlashPwner)); - this.label1 = new System.Windows.Forms.Label(); - this.addFile = new System.Windows.Forms.Button(); - this.cringe = new System.Windows.Forms.Label(); - this.defuseBomb = new System.Windows.Forms.Button(); - this.console = new System.Windows.Forms.TextBox(); - this.flashExes = new System.Windows.Forms.ListBox(); - this.deleteFile = new System.Windows.Forms.Button(); - this.progressBar = new System.Windows.Forms.ProgressBar(); - this.projectorPatch = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(9, 9); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(263, 13); - this.label1.TabIndex = 0; - this.label1.Text = "Flash Executables: (pepflash.dll, NPSWF64, flash.ocx)"; - // - // addFile - // - this.addFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.addFile.Location = new System.Drawing.Point(434, 2); - this.addFile.Name = "addFile"; - this.addFile.Size = new System.Drawing.Size(39, 20); - this.addFile.TabIndex = 1; - this.addFile.Text = "Add "; - this.addFile.UseVisualStyleBackColor = true; - this.addFile.Click += new System.EventHandler(this.addFile_Click); - // - // cringe - // - this.cringe.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.cringe.AutoSize = true; - this.cringe.Location = new System.Drawing.Point(2, 530); - this.cringe.Name = "cringe"; - this.cringe.Size = new System.Drawing.Size(211, 13); - this.cringe.TabIndex = 4; - this.cringe.Text = "The quieter you becom, the moar u cn hear"; - // - // defuseBomb - // - this.defuseBomb.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.defuseBomb.Location = new System.Drawing.Point(11, 468); - this.defuseBomb.Name = "defuseBomb"; - this.defuseBomb.Size = new System.Drawing.Size(462, 23); - this.defuseBomb.TabIndex = 5; - this.defuseBomb.Text = "!!! DEFUSE THE BOMB !!!"; - this.defuseBomb.UseVisualStyleBackColor = true; - this.defuseBomb.Click += new System.EventHandler(this.defuseBomb_Click); - // - // console - // - this.console.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.console.Location = new System.Drawing.Point(12, 178); - this.console.Multiline = true; - this.console.Name = "console"; - this.console.Size = new System.Drawing.Size(462, 284); - this.console.TabIndex = 6; - // - // flashExes - // - this.flashExes.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.flashExes.FormattingEnabled = true; - this.flashExes.HorizontalScrollbar = true; - this.flashExes.Location = new System.Drawing.Point(12, 25); - this.flashExes.Name = "flashExes"; - this.flashExes.Size = new System.Drawing.Size(462, 147); - this.flashExes.TabIndex = 7; - // - // deleteFile - // - this.deleteFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.deleteFile.Location = new System.Drawing.Point(386, 2); - this.deleteFile.Name = "deleteFile"; - this.deleteFile.Size = new System.Drawing.Size(48, 20); - this.deleteFile.TabIndex = 8; - this.deleteFile.Text = "Delete"; - this.deleteFile.UseVisualStyleBackColor = true; - this.deleteFile.Click += new System.EventHandler(this.deleteFile_Click); - // - // progressBar - // - this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.progressBar.Location = new System.Drawing.Point(14, 497); - this.progressBar.Name = "progressBar"; - this.progressBar.Size = new System.Drawing.Size(459, 23); - this.progressBar.TabIndex = 9; - // - // projectorPatch - // - this.projectorPatch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.projectorPatch.Location = new System.Drawing.Point(422, 532); - this.projectorPatch.Name = "projectorPatch"; - this.projectorPatch.Size = new System.Drawing.Size(63, 19); - this.projectorPatch.TabIndex = 10; - this.projectorPatch.Text = "Projector+"; - this.projectorPatch.UseVisualStyleBackColor = true; - this.projectorPatch.Click += new System.EventHandler(this.projectorPatch_Click); - // - // FlashPwner - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(486, 552); - this.Controls.Add(this.projectorPatch); - this.Controls.Add(this.progressBar); - this.Controls.Add(this.deleteFile); - this.Controls.Add(this.flashExes); - this.Controls.Add(this.console); - this.Controls.Add(this.defuseBomb); - this.Controls.Add(this.cringe); - this.Controls.Add(this.addFile); - this.Controls.Add(this.label1); - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.MaximumSize = new System.Drawing.Size(1920, 591); - this.MinimumSize = new System.Drawing.Size(502, 591); - this.Name = "FlashPwner"; - this.Text = "Flash Pwner"; - this.Load += new System.EventHandler(this.FlashPwner_Load); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Button addFile; - private System.Windows.Forms.Label cringe; - private System.Windows.Forms.Button defuseBomb; - private System.Windows.Forms.TextBox console; - private System.Windows.Forms.ListBox flashExes; - private System.Windows.Forms.Button deleteFile; - private System.Windows.Forms.ProgressBar progressBar; - private System.Windows.Forms.Button projectorPatch; - } -} - diff --git a/FlashPatcher/FlashPwner.cs b/FlashPatcher/FlashPwner.cs deleted file mode 100644 index 0eceb20..0000000 --- a/FlashPatcher/FlashPwner.cs +++ /dev/null @@ -1,248 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using System.Security.AccessControl; -using System.Security.Principal; -using System.Windows.Forms; - -namespace FlashPatcher -{ - public partial class FlashPwner : Form - { - - public FlashPwner() - { - InitializeComponent(); - } - public byte[] Timestamp = new byte[] { 0x00, 0x00, 0x40, 0x46, 0x3E, 0x6F, 0x77, 0x42 }; - public byte[] Infintiy = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F }; - public Int64 GetPositionAfterMatch(byte[] data, byte[] pattern) - { - for (Int64 i = 0; i < data.LongLength - pattern.LongLength; i++) - { - bool match = true; - for (Int64 k = 0; k < pattern.LongLength; k++) - { - if (data[i + k] != pattern[k]) - { - match = false; - break; - } - } - if (match) - { - return i; - } - } - return -1; - } - - public void TakeOwn(string filepath) - { - FileSecurity fileS = File.GetAccessControl(filepath); - - SecurityIdentifier cu = WindowsIdentity.GetCurrent().User; - SecurityIdentifier everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null); - - try - { - Privileges.EnablePrivilege(SecurityEntity.SE_TAKE_OWNERSHIP_NAME); - } - catch(Exception) - { - console.AppendText("Failed to get SeTakeOwnershipPrivledge\r\n"); - } - - fileS.SetOwner(cu); - File.SetAccessControl(filepath, fileS); - - - fileS.SetAccessRuleProtection(false, false); - - fileS.RemoveAccessRuleAll(new FileSystemAccessRule(everyone, FileSystemRights.FullControl, AccessControlType.Deny)); - fileS.RemoveAccessRuleAll(new FileSystemAccessRule(cu, FileSystemRights.FullControl, AccessControlType.Deny)); - - fileS.SetAccessRule(new FileSystemAccessRule(everyone, FileSystemRights.FullControl, AccessControlType.Allow)); - fileS.SetAccessRule(new FileSystemAccessRule(cu, FileSystemRights.FullControl, AccessControlType.Allow)); - - File.SetAccessControl(filepath, fileS); - File.SetAttributes(filepath, FileAttributes.Normal); - - } - - public bool CheckFileAndAdd(string filepath) - { - try - { - byte[] fileData = File.ReadAllBytes(filepath); - Int64 timestampLocation = GetPositionAfterMatch(fileData, Timestamp); - if (timestampLocation != -1) - { - flashExes.Items.Add(filepath); - console.AppendText("Found killswitch timestamp in " + Path.GetFileName(filepath) + " @ 0x" + timestampLocation.ToString("X") + "\r\n"); - return true; - } - return false; - } - catch(Exception) - { - return false; - } - } - public void ScanFolder(string path) - { - if(Directory.Exists(path)) - { - String[] fileList = Directory.GetFiles(path, "*", SearchOption.AllDirectories); - foreach (string file in fileList) - { - if (file.ToLower().EndsWith(".ocx") || file.ToLower().EndsWith(".dll") || file.ToLower().EndsWith(".exe")) - { - CheckFileAndAdd(file); - } - } - } - } - - public bool PatchExe(string filepath) - { - try - { - Process[] lockingProcesses = FileUtil.WhoIsLocking(filepath).ToArray(); - foreach(Process proc in lockingProcesses) - { - DialogResult res = MessageBox.Show("Flash is currently in use by (" + proc.Id.ToString() + ")" + proc.ProcessName + "\nEnd Process?", "File in use :/", MessageBoxButtons.YesNo, MessageBoxIcon.Information); - if (res == DialogResult.Yes) - proc.Kill(); // DIE HHAHA - else - return true; - } - byte[] fileData = File.ReadAllBytes(filepath); - Int64 timestampLocation = GetPositionAfterMatch(fileData, Timestamp); - - - TakeOwn(filepath); - FileStream fs = File.OpenWrite(filepath); - fs.Seek(timestampLocation, SeekOrigin.Begin); - fs.Write(Infintiy, 0x00, Infintiy.Length); - fs.Close(); - - - console.AppendText("Patched: " + Path.GetFileName(filepath) + ".\r\n"); - flashExes.Items.Remove(filepath); - Application.DoEvents(); - progressBar.Increment(1); - return false; - } - catch(Exception e) - { - MessageBox.Show(e.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); - return true; - } - - } - public void LocateExes() - { - string windir = Environment.GetEnvironmentVariable("WINDIR"); - string localappdata = Environment.GetEnvironmentVariable("LOCALAPPDATA"); - - string flashPath = Path.Combine(windir, "System32", "Macromed", "Flash"); - ScanFolder(flashPath); - - flashPath = Path.Combine(windir, "SysWOW64", "Macromed", "Flash"); - ScanFolder(flashPath); - - flashPath = Path.Combine(localappdata, "Google", "Chrome", "User Data", "PepperFlash"); - ScanFolder(flashPath); - - flashPath = Path.Combine(localappdata, "Microsoft", "Edge", "User Data", "PepperFlash"); - ScanFolder(flashPath); - } - private void FlashPwner_Load(object sender, EventArgs e) - { - LocateExes(); - } - - private void defuseBomb_Click(object sender, EventArgs e) - { - defuseBomb.Enabled = false; - if(flashExes.Items.Count > 0) - { - progressBar.Maximum = flashExes.Items.Count; - List copyFlashExes = new List(); - foreach (string flashExe in flashExes.Items) - { - copyFlashExes.Add(flashExe); - } - bool errored = false; - foreach (string flashExe in copyFlashExes) - { - errored = PatchExe(flashExe); - } - if(!errored) - MessageBox.Show("Patched! Your flash should work again!!!", "SUCCESS", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - else - { - MessageBox.Show("No files to patch!", "File Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); - } - defuseBomb.Enabled = true; - } - - private void addFile_Click(object sender, EventArgs e) - { - OpenFileDialog ofd = new OpenFileDialog(); - ofd.Title = "Flash Executable"; - ofd.Filter = "PE Executables (*.exe, *.ocx, *.dll)|*.dll;*.exe;*.ocx|ELF Executables (*.so, *.elf, *.dylib)|*.so;*.elf;*.dylib"; - DialogResult res = ofd.ShowDialog(); - if(res == DialogResult.OK) - { - if (!CheckFileAndAdd(ofd.FileName)) - { - MessageBox.Show("File selected does not contain the killswitch timestamp, cannot patch!", "Timestamp Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - } - - private void patchProjetor(string path) - { - byte[] projBytes = File.ReadAllBytes(path); - byte[] getUrlPattern = new byte[] { 0xF4, 0xE8, 0xBE, 0xFE, 0xFF, 0xFF }; - byte[] nops = new byte[] { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; - Int64 getUrlLocation = GetPositionAfterMatch(projBytes, getUrlPattern); - - if (getUrlLocation == -1) - return; - - FileStream fs = File.OpenWrite(path); - fs.Seek(getUrlLocation+1, SeekOrigin.Begin); - fs.Write(nops, 0x00, nops.Length); - fs.Close(); - - } - - private void deleteFile_Click(object sender, EventArgs e) - { - if(flashExes.SelectedIndex >= 0) - flashExes.Items.RemoveAt(flashExes.SelectedIndex); - } - - private void projectorPatch_Click(object sender, EventArgs e) - { - MessageBox.Show("This is a patch for the standalone \"projector\" program from adobe, it stops it opening your browser whenever a game tries to call javascript with getURL()\n\nNote: the projector DOES NOT HAVE A KILLSWITCH/TIMEBOMB and this is not needed to use the Flash Projector.", "Projector", MessageBoxButtons.OK, MessageBoxIcon.Information); - - OpenFileDialog ofd = new OpenFileDialog(); - ofd.Title = "Flash Projector"; - ofd.Filter = "PE Executables (*.exe)|*.exe;|ELF Executables (*.elf)|*.elf"; - DialogResult res = ofd.ShowDialog(); - if(res == DialogResult.OK) - { - patchProjetor(ofd.FileName); - MessageBox.Show("Patched! Projector should no longer open the browser!!!", "SUCCESS", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - } - } -} diff --git a/FlashPatcher/FlashPwner.resx b/FlashPatcher/FlashPwner.resx deleted file mode 100644 index 7c37f7d..0000000 --- a/FlashPatcher/FlashPwner.resx +++ /dev/null @@ -1,4615 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 - - - - - AAABAAEAAP8AAAEAIAAIHAQAFgAAACgAAAAAAQAA/gEAAAEAIAAAAAAAAPwDAMMOAADDDgAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AACsqK0ArKitAKyorQCsqK0ArKitAKyorQCsqK0ArKitAKyorQCsqK0AAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAKyorQCsqK0ArKitAKyorQCsqK0ArKitAKyorQCsqK0ArKitAKyorQAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArKitAKyorQCsqK0ArKitAKyorQCsqK0ArKitAKyo - rQCsqK0ArKitAKyorQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsqK0ArKitAKyorQCsqK0ArKitAKyo - rQCsqK0ArKitAKyorQCsqK0ArKitAKyorQCsqK0ArKitAKyorQCsqK0ArKitAKyorQCsqK0AAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKyo - rQCsqK0ArKitAKyorQCsqK0ArKitAKyorQCsqK0ArKitAKyorQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqoqACrqagApqWoAKiirACnoacApaGiAKSg - oQCjnaMAo5ylALSvtAiyrbILsq2yC7KtsgqyrrIKsq2yC7Ktsgu1sLUHop6jAKKdogCinaIAop2iAKKd - ogCinaIAop2iAKKdogCjnqMAv7u/A7KtsguyrbILsq2yC7KtsguyrbILsq2yC7KuswqemqAAop2iAKKd - ogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKd - ogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKd - ogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKd - ogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKd - ogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogChnaMArY+PAMB3bgClmZ0Aop2iAKKd - ogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKOeowDHw8gCsa2yC7KtsguyrbILsq2yC7Kt - sguyrbILsq2yC5yYngCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAJaRlgCyrbILtbC2C7y3 - vQu9ub4Lvbm+C725vgu9ub4Lvbm+C725vgq9ub4Kvbm+C725vgu8uL0LtrK3C7KuswuyrrMKn5ugAKKd - ogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKd - ogCjnqMAuLS5BbKtsguyrbIKsq2yC7KtsguyrbILsq2yC7KuswmgnKEAop2iAKKdogCinaIAop2iAKKd - ogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogChnKEAoZyhAKGc - oQChnKEAop2hAKKdogCinaIAop2iAKKdogCinaIAop2iAKKdogCinaIAoZyhAKGcoQChnKEAoZyhAKGc - oQChnKEAoZyhAKGcoQChnKEAoZyhAKGcoQChnKEAoZ2gAKOhogClpKUAqKaoAKilrAClorcAp6SzAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqKiuAKiorgCpqasA/++sAKqoqA2qo6xAqKKndqWh - onSloKF0pJ6jdKOcpHOkoKWhpKGmrKShpqukoaarpKGmq6ShpqukoaaspKCln6GdonKjnaJ0o52idKOd - onSjnaJ0o52idKOdonSjnaJ0op2icqOfpJGloaatpKGmq6ShpqukoaarpKGmq6ShpqukoaWqop6id6Od - onSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOd - onSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOd - onSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOd - onSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOd - onSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0op6kdKuSk3S/eXF0pJugdKKe - onSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJyo5+kjqWhpq2koaarpKGmq6Sh - pqukoaarpKGmq6ShpquinqJ5op2idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKWgpXSopKl9qaWqrKSg - pauYlJmrlpKXq5aSl6uWkperlpKXq5aSl6uWkperlpKXq5aSl6uWkperl5OYq6GdoquopaqrqaWqqqWh - pnejnqJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOd - onSjnaJ0op2icqSgpZekoaaspKGmq6ShpqukoaarpKGmq6ShpqukoaWnoZ2idaOdonSjnaJ0o52idKKe - o3SinqN0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0op2hdKKc - oXSinKF0opyhdKKdoXSjnaJ0o52idKOdonSjnaJ0o52idKOdonSjnaJ0o52idKKcoXSinKF0opyhdKKc - oXSinKF0opyhdKKcoXSinKF0opyhdKKcoXSinKF0opyhdKKdoHSkoqJ0pqSkdKimqHKqp6wojXP/AKij - xACVj7wAv7rWALm00gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAANDRzwDQ0c8A0NHPAKSiqgCMAP8As7ezBqioqlSjoanQnZup7JmZ - pP+XmZ7/l5id/5eVn/+XlKD/lZWf/5SVnv+UlZ7/lJWe/5SVnv+UlZ7/lJWe/5SVnv+VlZ7/lZWf/5WV - n/+VlZ//lZWf/5WVnv+VlZ7/lZWe/5WVnv+VlZ7/lJWe/5SVnv+UlZ7/lJWe/5SVnv+UlZ7/lJWe/5WV - nv+WlZ7/l5We/5eVnv+XlZ7/l5We/5eVn/+XlZ//l5Wf/5aVnv+VlZ7/lZWe/5WVnv+VlZ7/lZWf/5WV - n/+VlZ//lZWf/5WVn/+VlZ//lZWf/5WVn/+VlZ7/lZWe/5WVnv+VlZ7/lZWe/5WVn/+VlZ//lZWf/5WV - n/+VlZ//lZWf/5WVn/+VlZ//lZWe/5WVnv+VlZ7/lZWe/5WVnv+VlZ//lZWf/5WVn/+VlZ//lZWf/5WV - n/+VlZ//lZWf/5WVn/+VlZ//lZWf/5WVn/+VlZ//lZWf/5WVn/+VlZ//lZWf/5WVn/+VlZ//lZWf/5WV - n/+VlZ//lZWf/5WVn/+VlZ//lZWe/5WVnv+VlZ7/lZWe/5WVnv+VlZ//lJWf/5iRmf/KYFL/7D0g/7N2 - cv+UlJ7/lZWf/5aVnv+XlZ7/l5We/5eVnv+XlZ7/l5We/5eVnv+XlZ7/l5We/5WVnv+UlZ7/lJWe/5SV - nv+UlZ7/lJWe/5SVnv+UlZ7/lZWe/5WVnv+VlZ7/lZWe/5WVn/+WlqD/kpKc/5CQmf9+fYT/YWFk/19f - Yv9NTE//IyIk/xsaG/8bGxz/Gxsc/xsbHP8bGxz/Gxsc/xsbHP8bGxz/Gxsb/x8eH/9EREb/X15h/19f - Yv93dnz/kJCY/5GRmv+VlaD/lZWg/5WVnv+VlZ7/lZWe/5WVnv+VlZ7/lZWf/5WVn/+VlZ//lZWf/5WV - nv+VlZ7/lZWe/5WVnv+VlZ7/lJWe/5SVnv+UlZ7/lJWe/5SVnv+UlZ7/lJWe/5WVnv+WlZ7/lpWd/5WW - nv+djZL/no2R/5WVnv+WlZ7/lpWe/5eVnv+XlZ7/l5We/5eVnv+XlZ7/l5We/5eVnv+XlZ7/lpWe/5aV - nv+WlZ3/lpWd/5aVnf+WlZ3/lpWe/5aVnv+WlZ7/lpWe/5aVnv+WlZ7/lpWe/5aVnv+WlZ3/lpWd/5aV - nf+WlZ3/lpWd/5aVnf+WlZ3/lpWd/5aVnf+WlZ3/lpWd/5aVnf+WlZ//l5ak/5qZp/+dm6r/oZ6z4aei - wISzrdMn6+T/B//8/wLGxN0AwL/ZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQ0c8A0NHPINHS0AutrLoAqaawX5+grsl8fZPtaWqL/2Nj - j/9fYY3/XWGI/15hhv9fYIf/X1+J/15giP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11g - iP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11gif9dYIn/XWCJ/11gif9dYIj/XWCI/11g - iP9eYIj/X2CJ/19gif9fYIn/X2CJ/19fiP9fX4j/X1+I/19fiP9eYIn/XWCJ/11gif9dYIn/XWCJ/11g - iP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11g - iP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11g - iP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11g - iP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIj/XGCJ/2Rghf+2Tkz/+yoG//8k - AP/tMxb/lFhn/1xgif9dYIj/X2CI/19gif9fYIn/X2CJ/19gif9fYIn/X2CJ/19gif9eYIj/XWCI/11g - iP9dYIj/XWCI/11giP9dYIj/XWCI/11giP9dYIr/XWCK/11giP9YWnn/UlRp/zEyPP8dHSH/ERIU/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/DQ0P/xwdIP8oKTD/TlBj/1ZYdf9cX4f/XWCK/11giv9dYIj/XWCI/11giP9dYIj/XWCI/1xf - iP9bXof/W16H/1teh/9bXof/W16H/1xeh/9cXof/XF6H/1xfh/9cX4f/XF+H/1xfh/9dX4b/Xl+G/1xf - h/9wXn3/y0Y4/9JDMv90XXn/W1+G/11fhf9dXob/Xl6H/15eh/9eXof/Xl6H/15eh/9eXof/Xl6H/15e - hv9eX4b/Xl+G/15fhv9eX4b/XV+F/11ehf9dXoX/XV6F/11ehf9dXoX/XV6F/11ehf9dXoX/Xl+G/15f - hv9eX4b/Xl+G/15fhv9eX4b/Xl+G/15fhv9eX4b/Xl+G/15fhv9eX4b/Xl6H/11ci/9eX43/YGOR/2Rl - mP9saaL/bWeh3nhyoMurqMeF1NPpBr++2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0dLQANHS0BzV1tMJp6KxX6Gcr/Fva5L/KSVi/yId - a/8dGXP/Gxl2/xkZcv8aGnD/HRlw/x4Ycf8bGXH/Ghlx/xoZcf8aGXH/Ghlx/xoZcf8aGXH/Ghlx/xkZ - cf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZcv8aGHP/Ghhz/xoYc/8aGHL/Ghhy/xoY - cv8aGHL/Gxhy/xsYc/8cGHP/HBhz/xwYc/8cGHL/HBhy/xwYcv8cGHL/Ghhy/xkYc/8ZGHP/GRhz/xkY - c/8ZGHL/GRhy/xkYcv8ZGHL/GRlx/xkZcf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZ - cf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZ - cf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZ - cf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZcf8ZGXH/GRlx/xkZcf8ZGXH/GBly/yIZbP+KIDb/9iUD//8m - AP//JgD//yUA/+AlDf9cHk7/Ghly/xsYc/8cGHP/HBhz/xwYc/8cGHP/HBhz/xwYc/8cGHP/Gxlx/xoZ - cf8aGXH/Ghlx/xoZcf8aGXH/Ghly/xsZc/8aGXP/FhZg/xISR/8KCyH/BAUO/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8DAwr/CQob/xARQP8VFVn/GRlx/xkZc/8ZGHH/GBhx/xkY - cf8YGHH/GBhw/xgYcP8YGHD/GBhw/xgYcP8ZF3D/GRdw/xkXcP8ZF3D/GRdw/xkXcP8ZF3D/Ghhw/xgY - cP8vGmT/qyIm//0lAP//JQD/tiMh/zUbYv8aGXH/Gxhw/xsXcP8bF3D/Gxdw/xsXcP8bF3D/Gxdw/xsX - cP8bF3D/Gxhv/xsYb/8bGG//Gxhv/xoXbv8aF27/Ghdu/xoXbv8aF27/Ghdu/xoXbv8aF27/Ghdu/xsY - b/8bGG//Gxhv/xsYb/8bGG//Gxhv/xsYb/8bGG//Gxhv/xsYb/8bGG//Gxhv/xoXbv8YFmv/Fxlo/xcb - aP8WGm3/GRdz/x0Yb/8wLW3/kZC5wc3Q5SzExOEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAop+oAJ6apgC5tsEAo56uYJ+YrfF0a4n/Jh1X/xgO - Yf8hF33/GBCF/xUQif8VEYj/FxOF/xoTg/8bEoT/FxKG/xcShv8XEob/FxKG/xcShv8XEob/FxKG/xcS - hv8WEob/FBKF/xQShf8UEoX/FBKG/xUShv8VEob/FRKG/xUShv8WEYf/FxGI/xcRiP8XEYj/FhGH/xYQ - h/8WEYf/FhCH/xcRh/8YEYj/GRGI/xkRiP8ZEYj/GBCH/xgQh/8YEIf/GBCH/xYRh/8VEYj/FRGI/xUR - iP8UEYj/FBGH/xQRh/8UEYf/FBGH/xQRhv8UEoX/FBKF/xQShf8UEob/FRKG/xUShv8VEob/FBKG/xQS - hf8UEoX/FBKF/xQShf8UEoX/FBKF/xQShf8UEoX/FBKG/xUShv8VEob/FRKG/xQShv8UEoX/FBKF/xQS - hf8UEoX/FBKF/xQShf8UEoX/FBKF/xQShf8UEoX/FBKF/xQShf8UEoX/FBKF/xQShf8UEoX/FBKF/xQS - hf8UEoX/FBKF/xQShf8UEoX/FBKF/xQShf8UEoX/FBKG/xUShv8VEob/FBKG/xYShf96Gkv/+CUE//8m - AP//JgD//yYA//8mAP//JgD/3yMR/1oXX/8YEYj/GBGI/xkRiP8ZEYj/GRGI/xkRiP8ZEYj/GRGI/xcS - h/8XEob/FxKG/xcShv8XEob/FxKI/xYSg/8TD27/CwlB/wMCE/8AAAH/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEK/wcGM/8PDWj/EhCA/xMR - hv8TEIX/ExCE/xMRhP8TEYT/ExGE/xQRhP8UEYT/FRCE/xUQhP8VEIT/FRCE/xUQhP8VEIT/FRCE/xQQ - hf8rEnf/qh0v//4mAf//JgD//yYA//8mAP+0Hyn/MRNz/xYQhP8XEIX/FxCE/xcQhP8XEIT/FxCE/xcQ - hP8XEIT/FxCE/xcQg/8XEYP/FxGD/xcRg/8WEIL/FQ+B/xUPgf8VD4H/FQ+B/xUPgf8VD4H/FQ+B/xYP - gv8XEIP/FxGD/xcRg/8XEYP/FxGD/xcRg/8XEYP/FxGD/xcRg/8XEYP/FxGD/xcRg/8YEYL/GBJ//xYV - ef8TF3b/ExZ7/xQSgf8XEnr/KSVx/4+Qu8TKzt9LxcjiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAA1M/RANTP0QDUz9EA////AKOhqQCSlbAAop6qYp6Yq/F1a4n/LyNJ/xwS - SP8cE17/HhV0/xkSgf8TEIT/FROE/xcUgP8bFH//HBSA/xgTgf8XFIL/FxSC/xcUgv8XFIL/FxSC/xcU - gv8XFIL/FhSC/xUUgv8VFIL/FRSC/xUUgv8UFIL/FBSC/xQUgv8UFIL/FhOD/xcShP8XEoT/FxKE/xcT - hP8YE4T/GBOE/xgThP8YE4T/GBKE/xkShP8ZEoT/GRKE/xkThP8ZE4T/GROE/xkThP8XE4T/FBOE/xQT - hP8UE4T/FBOE/xUUhP8VFIT/FRSE/xUUhP8VFIP/FRSC/xUUgv8VFIL/FBSC/xQUgv8UFIL/FBSC/xQU - gv8VFIL/FRSC/xUUgv8VFIL/FRSC/xUUgv8VFIL/FRSC/xQUgv8UFIL/FBSC/xQUgv8UFIL/FRSC/xUU - gv8VFIL/FRSC/xUUgv8VFIL/FRSC/xUUgv8VFIL/FRSC/xUUgv8VFIL/FRSC/xUUgv8VFIL/FRSC/xUU - gv8VFIL/FRSC/xUUgv8VFIL/FRSC/xUUgv8VFIL/FRSC/xQUgv8UFIL/FBSC/xQUgv8VFIH/XRpY/+Qk - Dv//JgD//yYA//8mAP//JgD//yYA//8mAP/gIxL/XBde/xgShP8YEoT/GRKE/xkShP8ZEoT/GRKE/xkS - hP8YE4P/FxOC/xcTgv8XFIP/FxOA/xIPZ/8JBzT/AgIM/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEI/wYF - LP8NDFz/EhF9/xMSgf8TE4H/ExOB/xMTgf8UE4H/FhOB/xcTgf8XE4H/FxOB/xYTgf8WEoH/FhKB/xQS - gv8sFHX/qh4w//4mAf//JgD//yYA//8mAP//JgD//yYA/7AeK/8oFHf/FxOC/xgTgf8YE4H/GBOB/xgT - gf8YE4H/GBOB/xgTgf8YE4D/GBOA/xgTgP8YE4D/FxJ//xYRfv8WEX7/FhF+/xYRfv8WEX7/FhF+/xYR - fv8XEn7/GBOA/xgTgP8YE4D/GBOA/xgTgP8YE4D/GBOA/xgTgP8YE4D/GBOA/xgTgP8YE4D/GROB/xkR - gv8XE33/ExV5/xITff8UEIP/GRF9/ykkb/+Zmr3yyMzYXMTH2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAANTP0QDUz9EB1M/RDv///wCMdqIAoaCoYp2aqfFxa4f/LSJN/x8S - R/8dEU3/GxNb/x4Zc/8WFH3/FRSD/xcUgP8ZFX3/GhV+/xkVfv8ZFn//GRZ//xkWf/8ZFn//GRZ//xkW - f/8ZFn//GRZ//xgWf/8XFoD/FxaA/xcWgP8XFoD/FxaA/xcWgP8XFoD/FxaA/xgVgf8ZFYL/GRWC/xkV - gv8ZFYL/GRWB/xkVgf8ZFYH/GRWB/xkVgv8aFYL/GRWC/xkVgv8ZFYH/GRWB/xkVgf8ZFYH/GBWC/xcV - gv8XFYL/FxWC/xcVgv8XFYH/FxWB/xcVgf8XFYH/FxaB/xcWgP8XFoD/FxaA/xcWgf8XFoH/FxaB/xcW - gf8XFoH/FxaA/xcWgP8XFoD/FxaA/xcWgP8XFoD/FxaA/xcWgP8XFoH/FxaB/xcWgf8XFoH/FxaB/xcW - gP8XFoD/FxaA/xcWgP8XFoD/FxaA/xcWgP8XFoD/FxaA/xcWgP8XFoD/FxaA/xcWgP8XFoD/FxaA/xcW - gP8XFoD/FxaA/xcWgP8XFoD/FxaA/xcWgP8XFoD/FxaA/xcWgP8XFoD/FxaB/xcWgf8XFoH/FxaB/xgW - gP9gGlj/5CQP//8mAP//JgD//yYA//8mAP//JgD//yYA/+AjEf9cGlv/GRWC/xkVgv8ZFYL/GRWC/xkV - gv8ZFYL/GRWB/xkWgf8ZFoH/FhNw/wsKOf8CAgz/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AQEG/wcHLf8QEGL/FBR7/xUVfv8VFH3/FRR9/xYUfP8XFXz/FxV8/xcVfP8XFX3/FxV9/xYV - fv8sF3L/qSAt//4mAP//JgD//yYA//8mAP//JgD//yYA//0mAf+hHzL/JBV1/xYTff8XFHz/FxR8/xcU - ff8XFH3/FxR9/xcUff8XFH3/FxV7/xcVe/8XFXv/FxV7/xcUev8WFHr/FhR6/xYUev8WFHr/FhN6/xYT - ev8WE3r/FhR6/xcUe/8XFHv/FxR7/xcUe/8XFHv/FxR7/xcUe/8XFHv/FxR7/xcUe/8XFHv/FxR7/xcT - fP8VEX7/FhF+/xcTff8XFH3/FxOC/xkSf/8qI3P/nJu99czO1lHGx9cAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADUz9EA1M/RBdTP0TX///8Bo6CpYp6cqPFvbIP/KyNK/xoQ - Rf8bEE//Gw1T/xoQX/8aGHf/FBWB/xMShP8XE4H/GROA/xYSgf8UE4P/GBWC/xgVgv8YFYL/GBWC/xgV - gv8YFYL/GBWC/xgVgv8YFYL/GBWD/xgVg/8YFYP/GBWD/xgVg/8YFYP/GBWD/xgVg/8YFIT/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSE/2EaW//kJA///yYA//8mAP//JgD//yYA//8mAP//JgD/4CMS/1oZXv8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUh/8WE3z/DgxM/wMDEv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AgIK/woJO/8UEXL/FhOB/xYTgP8WFH7/FhR+/xYUfv8WFH7/FhR+/xQU - f/8rFnL/qB8u//4mAP//JgD//yYA//8mAP//JgD//yYA//0mAf+iHzL/JxV0/xQTf/8VEn//FRJ//xUS - f/8VEn//FhOA/xYTgP8WE4D/FhR//xYUff8WFX3/FhV9/xYVff8VFHz/FRR8/xUUfP8VFHz/FRR8/xUT - ff8VE33/FRN9/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUT - ff8VE33/FBN9/xcRgf8ZEX//FxR6/xUTfv8VD3//KSJ5/5mWvevS0t8ixcXXAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtrW5ALSyuACvrbYApKCrYqCbq/JybIb/LSRK/x4T - Rf8fE03/HRFQ/xoMUf8aEGD/Ghh3/xMVgf8TEoT/FxKB/xkTgP8WEoL/FBOD/xgVgv8YFYL/GBWC/xgV - gv8YFYL/GBWC/xgVgv8YFYL/GBWC/xgVg/8YFYP/GBWD/xgVg/8YFYP/GBWD/xgVg/8YFYP/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/YRpb/+UkD///JgD//yYA//8mAP//JgD//yYA//8mAP/gIxL/Whlf/xgU - hf8YFIX/GBSF/xgUhf8TEGr/BwYp/wAAAv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/BAQY/xAOX/8WE3//FhR//xYUfv8WFH7/FhR+/xQU - f/8rFXL/qB8u//4mAP//JgD//yYA//8mAP//JgD//yYA//0mAf+iHzH/JxV1/xQUf/8VE3//FRJ//xUS - f/8VEn//FRJ//xYTgP8WE4D/FhOA/xYTgP8WFH7/FhV9/xYVff8WFX3/FRR9/xUUfP8VFHz/FRR8/xUT - ff8VE33/FRN9/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUT - ff8VE33/FRN9/xMTff8XEYH/GRF//xcUev8VE37/FQ9//ykief+Zlr3r0dLeJMXF1wAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKKfrgCgma0Ap6auX6KerfJza4j/LCFM/x0P - Rv8hEk7/HhFQ/x8RUf8bDVH/GhBg/xoYd/8TFYH/ExKE/xcSgf8ZEoD/FhKC/xQTg/8YFYP/GBWC/xgV - gv8YFYL/GBWC/xgVgv8YFYL/GBWC/xgVg/8YFYP/GBWD/xgVg/8YFYP/GBWD/xgVg/8YFYP/GBWD/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf9hGlv/5SQP//8mAP//JgD//yYA//8mAP//JgD//yYA/+Aj - Ev9bGV7/GBSG/xcUhf8PDFL/AgIN/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB/wEBAf8BAQH/AgIC/wIC - Av8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8CAgL/AgIC/wEBAf8BAQH/AQEB/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8CAgv/Cgg5/xUTev8WFID/FhR//xQU - gP8rFXP/qR8u//4mAP//JgD//yYA//8mAP//JgD//yYA//wmAf+iHjL/JxV1/xQUgP8WFH//FRN//xUS - f/8VEn//FRJ//xUSf/8WE4D/FhOA/xYTgP8WE4D/FhR+/xYUfv8WFH7/FhR+/xUTff8VE33/FRN9/xUT - ff8VE33/FRN9/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUT - ff8VE33/FRN9/xUTff8UE33/FxGB/xkRf/8XFHr/FRN+/xUPf/8pInn/mZa969LS4CLFxdcAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmpK8AqqixE6KgrXx0bob/LCJL/x4P - Sf8hEFP/Hg1S/x4PUv8fEVD/HA5S/xoRYP8aGHf/FBWC/xMThP8XE4L/GROB/xcTgv8UE4T/GBWE/xgV - g/8YFYP/GBWD/xgVg/8YFYP/GBWD/xgVg/8YFYP/GBWD/xgVg/8YFYP/GBWD/xgVg/8YFYP/GBWD/xgV - g/8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIb/GBSF/2EaW//kJBD//yYA//8mAP//JgD//yYA//8m - AP//JgD/4SMS/1oXUv8KCTz/AQEG/wAAAP8AAAD/AQEB/wICAv8DAwP/BAQE/wUFBf8GBgb/BwcH/wgI - CP8ICAj/CQkJ/wkJCf8JCQn/CQkJ/wkJCf8JCQn/CAgI/wgICP8HBwf/BgYG/wUFBf8EBAT/AgIC/wIC - Av8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8IBy//EhBq/xQT - g/8sFXT/qh8u//4mAf//JgD//yYA//8mAP//JgD//yYA//wmAv+hHzT/JxR3/xQTgf8WE4D/FhOA/xYT - gP8VEn//FRJ//xUSf/8VEn//FhOA/xYTgP8WE4D/FhOA/xYUf/8WFH7/FhR+/xYUfv8WE37/FRN+/xUT - fv8VE37/FRN+/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUTff8VE33/FRN9/xUT - ff8VE33/FRN9/xUTff8VE33/FBN9/xcRgf8ZEX//FxR6/xUTfv8VD3//KSF5/5qXvfLNztZAxcXVAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGfJoAko2jAJ6brC1gXHa5LSVK/x4R - Rv8hEFL/IA1W/yANVv8eD1L/HhFP/xwOUv8bEmH/Gxl4/xUWg/8UFIX/GRSD/xsUgv8YFIT/FRSG/xgU - hP8YFYP/GBWD/xgVg/8YFYP/GBWD/xgVg/8YFYP/GBWD/xgVg/8YFYP/GBWD/xgVg/8YFYP/GBWD/xgV - g/8YFYP/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/YBpc/+MkEP//JgD//yYA//8m - AP//JgD//yYA//8mAP/eIQH/TAsA/wAAAP8BAgL/AwMD/wUFBf8HBwf/CAgI/woKCv8LCwv/DAwM/w0N - Df8ODg7/Dg4O/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w4ODv8ODg7/DQ0N/wwMDP8LCwv/CgoK/wgI - CP8HBwf/BQUF/wMDA/8CAgL/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wEC - Ev8nEVX/rCAv//4mAP//JgD//yYA//8mAP//JgD//yYA//wmAv+hHzX/KBZ5/xUTgv8WE4H/FhOB/xYT - gf8WE4D/FhOA/xYTgP8WE4D/FhOA/xYTgP8WE4D/FhOA/xYTgP8WE4D/FhOA/xYTgP8WE4D/FhOA/xYT - gP8WE4D/FhOA/xYTf/8WFH7/FhR+/xYUfv8WFH7/FhR+/xYUfv8WFH7/FhR+/xYUfv8WFH7/FhR+/xYU - fv8WFH7/FhR+/xYUfv8WFH7/FhR+/xQTff8XEYH/GRF//xcUev8WFH7/FhCA/yghef+cmr3/ysvPlcTF - 0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMvF2ADSzd4AsajCAJ+WshJiWnykKyNL/x0T - RP8gEk3/IA9T/x8NVf8eDlX/Hg9S/x4RT/8cDlL/GxJh/xsZeP8VFoP/FBSF/xkUg/8bFYL/GBSE/xUU - hv8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhP8YFYP/GBWD/xgVg/8YFYP/GBWD/xgV - g/8YFYP/GBWD/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv9gGlz/4yQQ//8m - AP//JgD//yYA//8mAP//JgD//yYA/98hAP9PDgP/BwcH/wkKCv8LCwv/DQ0N/w4ODv8QEBD/ERER/xIS - Ev8TExP/FBQU/xQUFP8VFRX/FRUV/xYWFv8WFhb/FRUV/xUVFf8UFBT/FBQU/xMTE/8SEhL/ERER/xAQ - EP8PDw//DQ0N/wsLC/8KCgr/CAgI/wUFBf8DAwP/AgIC/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8YAwD/pBgD//4mAf//JgD//yYA//8mAP//JgD//yYA//wmAv+gHzb/KBZ6/xYVhP8WE4H/FhOB/xYT - gf8WE4H/FhOA/xYTgP8WE4D/FhOA/xYTgP8WE4D/FhOA/xYTgP8WE4D/FhOA/xYTgP8WE4D/FhOA/xYT - gP8WE4D/FhOA/xYTgP8WE3//FhR+/xYUfv8WFH7/FhR+/xYUfv8WFH7/FhR+/xYUfv8WFH7/FhR+/xYU - fv8WFH7/FhR+/xYUfv8WFH7/FhR+/xYUfv8UE33/FxGB/xkRf/8XFHr/FhR+/xYQgP8oIXn/nJq9/8rL - z5fExdIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADLxdgA0MvcDsK60mtyZ4ezMCVP/xwR - SP8fE03/HxFQ/x8RUv8fEFL/HhBR/yAQUf8gEU//HQ5S/xsSYf8bGXj/FRaD/xUUhf8ZFIP/GxWC/xgU - hP8VFIb/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIT/GBWD/xgVg/8YFYP/GBWD/xgV - g/8YFYP/GBWD/xgVg/8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/2Aa - Xf/jJBD//yYA//8mAP//JgD//yYA//8mAP//JgD/3yIB/1QUCf8PDw//ERER/xMSEv8UFBT/FhYW/xcX - F/8YGBj/GRkZ/xoaGv8aGhr/Gxsb/xsbG/8cHBz/HBwc/xsbG/8bGxv/Gxsb/xoaGv8ZGRn/GBgY/xcX - F/8WFhb/FBQU/xMTE/8RERH/EBAQ/w4ODv8LCwv/CQkJ/wcHB/8EBAT/AgIC/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8YAwD/oxgA//4mAP//JgD//yYA//8mAP//JgD//yYA//wmAv+gHzb/KBZ6/xcVhP8YFYP/FhOB/xYT - gf8WE4H/FhOB/xYTgP8WE4D/FhOA/xYTgP8WE4D/FhOA/xYTgP8WE4D/FhOA/xYTgf8WE4H/FhOB/xYT - gf8WE4H/FhOB/xYTgf8WE4H/FhOA/xYUfv8WFH7/FhR+/xYUfv8WFH7/FhR+/xYUfv8WFH7/FhR+/xYU - fv8WFH7/FhR+/xYUfv8WFH7/FhR+/xYUfv8WFH7/FBN9/xcRgf8ZEX//FxR6/xYUfv8WEID/KCF5/5ya - vf/Ky8+YxMXSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAysPYANvV5hOmnbjDQjdc/x0Q - RP8dEVH/HRFR/x8RUf8eEVD/HhFP/x4RT/8gEU//IBFQ/x0OUv8bEmH/Gxh4/xUWg/8UFIX/GRWD/xsV - g/8YFIT/FRSG/xgThv8YE4b/GBOG/xgThv8YE4b/GBOG/xgThv8YE4b/GBSF/xgVg/8YFYP/GBWD/xgV - g/8YFYP/GBWD/xgVg/8YFYP/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/YBpd/+MkDv//JgD//yYA//8mAP//JgD//yYA//8mAP/gIwL/WRkO/xcXF/8YGBj/Ghoa/xsb - G/8dHR3/Hh4e/x8fH/8gICD/ICAg/yEhIf8hISH/ISEh/yEhIf8hISH/ISEh/yAgIP8gICD/Hx8f/x4e - Hv8dHR3/HBwc/xoaGv8ZGRn/FxcX/xUVFf8TExP/ERER/w8PD/8MDAz/CgoK/wcHB/8EBAT/AgIC/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8YAwD/ohgA//4mAP//JgD//yYA//8mAP//JgD//yYA//wmAf+hHzb/KBV7/xYUhv8YFIX/GBSF/xYT - g/8WEoP/FhKD/xYSg/8WE4H/FhOA/xYTgP8WE4D/FhOA/xYTgP8WE4D/FhOA/xYTgf8WE4H/FhOB/xYT - gf8WE4H/FhOB/xYTgf8WE4H/FhOB/xYTgf8WFH//FhR//xYUf/8WFH//FhR//xYUf/8WFH//FhR//xYU - fv8WFH7/FhR+/xYUfv8WFH7/FhR+/xYUfv8WFH7/FhR+/xQTff8WEYH/GBF//xcUe/8VFH//FhCB/ygh - ef+cmr3/ysvPj8TF0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMbE0gDQztolo5627DMp - V/8dD03/HhBS/x4QUv8eEFH/HxFS/x4QUf8eEFH/HhBR/x4QUf8dD1T/HBJj/xwaev8VF4T/FRWG/xkV - hf8bFYP/GBWE/xYUh/8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWF/xkV - hf8ZFYX/GRWF/xkVhf8ZFYX/GRWF/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GBWG/xcV - hv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcV - hv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xkW - h/8ZF4j/GReI/xkXiP8ZFoj/GRaJ/xkWif8ZFon/GRaJ/xkWif8ZFon/GRaJ/xkWif8ZFon/GRaJ/xkW - if8ZFon/GRaJ/xkWif8ZFon/GRaJ/xkWif8ZFon/GRaJ/xkWif8ZFon/GRaJ/xkWif8ZFon/GRaJ/xgV - h/8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcV - hv8XFYb/GBWI/xYTdf9WEhn/4iIA//8mAP//JgD//yYA//8mAP//JgD//yYA/+EkA/9fHxP/Hh4e/x8g - IP8hISH/IyMj/yQkJP8lJSX/JiYm/yYmJv8nJyf/Jycn/ygoKP8oKCj/Jycn/ycnJ/8nJyf/JiYm/yUl - Jf8kJCT/IyMj/yIiIv8gICD/Hx8f/x0dHf8bGxv/GRkZ/xcXF/8UFBT/EhIS/w8PD/8NDQ3/CgoK/wcH - B/8EBAT/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8YAwD/ohgA//4mAP//JgD//yYA//8mAP//JgD//yYA//wmAv+iHzb/KRZ8/xYUhv8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSE/xgUhP8YFIT/GBSE/xgUhP8YFIT/GBSE/xgUhP8YFIT/GBSE/xgU - hP8YFIT/GBSE/xgUhP8YFIT/GBSE/xgUhP8YFIT/GBSD/xgUg/8YFIP/FxSD/xYTgv8WE4L/FhOC/xYT - gf8WE4D/FhOA/xYTgP8WE4D/FhOA/xYTgP8WE4D/FhOA/xUUf/8UFH//FhGD/xkSgf8XFXz/FRWB/xYR - gv8pInv/m5m/+cvN02LFxdUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADExc8AztDXJKOg - tuszKVv/HQ9R/x4QUv8eEFL/HhBS/x4QUv8eEFL/HhBS/x4QUv8eEFL/HA5V/xwSZP8cGnr/FRiE/xUW - h/8YFYX/GxWE/xgVhf8WFYf/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcV - hv8XFYb/FxWG/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcU - h/8ZFoj/GRaJ/xkWif8ZFon/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8YFYj/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFYb/FxWG/xcVhv8XFYb/FxWG/xcV - hv8XFYb/FxWH/xYTd/8MCyj/CgoJ/1gVCf/iIwL//yYA//8mAP//JgD//yYA//8mAP//JgD/4iUE/2Uk - Gf8lJSX/Jicn/ygoKP8pKSn/Kysr/ysrK/8sLCz/LS0t/y0tLf8tLS3/Li4u/y0tLf8tLS3/LCws/yws - LP8rKyv/Kioq/ykpKf8oKCj/JiYm/yUlJf8jIyP/ISEh/x8fH/8cHBz/Ghoa/xgYGP8VFRX/EhIS/w8P - D/8MDAz/CQkJ/wYGBv8DAwP/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8YBAD/pBgA//4mAP//JgD//yYA//8mAP//JgD//yYA//wlAP+YFwb/JBJh/xcViP8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8WEoP/FhKD/xYS - g/8WEoP/FhOB/xYTgP8WE4D/FhOA/xYTgP8WE4D/FhOA/xYTgP8VFID/FBSA/xcRhP8ZEoL/FxV9/xUW - gf8WEYL/KCJ7/52bwP/KzdGXxMbVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMXPAM7Q - 1ySjoLbrMylb/x0PUf8eEFL/HhBS/x4QUv8eEFL/HhBS/x4QUv8eEFL/HhBS/xwOVf8cEmT/HBp6/xUX - hf8VFYf/GBWG/xsVhP8YFYb/FhSH/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcVhv8XFYb/FxWG/xcV - hv8XFYb/FxWG/xcVhv8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcU - h/8XFIf/GRaJ/xkWif8ZFon/GRaJ/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GBWI/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxWG/xcVhv8XFYb/FxWG/xcV - hv8XFYb/FxWG/xcVhf8PDj7/DAwK/w8QEP8SExP/XRsP/+MkA///JgD//yYA//8mAP//JgD//yYA//8m - AP/kJgX/aykd/ywtLf8uLi7/Ly8v/zAwMP8xMTH/MjIy/zMzM/8zMzP/NDQ0/zQ0NP80NDT/MzMz/zMz - M/8yMjL/MTEx/zAwMP8vLy//Li4u/ywsLP8qKir/KSkp/ycnJ/8lJSX/IiIi/yAgIP8dHR3/Gxsb/xgY - GP8VFRX/EhIS/w8PD/8LCwv/CAgI/wQEBP8CAgL/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8ZBAD/pRgA//4mAP//JgD//yYA//8mAP//JgD//yYA//wlAP+WFgD/EgIA/wYGK/8XFH//GBSG/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/FhKD/xYS - g/8WEoP/FhKD/xYTgf8WE4D/FhOA/xYTgP8WE4D/FhOA/xYTgP8WE4D/FRSA/xQUgP8XEYT/GRKC/xcV - ff8VFoH/FRGC/ygie/+dm8D/ys3Rl8TG1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTF - zwDO0Ncko6C26zMpW/8dD1H/HhBS/x4QUv8eEFL/HhBS/x4QUv8eEFL/HhBS/x4QUv8cDlX/HBJk/xwZ - fP8VF4X/FRWI/xgUh/8bFYb/GBWG/xYUiP8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkU - h/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkU - h/8ZFIf/GRSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcU - h/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcU - h/8XFIf/FxSH/xkWif8ZFon/GRaJ/xkWif8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xgViP8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcUh/8XFIf/FxSH/xcU - h/8XFIf/FxSH/xcUhv8TEVb/Dg4U/xEREf8UFBT/FxgY/xsbG/9iIBX/4yUE//8mAP//JgD//yYA//8m - AP//JgD//yYA/+UnBf9wLiL/MzQ0/zU1Nf82Njb/Nzc3/zg4OP85OTn/OTk5/zk5Of86Ojr/OTk5/zk5 - Of85OTn/ODg4/zc3N/82Njb/NTU1/zQ0NP8yMjL/MDAw/y4uLv8sLCz/Kioq/ygoKP8lJSX/IyMj/yAg - IP8dHR3/Ghoa/xcXF/8UFBT/EBAQ/w0NDf8KCgr/BgYG/wMDA/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8ZBAD/phgA//4mAP//JgD//yYA//8mAP//JgD//yYA//wlAP+VFgD/EQIA/wAAAP8AAAD/Cgg3/xcT - gP8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xYS - g/8WEoP/FhKD/xYSg/8WE4L/FhOB/xYTgf8WE4H/FhOB/xYTgf8WE4H/FhOB/xUUgP8UFID/FxGD/xkS - gv8XFX3/FRaB/xURgv8oInv/nZvA/8rN0ZfExtUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADExc8AztDXJKOgtuszKVv/HRBR/x8RU/8fEVP/HxFT/x8RU/8eEFL/HhBS/x4QUv8eEFL/HA5W/xwS - Zf8cGXz/FRaG/xUUiP8YFIf/GxWG/xgUh/8WFIj/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkU - h/8aFYj/GhWI/xoViP8aFYj/GhWI/xoViP8aFYj/GhWI/xoViP8aFYj/GhWI/xoViP8aFYj/GhWI/xoV - iP8aFYj/GhWI/xoViP8YFYj/GBWI/xgViP8YFYj/GBWI/xgViP8YFYj/GBWI/xgViP8YFYj/GBWI/xgV - iP8YFYj/GBWI/xgViP8YFYj/GBWI/xgVif8YFYn/GBWJ/xgVif8YFYn/GBWJ/xgVif8YFYn/GBWJ/xgV - if8YFYn/GBWJ/xgVif8ZFon/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8YFYn/GBWJ/xgVif8YFYn/GBWJ/xgVif8YFYn/GBWJ/xgVif8YFYj/GBWI/xgV - iP8YFYj/GBWI/xgViv8WE3D/EA8a/xISEf8WFhb/Ghoa/x0dHf8gICD/IyMj/2cmGv/jJgX//yYA//8m - AP//JgD//yYA//8mAP//JgD/5igG/3UzJ/87Ozv/PDw8/z09Pf8+Pj7/Pz8//z8/P/9AQED/QEBA/0BA - QP8/Pz//Pz8//z4+Pv89PT3/PDw8/zs7O/86Ojr/ODg4/zc3N/81NTX/MjIy/zAwMP8uLi7/Kysr/ykp - Kf8mJib/IyMj/yAgIP8dHR3/GRkZ/xYWFv8SEhL/Dw8P/wsLC/8HBwf/AwMD/wEBAf8AAAD/AAAA/wAA - AP8ZBAD/pRgA//4mAP//JgD//yYA//8mAP//JgD//yYA//wlAP+UFgD/EQIA/wAAAP8AAAD/AAAA/wEB - BP8QDln/GRWI/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GBSF/xgUhf8YFIX/GBSF/xgU - hf8XE4T/FxOE/xcThP8XE4T/FxSD/xcUgv8XFIL/FxSC/xcUgv8XFIL/FxSC/xcUgv8WFYL/FRWB/xgT - hf8aE4P/GBZ+/xUVgf8WEYP/KSN8/52bwP/JzNCXxMbUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAxMXPAM7Q1ySjoLbrMylb/x4QUf8gElT/IBJU/yASVP8gElT/HhBS/x4QUv8eEFL/HhBS/xwO - Vv8cEWb/HBl9/xUWhv8VFIn/GBSI/xsUh/8YFIj/FhOJ/xkTiP8ZFIf/GROI/xkTiP8ZE4j/GROI/xkT - iP8ZE4f/GhSI/xsWiv8bFor/GxaK/xsWiv8bFor/GxaK/xsWiv8bFor/GxaK/xsWiv8bFor/GxaK/xsW - iv8bFor/GxaK/xsWiv8bFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFov/GRaL/xkWi/8ZFov/GRaL/xkWi/8ZFov/GRaL/xkW - i/8ZFov/GRaL/xkWi/8ZFov/GRaL/xkVi/8ZFYv/GRWL/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaL/xkWi/8ZFov/GRaL/xkWi/8ZFov/GRaL/xkWi/8ZFov/GRaK/xkW - iv8ZFor/GRaK/xkWiv8YFoD/ExIz/xMTE/8XFxf/Gxsb/x4eHv8hISH/JSUl/ycoKP8rKyv/bCsg/+Un - Bv//JgD//yYA//8mAP//JgD//yYA//8mAP/nKQf/ejgs/0JCQv9DQ0P/RERE/0VFRf9FRUX/RkZG/0ZG - Rv9GRkb/RUVF/0VFRf9ERET/Q0ND/0JCQv9BQUH/Pz8//z4+Pv88PDz/Ojo6/zg4OP82Njb/MzMz/zEx - Mf8uLi7/Kysr/ygoKP8lJSX/IiIi/x4eHv8bGxv/GBgY/xQUFP8QEBD/DAwM/wgICP8EBAT/AQEB/wAA - AP8ZBAD/pRgA//4mAP//JgD//yYA//8mAP//JgD//yYA//wlAP+VFgD/EQIA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/BAMU/xQRbv8ZFYj/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8YFIX/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhP8YFYT/GBWE/xgVhP8YFYT/GBWE/xgVhP8YFYT/FxWD/xYW - gv8ZE4b/GxSE/xkXf/8VFYH/FhGD/ykjff+cm8D/yMvQl8PF1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMTFzwDO0Ncko6C26zMpW/8eEFH/IBJU/yASVP8gElT/IBJU/x4QUv8eEFL/HhBS/x4Q - Uv8cDlf/HBFm/xwZff8VFof/FRSJ/xgUiP8bFIf/GBSI/xYTiv8ZE4j/GROI/xkTiP8ZE4j/GROI/xkT - iP8ZE4j/GROI/xoUif8bFYr/GxWK/xsViv8bFYr/GxWK/xsViv8bFYr/GxWK/xsViv8bFYr/GxWK/xsV - iv8bFYr/GxWK/xsViv8bFYr/GxWK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkV - jP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFov/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkVi/8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkW - iv8ZFor/GRaK/xkWiv8ZFor/FhRV/xQUFf8YGBj/HBwc/x8fH/8jIyP/Jycn/ykpKf8tLS3/MDAw/zMz - M/9zMSb/5igH//8mAP//JgD//yYA//8mAP//JgD//yYA/+cqCP9+PTL/SUlJ/0pKSv9LS0v/S0tL/0xM - TP9MTEz/TExM/0tLS/9LS0v/SkpK/0lJSf9ISEj/R0dH/0VFRf9ERET/QkJC/0BAQP8+Pj7/PDw8/zk5 - Of82Njb/NDQ0/zAwMP8uLi7/Kioq/ycnJ/8kJCT/ICAg/xwcHP8ZGRn/FRUV/xEREf8NDQ3/CQkJ/wME - Bf8aBQH/pBgA//4mAP//JgD//yYA//8mAP//JgD//yYA//wlAP+WFgD/EQIA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8KCTj/GBWD/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GBSF/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xcV - hP8WFoL/GROF/xsUhP8ZF3//FRWB/xYRg/8pI33/nJvA/8jL0JfDxdQAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADExc8AztDXJKOgtuszKVv/HhBR/yASVP8gElT/IBJU/yASVP8eEFL/HhBS/x4Q - Uv8eEFL/HA5X/xwRZ/8cGH7/FRaI/xUUiv8YE4j/GhSH/xgTif8WE4r/GROJ/xkTiP8ZE4j/GROI/xkT - iP8ZE4j/GROI/xkTiP8aFIn/GxWK/xsViv8bFYr/GxWK/xsViv8bFYr/GxWK/xsViv8bFYr/GxWK/xsV - iv8bFYr/GxWK/xsViv8bFYr/GxWK/xsViv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkV - jP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRaL/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFYv/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkV - jP8ZFor/GRaK/xkWiv8ZFov/GBV1/xUVIP8YGBj/HBwc/yAgIP8kJCT/Jycn/ysrK/8uLi7/MjIy/zU1 - Nf83ODj/Ojs7/3g2K//oKQj//yYA//8mAP//JgD//yYA//8mAP//JgD/6CsJ/4RCNv9QUFD/UFFR/1FR - Uf9SUlL/UlJS/1JSUv9RUVH/UVFR/1BQUP9PT0//Tk5O/01NTf9LS0v/SkpK/0hISP9FRUX/Q0ND/0FB - Qf8+Pj7/PDw8/zk5Of82Njb/MzMz/zAwMP8sLCz/KSkp/yUlJf8hISH/HR0d/xoaGv8WFhb/EhIS/wsN - Df8hDAj/phoB//4mAP//JgD//yYA//8mAP//JgD//yYA//wlAP+WFgD/EQIA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AQEG/xEOXP8ZFYf/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xgU - hf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgU - hf8XFIT/FhaC/xkThf8bFIT/GRd//xUVgP8WEYP/KSN9/5ybwP/Iy9CXw8XUAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAxMXPAM7Q1ySjoLbrMylb/x4QUf8fElT/HxJU/x8SVP8fElT/HhFT/x4R - U/8eEVP/HhBT/xwOV/8cEmf/HBh+/xUWif8VE4z/GBOK/xoUiP8YFIn/FhSK/xgUiv8ZFIn/GRSJ/xkU - if8ZFIn/GRSJ/xkUif8ZFIn/GhSK/xoVi/8aFYv/GhWL/xoVi/8aFYv/GhWL/xoVi/8aFYv/GhWL/xoV - i/8aFYv/GhWL/xoVi/8aFYv/GhWL/xoVi/8ZFYv/GBaL/xgWi/8YFov/GBaL/xgWi/8YFov/GBaL/xgW - i/8ZFov/GRaL/xkWjP8ZFoz/GRaM/xkWjP8ZFoz/GRaL/xkWjP8ZFYz/GRaM/xkWjP8ZFoz/GRaM/xkW - jP8ZFoz/GRaM/xkWjP8ZFoz/GRaM/xkWjP8ZFoz/GRaM/xkWjP8ZFoz/GRaM/xkWi/8YFor/GBaK/xgW - iv8YFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GBaK/xgWiv8YFor/GRaK/xkW - iv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaL/xkWjP8ZFoz/GRaM/xkWjP8ZFoz/GRaM/xkW - jP8ZFYz/GRaM/xkWi/8ZFoz/GRaL/xcWRv8YGRf/HR0d/yEhIf8lJSX/KSkp/ywsLP8wMDD/MzMz/zc3 - N/86Ojr/PT09/0BAQP9CQ0P/fjwx/+gqCf//JgD//yYA//8mAP//JgD//yYA//8mAP/pKwr/iUY7/1dX - V/9XV1f/WFhY/1hYWP9YWFj/V1dX/1dXV/9WVlb/VVVV/1RUVP9TU1P/UVFR/1BQUP9OTk7/TExM/0lJ - Sf9HR0f/RERE/0FBQf8/Pz//PDw8/zk5Of81NTX/MTEx/y4uLv8qKir/JiYm/yMjI/8fHx//Gxoa/xQW - F/8qFBD/qh0F//4mAP//JgD//yYA//8mAP//JgD//yYA//slAP+VFgD/EQIA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8FBR7/FxN9/xkViP8ZFYf/GRWH/xkVh/8ZFYf/GBSH/xgU - h/8YFIf/GBSH/xgUh/8YFIf/GBSH/xgVh/8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhf8YFIX/GBSF/xgUhv8YFIb/GBSG/xgUhv8YFIb/GBSG/xgU - hv8YFIb/GBSF/xcWg/8ZE4b/GhSF/xgXgP8UFYP/FRGE/ykjff+dm8D/ycvQl8TF1AAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTFzwDO0Ncko6C26zMpW/8dEFH/HhJU/x4SVP8eElT/HhJU/x4S - VP8eElT/HhJU/x4SVP8cEFj/HBNo/xwZf/8XFoz/FRSP/xkVjf8bFYr/GBaK/xcWi/8ZFYz/GRWM/xkV - jP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xgV - jP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcV - jP8XFYz/GBaN/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaM/xgXi/8YF4v/GBeL/xgX - i/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8XFor/FxaK/xcW - iv8XFor/FxaK/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/FxaK/xcWiv8XFor/FxaK/xcW - iv8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgX - i/8YF4v/GBeM/xgWjv8YFo7/GBaP/xgWc/8ZGCL/HBwc/yEhIf8lJSX/KSkp/y0tLf8xMTH/NTU1/zg4 - OP87Ozv/Pz8//0JCQv9FRUX/SEhI/0pLS/+CQTb/6CsK//8mAP//JgD//yYA//8mAP//JgD//yUA/+ss - C/+OSz//XV1d/11eXv9eXl7/Xl5e/15eXv9dXV3/XFxc/1tbW/9aWlr/WVlZ/1dXV/9VVVX/U1NT/1FR - Uf9PT0//TExM/0pKSv9HR0f/RERE/0BAQP89PT3/Ojo6/zY2Nv8zMzP/Ly8v/ysrK/8nJyf/IyMj/x0f - H/8yHBj/ryAI//8mAP//JgD//yYA//8mAP//JgD//yYA//slAP+UFgD/EQIA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAC/w8NUv8ZFoz/GRaK/xkWiv8ZFor/GBWJ/xcU - iP8XFIj/FxSI/xcUiP8XFIj/FxSI/xcUiP8XFIf/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkWhf8XF4P/GRSH/xkUh/8WF4P/FBWH/xQSiP8pJH//npvA/8rL0JfFxdQAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADExc8AztDXJKOgtuszKVv/HRBR/x4SVP8eElT/HhJU/x4S - VP8eElT/HhJU/x4SVP8eElT/HBBY/xwTaP8cGX//FxaM/xUUj/8YFY3/GhWK/xgWiv8XFor/GRWM/xkV - jP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkV - jP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcV - jP8XFYz/FxWM/xgWjf8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjf8YF4v/GBeL/xgX - i/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/FxaL/xcW - iv8XFor/FxaK/xcWi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xcWi/8XFor/FxaK/xcW - iv8XFov/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgXi/8YF4v/GBeL/xgX - i/8YF4v/GBeL/xgXjP8YFo7/GBaO/xgWjf8ZGEb/HBwb/yAgIf8lJSX/KSkp/y0tLf8xMTH/NTU1/zk5 - Of89PT3/QEBA/0RERP9HR0f/SkpK/01NTf9QUFD/UlNT/4dHPP/pLQz//yUA//8mAP//JgD//yYA//8m - AP//JQD/7CwL/5NPRP9kZGT/ZGRk/2RkZP9kZGT/Y2Nj/2JiYv9hYWH/YGBg/19fX/9dXV3/W1tb/1lZ - Wf9XV1f/VVVV/1JSUv9PT0//TExM/0lJSf9GRkb/Q0ND/z8/P/88PDz/ODg4/zQ0NP8wMDD/LCws/yYo - KP86JCD/siMK//8mAP//JgD//yYA//8mAP//JgD//yYA//slAP+TFQD/EQIA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8FBR3/FxR//xkWi/8ZFor/GRaK/xgV - if8XFIj/FxSI/xcUiP8XFIj/FxSI/xcUiP8XFIj/FxSI/xkUh/8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFoX/FxeD/xkTh/8YFIf/FheE/xQVh/8UEon/KSSA/56bwP/Ky9CXxcXUAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMXPAM7Q1ySjoLbrMylb/x0QUf8eElT/HhJU/x4S - VP8eElT/HhJU/x4SVP8eElT/HhJU/xwQWP8cE2j/HBl//xcWjP8VFI//GBWN/xoViv8YFor/FxaK/xkV - jP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkV - jP8ZFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcV - jP8XFYz/FxWM/xcVjP8YFo3/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo3/GBaN/xgW - jf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xcV - jP8XFYz/FxWM/xcVjP8XFYz/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8XFYz/FxWM/xcV - jP8XFYz/FxWM/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgW - jf8YFo3/GBaN/xgWjf8YFo3/GBaO/xgWj/8YF3f/Gxsm/yAgH/8kJCT/KSkp/y0tLf8xMTH/NjY2/zk5 - Of89PT3/QUFB/0VFRf9ISEj/TExM/09PT/9SUlL/VVVV/1hYWP9bW1v/jE1C/+otDP//JQD//yYA//8m - AP//JgD//yYA//8lAP/tLgz/mFRI/2pqav9qamr/ampq/2lpaf9oaGj/Z2dn/2ZmZv9kZGT/Y2Nj/2Fh - Yf9fX1//XV1d/1paWv9YWFj/VVVV/1JSUv9PT0//S0tL/0hISP9ERET/QUFB/z09Pf85OTn/NTU1/y8x - Mf9CLCj/tSYN//8mAP//JgD//yYA//8mAP//JgD//yYA//slAP+UFwH/EQMA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAB/w8NUv8ZFoz/GRaK/xkW - iv8YFYn/FxSI/xcUiP8XFIj/FxSI/xcUiP8XFIj/FxSI/xcUiP8ZFIf/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkVhv8ZFYb/GRWG/xkV - hv8ZFYb/GRWG/xkVhv8ZFYb/GRaF/xcXhP8ZE4f/GBSH/xYXhP8UFYf/FBKI/ykkgP+em8D/ysvQl8XF - 1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTFzwDO0Ncko6C26zMpW/8dEFH/HhJU/x4S - VP8eElT/HhJU/x4SVP8eElT/HhJU/x4SVP8cEFj/HBNo/xwZf/8XFoz/FRSP/xgVjf8aFYr/GBaK/xcW - iv8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkV - jP8ZFYz/GRWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcV - jP8XFYz/FxWM/xcVjP8XFYz/GBaN/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaN/xgW - jf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgW - jf8XFY3/FxWM/xcVjP8XFYz/FxWM/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/FxWN/xcV - jP8XFYz/FxWM/xcVjP8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgW - jf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjv8YFo3/GhlN/x8fHf8kJCT/KCgo/y0tLf8xMTH/NTU1/zo6 - Ov8+Pj7/QkJC/0VFRf9JSUn/TU1N/1BQUP9UVFT/V1dX/1paWv9dXV3/YGBg/2JiYv+SUkf/6y4N//8l - AP//JgD//yYA//8mAP//JgD//yUA/+0uDf+bWEz/cHBw/29wcP9vb2//bm5u/21tbf9sbGz/a2tr/2lp - af9nZ2f/ZWVl/2JiYv9gYGD/XV1d/1paWv9XV1f/VFRU/1FRUf9NTU3/SUlJ/0ZGRv9CQkL/PT09/zg6 - Ov9KNDD/tyoR//4mAP//JgD//yYA//8mAP//JgD//yYA//smAP+YGgX/FwkH/wECAv8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8GBSP/FxSB/xkW - i/8ZFor/GBWJ/xcUiP8XFIj/FxSI/xcUiP8XFIj/FxSI/xcUiP8XFIj/GRSH/xkUh/8ZFIf/GRSH/xkU - h/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkU - h/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkVhv8XF4T/GROH/xgUh/8WF4T/FBWH/xQSiP8pJID/npvA/8rL - 0JfFxdQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADExc8AztDXJKOgtuszKVv/HRBR/x4S - VP8eElT/HhJU/x4SVP8eElT/HhJU/x4SVP8eElT/HBBY/xwTaP8cGX//FxaM/xUUj/8YFY3/GhWK/xgW - iv8XFor/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoW - jf8aFo3/GhaN/xoWjf8XFYz/FhWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8YFo3/GBaN/xgW - jf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo//GBd//x0dLv8jIyH/Jycn/ywsLP8xMTH/NTU1/zk5 - Of8+Pj7/QkJC/0ZGRv9KSkr/Tk5O/1FRUf9VVVX/WVlZ/1xcXP9fX1//YmJi/2VlZf9naGj/ampq/5hY - TP/sLw7//yUA//8mAP//JgD//yYA//8mAP//JQD/7i8O/6BcUf92dnX/dXV1/3R0dP9zc3P/cnJy/3Bw - cP9ubm7/bW1t/2pqav9oaGj/ZWVl/2NjY/9gYGD/XFxc/1lZWf9WVlb/UlJS/05OTv9LS0v/RkZG/0FC - Q/9SPDj/ui0U//4mAP//JgD//yYA//8mAP//JgD//yYA//wmAP+cHgj/HxEP/wkLC/8GBgb/AQEB/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEG/xMR - af8ZFoz/GRaK/xgVif8XFIj/FxSI/xcUiP8YFYn/GRaK/xkWiv8ZFor/GRaK/xoWif8bFon/GxaJ/xsW - if8aFYj/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkU - h/8ZFIf/GRSH/xkUh/8ZFIf/GRSH/xkUh/8ZFYb/FxaE/xkTh/8YFIf/FheE/xQVh/8UEoj/KSSA/56b - wP/Ky9CXxcXUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMXPAM7Q1ySjoLbrMylb/x0Q - Uf8eElT/HhJU/x4SVP8eElT/HhJU/x4SVP8eElT/HhJU/xwQWP8cE2j/HBl//xcWjP8VFI//GBWN/xoV - iv8YFor/FxaK/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoW - jf8aFo3/GhaN/xoWjf8aFo3/GBaN/xcVjP8XFYz/FxWM/xcVjP8XFYz/FxWM/xcVjP8XFYz/GBaN/xgW - jf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaQ/xoZY/8hISL/JiYm/ysrK/8vLy//NDQ0/zk5 - Of89PT3/QkJC/0ZGRv9KSkr/Tk5O/1JSUv9WVlb/Wlpa/15eXv9hYWH/ZGRk/2dnZ/9qamr/bW1t/29w - cP9xcnL/nV1R/+4wD///JQD//yYA//8mAP//JgD//yYA//8lAP/uMA7/pGBU/3t7e/96env/eXl5/3h4 - eP92dnb/dHR0/3Jycv9wcHD/bm5u/2tra/9oaGj/ZWVl/2FhYf9fX1//W1tb/1dXV/9TU1P/T09P/0pL - TP9aQz//vTAX//8mAP//JgD//yYA//8mAP//JgD//yYA//wmAP+gIgz/JxkX/xITFP8PDw//CQkJ/wQE - BP8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8KCTf/GRaL/xkWiv8YFYn/GBWJ/xgVif8YFYn/GBWJ/xkWiv8ZFor/GRaK/xkWiv8bFYr/GxWK/xsV - iv8bFYr/GhSJ/xkTiP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkT - iP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkTiP8ZE4j/GRSH/xcWhP8ZE4f/GBSH/xYXhP8UFYf/FBKI/ykk - gP+em8D/ysvQl8XF1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTFzwDO0Ncko6C26zMp - W/8dEFH/HhJU/x4SVP8eElT/HhJU/x4SVP8eElT/HhJU/x4SVP8cEFj/HBNo/xwZf/8XFoz/FRSP/xgV - jf8aFYr/GBaK/xcWiv8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoW - jf8aFo3/GhaN/xoWjf8aFo3/GhaN/xkWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgW - jf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8YFo7/GBWP/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgV - kP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgV - kP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgV - kP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgWiv8eHUD/JCQj/ykpKf8uLi7/MzMz/zg4 - OP88PDz/QUFB/0VFRf9KSkr/Tk5O/1JSUv9XV1f/W1tb/15eXv9iYmL/ZmZm/2lpaf9sbGz/cHBw/3Jy - cv91dXX/d3h4/3l6ev+iYlf/7jEQ//8lAP//JgD//yYA//8mAP//JgD//yUA//AwD/+oZFj/gYGB/39/ - gP9+fn7/fHx8/3t7e/94eHj/dnZ2/3Nzc/9wcHD/bW1t/2pqav9nZ2f/Y2Nj/2BgYP9cXFz/WFhY/1JU - Vf9iS0f/wTIa//8mAP//JgD//yYA//8mAP//JgD//yYA//wmAf+jJhD/LyEf/xscHf8XFxf/EhIS/w0N - Df8ICAj/AwMD/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/BAQY/xYTef8ZFov/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GRaK/xkWiv8ZFor/GxWK/xsV - iv8bFYr/GxWK/xoUif8ZE4j/GROI/xkTiP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkT - iP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkUh/8XFoT/GROH/xgUh/8WF4T/FBWH/xQS - iP8pJID/npvA/8rL0JfFxdQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADExc8AztDXJKOg - tuszKVv/HRBR/x4SVP8eElT/HhJU/x4SVP8eElT/HhJU/x4SVP8eElT/HBBY/xwTaP8cGYD/FhaM/xUU - j/8YFY3/GhWK/xgWiv8XFov/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoW - jf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8ZF47/GReO/xkXjv8ZF47/GReO/xkXjv8ZF47/GReO/xkX - jv8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8YFo7/GBaO/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgV - kP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgV - kP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgV - kP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xgVkf8ZF37/IiEu/ycoJ/8sLCz/MTEx/zY2 - Nv87Ozv/QEBA/0VFRf9JSUn/Tk5O/1JSUv9WVlb/W1tb/19fX/9jY2P/Z2dn/2pqav9ubm7/cXFx/3V1 - df93d3f/enp6/319ff9/f3//gYKC/6doXf/vMxL//yUA//8mAP//JgD//yYA//8mAP//JQD/8TEP/6xn - W/+FhYX/g4SE/4KCgv+AgID/fn5+/3t7e/95eXn/dnZ2/3Nzc/9vb2//bGxs/2hoaP9kZGT/YWFh/1td - Xv9qU0//xTUc//8mAP//JgD//yYA//8mAP//JgD//yYA//wmAf+lKRT/Nykn/yMlJf8gICD/Gxsb/xUV - Ff8QEBD/CwsL/wYGBv8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAf8SEGT/GRaM/xkWiv8aF4v/GheL/xoXi/8aFov/GRaK/xkWiv8ZFor/GRaK/xoV - iv8bFYr/GxWK/xsViv8aFIn/GROI/xkTiP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkT - iP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkTiP8ZE4j/GROI/xkTiP8ZFIf/FxaE/xkTiP8YFIf/FheE/xQV - h/8UEoj/KSSA/56bwP/Ky9CXxcXUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMXQAM7P - 1ySioLfrMilc/xwPUv8dEVT/HBFU/xwRVP8cEVT/HBFU/xwRVP8cEVT/HBFU/xsQV/8cE2n/HRiE/xgV - kv8XFJP/GhaO/xwXi/8ZF43/GBaP/xkWj/8ZFo//GRaP/xkWj/8ZFo//GRaP/xkWj/8ZFo//GRaP/xkW - j/8ZFo//GRaP/xkWj/8ZFo//GRaP/xkWj/8ZFo//GReQ/xkXkP8ZF5D/GReQ/xkXkP8ZF5D/GReQ/xkX - kP8ZF5D/GRaP/xkWj/8ZFo//GRaP/xkWj/8ZFo//GRaP/xkWj/8ZFpD/GRaQ/xkWkP8ZFpD/GRaQ/xkW - kP8ZFpD/GRaQ/xkWkP8ZFpD/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8YFZP/HRtg/yUlJf8rKyr/Ly8v/zU1 - Nf86Ojr/Pj4+/0NDQ/9ISEj/TU1N/1FRUf9WVlb/W1tb/19fX/9jY2P/Z2dn/2tra/9vb2//c3Nz/3Z2 - dv95eXn/fHx8/4CAgP+CgoL/hYWF/4eHh/+JiYn/rG5j/+80E///JQD//yYA//8mAP//JgD//yYA//8l - AP/yMQ//r2pe/4qKiv+IiIj/hoaG/4SEhP+BgYH/f39//3t7e/94eHj/dXV1/3Fxcf9tbW3/aWlp/2Rm - Z/9yW1f/yDgf//8mAP//JgD//yYA//8mAP//JgD//yYA//wmAf+oLRj/PzIv/ywtLv8pKCj/IyMj/x4e - Hv8ZGRn/FBQU/w4ODv8JCQn/AwMD/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/Cgk5/xgXiv8YFov/GBaM/xgWjP8YFoz/GBWM/xgVjP8YFYz/GBWM/xgV - jP8YFYz/GRWM/xkVjP8ZFYz/GBSM/xgUi/8YFIv/GBSL/xkUi/8ZFIv/GRSL/xkUi/8ZFIv/GRSL/xkU - i/8ZFIv/GRSL/xkUi/8ZFIv/GRSL/xkUi/8ZFIv/GRSL/xkUi/8ZFIv/GRWJ/xkWh/8aFIv/GhWK/xcX - hv8VFYj/FBKJ/ykkgP+em8D/ysvQl8XF1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPF - 0ADN0NgkoqC36zIoXf8bD1P/HBFV/xwRVf8cEVX/HBFV/xwRVf8cEVX/HBFV/xwRVf8bEFf/HBNp/x4X - h/8ZFZX/GBSV/xoXjv8dGIv/GheP/xkWkv8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/x8eVP8oKCb/LS0t/zIy - Mv84ODj/PT09/0JCQv9HR0f/S0tL/1BQUP9VVVX/Wlpa/15eXv9jY2P/Z2dn/2tra/9vb2//c3Nz/3d3 - d/97e3v/fn5+/4GBgf+EhIT/h4eH/4qKiv+MjIz/jo+P/5CQkP+xc2j/8DUU//8lAP//JgD//yYA//8m - AP//JgD//yUA//IxEP+ybWH/jo6O/4uMjP+JiYn/h4eH/4SEhP+BgYH/fX19/3l5ef92dnb/cnJy/21v - b/96Y1//yzsi//8mAP//JgD//yYA//8mAP//JgD//yYA//wmAf+sMRv/Rzo3/zU2Nv8xMTH/LCws/ycn - J/8hISH/HBwc/xcXF/8RERH/DAwM/wYGBv8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wYFIf8XFof/FxaM/xcVjf8XFY3/FxWN/xcVjf8XFY3/FxWN/xcV - jf8XFY3/FxWN/xcVjf8XFY3/FxWN/xcVjf8XFY3/FxWN/xcVjf8YFY3/GRWM/xkVjP8ZFYz/GRWM/xkV - jP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkWi/8ZFon/GxSN/xoV - jP8YGIf/FRWJ/xQSif8pJH//npvA/8rL0JfFxdQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADDxdAAzdDYJKKgt+sxKF3/Gw9U/x0SVv8dElb/HRJW/x0SVv8dElb/HRJW/x0SVv8dElb/HBFX/xwT - af8eF4f/GRWV/xgUlf8aF47/HBiL/xoXj/8ZFZL/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaS/xoXhf8kIzT/Kysq/zAw - MP81NTX/Ozs7/0BAQP9FRUX/SkpK/09PT/9UVFT/WVlZ/11dXf9iYmL/Z2dn/2tra/9vb2//dHR0/3h4 - eP98fHz/f39//4ODg/+Ghob/ioqK/42Njf+Pj4//kpKS/5SUlP+Wlpb/l5iY/7Z4bf/xNhX//yUA//8m - AP//JgD//yYA//8mAP//JQD/8jIR/7VwZP+SkZH/j4+P/4yMjP+JiYn/hoaG/4KCgv9/f3//e3t7/3Z4 - eP+Camb/zT8l//8mAP//JgD//yYA//8mAP//JgD//yYA//wnAf+wNB//T0JA/z4/P/85OTn/NTU1/y8v - L/8qKir/JSUl/x8fH/8aGhr/FBQU/w8PD/8JCQn/BAQE/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8CAgr/EhFr/xgWj/8XFY3/FxWN/xcVjf8XFY3/FxWN/xcV - jf8XFY3/FxWN/xcVjf8XFY3/FxWN/xcVjf8XFY3/FxWN/xcVjf8XFY3/GBWN/xkVjP8ZFYz/GRWM/xkV - jP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFov/GRaJ/xsU - jf8aFYz/GBiH/xUVif8UEon/KSR//56bwP/Ky9CXxcXUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAw8XQAM3Q2CSioLfrMShd/xwPVP8eE1f/HhNX/x4TV/8eE1f/HhNX/x4TV/8eE1f/HhNX/xwR - V/8cE2n/HheH/xkVlf8YFJX/GheO/x0Yi/8aF4//GRaS/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkv8bGIL/JyYx/y0t - Lf8zMzP/ODg4/z09Pf9CQkL/R0dH/01NTf9SUlL/V1dX/1xcXP9hYWH/ZWVl/2pqav9vb2//c3Nz/3h4 - eP98fHz/gICA/4SEhP+IiIj/i4uL/46Ojv+SkpL/lJSU/5eXl/+ZmZn/m5ub/52dnf+en5//u3xx//I2 - Ff//JQD//yYA//8mAP//JgD//yYA//8lAP/zMxH/t3Jm/5WUlP+RkpL/jo6O/4uLi/+Hh4f/hISE/3+A - gf+Kcm7/0EEo//8mAP//JgD//yYA//8mAP//JgD//yYA//wnAf+0OCL/V0pI/0ZHSP9CQkL/PT09/zg4 - OP8yMjL/LS0t/ycnJ/8iIiL/HR0d/xcXF/8SEhL/DAwM/wYGBv8BAQH/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/xAPX/8YFpD/FxWN/xcVjf8XFY3/FxWN/xcV - jf8XFY3/FxWN/xcVjf8XFY3/FxWN/xcVjf8XFY3/FxWN/xcVjf8XFY3/FxWN/xgVjf8ZFYz/GRWM/xkV - jP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRaL/xkW - if8bFI3/GhWM/xgYh/8VFYn/FBKJ/ykkf/+em8D/ysvPl8XF1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMPF0ADN0NgkoqC46zIpXv8dEFX/HxRY/x4TV/8eE1f/HhNX/x4TV/8eE1f/HhNX/x8U - V/8cEVj/HBNp/x4Xh/8ZFZX/FxSU/xoXjv8cGIv/GReO/xgVkv8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xoXkv8aF5L/GheS/xoX - kv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoX - kv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoX - kv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoX - kv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoX - kv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aFpP/Hh1m/ykp - LP8vLy//NTU1/zo6Ov9AQED/RUVF/0pKSv9PT0//VVVV/1paWv9fX1//ZGRk/2lpaf9ubm7/cnJy/3d3 - d/98fHz/gICA/4SEhP+IiIj/jIyM/5CQkP+Tk5P/l5eX/5qamv+cnJz/n5+f/6Ghof+jo6P/pKWl/6Wm - pv/AgXb/8zcW//8lAP//JgD//yYA//8mAP//JgD//yUA//MzEv+5dGj/l5eX/5SUlP+QkJD/jY2N/4iK - iv+Renb/1EQr//8mAP//JgD//yYA//8mAP//JgD//yYA//wnAf+4PCb/YFJQ/09RUf9LS0v/RUVF/0BA - QP87Ozv/NTU1/zAwMP8qKir/JSUl/yAgIP8aGhr/FBQU/w8PD/8JCQn/AwMD/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8MC0j/GBaN/xcVjf8XFY3/FxWN/xcV - jf8XFY3/FxWN/xcVjf8XFY3/FxWN/xcVjf8XFY3/FxWN/xcVjf8XFY3/FxWN/xcVjf8YFY3/GRWM/xkV - jP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkVjP8ZFYz/GRWM/xkW - i/8ZFon/GxSN/xoVjP8YGIf/FRaK/xUTiv8qJID/npzB/8rM0JfFxdQAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADExtEAztHYJKOhues0K1//HhFW/x4TV/8eE1f/HhNX/x4TV/8eE1f/HhNX/x4T - V/8eE1f/HBFX/xwTaf8eF4f/GRWV/xcUlP8ZFo3/GxeK/xkWjv8YFZH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiV/yIh - V/8sLCn/MjIy/zc3N/88PDz/QkJC/0dHR/9NTU3/UlJS/1dXV/9dXV3/YmJi/2dnZ/9sbGz/cXFx/3Z2 - dv96enr/f39//4SEhP+IiIj/jIyM/5CQkP+UlJT/mJiY/5ubm/+fn5//oqKi/6SkpP+np6f/qKio/6qq - qv+rq6v/rKyt/8SGe//0OBf//yUA//8mAP//JgD//yYA//8mAP//JQD/9DMS/7t1af+ZmZn/lZaW/5CT - k/+Zgn7/10ct//8mAP//JgD//yYA//8mAP//JgD//yYA//wnAv+7QCr/Z1pY/1dZWf9TU1P/Tk5O/0lJ - Sf9DQ0P/Pj4+/zg4OP8zMzP/LS0t/ygoKP8iIiL/HBwc/xcXF/8RERH/DAwM/wYGBv8BAQH/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/BQUg/xcVif8YFo7/GBaO/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GRaO/xoW - jf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8ZFYz/GRWM/xkV - jP8ZFov/GRaJ/xsUjf8aFYz/GBiH/xYWiv8WFIv/KyaB/5+dwf/LzNGXxsbVAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAxMbRAM7R2CSjobnrNCtf/x4RVv8eE1f/HhNX/x4TV/8eE1f/HhNX/x4T - V/8eE1f/HhNX/xwRV/8cE2n/HheH/xkVlf8YFJX/GheO/xwYi/8aF4//GBWS/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - lf8jIlj/Li4s/zQ0NP85OTn/Pz8//0RERP9KSkr/T09P/1RUVP9aWlr/X19f/2VlZf9qamr/b29v/3R0 - dP95eXn/fn5+/4ODg/+Hh4f/jIyM/5CQkP+VlZX/mZmZ/52dnf+goKD/pKSk/6enp/+pqan/rKys/66u - rv+wsLD/sbGx/7Kysv+ys7P/yIuA//Q6Gf//JAD//yYA//8mAP//JgD//yYA//8lAP/0MxH/vXZp/5qb - m/+hiob/20kw//8mAP//JgD//yYA//8mAP//JgD//yYA//wnAv++RC//b2Jg/2BhYv9cXFz/V1dX/1FR - Uf9MTEz/RkZG/0FBQf87Ozv/NjY2/zAwMP8qKir/JSUl/x8fH/8ZGRn/FBQU/w4ODv8ICAj/AwMD/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wUEHP8XFYn/GBaO/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xkW - jv8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GRWM/xkV - jP8ZFYz/GRaL/xkWif8bFI3/GhWM/xgYh/8WFor/FhSL/ysmgf+fncH/y8zRl8bG1QAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTG0QDO0dgko6G56zQrX/8eEVb/HhNX/x4TV/8eE1f/HhNX/x4T - V/8eE1f/HhNX/x4TV/8cEVf/HBNp/x4Xh/8ZFZT/GBWV/xwYj/8eGYz/GxiQ/xkWk/8ZFpL/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGI//JiVO/zAwLv82Njb/Ozs7/0FBQf9GRkb/TExM/1JSUv9XV1f/XV1d/2JiYv9nZ2f/bW1t/3Jy - cv93d3f/fHx8/4GBgf+Ghob/i4uL/5CQkP+UlJT/mZmZ/52dnf+hoaH/paWl/6mpqf+srKz/r6+v/7Ky - sv+0tLT/tra2/7e3t/+4uLj/uLi5/7i5uf/Mj4T/9Toa//8kAP//JgD//yYA//8mAP//JgD//yUA//Qz - Ev/FbV3/3U00//8mAP//JgD//yYA//8mAP//JgD//yYA//wnAv/BSDP/d2po/2lqa/9lZGT/X19f/1lZ - Wf9UVFT/T09P/0lJSf9DQ0P/Pj4+/zg4OP8zMzP/LS0t/ycnJ/8hISH/HBwc/xYWFv8QEBD/CgoK/wUF - Bf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8FBBz/FxWI/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8ZFo7/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xoWjf8aFo3/GhaN/xkV - jP8ZFYz/GRWM/xkWi/8ZFon/GxSN/xoVjP8YGIf/FhaK/xYUi/8rJoH/n53B/8vM0ZfGxtUAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADExtEAztHZJKOhues0K1//HhFX/x4TWP8eE1j/HhNY/x4T - WP8eE1j/HhNY/x4TWP8eE1j/HBFY/xwTav8eGIj/GRWV/xgVlv8cGZH/HhqO/xwZkf8aF5T/GRaS/xkW - kv8ZFpL/GRaS/xkWkv8ZFpL/GRaS/xkWkv8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8bF5P/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxiT/xsXlP8bF5T/HBiS/x0Ykv8cGJP/GhiS/xoZkv8aGJL/GxiU/xsYk/8aGJP/GhiT/xoY - k/8aGJP/GxiT/xsYk/8bGJP/GhiT/xkYlf8ZF5X/GReV/xkXlf8aF5X/GhiU/xoYk/8bGJP/GxiT/xsY - k/8bGJT/GxeU/xsYk/8bGJP/GxiT/xsXlP8bF5X/GxeU/xsXlP8bF5T/GxeU/xsXlP8bGJT/GxiT/xsY - k/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJT/HRqE/yopOP8xMTH/Nzc3/z09Pf9DQ0P/SEhI/05OTv9TU1P/WVlZ/15eXv9kZGT/ampq/29v - b/90dHT/enp6/39/f/+EhIT/iYmJ/46Ojv+Tk5P/mJiY/52dnf+hoaH/paWl/6mpqf+tra3/sbGx/7S0 - tP+3t7f/ubm5/7u7u/+9vb3/vr6+/76+vv++vr7/vb6+/8+TiP/1Oxr//yQA//8mAP//JgD//yYA//8m - AP//JgD//CkE//4nAf//JgD//yYA//8mAP//JgD//yYA//0oAv/FTDb/f3Nx/3Fzc/9tbW3/Z2dn/2Ji - Yv9cXFz/V1dX/1FRUf9LS0v/RkZG/0BAQP87Ozv/NTU1/y8vL/8qKir/IyMj/x4eHv8YGBj/EhIS/wwM - DP8HBwf/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AgIO/xMR - cf8YFpD/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgW - jv8YFo7/GRaO/xoWjv8aFo7/GhaO/xoWjv8aFo7/GhaO/xoWjv8aFo7/GhaN/xoWjf8aFo3/GhaN/xkW - jf8ZFYz/GRWM/xkVjP8ZFov/GRaK/xsUjf8aFYz/GBiH/xUWi/8WFIv/KyaB/5+cwf/LzNCXxsbVAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMXTAM7Q2iSjobrrNCpg/x4RWP8eElr/HhJa/x4S - Wv8eElr/HhJa/x4SWv8eElr/HhJa/xwQWv8dE2z/IBqL/xoWmP8YFZf/HBiS/x4Zj/8cGJP/GhaW/xsX - lf8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8aFpf/GxaW/yAYkf8hGJH/HhiT/xgYkv8XG5H/FxeR/xwWlv8aFpT/GheU/xoX - lP8bGJX/GxiU/xsYlP8bGJP/GhiS/xgXlf8TFpn/ExaY/xQVl/8VFZf/GBeY/xoXl/8aFpT/GhaS/xwW - lP8cFpb/GxaW/xsWl/8bFpb/GheV/xoXlf8aFpb/GxaX/xsWl/8bFpf/GxaX/xsWl/8bFpb/GxeV/xsX - lP8bF5T/GxeU/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeV/x4agv8sLDP/MzMz/zk5Of8/Pz//RERE/0pKSv9QUFD/VVVV/1tbW/9gYGD/ZmZm/2xs - bP9xcXH/d3d3/3x8fP+CgoL/h4eH/4yMjP+RkZH/lpaW/5ubm/+goKD/paWl/6mpqf+urq7/srKy/7a2 - tv+5ubn/vLy8/7+/v//BwcH/w8PD/8TExP/ExMT/xMTE/8TExP/Cw8P/0paL//Y7G///JQD//yYA//8m - AP//JgD//yYA//8mAP//JgD//yYA//8mAP//JgD//yYA//0oAv/KTzr/h3t5/3p7e/91dXX/cHBw/2pq - av9lZWX/X19f/1paWv9UVFT/Tk5O/0hISP9DQ0P/PT09/zc3N/8xMTH/LCws/yYmJv8gICD/Ghoa/xQU - FP8ODg7/CQkJ/wMDA/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - Av8QDl3/GRaT/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpD/GRaQ/xkWkP8ZFpD/GRaQ/xkWkP8ZFpD/GRaQ/xgWjv8YFo3/GBaN/xgW - jf8YFo3/GBaN/xgWjf8YFo3/GBeM/xkXiv8cFY3/GxaN/xgYif8VF4z/FhSM/yolgv+dnMH/ycvPl8XG - 1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTF0wDO0Nsko6G66zQqYf8eEVj/HhJa/x4S - Wv8eElr/HhJa/x4SWv8eElr/HhJa/x4SWv8cEFr/HhNt/yEajP8aFpj/GBWX/xwYkv8eGY//HBiT/xsW - l/8bF5b/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GheV/xsXlP8gGJH/IheR/x8WlP8ZGJn/FhaY/xkUmf8bEZj/GxKW/xwU - lv8dFJf/HRWX/x0Vl/8dFZj/HRWY/x0UmP8dFJb/HBWS/xwWj/8dGI7/HxiN/yAYjf8gF4//IheS/yMW - lf8gFZj/HRWZ/x0Vmf8dFJr/HROc/xwTnP8cFZj/HBiS/xwaj/8bGJT/GxaW/xsWlv8bFpf/GxaW/xsX - lf8bF5X/GxeU/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlf8eG4L/Li00/zQ0NP86Ojr/QEBA/0ZGRv9MTEz/UVFR/1dXV/9dXV3/YmJi/2ho - aP9ubm7/dHR0/3h4eP9+fn7/hISE/4mJif+Pj4//lJSU/5mZmf+enp7/o6Oj/6ioqP+tra3/srKy/7a2 - tv+6urr/vb29/8HBwf/ExMT/xsbG/8jIyP/Kysr/ysrK/8rKyv/Jycn/yMjI/8bGx//VmI3/9zsb//8l - AP//JgD//yYA//8mAP//JgD//yYA//8mAP//JgD//yYA//0oA//NUz3/j4OA/4KEhP99fX3/eHh4/3Jy - cv9tbW3/Z2dn/2FhYf9cXFz/VlZW/1BQUP9LS0v/RUVF/z8/P/85OTn/MzMz/y0tLf8oKCj/IiIi/xwc - HP8WFhb/EBAQ/woKCv8EBAT/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/Dw1Y/xoWlP8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8YFo7/GBaN/xgW - jf8YFo3/GBaN/xgWjf8YFo3/GBaN/xgXjP8YGIr/HBWO/xsWjf8YGYn/FReM/xYUjP8pJIL/nJvC/8jL - z5fExtUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADExdMAztDbJKOhuus0KmH/HhFY/x4S - Wv8eElr/HhJa/x4SWv8eElr/HhJa/x4SWv8eElr/HBBa/x4Tbf8hGoz/GhaY/xgVl/8cGJL/HhmP/xwY - k/8bFpf/GxeW/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxeU/xoYk/8bGZL/HxiS/yEXkv8eFpf/GRSe/xcRof8cEp//Ihad/xgX - n/8TFp//EhWf/xIUn/8QEZ7/DxGf/xESof8SEqL/GBWd/yEYkf8iF5H/IRWU/yAUlv8fE5f/HxSV/yAW - k/8hGJP/HhmS/xsZkf8bGJT/GxeV/xsWlv8cFpf/HBaW/xwXlf8cF5X/GxeU/xsXlP8bF5T/GxeV/xsX - lP8bF5X/GxeV/xsXlf8bF5b/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5X/HhuD/y8uNf81NTX/Ozs7/0FBQf9HR0f/TU1N/1NTU/9ZWVn/Xl5e/2Rk - ZP9qamr/b29v/3V1df97e3v/gYGB/4aGhv+MjIz/kZGR/5aWlv+cnJz/oaGh/6ampv+rq6v/sLCw/7W1 - tf+6urr/vr6+/8LCwv/Gxsb/ycnJ/8zMzP/Ozs7/0NDQ/9DQ0P/Q0ND/0NDQ/87Ozv/MzMz/ycrK/9aa - j//3PBv//yUA//8mAP//JgD//yYA//8mAP//JgD//yYA//0oA//RV0L/l4uJ/4uMjP+Ghob/gICA/3t7 - e/91dXX/b29v/2pqav9kZGT/Xl5e/1hYWP9SUlL/TU1N/0dHR/9BQUH/Ozs7/zU1Nf8vLy//KSkp/yQk - JP8eHh7/GBgY/xISEv8MDAz/BgYG/wEBAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/w8NV/8aFpT/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GBaP/xgW - jv8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo3/GBeL/xwVj/8bFY7/GBiK/xUXjf8WFI3/KSSD/5yb - wv/Iy8+XxMbVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMXTAM7Q2ySjobrrNCph/x4R - WP8eElr/HhJa/x4SWv8eElr/HhJa/x4SWv8eElr/HhJa/xwQWv8eE23/IRqM/xoWmP8YFZf/HBiS/x4Z - j/8cGJP/GxaX/xsXlv8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsX - lf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsX - lf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8aGZL/GhiT/x8Wlf8gF5T/HBaU/xcSmv8ZEqD/LSOk/1dO - vv9KScv/QULQ/zs8zv83Nsv/MzLJ/y8tyP8qJ8T/JCG//yMbvP8kFLf/IhOx/x0Tqf8ZFKL/FBSc/xMV - mv8RFJr/EBSa/xQXlf8YGZL/GBiT/xgZkv8YG4//GBuN/xkakP8ZFpj/GhOd/xsWl/8bF5T/GxeU/xsY - k/8bGJP/GxeU/xsXlv8bFpf/GxaX/xsWl/8bFpb/GxaX/xsWl/8bFpf/GxaX/xsWl/8bFpb/GxeV/xsX - lf8bF5X/GxeV/xsXlf8bF5X/GxeW/x4bg/8vLzb/NjY2/zw8PP9CQkL/SEhI/05OTv9UVFT/Wlpa/19f - X/9lZWX/a2tr/3Fxcf93d3f/fHx8/4KCgv+IiIj/jo6O/5OTk/+ZmZn/np6e/6SkpP+pqan/rq6u/7Oz - s/+5ubn/vb29/8LCwv/Gxsb/ysrK/87Ozv/R0dH/1NTU/9XV1f/W1tb/1tbW/9bW1v/U1NT/0dHR/87Q - 0f/Rt7P/8ksv//8kAP//JgD//yYA//8mAP//JgD//yYA//8mAP/7Kgb/vm1f/5OUlP+Ojo7/iIiI/4OD - g/99fX3/d3d3/3Fxcf9sbGz/ZmZm/2BgYP9aWlr/VFRU/09PT/9ISEj/Q0ND/z09Pf83Nzf/MTEx/ysr - K/8lJSX/Hx8f/xkZGf8TExP/DQ0N/wcHB/8CAgL/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8PDVf/GhaU/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xgW - j/8YFo7/GBaO/xgWjv8YFo7/GBaO/xgWjv8YFo7/GBaN/xgXjP8cFJD/GxWP/xgYi/8VF43/FhOO/ykk - g/+cm8L/yMvQl8TG1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTF0wDO0Nsko6G66zQq - Yf8eEVj/HhJa/x4SWv8eElr/HhJa/x4SWv8eElr/HhJa/x4SWv8dEVv/HRNs/yAZi/8ZFZf/GRaY/xwY - kv8eGY//HBiT/xsWl/8bF5b/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8cGJb/HBiW/xwY - lv8cGJb/HBiW/xwYlv8cGJb/HBiW/xwYlv8cGJb/HBiW/xwYlv8cGJb/HBiW/xwYlv8cGJb/HBiW/xwY - lv8cGJb/HBiW/xwYlv8cGJb/HBiW/xwYlv8cGJb/GhmU/xoXl/8eFJv/IBeV/xwZkP8YFpT/GBOW/09J - r//FxPj/0dL5/83O9//Jyff/xcT1/8PB8/+9uvD/sq7r/6aj4P+YleD/fn3j/2tp2P9ZVc7/RkLJ/zUv - xf8oIsD/Hxm+/xcSuP8VEqr/Fxae/xUXlv8UF5T/ExWb/xMQof8TEaP/FRag/xYYmv8aFpf/GhWV/xsX - lP8cGZT/HBmU/xwYlf8cF5f/HBaZ/xwWmf8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwX - l/8cGJb/HBiW/xwYlv8cGJb/HBiW/xsXl/8fHIT/MDA3/zc3N/89PT3/Q0ND/0lJSf9PT0//VVVV/1tb - W/9gYGD/ZmZm/2xsbP9ycnL/eHh4/35+fv+EhIT/iYmJ/4+Pj/+VlZX/m5ub/6CgoP+mpqb/q6ur/7Gx - sf+2trb/vLy8/8HBwf/Gxsb/ysrK/8/Pz//T09P/1tbW/9nZ2f/b29v/3d3d/9zc3P/b29v/2tra/9fZ - 2f/YwLz/71xD//8nAf//JgD//yYA//8mAP//JgD//yYA//8mAP//JgD//yUA//QyEP+4cGP/kZCQ/4uL - i/+FhYX/f39//3p6ev9zc3P/bW1t/2hoaP9iYmL/XFxc/1ZWVv9QUFD/SkpK/0RERP8+Pj7/ODg4/zIy - Mv8sLCz/Jycn/yEhIf8bGxv/FBQU/w8PD/8JCQn/AwMD/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/EA5Y/xsYlf8aF5L/GheS/xoXkv8aF5L/GheS/xoXkv8aF5L/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8YFZD/GBWQ/xgVkP8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpD/GRaQ/xkWkP8ZFpD/GRaQ/xkWkP8ZFpD/GRaQ/xkWj/8ZF47/HBWR/xwVkP8YGIz/FReO/xcU - j/8rJob/nZzE/8jK0ZfExtYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADExdMAztDbJKOh - uus0KmH/HhFY/x4SWv8eElr/HhJa/x4SWv8eElr/HhJa/x4SWv8eElr/HRFb/x0SbP8gGYv/GRSX/xoW - mP8cGJL/HhmP/xwYk/8bFpf/GxeW/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5b/HBeX/xwX - l/8cF5f/HBeX/xwXl/8cF5f/HBeX/xwXl/8cF5f/HBeX/xwXl/8cF5f/HBeX/xwXl/8cF5f/HBeX/xwX - l/8cF5f/HBeX/xwXl/8cF5f/HBeX/xwXl/8cF5f/HBeX/xoZlv8aFpr/HROg/x8Xl/8cHI3/GRmR/xoV - j/9TUaL/19zv/+3r6f/w6+b/8Orn//Dp6f/y6uz/8+vv//Pr8f/z6vH/7ur1/+Pm9//b3/T/1dn2/8rL - +f+7uff/p6Tw/46K4/9ybM7/VE/B/z01v/8tH77/IhHA/xoKuP8VDaz/ExSf/xIZlf8RGZL/GRWa/xwV - nP8bFZf/HBeW/xsYlP8cGJb/HBeY/xwVm/8cFZv/HBaZ/xwWmf8cFpn/HBaZ/xwWmf8cFpn/HBaZ/xwX - mf8cF5j/HBeX/xwXl/8cF5f/HBeX/xwXl/8cF5n/HxuG/zExOP84ODf/Pj4+/0RERP9KSkr/UFBQ/1VV - Vf9bW1v/YWFh/2dnZ/9tbW3/c3Nz/3l5ef9/f3//hYWF/4uLi/+RkZH/l5eX/5ycnP+ioqL/qKio/62t - rf+zs7P/uLi4/76+vv/Dw8P/ycnJ/87Ozv/S0tL/19fX/9vb2//e3t7/4eHh/+Li4v/i4uL/4eHh/9/h - 4f/gx8P/8l9F//8lAP//JgD//yYA//8mAP//JgD//yYA//8mAP//JgD//yYA//8mAP//JQD/9DEP/7Zt - Yf+NjY3/h4eH/4GBgf97e3v/dXV1/29vb/9paWn/Y2Nj/15eXv9XV1f/UlJS/0xMTP9GRkb/QEBA/zo6 - Ov80NDT/Li4u/ygoKP8iIiL/HBwc/xYWFv8QEBD/CgoK/wQEBP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/xAOWP8cGZb/GxiT/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xkW - kf8ZFpH/GRaR/xkWkf8YFZD/GBWQ/xgVkP8YFZD/GBWQ/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZF5D/GReO/x0Vkv8cFZH/GRiM/xUX - j/8YFZD/LCeH/52cxf/IytGXxMXXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMXTAM7Q - 2ySjobrrNCph/x4RWP8eElr/HhJa/x4SWv8eElr/HhJa/x4SWv8eElr/HhJa/x0RW/8dEmz/IBmL/xkU - l/8aFpj/HBiS/x4Zj/8cGJP/GxaX/xsXlv8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeW/xwX - mP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwX - mP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8aGZT/Ghaa/x0Rov8eFpj/Gx2N/xoY - k/8bE5L/VFCf/9fd5//o6uj/6Ofq/+jn6v/o5+v/6eft/+ro7//q5+7/6ebu/+vn6//u6Ob/7ujm//Dr - 6v/v6+3/7enu/+vo8v/q5/b/5OHz/9LQ9v+3tfX/mpPt/3dr4P9WR9D/Nie8/yQar/8cF6f/FxOh/xoQ - ov8cEqL/GxOc/xwWmf8bF5b/HBiW/xwWmf8cFZv/HBWc/xwWmv8cFpn/HBaZ/xwWmf8cFpn/HBaZ/xwW - mf8cFpn/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeZ/x8bhv8xMTj/ODg4/z4+Pv9ERET/SkpK/1BQ - UP9WVlb/XFxc/2JiYv9oaGj/bm5u/3R0dP96enr/gICA/4aGhv+MjIz/kpKS/5iYmP+dnZ3/o6Oj/6mp - qf+vr6//tbW1/7q6uv/AwMD/xcXF/8vLy//Q0ND/1tbW/9ra2v/f39//4+Pj/+bm5v/o6Oj/6Ojo/+fp - 6f/oz8v/9WJJ//8mAP//JgD//yYA//8mAP//JgD//yYA//8kAP//JQD//yYA//8mAP//JgD//yYA//8l - AP/zMQ//s2te/4mIiP+Cg4P/fX19/3d3d/9xcXH/a2tr/2VlZf9fX1//WVlZ/1NTU/9NTU3/R0dH/0FB - Qf87Ozv/NTU1/y8vL/8pKSn/IyMj/x0dHf8XFxf/ERER/wsLC/8FBQX/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8RD1v/HBiW/xsYk/8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFZL/GRWS/xkVkv8ZFZL/GRWS/xkVkv8ZFZL/GRaQ/xkXj/8dFZL/HBWS/xkY - jf8VFo//GBWR/ywmiP+dm8b/yMrSl8TF2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTF - 0wDO0Nsko6G66zQqYf8eEVj/HhJa/x4SWv8eElr/HhJa/x4SWv8eElr/HhJa/x4SWv8dEVv/HRJs/yAZ - i/8ZFJf/GhaY/xwYkv8eGY//HBiT/xoWl/8bF5b/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsX - lv8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwX - mP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/GhqS/xoYl/8dEaL/HRaa/xsb - j/8ZFZn/HA6c/1lNqP/b3uv/6ezo/+jq6f/o6un/6Oro/+nq6f/p6+n/6Oro/+fp5//p6eb/7unl/+/p - 5//u5+n/7Obr/+zn7f/s6O7/7Onu/+vp7P/r6O7/6ent/+br6//e5u3/ztPx/62r8/+Gfen/W07S/zor - vv8pGrX/HxKp/x4To/8bFJv/HBaY/xwXmP8cFpn/HBWc/xwVnP8cFpr/HBaZ/xwWmf8cFpn/HBaZ/xwW - mf8cFpn/HBaZ/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmf8fG4f/MTA5/zg4OP8+Pj7/RERE/0pK - Sv9RUVH/VlZW/11dXf9iYmL/aGho/25ubv90dHT/enp6/4CAgP+Ghob/jIyM/5KSkv+YmJj/np6e/6Sk - pP+qqqr/sLCw/7a2tv+8vLz/wsLC/8fHx//Nzc3/09PT/9nZ2f/d3d3/4+Pj/+jo6P/r6+v/7u7u/+7w - 8P/v1tH/+GZM//8mAP//JgD//yYA//8mAP//JgD//yYA//0qBf/qVz3/9Twc//8lAP//JgD//yYA//8m - AP//JgD//yUA//MxD/+waFv/hIOD/35+fv94eHj/cnJy/2xsbP9mZmb/YGBg/1paWv9UVFT/Tk5O/0hI - SP9CQkL/PDw8/zY2Nv8wMDD/Kioq/yQkJP8eHh7/GBgY/xISEv8MDAz/BQUF/wEBAf8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8BAQj/ExFp/xsYlf8bGJP/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GRaR/xkWkf8ZFpH/GRaR/xoXkv8bGJP/GhiS/xsYk/8aF5L/GRaR/xkWkf8ZFpH/GRaR/xkW - kf8ZFpH/GRaR/xkWkf8ZFZL/GRWS/xkVkv8ZFZL/GRWS/xkVkv8ZFZL/GRWS/xkWkf8ZF4//HRSS/xwV - kv8ZF47/FRaQ/xgUkf8sJoj/nZvG/8jK0pfExdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADExdMAztDbJKKhuuszK2H/HRFY/x4SWv8eElr/HhJa/x4SWv8eElr/HhJa/x4SWv8eElr/HRJa/x0S - b/8gGJD/GRSZ/xkXl/8cGJP/HheU/xwXlv8aF5f/GxeX/xsXl/8bF5f/GxeX/xsXl/8bF5f/GxeX/xsW - l/8bFpj/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwX - mP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xoYlv8bGJf/HRSd/xwV - mv8ZGZX/GBWb/x0Pnf9aTaz/3d7v/+zs6f/t6en/7eno/+3q6P/t6ej/7enn/+3p5//t6ef/7Onn/+rp - 5v/q6eb/6Onl/+nq5f/p6ub/6evp/+nq6v/p6ur/7unr/+/p6v/r6uX/6e3i/+fw4v/l7+r/3+T3/9DN - +P+yqPL/iH3Z/1ZJvf80JLX/HxOv/xYRpP8WF5v/GRqX/xkXmP8aFZz/Ghad/xsWmv8eFpn/HhWU/x8X - lP8eGJT/GxiV/xoXmf8bFpr/HBaZ/xwWmf8cFpn/HBaZ/xwWmf8bFpr/HRiQ/y0sS/84OTf/Pj4+/0RE - RP9KSkr/UVFR/1ZWVv9dXV3/YmJi/2lpaf9ubm7/dXV1/3t7e/+BgYH/h4eH/42Njf+Tk5P/mZmZ/5+f - n/+lpaX/q6ur/7Gxsf+3t7f/vb29/8PDw//IyMj/zs7O/9TU1P/a2tr/4ODg/+bm5v/r6+v/7+/v//P1 - 9f/13Nj/+mhO//8mAP//JgD//yYA//8mAP//JgD//yUA//4pBP/lbFf/xLi1/86Tif/1Ohr//yUA//8m - AP//JgD//yYA//8mAP//JQD/8jAP/61lWP+Af37/eXl5/3Nzc/9tbW3/Z2dn/2FhYf9bW1v/VVVV/09P - T/9JSUn/Q0ND/z09Pf83Nzf/MDAw/ysrK/8kJCT/Hx8f/xgYGP8SEhL/DAwM/wYGBv8BAQH/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/BQQZ/xkVhv8bGJT/GxiT/xsYk/8bGJP/GxiT/xsY - k/8bGJP/GxeT/xoXkv8aFpL/GhaS/xoWkv8bF5P/GxiT/xsYk/8bGJP/GxeT/xoWkv8aFpL/GhaS/xoW - kv8aFpL/GhaS/xoWkv8aFpL/GhaT/xoWk/8aFpP/GhaT/xkVkv8ZFZL/GRWS/xkVkv8ZFZH/GRaQ/x0U - lP8cFJP/GReP/xUWkP8YFJH/LCaI/52bxv/IytKXxMXYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAwsXTAMzQ2yShobrrMith/xwRWP8dElr/HRJa/x0SWv8dElr/HRJa/x0SWv8dElr/HRJa/xwT - Wf8dEnH/IBaX/xkVnP8ZGZX/HBmU/x4Vmv8cFpr/GhiW/xsXmP8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFZz/HBaa/x4X - lv8cFZv/GReb/xkYnP8dFJf/WE+n/9vd7f/q6+n/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6P/r6ej/6uno/+rp - 6v/r6ez/6+jv/+jl8//QzO7/nJjm/2Bc1f8wLML/Gha1/xgUq/8YFpz/FxiV/xYamf8ZF5v/HhaZ/yIW - mP8iF5X/HxiU/xsXl/8XF5n/GBea/xsWm/8bFpv/Gxab/xsWm/8bFpv/Gxab/xsWm/8pJ1//ODg2/z4+ - Pv9ERET/SkpK/1FRUf9WVlb/XV1d/2JiYv9paWn/bm5u/3V1df97e3v/gYGB/4eHh/+NjY3/k5OT/5mZ - mf+fn5//paWl/6urq/+xsbH/t7e3/729vf/Dw8P/ycnJ/8/Pz//V1dX/29vb/+Hh4f/n5+f/7e3t//P1 - 9f/439v//WpQ//8mAP//JgD//yYA//8mAP//JgD//yUA//4qBP/ocFv/y7+9/8LDxP+8vb3/yo+E//Q6 - Gf//JQD//yYA//8mAP//JgD//yYA//8lAP/yMA7/qmFU/3p5ef9zdHT/bm5u/2hoaP9iYmL/W1tb/1ZW - Vv9PT0//SkpK/0NDQ/89PT3/Nzc3/zExMf8rKyv/JSUl/x8fH/8ZGRn/ExMT/w0NDf8HBwf/AgIC/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wUFHv8aFo//GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8aFpP/GBSR/xgUkf8YFJH/GBWQ/xkW - kf8dE5X/HBSU/xkXj/8VFpD/GBSR/ywniP+dnMX/yMrRl8TF1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMLF0wDM0NskoaG66zIrYf8cEVj/HRJa/x0SWv8dElr/HRJa/x0SWv8dElr/HRJa/x0S - Wv8cE1j/HRJx/yAWmP8ZFZz/GRmV/xwZlP8dFZv/Gxaa/xoYlv8bF5j/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxWd/xwW - mv8eGJb/HBWb/xkWnP8ZGJv/HRSX/1hPp//a3u3/6uvp/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vo6//p5vD/5Orp/9/v5v/N3O7/panw/21i5f87Ksr/JRWw/xsUnf8ZGZf/GRia/xoX - mv8cFpv/HBSd/xsSof8bEqL/GRWd/xoWm/8bFpv/Gxab/xsWm/8bFpv/Gxab/xsWm/8bFZ3/KSdh/zg4 - Nf8+Pj7/RERE/0pKSv9QUFD/VlZW/1xcXP9iYmL/aGho/25ubv90dHT/enp6/4CAgP+Ghob/jIyM/5KS - kv+YmJj/n5+f/6Wlpf+rq6v/sbGx/7a2tv+9vb3/w8PD/8nJyf/Pz8//1dXV/9vb2//h4eH/5+fn/+3v - 7//02tb//GhO//8mAP//JgD//yYA//8mAP//JgD//yUA//4qBf/rdF//0cXD/8jKyv/Dw8P/vb29/7a3 - t//Gi4H/8zoZ//8lAP//JgD//yYA//8mAP//JgD//yUA//EvDf+mXVD/dXR0/25ubv9oaGj/YmJi/1xc - XP9WVlb/UFBQ/0pKSv9ERET/Pj4+/zg4OP8yMjL/LCws/yUlJf8gICD/GRkZ/xQUFP8NDQ3/BwcH/wIC - Av8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8FBR3/GhaO/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GhaT/xkVkv8ZFZL/GRWS/xkW - kf8ZFpH/HROV/xwUlP8ZF4//FRaQ/xgUkf8sJ4j/nZzF/8jK0ZfExdcAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADCxdMAzNDbI6GhuusyK2H/HBFY/x0SWv8dElr/HRJa/x0SWv8dElr/HRJa/x0S - Wv8dElr/HBNY/x0Scf8gFpj/GRSc/xkZlf8cGZT/HRWb/xsWmv8aGJb/GxeY/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsV - nf8cFpr/HhiW/xwVm/8ZFpz/GRib/x0Ul/9YT6f/2t7t/+rr6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6ujt/+nn7v/m5+n/5uvn/+Xu7P/Z4PT/srHv/3Rn2f89KsD/IxOt/xwY - nP8WGZH/FBqV/xQVnf8WEqP/GhOg/xwTn/8bFZ3/Gxab/xsWm/8bFpv/Gxab/xsWm/8bFpv/Gxad/ycl - Zv83Nzb/PT09/0NDQ/9JSUn/UFBQ/1VVVf9cXFz/YWFh/2hoaP9ubm7/dHR0/3p6ev+AgID/hoaG/4yM - jP+SkpL/mJiY/56env+kpKT/qqqq/7CwsP+2trb/vLy8/8LCwv/IyMj/zs7O/9TU1P/a2tr/39/f/+Xn - 6P/t1M//+mVL//8lAP//JgD//yYA//8mAP//JgD//yUA//4qBf/td2L/18vJ/87Q0P/Jycn/wsLC/729 - vf+3t7f/sLGx/8GHff/xORn//yUA//8mAP//JgD//yYA//8mAP//JQD/8S4M/6NZTP9vbm7/aGlp/2Ji - Yv9cXFz/VlZW/1BQUP9KSkr/RERE/z4+Pv84ODj/MjIy/ywsLP8mJib/ICAg/xoaGv8UFBT/Dg4O/wgI - CP8CAgL/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/Cgg3/xsXkv8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8aFpP/GhaT/xoW - k/8aF5L/GRaR/xwTlf8cFJT/GReP/xUWkP8YFJH/LCeI/52cxf/IytGXxMXXAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAwsXSAMrO1jaiobrvMith/xwRWP8dElr/HRJa/x0SWv8dElr/HRJa/x0S - Wv8dElr/HRJa/xwTWf8dEnL/IBaY/xkVnP8ZGZX/HBmU/x4Vm/8cFpr/GhiW/xsXmP8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFZ3/HBaa/x4Ylv8cFZv/GRec/xkYm/8dFJf/WE+n/9re7f/q6+n/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+np6P/r5+r/8Obt//Ln7P/v5+j/6efp/+Xp8v/Y3vX/razs/2ha - 0/8zKLD/Gxif/xIToP8RFJ7/FBmX/xkXmP8eFpn/HRaa/xsWm/8bFpv/Gxab/xsWm/8bFpv/Gxab/xsW - nP8gHIX/NTQ+/z09PP9DQ0P/SUlJ/09PT/9UVFT/W1tb/2BgYP9nZ2f/bW1t/3Nzc/95eXn/f39//4WF - hf+Li4v/kZGR/5eXl/+dnZ3/o6Oj/6mpqf+vr6//tLS0/7u7u//AwMD/xsbG/8zMzP/S0tL/2NjY/93f - 3//mzMj/92NJ//8lAP//JgD//yYA//8mAP//JgD//yUA//4qBf/veWX/28/N/9PV1f/Ozs7/yMjI/8LC - wv+8vLz/tra2/7CwsP+qqqv/vIN5//A4GP//JQD//yYA//8mAP//JgD//yYA//8lAP/xLQv/n1VI/2lo - aP9iYmL/XFxc/1ZWVv9QUFD/SkpK/0RERP8+Pj7/ODg4/zIyMv8sLCz/JiYm/yAgIP8aGhr/FBQU/w4O - Dv8ICAj/AgIC/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/xIPYf8cGJj/GxeV/xsX - lf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsXlf8bF5X/GxeV/xsX - lf8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeT/xoWkv8dFJX/HRSU/xkXj/8WFpH/GBWR/ywniP+dnMX/yMrSl8TF1wAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPG0QDJzdCQpKS8/zIqYP8cEFf/HRJa/x0SWv8dElr/HRJa/x0S - Wv8dElr/HRJa/x0SWv8dFFn/HhRz/yIYmf8aFp7/GhqW/x0alf8eFpz/HBeb/xsZl/8cGJn/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBae/x0Xm/8fGZf/HRac/xkXnP8ZGJv/HRSX/1hPp//a3u3/6uvp/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vq5//q7OH/7ezi//Lp5v/25+j/9ufo//Ho6P/p6Or/4+ju/+Dp - 9P/T1vf/npfq/1FD0P8jG6//FxWi/xYUoP8aGJn/HxuW/x0Xmf8cF5z/HBec/xwXnP8cF5z/HBec/xwX - nP8cF53/HxqP/zQzP/88PDv/QkJC/0hISP9OTk7/VFRU/1paWv9gYGD/ZmZm/2xsbP9ycnL/eHh4/35+ - fv+EhIT/iYmJ/5CQkP+Wlpb/m5ub/6Ghof+np6f/ra2t/7Ozs/+5ubn/v7+//8TExP/Kysr/z8/P/9XW - 1v/exMD/9GBH//8mAP//JgD//yYA//8mAP//JgD//yUA//4qBf/wemX/3dLQ/9bX2P/R0dH/zMzM/8fH - x//BwcH/u7u7/7W1tf+vr6//qamp/6OkpP+4fnT/8DcX//8lAP//JgD//yYA//8mAP//JgD//yUA//At - C/+aUUT/Y2Jh/1tcXP9WVlb/UFBQ/0pKSv9ERET/Pj4+/zg4OP8yMjL/LCws/yYmJv8gICD/Ghoa/xQU - FP8ODg7/CAgI/wICAv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAv8TEWj/HBiZ/xwY - lv8cGJb/HBiW/xwYlv8cGJb/HBiW/xwYlv8cGJb/HBiW/xwYlv8cGJb/HBiW/xwYlv8cGJb/HBiW/xwY - lv8cGJX/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsYk/8bGJP/HhWW/x4Wlv8aGZH/GBiT/xoXk/8tKIn/npzF/8jK0pfExdcAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDxtEAyc3QmKWkvP8yKmD/HBBX/x0SWv8dElr/HRJa/x0S - Wv8dElr/HRJa/x0SWv8dElr/HRRa/x8Uc/8iGJn/Ghae/xoalv8dGpX/Hhac/xwXm/8bGZf/HBiZ/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwWnv8dF5v/HxmX/x0WnP8ZF53/GRib/x0Ul/9YT6f/2t7t/+rr6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/q6Ov/6eXw/+rp6f/v7t3/8vDY//Pt3v/x6Of/7eXu/+jm - 8P/l5+7/5urv/+Hn8v/Ex/P/fHPd/zoruv8fF6P/Hhaj/xwTpP8cFZ//HBec/xwXnP8cF5z/HBec/xwX - nP8cF5z/HBed/xwZlf8tLVL/Ozs5/0FBQf9GRkb/TU1N/1NTU/9ZWVn/Xl5e/2RkZP9ra2v/cHBw/3Z2 - dv98fHz/goKC/4iIiP+Ojo7/lJSU/5qamv+goKD/paWl/6urq/+xsbH/t7e3/7y8vP/CwsL/x8fH/8zN - zv/Xvbj/8l5E//8mAP//JgD//yYA//8mAP//JgD//yUA//4qBf/weWT/3tPR/9ja2v/U1NT/z8/P/8nJ - yf/ExMT/v7+//7m5uf+0tLT/rq6u/6ioqP+ioqL/nJ2d/7N5bv/vNhX//yUA//8mAP//JgD//yYA//8m - AP//JQD/7ywK/5ZMQP9cW1v/VVZW/09PT/9KSkr/Q0ND/z4+Pv84ODj/MTEx/ywsLP8lJSX/ICAg/xkZ - Gf8UFBT/Dg4O/wcHB/8CAgL/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8FBB3/GRWK/xwX - mf8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwX - mP8cF5j/HBeW/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bGJP/GxiT/x8Vl/8eFpb/GxmR/xgYk/8aF5T/LSiJ/56cxf/IytKXxMXXAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw8bRAMnN0JelpLz/Mipg/xwQV/8dElr/HRJa/x0S - Wv8dElr/HRJa/x0SWv8dElr/HRJa/x0UWv8fFHP/IhiZ/xoWnv8aGpb/HRqV/x8WnP8cF5v/GxmX/xwY - mf8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cFp7/HReb/x8Zl/8dFpz/GRed/xkYm/8dFJf/WE+n/9re7f/q6+n/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6ujq/+jn7v/o5+z/6enp/+rq5//s6en/7Ojq/+3p - 6P/s6+T/7Orm/+3o6f/s6+f/6e3o/93i7/+no+f/U0XI/yMVsv8XEqf/GRWe/xwXnP8cF5z/HBec/xwX - nP8cF5z/HBec/xwXnP8aGJv/Jihm/zo6OP8/Pz//RUVF/0tLS/9RUVH/V1dX/11dXf9jY2P/aWlp/29v - b/91dXX/enp6/4CAgP+Ghob/jIyM/5KSkv+YmJj/nZ2d/6Ojo/+pqan/rq6u/7S0tP+5ubn/vr6+/8PF - xf/PtLD/71tB//8mAP//JgD//yYA//8mAP//JgD//yUA//4qBf/veGP/3dHP/9jZ2v/U1NT/0NDQ/8zM - zP/Hx8f/wsLC/7y8vP+3t7f/sbGx/6ysrP+mpqb/oaGh/5ubm/+Vlpb/rnNp/+41FP//JQD//yYA//8m - AP//JgD//yYA//8lAP/uKwr/kkg7/1ZVVP9OT0//SUlJ/0NDQ/89PT3/Nzc3/zExMf8rKyv/JSUl/x8f - H/8ZGRn/ExMT/w0NDf8HBwf/AgIC/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/CAYq/xwX - l/8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwX - mP8cF5j/HBeY/xwXlv8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxiT/xsYk/8fFZf/HhaW/xsZkf8YGJP/GheU/y0oif+enMX/yMrSl8TF - 1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPG0QDJzdCWpaS8/zIqYP8cEFf/HRJa/x0S - Wv8dElr/HRJa/x0SWv8dElr/HRJa/x0SWv8dFFr/HhRz/yIYmf8aFp7/GRqW/x0alf8eFpz/HBec/xsZ - l/8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBae/x0Xm/8fGZf/HRac/xkXnf8ZGJv/HRSX/1hPp//a3u3/6uvp/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+rp6P/o6uf/5unq/+Xn7f/k5+7/5Onr/+fq - 6f/q6uf/7enn//Do6P/z6er/9Onq/+7m6f/q5u7/5OT5/8DB9/9qa9D/JiWt/xkVo/8bFp3/HBed/xwW - nf8cF5z/HBeb/xwXm/8cF5z/Ghec/x8iev82Nj3/Pj4+/0RERP9KSkr/UFBQ/1ZWVv9bW1v/YWFh/2dn - Z/9tbW3/c3Nz/3l5ef9+fn7/hISE/4qKiv+QkJD/lZWV/5ubm/+goKD/pqam/6urq/+xsbH/tra2/7q9 - vf/Hran/7Fc9//8mAP//JgD//yYA//8mAP//JgD//yUA//4qBf/td2L/2s/N/9bX2P/T09P/0NDQ/8zM - zP/IyMj/w8PD/7+/v/+6urr/tbW1/6+vr/+qqqr/pKSk/5+fn/+ZmZn/lJSU/46Pj/+pbmT/7TQU//8l - AP//JgD//yYA//8mAP//JgD//yUA/+4rCf+ORDf/T05O/0hISP9CQkL/PDw8/zY2Nv8wMDD/Kysr/yQk - JP8fHx//GRkZ/xMTE/8NDQ3/BwcH/wEBAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/xEO - X/8cF5r/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwX - mP8cF5j/HBeY/xwXmP8cF5b/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsX - lP8bF5T/GxeU/xsXlP8bF5T/GxeU/xsXlP8bGJP/HxWX/x4Wlv8bGZH/GBiU/xoXlP8tKIn/npzF/8jK - 0pfExdcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADExdIAy87UQqOiu/IzKmH/HRFY/x8U - XP8eE1v/HhNb/x4TW/8eE1v/HhNb/x4TW/8fFFv/HRRb/x0TdP8hGJr/GRaf/xgZmP8cGZj/HRWe/xwV - nv8aGJr/HBec/xwWnP8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwX - nP8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cFpz/HRed/x4Ynv8eGJ7/Hhie/x4Znv8dGZz/HRib/x0Y - m/8dGJv/HBea/xwXmv8cF5r/HBea/xsWnv8cF5v/HRmX/xwXnP8YF53/Fxib/xsUl/9XT6f/2t3t/+rr - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6uro/+np6f/o6Or/6Onq/+jp - 6f/p6en/6+np/+zo6v/t6Or/7ujq/+7o6v/t5+v/7Oft/+ro8P/o6Pf/2tf6/5aP0/89MbP/HRSp/xsU - ov8bEqT/HBWd/xwalP8cGpT/HBae/xsTpf8aGJn/MTFK/z09O/9CQkL/SEhI/05OTv9UVFT/WVlZ/19f - X/9lZWX/a2tr/3Fxcf92dnb/fHx8/4KCgv+Hh4f/jY2N/5OTk/+YmJj/nZ2d/6Ojo/+oqKj/ra2t/7G0 - tP/ApaH/6lQ6//8mAP//JgD//yYA//8mAP//JgD//yUA//4qBf/qdWD/1crI/9LT1P/Q0ND/zs7O/8vL - y//IyMj/xMTE/8DAwP+7u7v/tra2/7Kysv+tra3/p6en/6Kiov+dnZ3/l5eX/5KSkv+MjI3/hoeH/6Jp - X//rMxP//yUA//8mAP//JgD//yYA//8mAP//JgD/7ioI/4o/Mv9IR0f/QUFB/zs7O/81NTX/Ly8v/yoq - Kv8kJCT/Hh4e/xgYGP8SEhL/DAwM/wYGBv8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wIC - Df8WEnz/HBac/xwXmf8cF5n/HBeZ/xwXmf8cF5n/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaY/xsXl/8bF5f/GxeX/xsXl/8bF5f/GxeX/xsXl/8bF5f/GxeX/xwX - l/8cF5f/HBeX/xwXl/8cF5f/HBeX/xwXl/8cGJb/HBiU/x8WmP8fFZn/GxiV/xgXlv8aFpb/LSeK/56c - xv/IytKXxMXXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMXTAM7Q2yKjoLrrNCph/x0S - WP8fFFz/HxRc/x8UXP8fFFz/HxRc/x8UXP8fFFz/HxRc/xwUXP8cE3X/IBib/xgWn/8YGZj/GxiY/x0U - n/8bFaD/GReb/xwXnP8cFp3/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwW - nf8cFp3/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/x0Xnv8dF57/HRee/x0Xnv8eGJ7/Hhmd/x4Z - nP8eGZz/Hhmc/x0Ym/8dGJv/HRib/x0Ym/8cF57/HBib/x4ZmP8cF53/GBid/xcYnP8bFJj/V06o/9rd - 7v/q6+n/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+jq/+vn7P/r6en/6+no/+vq6P/s6uv/7Ofv/+3l9f/r4fr/qKPq/0g+ - wv8kF6z/GxKi/xwWof8aGpn/GxuW/xsYm/8bFqD/GRif/ygma/87Ozn/QEBA/0ZGRv9MTEz/UlJS/1dX - V/9dXV3/Y2Nj/2lpaf9vb2//dHR0/3p6ev9/f3//hYWF/4qKiv+QkJD/lZWV/5qamv+goKD/pKSk/6mr - q/+4npn/51E2//8lAP//JgD//yYA//8mAP//JgD//yUA//4qBf/ncl7/0MXD/83Oz//MzMz/y8vL/8nJ - yf/Gxsb/w8PD/8DAwP+8vLz/uLi4/7Ozs/+urq7/qqqq/6SkpP+fn5//mpqa/5WVlf+QkJD/ioqK/4WF - hf9+f4D/nGRa/+kyEv//JQD//yYA//8mAP//JgD//yYA//8mAP/uKQf/hjot/0FAQP86Ojv/NTQ0/y4u - Lv8pKSn/IyMj/x0dHf8XFxf/ERER/wsLC/8FBQX/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8IBzD/GxaZ/xsWm/8cF5r/HBea/xwXmv8cF5r/HBea/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xwX - mP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBiX/xwZlf8gFpn/HxWa/xwXl/8YFpj/GhWX/y0m - iv+enMb/yMrSl8TF1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTF0wDO0Nsko6G66zQq - Yf8dElj/HxRc/x8UXP8fFFz/HxRc/x8UXP8fFFz/HxRc/x8UXP8cFFz/HBN1/yAYm/8YFp//GBmY/xsY - mP8dFJ//GxWg/xkXm/8cF5z/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwW - nf8cFp3/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HRee/x0Xnv8dF57/HRee/x4Z - nv8eGZ3/Hhmd/x4Znf8eGZ3/Hhmd/x4Znf8eGZ3/HReg/x0Znf8fGpn/HRie/xkYn/8XGJ3/GxSY/1dO - qP/a3e7/6uvp/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vo6v/r5+z/6+np/+vp6P/r6ub/6+nn/+rn6v/q5O//6+X0/+Hk - 9v+2te7/WEvD/yQYqP8bFqL/Fxak/xkZn/8bHJj/HR2V/xobnP8iHor/NzZC/z4+Pf9ERET/SkpK/1BQ - UP9VVVX/W1tb/2FhYf9mZmb/bGxs/3Fxcf93d3f/fHx8/4KCgv+Hh4f/jIyM/5KSkv+Xl5f/nJyc/6Ci - ov+wlpH/5E80//8lAP//JgD//yYA//8mAP//JgD//yUA//0qBP/jb1v/yb69/8fIyP/Hx8f/xsbG/8XF - xf/Dw8P/wcHB/76+vv+7u7v/t7e3/7Ozs/+vr6//q6ur/6ampv+hoaH/nJyc/5eXl/+Tk5P/jY2N/4iI - iP+CgoL/fX19/3d4eP+WXlT/6DER//8lAP//JgD//yYA//8mAP//JgD//yYA/+0oBv+BNSj/Ojk5/zMz - M/8tLS3/KCgo/yIiIv8cHBz/FhYW/xAQEP8KCgr/BAQE/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAL/EA1f/xsWnf8bFpv/HBea/xwXmv8cF5r/HBea/xwXmv8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwYl/8cGZX/IBaZ/x8Vmv8cF5f/GBaY/xoV - l/8tJor/npzG/8jK0pfExdcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADExdMAztDcIqOg - uus0KmH/HRFZ/x8UXf8fFF3/HxRd/x8UXf8fFF3/HxRd/x8UXf8fFFz/HBRc/xwTdf8gF5v/GBaf/xcZ - mP8bGJj/HRSf/xsVoP8ZF5v/HBac/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwW - nf8cFp3/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HRee/x4Yn/8eGJ//Hhif/x4Y - nv8eGZ7/Hhme/x4Znv8eGZ7/Hxqf/x8an/8fGp//Hxqf/x4Yov8eGp//IBub/x8ZoP8aGaD/Fxid/xsU - mP9XTqn/2t3u/+rr6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6Or/6+fs/+vp6f/r6uf/6+rl/+zs5//t6+n/7Onr/+rn - 7P/p6ef/5ejs/8G+8/9fVMv/IRir/xgWpv8YGKX/HByb/x4flf8bHJ7/Hhyb/zIxT/88PDr/QkJC/0dH - R/9NTU3/U1NT/1hYWP9eXl7/Y2Nj/2lpaf9ubm7/dHR0/3l5ef9/f3//hISE/4mJif+Ojo7/k5OT/5eZ - mf+pjon/4Uwy//8mAP//JgD//yYA//8mAP//JgD//yUA//0pBP/ga1f/wre2/8DBwf/BwcH/wcHB/8HB - wf+/v7//vr6+/7y8vP+5ubn/tra2/7Ozs/+vr6//q6ur/6enp/+jo6P/np6e/5mZmf+UlJT/j4+P/4qK - iv+FhYX/gICA/3t7e/91dXX/b3Bw/5FZT//nMA///yUA//8mAP//JgD//yYA//8mAP//JgD/6ygF/3wx - JP8zMjL/Kyws/yYmJv8gICD/Gxsb/xUVFf8PDw//CQkJ/wMDA/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/BAQZ/xgTif8bFpz/Gxab/xwXmv8cF5r/HBea/xwXmv8cF5r/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cGJf/HBmV/yAWmf8fFZr/HBeX/xgW - mP8aFZf/LSaK/56cxv/IytKXxMXXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMXRAMvN - 0lmkorr3NCph/x4SWv8gFF7/HxRd/x8UXf8fFF3/HxRd/x8UXf8fFF3/IBVd/xwUXP8cE3X/IRib/xkX - oP8YGpn/GxiY/x0Un/8bFaD/Ghib/x0Ynv8dF57/HRee/x0Xnv8dF57/HRee/x0Xnv8dF57/HRee/x0X - nv8dF57/HRee/x0Xnv8dF57/HRee/x0Xnv8dF57/HRee/x0Xnv8dF57/HRee/x4Yn/8fGaD/Hxmg/x8Z - oP8fGaD/Hhmf/x4Zn/8eGZ//Hhmf/x8Zn/8fGp//Hxqf/x8ZoP8eGKP/Hhmg/yAbnP8fGKH/Ghmh/xgY - n/8cFJr/V06q/9rc7//q6+n/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6un/6+jq/+vn6//r6On/6+no/+vq5f/r6+X/6+rl/+vp - 5//p5+b/8Onl/+/r5v/l6PH/wsH4/19W0v8hGaz/Ghei/xwZoP8eG57/HBqg/x0cnf8oKHH/OTk7/z8/ - P/9FRUX/S0tL/1BQUP9WVlb/W1tb/2FhYf9mZmb/a2tr/3Fxcf92dnb/e3t7/4CAgP+FhYX/ioqK/46Q - kP+hhoH/30kv//8mAP//JgD//yYA//8mAP//JgD//yYA//0pBP/cZ1P/u7Cu/7m6uv+6urr/u7u7/7u7 - u/+7u7v/urq6/7i4uP+2trb/tLS0/7Gxsf+urq7/q6ur/6enp/+jo6P/n5+f/5qamv+Wlpb/kZGR/4yM - jP+Hh4f/goKC/319ff94eHj/c3Nz/21tbf9naGn/i1NJ/+YuDv//JgD//yYA//8mAP//JgD//yYA//8m - AP/qJwX/dywf/ywqKv8kJSX/Hx8f/xkZGf8UFBT/Dg4O/wgICP8CAgL/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wwKQ/8cF5z/Gxac/xsWm/8cF5v/HBea/xwXmv8cF5r/HBea/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsWmf8bFpn/GxaZ/xsW - mf8bFpn/GxaZ/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBiX/xwZlf8gFpn/HxWa/xwY - l/8YF5j/GhWX/y4ni/+dm8X/yMvSl8TF1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTF - 0ADKzM+ZpaO6/zQqYf8gE1v/IBVf/yAVX/8gFV//IBVf/yAVX/8gFV//IBVf/yAVXv8cFFz/HRR1/yIZ - nP8bGaL/Ghua/xsZmf8dFaD/GxWg/xoYnP8fGZ//Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hhij/x4Zof8gG5z/Hxih/xoZ - o/8ZGaH/HRWc/1hOrP/a3O//6uvq/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/7Orq/+zq6v/s6ur/7Orq/+zp6v/r6Or/6+np/+vp6P/r6ef/6+rm/+vq - 5v/r6ef/7Ono//Hn6f/x5+r/6ejp/+Pp8//Fxvv/YVfP/yEXo/8cFZ//HRei/xwcnP8dGaH/Hxmd/zIw - Uf89PTv/QkJC/0hISP9NTU3/U1NT/1hYWP9eXl7/Y2Nj/2hoaP9tbW3/c3Nz/3h4eP99fX3/goKC/4aI - iP+afnr/3EYs//8mAP//JgD//yYA//8mAP//JgD//yYA//0pBP/ZZE//s6im/7Gzs/+zs7P/tLS0/7W1 - tf+1tbX/tbW1/7S0tP+ysrL/sbGx/66urv+srKz/qamp/6ampv+ioqL/n5+f/5ubm/+Wlpb/kpKS/42N - jf+JiYn/hISE/39/f/96enr/dXV1/3BwcP9ra2v/ZWZm/19hYf+GTUP/5S0N//8mAP//JgD//yYA//8m - AP//JgD//yYA/+onBP9zJxr/JSMj/x0dHv8YGBj/EhIS/wwMDP8HBwf/AQEB/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wICDP8WEnz/HBee/xwXnP8cF5z/HBeb/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5n/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwYl/8cGZX/IBaZ/x8V - mv8cGJf/GReY/xoUlv8uJ4v/nZvF/8nL0pfDxNcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADExdAAyszPl6Wjuv80KmH/IBNc/yAUYP8gFGD/IBRg/yAUYP8gFGD/IBRg/yAUYP8gFF//HBRc/x0U - df8iGZz/Gxmi/xobmv8cGpr/Hhah/xwWof8bGZ3/Hxmf/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x4YpP8eGKH/IBqd/x8Y - ov8aGaP/GRmi/x0Unf9YTqz/2tzw/+rr6v/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+zq6v/s6ur/7Orq/+zq6v/s6ur/7Onq/+zq6v/s6ur/7Orp/+zq - 6f/s6un/7Orp/+zp6v/u6O3/7+fu/+/r7f/p6ur/5ury/8fG9f9fU8j/Ihik/x0YoP8dHpj/HRam/xwQ - sv8mIIH/Ojo7/z8/P/9FRUX/SkpK/1BQUP9VVVX/W1tb/2BgYP9lZWX/ampq/29vb/90dHT/eXl5/3x/ - f/+Sd3L/2kMp//8mAP//JgD//yYA//8mAP//JgD//yUA//0pBP/VYEz/rKGf/6mrq/+srKz/ra2t/6+v - r/+vr6//r6+v/6+vr/+urq7/ra2t/6urq/+pqan/p6en/6SkpP+hoaH/np6e/5qamv+Wlpb/kpKS/46O - jv+Kior/hYWF/4GBgf98fHz/d3d3/3Jycv9tbW3/aGho/2NjY/9dXl7/V1lZ/4BHPf/jLAz//yYA//8m - AP//JgD//yYA//8mAP//JgD/6iYD/28jFf8dHBz/FhYW/xAQEP8LCwv/BQUF/wEBAf8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8LCT//HBea/xwXnP8cF5z/HBec/xwXm/8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBeZ/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cGJf/HBmV/yAW - mf8fFZr/HBiX/xkXmP8aFJb/LieL/52bxf/Jy9KXw8TXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAxMXQAMrMz5elo7r/NCph/yATXP8gFGD/IBRg/yAUYP8gFGD/IBRg/yAUYP8gFGD/IBRf/xwU - XP8dFHX/Ihmc/xsZov8aHJv/Hhub/x8Xov8dGKL/HBqe/x8an/8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hxih/x8Yof8fGKH/Hxih/x8Yof8fGKH/Hxih/x8Yof8eF6T/Hhih/yAa - nv8fGKP/Ghik/xkYov8dFJ3/WE6s/9rc8P/q6+r/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp - 6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/s6ur/7Orq/+zq6v/s6ur/7Orq/+3r6//t6+v/7err/+3q - 7P/t6uz/7ers/+3q7P/s6uz/6Ozr/+rt7v/u6O7/8urt/+7r5v/o6+3/wsLz/1NKxf8fGKX/Hhqd/x0Y - ov8bFKz/Gxmd/zEyT/89PTv/QkJC/0dHR/9NTU3/UlJS/1dXV/9cXFz/YWFh/2ZmZv9ra2v/cHBw/3N2 - dv+Kb2r/2EAm//8mAP//JgD//yYA//8mAP//JgD//yUA//wpBP/RXUn/pJmY/6Gio/+kpKT/pqam/6en - p/+oqKj/qamp/6mpqf+pqan/qKio/6enp/+lpaX/o6Oj/6Ghof+fn5//nJyc/5mZmf+VlZX/kpKS/46O - jv+Kior/hoaG/4GBgf99fX3/eHh4/3R0dP9vb2//ampq/2VlZf9gYGD/W1tb/1VWVv9QUVH/eUE4/+Ir - C///JgD//yYA//8mAP//JgD//yYA//8mAP/qJQP/ax0Q/xUVFP8ODw//CQkJ/wMDA/8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8DAhH/FxN+/xwXnv8cF5z/HBec/xwXnP8cF5v/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5r/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmf8cF5j/HBeY/xwXmP8cF5j/HBeY/xwXmP8cF5j/HBiX/xwZ - lP8gFZn/HxWa/xwYl/8ZF5j/GhSW/y4ni/+dm8X/ycvSmcPE1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMTF0ADJzM+XpKO6/zMqYv8fE1z/IBRg/yAUYP8gFGD/IBRg/yAUYP8gFGD/IBRg/yAU - YP8cFF3/HRR1/yIZnf8bGKL/Gxyb/x4bnP8gF6P/Hhij/xwan/8eGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Yof8fGKH/Hxih/x8Yof8fGKH/Hxih/x8Yof8fGKH/HRik/x0Z - oP8fGp3/Hhij/xoYpP8ZGaL/HRWc/1hOrf/a2/D/6urr/+ro6v/q6Or/6+jq/+vo6//r6Ov/6+fs/+vn - 7P/r6Ov/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+rp - 6f/q6en/6unp/+rp6f/r6en/6+np/+vp6f/r6en/6+rq/+zq6v/s6ur/7Orq/+zq6v/t6+r/7evr/+3q - 7P/t6u3/7ent/+3p7v/t6e3/7Ort/+fv6P/o7+n/7uvv//Tq7v/y7OX/7e7m/+Xq9f+0tfL/ST3B/x4U - qv8cHJv/Gxue/xsbn/8lJ3f/OTk8/z8/Pv9ERET/SUlJ/05OTv9TU1P/WVlZ/11dXf9jY2P/Z2dn/2tt - bf+DZ2P/1T4j//8mAP//JgD//yYA//8mAP//JgD//yUA//wpBP/MWkb/nJKQ/5mbm/+cnJz/np6e/6Cg - oP+hoaH/oqKi/6Ojo/+jo6P/o6Oj/6Kiov+hoaH/oKCg/56env+cnJz/mpqa/5eXl/+UlJT/kZGR/42N - jf+JiYn/hoaG/4KCgv9+fn7/eXl5/3V1df9wcHD/bGxs/2dnZ/9iYmL/XV1d/1hYWP9TU1P/Tk5O/0dI - Sf9zPDL/4CoK//8mAP//JgD//yYA//8mAP//JgD//yYA/+okAv9mGQv/Dg0N/wcHB/8CAgL/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAH/DgtO/xwXm/8cF5z/HBec/xwXnP8cF5z/HBeb/xwXm/8cF5v/HBeb/xwX - m/8cF5v/HBeb/xwXm/8cF5v/HBeb/xwXm/8cF5v/HBeb/xwXm/8cF5v/HBeb/xwXm/8cF5v/HBea/xwX - mv8cF5r/HBea/xwXmv8cF5r/HBea/xwXmv8cF5n/HBeZ/xwXmf8cF5n/HBeZ/xwXmf8cF5n/HBeZ/xwX - mP8cGJb/HhaZ/x4Vm/8bF5n/GBiY/xoVlv8vJ43/nJrF/8rM0oHExdYAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADDxdAAyMzPl6Oiu/8yKWT/HxJe/yATYf8gE2H/IBNh/yATYf8gE2H/IBNh/yAT - Yf8gE2H/HBNe/x0Tdv8iGJ7/Gxik/xsbnf8eG53/IBek/x4XpP8cGaD/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/xoZ - of8aG53/HBue/xwXpv8ZF6X/GRqg/x0Wm/9aT67/2tnx/+jq7P/o6Ov/6ejr/+no6//p6Oz/6eft/+nn - 7f/p5+3/6ufs/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6urq/+rq6v/q6ur/6urq/+rq - 6v/p6en/6enp/+np6f/p6en/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr - 6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//q7On/6uzo/+vs6P/s7Oj/6+vn/+zr6//p6PH/6uX5/7Cn - 5v81Lbz/GRqa/x0dlf8hHZ3/IRqb/y8sXP87Ozv/QEBA/0VFRf9LS0v/UFBQ/1VVVf9aWlr/X19f/2Jk - ZP97X1v/0jsg//8mAP//JgD//yYA//8mAP//JgD//yYA//woA//IVkL/lIqI/5GSkv+UlJT/lpaW/5iY - mP+ampr/m5ub/5ycnP+dnZ3/nZ2d/52dnf+cnJz/m5ub/5qamv+YmJj/lpaW/5SUlP+SkpL/j4+P/4yM - jP+IiIj/hYWF/4GBgf99fX3/eXl5/3V1df9xcXH/bGxs/2hoaP9jY2P/X19f/1paWv9VVVX/UFBQ/0tL - S/9FRkb/QEFB/2w2LP/eKAn//yYA//8mAP//JgD//yYA//8mAP//JgD/6SQB/2EUBv8HBQX/AAEB/wAA - AP8AAAD/AAAA/wAAAP8AAAD/BgUf/xkVjP8cF5v/HBea/xwXmv8cF5r/HBea/xwXnP8cFp3/HBad/xwW - nf8dF53/Hhif/x4Yn/8eGJ//Hhif/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HBec/xwX - nP8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwXm/8cF5z/HBec/xwXnP8cF5z/HBec/xwX - nP8cF5z/Gxea/xwZmP8dFp3/Gxae/xgZmP8aGJX/MSeR/5yWx+zQ0NspxcTYAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAwsXQAMjMz5ejorz/Milk/x8SX/8gE2H/IBNh/yATYf8gE2H/IBNh/yAT - Yf8gE2H/IBNh/xwTXv8dEnf/Ihie/xsYpP8bG53/Hhud/yAXpP8eF6T/HBmg/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8aGaH/Ghud/xwbnv8bF6b/GRij/xkbnv8eF5n/WVCs/9nZ8f/r6ur/6+no/+vq5//r6+X/6uvk/+ns - 4//p7OL/6e3h/+ns5P/r6ej/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+rq6v/q6ur/6urq/+rq - 6v/q6ur/6urq/+rq6v/q6ur/6urq/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr - 6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vq/+vs6f/r7Oj/6+zo/+rq6P/q6uz/7Onw/+zn - 8//m4/v/jY7g/ysjrP8eGJr/IBmi/x4Xpf8hHo//NTVC/z09PP9CQkL/R0dH/0xMTP9RUVH/VlZW/1lb - W/90V1P/zzge//8mAP//JgD//yYA//8mAP//JgD//yYA//woA//EUT3/jIKA/4mKiv+MjIz/j4+P/5GR - kf+Tk5P/lJSU/5WVlf+Wlpb/lpaW/5eXl/+Wlpb/lpaW/5WVlf+UlJT/k5OT/5GRkf+Pj4//jIyM/4qK - iv+Hh4f/g4OD/4CAgP99fX3/eXl5/3V1df9xcXH/bW1t/2lpaf9kZGT/YGBg/1tbW/9WVlb/UlJS/01N - Tf9ISEj/Q0ND/z4+Pv84OTn/ZzAm/90nB///JgD//yYA//8mAP//JgD//yYA//8mAP/oIwH/XA8C/wIA - AP8AAAD/AAAA/wAAAP8AAAD/AQEF/xMQaP8dGJ3/HRib/x0Ym/8dGJv/HRib/x0Ym/8dF53/HRee/x0X - nv8dF57/HRee/x4Yn/8eGJ//Hhif/x4Yn/8cFp3/HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwW - nf8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwX - nP8cF5z/HBec/xoXm/8cGZj/HRad/xsWn/8YGZj/GRiU/zEnkv+clsfr0NHdJMXE2AAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLF0ADIzM+Xo6K8/zIpZP8fEl//IBNh/yATYf8gE2H/IBNh/yAT - Yf8gE2H/IBNh/yATYf8cE17/HRJ3/yIYnv8bGKT/Gxud/x4bnf8gF6T/Hhek/xwZoP8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/Gxmh/xsan/8dGp7/HBik/xkZov8YHJz/HRmX/1lRqv/Z2vD/7unr/+/o6v/u6ej/7erl/+zr - 5P/q7eL/6e7g/+ju3//p7eH/6+no/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/q6ur/6urq/+rq - 6v/q6ur/6urq/+rq6v/q6ur/6urq/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr - 6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+zq/+vs6v/s7Ov/7e3t/+rp - 7f/s6fD/6erz/9Xc9f93bNb/KBir/x4Vqf8ZF6b/GByd/yQndP85OD3/Pz8+/0NDQ/9ISEj/TU1N/1BS - Uv9sUEv/zTYb//8mAP//JgD//yYA//8mAP//JgD//yYA//soA//BTTn/hHp4/4CBgv+EhIT/hoaG/4mJ - if+Li4v/jY2N/46Ojv+Pj4//kJCQ/5GRkf+RkZH/kZGR/5CQkP+Pj4//jo6O/42Njf+Li4v/iYmJ/4eH - h/+EhIT/goKC/39/f/97e3v/eHh4/3V1df9xcXH/bW1t/2lpaf9lZWX/YGBg/1xcXP9XV1f/U1NT/05O - Tv9JSUn/RUVF/0BAQP87Ozv/NTY2/y8xMf9hKiD/3CYG//8mAP//JgD//yYA//8mAP//JgD//yYA/+Yi - AP9aDQD/AgAA/wAAAP8AAAD/AAAA/w0LQ/8dGZn/Hhme/x4Znv8eGZ7/Hhme/x4Znv8eGZ7/Hhmf/x4Y - n/8eGJ//Hhif/x4Yn/8eGJ//Hhif/x4Yn/8eGJ//HBad/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwW - nf8cFp3/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwX - nP8cF5z/HBec/xwXnP8aF5v/HBmY/x0Wnf8bFp//GBmY/xkYlP8xJ5L/nJbH69DR3STFxNgAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCxdAAyMzPl6OivP8yKWT/HxJf/yATYf8gE2H/IBNh/yAT - Yf8gE2H/IBNh/yATYf8gE2H/HBNe/x0Sd/8iGJ7/Gxik/xsbnf8eG53/IBek/x4XpP8cGaD/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/xwYo/8dGaD/Hxqf/x0YpP8YGqD/Fx2a/xwalv9XUqr/2Nrw/+/n7f/x5e3/7+bs/+7n - 7P/s5+z/6ujr/+no6v/o6er/6Onp/+vp6f/r6en/6+np/+vp6f/r6en/6+np/+vp6f/r6en/6urq/+rq - 6v/q6ur/6urq/+rq6v/r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr - 6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6uz/6+rs/+vr6//r6+v/6+vr/+rq - 6v/r6+v/6urr/+jq6f/q7+3/zsz0/1pIyv8eEav/Fxek/xYboP8ZG5v/Ly5W/zs7Of9AQED/RERE/0dJ - Sv9kSEP/yjMZ//8mAP//JgD//yYA//8mAP//JgD//yYA//soA/+8STX/fHFw/3h5ef98fHz/fn5+/4GB - gf+Dg4P/hYWF/4aGhv+IiIj/iYmJ/4qKiv+Kior/i4uL/4uLi/+Kior/ioqK/4iIiP+Hh4f/hoaG/4SE - hP+BgYH/f39//3x8fP96enr/d3d3/3Nzc/9wcHD/bGxs/2hoaP9lZWX/YGBg/1xcXP9YWFj/VFRU/09P - T/9LS0v/RkZG/0FBQf88PDz/ODg4/zMzM/8tLi7/Jygp/1skGv/bJQX//yYA//8mAP//JgD//yYA//8m - AP//JgD/5yIA/1sNAP8CAAD/AAAA/wYFH/8cGJD/Hxqg/x8an/8fGp//Hxqf/x8an/8fGp//Hxqf/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hhif/x4Yn/8eGJ//Hhif/xwWnf8cFp3/HBad/xwWnf8cFp3/HBad/xwW - nf8cFp3/HBad/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/xwX - nP8cF5z/HBec/xwXnP8cF5z/Gheb/xwZmP8dFp3/Gxaf/xgZmP8ZGJT/MSeS/5yWx+zQ0NsoxcTYAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw8bRAMjMz5ekpL3/NCpm/x8SX/8gE2H/IBNh/yAT - Yf8gE2H/HxJg/x8SYP8fEmD/HxNg/x0UXv8eFHj/Ixmf/xwYpf8bG57/Hhud/yAXpP8eF6T/HBmg/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8eGKX/Hxqk/yEbov8eGab/GRuh/xccmv8dG5n/V1Kt/9nb8P/s6ej/7+jm/+/p - 6f/v6Ov/7enu/+rn7v/p5e//6Obw/+fl7f/s6uv/7Orq/+vp6f/q6Oj/7Orq/+3r6//t6+v/7evr/+zr - 6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr - 6//r6+v/7Ozs/+3t7f/t7e3/7e3t/+3t7f/t7e3/7e3t/+3t7f/t7e3/7ezt/+3s7f/t7O3/7ezt/+3s - 7f/s7Oz/7e7s/+3u6//u7ur/8O/n/+vt8f+zre//OC61/xkWov8XF6X/GRik/yAekP8xMFH/PDw7/z5A - Qf9dQTz/yTAW//8mAP//JgD//yYA//8mAP//JgD//yYA//soA/+4RTH/c2ln/29xcf9zc3P/dnZ2/3l5 - ef97e3v/fX19/39/f/+BgYH/goKC/4ODg/+EhIT/hYWF/4WFhf+FhYX/hISE/4SEhP+Dg4P/gYGB/4CA - gP9+fn7/fHx8/3p6ev94eHj/dXV1/3Jycv9vb2//a2tr/2hoaP9kZGT/YGBg/1xcXP9YWFj/VFRU/1BQ - UP9LS0v/R0dH/0NDQ/8+Pj7/OTk5/zQ0NP8vLy//Kysr/yUmJv8fICH/VR4U/9kjA///JgD//yYA//8m - AP//JgD//yYA//8mAP/nIgD/Ww0A/wUDE/8VEnX/Hxmh/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8eGJ//Hhif/x4Yn/8eGJ//HRee/xwW - nf8cFp3/HBad/xwWnf8cF5z/HBec/xwXnP8cF5z/HBec/xwXnP8cF5z/HBec/x0Ynf8eGZ7/Hhme/x4Z - nv8dGJ3/HBec/xwXnP8cF5z/HBec/xoXm/8cGZj/HRad/xsWn/8ZGpn/GhmV/zAmkf+fmcf/y87OfsXG - 1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPG0QDIzM+XpaS9/zQrZv8gEl//IBNh/yAT - Yf8gE2H/IBNh/x8SYP8fEmD/HxJg/x8TYP8dFF7/HhR4/yMaoP8cGaX/Gxue/x4bnf8gF6T/Hhek/xwZ - oP8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/Hxil/yEapP8iG6P/IBmn/xscpP8XHJ3/Gxib/1VOsP/W2PH/5urj/+nr - 3v/q7OH/7O3l/+vs5//p6uf/6enp/+rp6//o5+n/6ujo/+ro6P/r6en/6+np/+3r6//t6+v/7evr/+3r - 6//s6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr - 6//r6+v/6+vr/+zs7P/t7e3/7e3t/+3t7f/t7e3/7e3t/+3t7f/t7e3/7e3t/+3t7f/t7ez/7e3t/+3s - 7v/t7O7/7e3t/+3u7P/t7ur/7+/p/+/s5v/t7e7/4Oj4/4qJ2/8oIKj/GxSn/xsZof8bGaD/Ih6J/zM1 - Qv9VOTP/xy4T//8mAP//JgD//yYA//8mAP//JgD//yYA//snAv+zQi7/a2Fg/2ZoaP9ra2v/bm5u/3Bw - cP9zc3P/dXV1/3d3d/95eXn/e3t7/3x8fP99fX3/fn5+/35+fv9/f3//f39//35+fv9+fn7/fX19/3t7 - e/96enr/eHh4/3d3d/90dHT/cnJy/29vb/9sbGz/aWlp/2ZmZv9jY2P/X19f/1xcXP9YWFj/VFRU/1BQ - UP9MTEz/SEhI/0NDQ/8/Pz//Ojo6/zU1Nf8xMTH/LCws/ycnJ/8iIiL/HR0e/xcYGP9OGA7/1yIC//8m - AP//JgD//yYA//8mAP//JgD//yYA/+giAP9pGUf/Hxmg/x4Zof8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x4Y - n/8dF57/HRee/x0Xnv8dF53/HRid/x0Ynf8dGJ3/HRid/x0Ynf8dGJ3/HRid/x0Ynf8eGZ7/Hhme/x4Z - nv8eGZ7/HRid/xwXnP8cF5z/HBec/xwXnP8aF5v/HBmY/x0Wnf8bFp//GRuZ/xoZlf8wJpH/n5rG/8vO - zZnFxtMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDxtEAyMzPl6Wkvf80K2b/IBJf/yAT - Yf8gE2H/IBNh/yATYf8gE2H/IBNh/yATYf8gFGH/HRRf/x4UeP8jGqD/HBml/xsbnv8eG53/IBek/x4X - pP8cGaD/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x8Ypv8iGaX/Ihqj/yEYqP8bGqX/GRyi/xsWoP9WTbb/2Nj5/+ns - 9P/p7PD/6ezv/+ns7//q7O3/6uvq/+rr5//r6+b/6urm/+no5//r6ej/7Orq/+3r6//t6+v/7evr/+3r - 6//t6+v/7Ovr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr - 6//r6+v/6+vr/+vr6//s7Oz/7e3t/+3t7f/t7e3/7e3t/+3t7f/t7e3/7e3t/+3t7f/t7uv/7e/p/+3u - 6//t7e3/7ezu/+3t7f/t7uz/7e7q/+7v6f/t7On/6+vt/+fx7v/U2/f/Z13J/yIYn/8cGKH/Ghao/xkY - p/9EJWb/xCsP//8mAP//JgD//yYA//8mAP//JgD//yYA//onAv+uPir/Y1lY/19gYP9iYmL/ZWVl/2ho - aP9ra2v/bW1t/29vb/9xcXH/c3Nz/3V1df92dnb/d3d3/3h4eP94eHj/eXl5/3l5ef94eHj/eHh4/3d3 - d/92dnb/dXV1/3Nzc/9xcXH/b29v/21tbf9qamr/Z2dn/2RkZP9hYWH/Xl5e/1tbW/9XV1f/VFRU/1BQ - UP9MTEz/SEhI/0RERP8/Pz//Ozs7/zY2Nv8yMjL/LS0t/ykpKf8kJCT/Hx8f/xsbG/8VFRX/DxAQ/0cS - CP/VIAH//yYA//8mAP//JgD//yYA//8mAP//JgD/6yUP/28dZv8gGKD/Hhih/x8Yof8fGKH/Hxih/x8Y - of8fGKH/Hxih/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8eGJ//Hhif/x4Yn/8eGJ//Hhif/x4Znv8eGZ7/Hhme/x4Znv8eGZ7/Hhme/x4Znv8eGZ7/Hhme/x4Z - nv8eGZ7/Hhme/x0Ynf8cF5z/HBec/xwXnP8cF5z/Gheb/xwZmP8dFp3/Gxaf/xkbmf8aGZX/MCaR/5+a - xv/Lzs2XxcbTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw8bRAMjMz5qlpL3/NCtm/yAS - X/8gE2H/IBNh/yATYf8gE2H/IRRi/yEUYv8hFGL/IRRi/x4VX/8eFHj/Ixqg/xwZpf8bG57/Hhud/yAX - pP8eF6T/HBmg/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8fF6b/Ihmm/yMao/8hGKj/Gxmn/xkbpP8bFaP/PTOl/4aD - t/+XlMD/n5rK/6yo1P+4s9r/yMPi/9fU6P/j3uz/6+fu//Dt8P/v7e//7uzt/+3r6//t6+v/7evr/+3r - 6//t6+v/7evr/+zr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr - 6//r6+v/6+vr/+vr6//r6+v/7Ozs/+3t7f/t7e3/7e3t/+3t7f/t7e3/7e3t/+3t7f/t7e3/7e/p/+3w - 5//t7+n/7e3t/+3s7v/t7O7/7e3t/+3u6//t7uv/7Ozt/+jr6f/n7O3/5ur2/7y77/9GPa//HhKp/xcT - sP85G5T/vCIx//8mAP//JgD//yYA//8mAP//JgD//yYA//onAv+qOSX/WlFP/1ZXV/9aWlr/XV1d/2Bg - YP9jY2P/ZWVl/2hoaP9qamr/a2tr/21tbf9vb2//cHBw/3Fxcf9ycnL/cnJy/3Nzc/9ycnL/cnJy/3Jy - cv9xcXH/cHBw/25ubv9tbW3/a2tr/2lpaf9nZ2f/ZWVl/2JiYv9fX1//XFxc/1lZWf9WVlb/U1NT/09P - T/9LS0v/R0dH/0NDQ/8/Pz//Ozs7/zc3N/8zMzP/Li4u/yoqKv8lJSX/ISEh/xwcHP8XFxf/EhIS/w0N - Df8HCAj/QQwC/9QfAP//JgD//yYA//8mAP//JgD//yYA//8mAP/rJA7/cB1m/yEYoP8eGKH/Hxih/x8Y - of8fGKH/Hxih/x8Yof8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8Z - oP8fGaD/Hxmg/x8ZoP8fGaD/Hxmg/x8ZoP8fGp//Hxqf/x8an/8fGp//Hxqf/x8an/8fGp//Hxqf/x4Z - nv8eGZ7/Hhme/x4Znv8dGJ3/HBec/xwXnP8cF5z/HBec/xoXm/8cGZj/HRad/xsWn/8ZG5n/GhmV/zAm - kf+fmsf/y87Nl8XG0wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHE0QDIzNFcoqG89zUr - Z/8fEl//IBRi/yAVYv8gFWL/IBVi/yEVY/8hFWP/IRVj/yEWY/8eFGD/HRR6/yIZof8bGKb/Ghuf/x0a - nv8gFqX/HRam/xsZof8dGaL/HRii/x0Yov8dGKL/HRii/x0Yov8dGKL/HRii/x0Yo/8cGKT/HBik/xwY - pP8cGKT/HBik/xwYpP8cGKT/HBik/x0ZpP8dGaX/HRml/x0Zpf8dGaX/HRml/x0Zpf8dGaX/HRml/x0Z - pf8dGaX/HRml/x0Zpf8dGaX/HRml/x0Zpf8dGaX/Hhin/yAZp/8gGaX/Hxio/xwZp/8ZGKT/Hhio/x8Y - mv8eGoH/HhZ//yAXgv8lHYP/KiKB/zMtg/9BPIr/U1CW/3FvsP+Vksn/u7bd/9jW7//p6fT/7O/u/+zu - 5//u7Ob/8Orr//Ho7v/x5/L/8Onw/+3r6f/r7ef/6uzo/+rq7f/r6fD/7enu/+7r6//t7Ov/7O3s/+zt - 7P/s7ez/7O3s/+zt7P/s7ez/7O3s/+zt6//s7Ov/7Ozr/+zs6//s7ez/7e3s/+3u7P/t7uz/7e7s/+3v - 6v/u7+n/7u/r/+7u7f/u7u3/7u7u/+7u7f/u7+z/7e7s/+vu7f/r7e3/7ev0/+vt8v/k7vD/k5La/ycb - sP84FZj/uiEy//8mAP//JgD//yYA//8mAP//JgD//yYA//onAv+nNSH/UkhH/01OTv9RUVH/VFRU/1dX - V/9aWlr/XV1d/19fX/9iYmL/ZGRk/2ZmZv9oaGj/aWlp/2pqav9ra2v/bGxs/2xsbP9tbW3/bW1t/2xs - bP9sbGz/a2tr/2pqav9paWn/Z2dn/2ZmZv9kZGT/YmJi/19fX/9dXV3/Wlpa/1dXV/9VVVX/UVFR/05O - Tv9KSkr/R0dH/0NDQ/8/Pz//Ozs7/zc3N/8zMzP/Ly8v/yoqKv8mJib/IiIi/x0dHf8YGBj/FBQU/w8P - D/8KCgr/BQUF/wABAf8/CQD/1R8A//8mAP//JgD//yYA//8mAP//JgD//yYA/+okDv9vHWb/IBmf/x0Y - of8eGaD/Hhmg/x4ZoP8eGaD/Hhmh/x4Zof8eGaH/Hhmh/x4Zof8eGaH/Hhmh/x4Zof8eGaH/Hhmh/x4Z - of8eGaH/Hhmh/x4Zof8eGaH/Hhmh/x4Zof8eGaD/Hhmg/x4ZoP8eGaD/Hhmg/x4ZoP8eGaD/Hhmg/x4Z - oP8eGZ//HRmf/x0Zn/8eGZ//HRmf/x0Ynv8dGJ7/HRie/xwXn/8aFp7/HBiY/x0WnP8bFZ//GRqb/xsY - mf8xJpX/oJrI/8vOzZfGxtMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/wtEAyMzZIqCf - uus1LGf/HxJf/yEWY/8gFmP/IBZj/yAWY/8gFmP/IBZj/yAWY/8gFmP/HRRh/x0Te/8iGaL/Gheo/xka - oP8dGqD/Hxam/xwWp/8aGKP/HRij/x0Yo/8dGKP/HRij/x0Yo/8dGKP/HRij/x0Yo/8cGKT/Gxem/xsX - pv8bF6b/Gxem/xsXpv8bF6b/Gxem/xsXpv8dGaf/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0Z - qP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/Gxim/xsX - pv8cGKb/HBil/yEapv8hGqT/Hxig/x0XnP8aFpf/GheT/xcVjv8UFIr/HBiH/y0kg/9KQ5H/dXOp/6yt - zP/Y2+f/7O7x/+7s7v/w6+//8evu//Dr7P/u6+r/7ezr/+vs7P/q6u3/7Onu/+7p7//u6e7/7u3t/+3u - 7P/t7uz/7e7s/+3u7P/t7uz/7e7s/+3u7P/t7uv/6+zq/+vs6v/r7Or/7O3r/+3u7P/t7uz/7e7s/+3u - 7P/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+3w7P/r8Ov/7e3w//Dq9v/v7u3/6fPl/9Ha - 8/93WrP/uyAz//8mAP//JgD//yYA//8mAP//JgD//yYA//kmAf+jMR3/SkA//0RFRf9JSUn/TExM/09P - T/9SUlL/VFRU/1dXV/9aWlr/XFxc/15eXv9gYGD/YWFh/2NjY/9kZGT/ZWVl/2ZmZv9mZmb/ZmZm/2Zm - Zv9mZmb/ZmZm/2VlZf9kZGT/Y2Nj/2FhYf9gYGD/Xl5e/1xcXP9aWlr/V1dX/1VVVf9SUlL/T09P/0xM - TP9JSUn/RUVF/0JCQv8+Pj7/Ozs7/zc3N/8zMzP/Ly8v/ysrK/8mJib/IiIi/x4eHv8ZGRn/FRUV/xAQ - EP8LCwv/BwcH/wICAv8AAAD/AAAA/0AJAf/WIQf//yYA//8mAP//JgD//yYA//8mAP//JgD/6iUP/28d - Zv8fGZ7/HBmg/x0ZoP8dGaD/HRmg/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0Z - oP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGKH/GxWh/xwYmv8dF5z/Gxaf/xkY - nP8cF53/MyaZ/6Gbyv/Lzs2XxsfTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv8LRAMjM - 2CSgn7rrNSxn/x8SX/8hFmP/IBZj/yAWY/8gFmP/IBZj/yAWY/8gFmP/IBZj/x0UYf8dE3v/IRmi/xoY - qP8ZGqD/HRqg/x8Wpv8cFqf/Ghij/x0Yo/8dGKP/HRij/x0Yo/8dGKP/HRij/x0Yo/8dGKP/HBik/xsX - pv8bF6b/Gxem/xsXpv8bF6b/Gxem/xsXpv8bF6b/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0Z - qP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/xwY - p/8cGKf/HBin/x0YqP8gF6n/IRep/yEYqf8hGKf/IRmm/yAZo/8iHKP/Ih2j/yAZn/8eFpz/HRWU/xoT - h/8kH4D/SEeQ/4aJuf/Hz+T/5O/z/+n05//r8eP/7evv/+zl8v/u5+//7+vp/+7t5v/s6uz/6+jy/+3s - 7v/t7uz/7e7s/+3u7P/t7uz/7e7s/+3u7P/t7uz/7e7s/+zt6//s7ev/7O3r/+zt6//t7uz/7e7s/+3u - 7P/t7uz/7u/t/+7v7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v7f/t7+3/6/Dr/+3v7P/w7PL/8evz/+rs - 7v/j7vT/zbXP/+E5Lf//JQD//yYA//8mAP//JgD//yYA//kmA/+eLBv/Qjg1/zs9Pf9AQED/RERE/0dH - R/9KSkr/TExM/09PT/9SUlL/VFRU/1ZWVv9YWFj/Wlpa/1xcXP9dXV3/Xl5e/19fX/9gYGD/YGBg/2Fh - Yf9hYWH/YGBg/2BgYP9fX1//Xl5e/11dXf9cXFz/Wlpa/1lZWf9XV1f/VVVV/1JSUv9QUFD/TU1N/0pK - Sv9HR0f/RERE/0FBQf89PT3/Ojo6/zY2Nv8zMzP/Ly8v/ysrK/8nJyf/IiIi/x4eHv8aGhr/FhYW/xER - Ef8NDQ3/CAgI/wMDA/8AAAD/AAAA/wEBBv8KCkP/VBtv/9okG///JgD//yYA//8mAP//JgD//yYA//8m - AP/qJQ7/bx1m/x8Zn/8cGaD/HRmg/x0ZoP8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0Z - oP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRih/xwWov8dGZv/Hhid/xwX - oP8ZGZ3/HBed/zMmmf+hm8r/y87Nl8bH0wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/C - 0QDIzNgkoJ+66zUsZ/8fEl//IRZj/yAWY/8gFmP/IBZj/yAWY/8gFmP/IBZj/yAWY/8dFGH/HRN7/yEZ - ov8aF6j/GRqg/x0aoP8fFqb/HBan/xoYo/8dGKP/HRij/x0Yo/8dGKP/HRij/x0Yo/8dGKP/HRij/xwX - pf8bF6b/Gxem/xsXpv8bF6b/Gxem/xsXpv8bF6b/Gxem/xwYp/8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0Z - qP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0Z - qP8dGaj/HRmo/x0ZqP8dGan/Hhap/x8Vqv8fFqr/IBaq/yEYq/8hF6r/IBep/yIZqv8dF6f/GRmp/xsY - rf8cFa3/HBWn/xgTlf8YGYD/MDiA/3SCsP/Az+D/4u3u/+jr8f/t6PD/8eru//Hq6v/v6+n/6+vr/+jr - 7f/r7ez/7e7s/+3u7P/t7uz/7e7s/+3u7P/t7uz/7e7s/+3u7P/u7+3/7u/t/+7v7f/u7+3/7e7s/+3u - 7P/t7uz/7e7s/+7v7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v7f/u7+3/7e/t/+rv7f/t7+z/8O/s//Lr - 8//v6fb/6fHs/9/s8P+0iLf/1Sgn//8mAP//JgD//yYA//gmBf+SIE7/LiJ5/y8vTP84ODb/Ozs7/z4+ - Pv9BQUH/RERE/0dHR/9JSUn/TExM/05OTv9QUFD/UlJS/1RUVP9WVlb/V1dX/1hYWP9ZWVn/Wlpa/1pa - Wv9aWlr/Wlpa/1paWv9aWlr/WVlZ/1hYWP9XV1f/VlZW/1VVVf9TU1P/UVFR/09PT/9NTU3/SkpK/0hI - SP9FRUX/QkJC/z8/P/88PDz/OTk5/zU1Nf8xMTH/Li4u/yoqKv8mJib/IiIi/x4eHv8aGhr/FhYW/xIS - Ev8NDQ3/CQkJ/wQEBP8BAQH/AAAA/wMDEv8SEGf/HBid/xwZpP9VHHr/2SMb//8mAP//JgD//yYA//8m - AP//JgD//yYA/+slDv9wHmX/IBme/x0ZoP8dGaD/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmg/x0ZoP8dGaD/HRmg/x0Z - oP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0Zof8dGKP/Hxqc/x8Z - nv8eGKL/Ghmd/xwXnf8zJpn/oZvK/8vOzZfGx9MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAC/wtEAyMzYJKCfuus1LGf/HxJf/yEWY/8gFmP/IBZj/yAWY/8gFmP/IBZj/yAWY/8gFmP/HhRh/x0T - e/8iGaL/Gxio/xobof8dGaD/Hxam/xwWp/8aGKP/HRek/x0XpP8dF6T/HRek/x0XpP8dF6T/HRek/x0X - pP8cF6X/HBin/xwYp/8cGKf/HBin/xwYp/8cGKf/HBin/xwYp/8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0Z - qP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0Z - qP8dGaj/Hhqp/x4aqf8eGqn/Hhqp/yAZqv8gGar/IBip/x8Yqf8fGKn/IBir/yAZq/8gGKv/Gxem/xYb - of8ZHKn/Ghmt/xoWr/8cFq3/IBum/xsZlv8XGYj/NDeM/4aLvv/T2O//7vDz//Lv6//x6+v/7+rt/+rt - 6v/o7+f/7O/r/+3u7P/t7uz/7e7s/+3u7P/t7uz/7e7s/+3u7P/t7uz/7u/t/+7v7f/u7+3/7u/t/+3u - 7P/t7uz/7e7s/+3u7P/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+3v7v/q7vD/7e7v//Hy - 5v/z8Oj/8+v2/+/v7//p8ur/1NT2/4ZUov/MIiP//yYA//gmBf+QIFL/JRud/xwbpf8jHZb/LixU/zY2 - Nf85OTj/PDw8/z4+Pv9BQUH/RERE/0ZGRv9ISEj/S0tL/01NTf9OTk7/UFBQ/1FRUf9SUlL/U1NT/1RU - VP9UVFT/VFRU/1VVVf9UVFT/VFRU/1NTU/9TU1P/UlJS/1BQUP9PT0//TU1N/0tLS/9JSUn/R0dH/0VF - Rf9DQ0P/QEBA/z09Pf86Ojr/Nzc3/zQ0NP8xMTH/LS0t/yoqKv8mJib/IiIi/x4eHv8aGhr/FhYW/xIS - Ev8ODg7/CQkJ/wUFBf8BAQH/AAAA/wUEHP8WEnn/Hhmm/x4ZpP8dGKT/HBik/1QcfP/YJBz//yYA//8m - AP//JgD//yYA//8mAP//JgD/6iUO/1gcd/8bGaP/HRmi/x0Zov8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0ZoP8dGaD/HRmg/x0Z - oP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaH/HRik/x8a - nf8gGp7/Hhii/xoanf8cF53/MyaZ/6Cayf/KzcyXxsbTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAv8LRAMjM2CSgn7rrNSxn/x8SX/8hFmP/IBZj/yAWY/8gFmP/IBZj/yAWY/8gFmP/IBZj/x4U - Yv8eFHz/Ixqj/xwZqf8aHKL/HRqg/x8Wp/8cFqf/Ghij/x0XpP8dF6X/HRel/x0Xpf8dF6X/HRel/x0X - pf8dF6T/Hhim/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqP8fG6b/IBum/yAbpv8gGqf/Hxqn/yAaqP8gGqn/IBqp/x4a - qP8bHKX/HByl/xscpP8dHKT/Hhum/yAaqP8gGav/IBir/x4WnP8fGoT/UE6W/7W31v/o6/H/7u/t/+7v - 7f/r7+z/6/Ds/+zv7P/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v - 7f/u7+3/7u/t/+7v7f/u7+3/7/Du/+/w7v/v8O7/7/Du/+/w7v/v8O7/7/Du/+/w7v/u7+//6+7y/+3t - 8//x9OT/9Pfe//Pt7v/y6ff/7Ozw/+zt+P+rqur/XjOL/8QhJv+RHlP/JBmm/xkbqP8dHaP/IBum/yQb - nv8pJXH/MjI7/zY2NP85OTn/Ozs7/z4+Pv9BQUH/Q0ND/0VFRf9GRkb/SEhI/0pKSv9LS0v/TExM/01N - Tf9OTk7/Tk5O/05OTv9OTk7/Tk5O/05OTv9NTU3/TU1N/0xMTP9KSkr/SUlJ/0dHR/9GRkb/RERE/0JC - Qv9AQED/PT09/zs7O/84ODj/NTU1/zIyMv8vLy//LCws/ygoKP8lJSX/ISEh/x0dHf8aGhr/FhYW/xIS - Ev8ODg7/CgoK/wUFBf8BAQD/AAAC/w0LRf8bFpD/Hxqn/x8apf8fGqX/Hxql/x8apf8eGqb/VBx+/9gk - HP//JgD//yYA//8mAP//JgD//yYA/7wiMf87G5D/Hhqm/x8apf8fG6T/Hxuj/x8bo/8fG6P/Hhqi/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaD/HRmg/x0Z - oP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmh/x0Y - pP8fGp3/IBqe/x4Yov8bGp7/HRie/zImmf+fmcj/yczLl8TF0QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAL/C0QDIzNgkoJ+66zUsZ/8fEl//IRZj/yAWY/8gFmP/IBZj/yAWY/8gFmP/IBZj/yAW - Y/8eFGL/HhR8/yMao/8cGan/Gxyi/x4bof8gF6f/HReo/xsZpf8eGKb/Hhin/x4Yp/8eGKf/Hhin/x4Y - p/8eGKf/Hhin/x4ZqP8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqj/Hhum/x4bpf8eG6X/Hhum/x4bpv8eG6f/Hhun/x4b - p/8eGav/Hxav/x8Yq/8fHKT/Hx+f/yAfnf8gHqD/IBul/yAZqv8hGKn/Ixmj/yEYkv8sKIL/hom5/9zl - 8f/q8vH/6Ozu/+zs8//u7u//7u/t/+7v7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v - 7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+/w7v/v8O7/7/Du/+/w7v/v8O7/7/Du/+/w7v/v8O7/7vDu/+zv - 8f/t7vH/8fPn//P33v/08ur/8+n5//Hr+P/t8Oz/4eX2/3l4yv89Ion/Khih/xkVrv8bGqr/HByl/x8c - pf8hGan/IBmq/yMgh/8sK1X/MzMz/zY2Nf84ODj/Ozs7/z09Pf8/Pz//QUFB/0JCQv9ERET/RUVF/0ZG - Rv9HR0f/SEhI/0hISP9ISEj/SUlJ/0hISP9ISEj/R0dH/0dHR/9GRkb/RUVF/0NDQ/9CQkL/QEBA/z4+ - Pv88PDz/Ojo6/zg4OP81NTX/MzMz/zAwMP8tLS3/Kioq/ycnJ/8jIyP/ICAg/x0dHf8ZGRn/FRUV/xER - Ef8ODg7/CQkJ/wUFBP8CAgH/BgUf/xMQaf8eGKD/Hxmo/x8Zpv8fGab/Hxmm/x8Zpv8fGab/Hxmm/x4Z - p/9UHH7/2CQc//8mAP//JgD//yYA/7oiMv87G5D/HRqm/x8apf8fGqX/Hxuk/x8bo/8fG6P/Hxuj/x4a - ov8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmg/x0Z - oP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0Z - of8dGKT/Hxqd/yAanv8eGKL/Gxqe/x0Ynv8yJpn/n5nI/8nMy5fExdEAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAC/wtEAyMzYJKCfuus1LGf/HxJf/yEWY/8gFmP/IBZj/yAWY/8gFmP/IBZj/yAW - Y/8gFmP/HhRi/x4UfP8jGqP/HBmp/xscov8fHKL/IRio/x4Yqf8cGqb/Hxmn/x8ZqP8fGaj/Hxmo/x8Z - qP8fGaj/Hxmo/x8ZqP8fGaj/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qP8eGqj/Hhmr/yAWsP8gF63/Hxqo/x8cpP8eHaL/HR2i/x0cpP8dG6f/Hxqn/yIZqf8hGKr/HRie/xsb - hP9hZab/y9Dt/+7u+P/w7fD/7+/u/+7v7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v - 7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v7f/v8O7/7/Du/+/w7v/v8O7/7/Du/+/w7v/v8O7/7/Du/+7w - 7v/s8e3/7fHs//Dw7f/y8Ov/8vHo//Hu7//v6/X/7fHr/+jw7f/ExfH/TEWo/yMXof8fFbD/HBit/xwb - pv8eHKX/IBqn/x8aqf8eGqv/Hxyf/yYkcf8uLkH/MzMy/zU1NP83Nzf/OTk5/zs7O/88PDz/Pj4+/z8/ - P/9AQED/QUFB/0JCQv9CQkL/QkJC/0JCQv9CQkL/QkJC/0FBQf9BQUH/QEBA/z8/P/89PT3/PDw8/zs7 - O/85OTn/Nzc3/zU1Nf8yMjL/MDAw/y4uLv8rKyv/KCgo/yUlJf8iIiL/Hx8f/xsbG/8YGBj/FRUV/xER - Ef8NDQ3/CQkJ/wUFA/8EBA7/DgtL/xsWkP8fGan/Hxmn/x8Zpv8fGab/Hxmm/x8Zpv8fGab/Hxmm/x8Z - pv8fGab/Hhmn/1Ucfv/ZJBz//yYA/7oiMv87G5D/HRqm/x8apf8fGqX/Hxql/x8bpP8fG6P/Hxuj/x8b - o/8eGqL/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - oP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0Z - oP8dGaH/HRik/x8anf8gGp7/Hhii/xsanv8dGJ7/MiaZ/5+ZyP/JzMuXxMXRAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAv8LRAMjM2CSgn7vrNSxn/x8TX/8gFmP/IBZj/yAWY/8gFmP/IBZj/yAW - Y/8gFmP/IBZj/x4UYv8eFHz/Ixqk/xsZqv8bHaP/IByj/yIYqv8fGar/HRun/x8aqP8gGqn/IBqp/yAa - qf8gGqn/IBqp/yAaqf8gGqn/Hxqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGKz/Hhet/x4Yrf8eGKz/Hhir/x4Y - q/8eGar/Hhmq/x4aqf8eGqj/Hhqp/x0Zqv8dGKz/HBis/xsZrP8aGav/Ghqq/x0ZqP8gG6r/Gxer/xkW - rf8ZFaf/GxaP/1FMm//Ewt//8vLv/+/w6v/v7+3/7u/u/+7v7f/u7+z/7u/t/+7u7//u7u7/7u/t/+7v - 7f/u7+3/7u/t/+7v7f/u7+3/7u/t/+7v7f/u7+3/7/Du/+/w7v/v8O7/7/Du/+/w7v/v8O7/7/Du/+/w - 7v/v8O3/7fLq/+3z5//v7vL/8er4//Hx7P/x9Oj/7u7v/+3w7f/p8Oz/5+j6/5mS2v8uIKT/IBSu/x0W - r/8cGqj/Hhum/yEbp/8fGqn/Hhqp/x4aqv8eGqr/IB2Z/yYkbP8tLUD/MTEw/zMzMv81NTX/NjY2/zg4 - OP85OTn/Ojo6/zs7O/88PDz/PDw8/zw8PP88PDz/PDw8/zw8PP87Ozv/Ozs7/zo6Ov85OTn/ODg4/zY2 - Nv81NTX/MzMz/zExMf8vLy//LS0t/ysrK/8oKCj/JiYm/yMjI/8gICD/HR0d/xoaGv8XFxf/ExMT/xAQ - EP8MDAv/CAgG/wYGEP8NC0L/GBSF/x8Zpv8fGan/Hxmo/x8ZqP8fGaj/Hxmo/x8ZqP8fGaj/Hxmo/x8Z - qP8fGaj/Hxmo/x8ZqP8dGaj/Vxx8/50gSP88G5D/HRmn/x8Zpv8fGab/Hxmm/x8Zpv8fGqX/Hxuk/x8b - pP8fG6T/Hhqj/x0Zov8dGaL/HRmi/x0Zov8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0ZoP8dGaD/HRmg/x0Z - oP8dGaD/HRmi/x0YpP8fGp3/IBmf/x0Yov8bGp//HRie/zImmf+fmcj/yczLl8TF0QAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/C0gDIzNgkoJ+86zYtaf8fFGH/Hxdi/x4XYv8eF2L/Hhdi/x4X - Yv8eF2L/Hhdi/x4XYv8eFmT/HhV//yIapv8bGaz/Gx2l/yAbpf8iGKz/Hhis/xwbqP8eG6f/Hhun/x4b - p/8eG6f/Hhun/x4bp/8eG6f/Hhun/x4bp/8eG6f/Hhun/x4bp/8eG6f/Hhun/x4bp/8eG6f/Hhun/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhmq/x4Zqv8eGar/Hhmq/x4Z - qv8eGar/Hhmq/x4aqf8eGqn/Hhun/x4aqP8eGqr/Hhmq/x0Zqv8dGar/HBmq/xwZqv8bG6r/GRmr/xkX - sP8ZFLP/HRaz/yEap/8eGor/QkSS/7O54f/u7+//8u7w//Lu9P/v8O3/7/Lq/+/u8P/w6/f/8ezz//Dv - 7v/v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v - 7//v7+//7/Dv//Dx7//w8u7/8fDy//Hv9P/x8fD/8fLt//Hx8f/x8fH/8PDv/+/v7//Z2PT/XlPB/yAY - pf8cGqv/Hxys/yEaq/8kG6n/IRup/x4aqf8eGqn/Hhqp/x4aqv8eGqr/IB2X/yYkav8rK0D/Ly8v/zEx - L/8yMjH/MzMz/zQ0NP81NTX/NjY2/zY2Nv82Njb/NjY2/zY2Nv82Njb/NjY2/zU1Nf80NDT/MzMz/zIy - Mv8xMTH/Ly8v/y4uLv8sLCz/Kioq/ygoKP8lJSX/IyMj/yAgIP8eHh7/Gxsb/xgYGP8VFRX/EhIR/w4O - DP8LCwv/CgoY/w8NRf8YFYX/Hhmn/x8aq/8eGqn/Hhqp/x4aqf8eGqn/Hhqp/xwYp/8cF6b/HBem/xwX - pv8cF6b/HBem/xwXpv8cF6b/HBin/x4Zp/8iGaT/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmn/x0a - p/8dGqf/HRqn/x0apv8dGab/HRmm/x0Zpv8dGab/Hhql/x8apP8fGqT/Hxqk/x8apP8fGqT/Hxqk/x8a - pP8fGqT/Hxqk/x8apP8fGqT/Hxqk/x8apP8fGqT/Hxqk/x8apP8eGaL/HRmh/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Yo/8cF6b/Hxmf/x8ZoP8cGKP/GRqg/xwYn/8xJpn/nprH/8jMypfDxdEAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/wdMAyMvaJKCfvOs3LWr/IBRh/x4XYv8eF2L/Hhdi/x4X - Yv8eF2L/Hhdi/x4XYv8eF2L/HRZk/x4UgP8iGqf/Gxms/xsdpv8fG6X/Ihes/x4Yrf8bGqn/Hhqo/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Ghym/xkc - p/8aGaz/HBax/x4WsP8iG6z/Ih6f/xwdjf82OJH/t7Xb//Lw+//u8O//7/Hp//Hv7f/x7PT/8ez1//Du - 8f/v7+7/7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v - 7//v7+//7+/v/+/v7//x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Lv7//z8PD/6+33/6qo - 6f8wJ7D/HRmp/xwZqP8iHKn/Ixiq/yEZq/8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqv8eGqv/IByZ/yMg - eP8nJlD/Kysy/y0tLP8uLiz/Ly8t/y8vL/8wMDD/MDAw/zAwMP8wMDD/MDAw/zAwMP8vLy//Li4u/y0t - Lf8sLCz/Kysr/ykpKf8oKCj/JiYm/yQkJP8iIiL/ICAg/x4eHv8bGxv/GRkZ/xYWFP8TExD/EBAP/w0N - Ev8PDjD/FRJl/xoWjv8eGan/Hhqr/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8cGKf/HBin/xwY - p/8cGKf/HBin/xwYp/8cGKf/HBin/xwYp/8dGaj/HBmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0Z - qP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmn/x8apv8fGqX/Hxql/x8apf8fGqX/Hxql/x8a - pf8fGqX/Hxql/x8apf8fGqX/Hxql/x8apf8fGqX/Hxql/x8apf8fGqX/Hhmi/x0Zof8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGKP/HBam/x8ZoP8eGKH/HBik/xkaoP8cGKD/MSaZ/52ax//HzcqXwsbQAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv8HTAMjL2iSgn7zrNy1q/yAUYv8eFmP/HhZj/x4W - Y/8eFmP/HhZj/x4WY/8eFmP/HhZj/x0VZf8eFID/Ihqn/xsZrP8bHab/Hxul/yIXrP8eGK3/Gxqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Z - qv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Z - qv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhqp/x0c - pP8cHqL/HRyl/x4Zqv8fGaz/Hhiq/yEcqv8hHaX/GxeW/0A5l/+6uuH/7fXx/+/x6P/z7PL/9Oz0//Lv - 7f/u8ev/7vDt/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v - 7//v7+//7+/v/+/v7//v7+//8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/08PD/9e3z/+7x - 9v/d5Pr/aV7Q/x8Vqv8eHKb/IB+n/yAYrv8fF63/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Z - q/8eGqr/Hhqm/yAdi/8iIHX/JiVL/ycnPf8oKCn/KSko/ygoKP8pKSn/KSkp/ykpKf8qKir/KSkp/ygo - KP8nJyf/JiYm/yUlJf8kJCT/IiIi/yEhIf8fHx//HR0d/xsbG/8YGBj/FhYV/xMTEv8SEiT/EhE1/xYT - X/8ZFYH/HRih/x4ZrP8eGaz/Hhqq/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/HRmo/x0Z - qP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0Z - qP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0Zp/8fGqb/Hxql/x8apf8fGqX/Hxql/x8a - pf8fGqX/Hxql/x8apf8fGqX/Hxql/x8apf8fGqX/Hxql/x8apf8fGqX/Hxql/x4Zo/8dGaH/HRmh/x0Z - of8dGaH/HRmh/x0Zof8dGaH/HRij/xwWpv8fGaD/Hhih/xwYpP8ZGqD/HBig/zEmmf+dmsf/x83Kl8LG - 0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/B0wDIy9okoJ+86zctav8gFGL/HhZj/x4W - Y/8eFmP/HhZj/x4WY/8eFmP/HhZj/x4WY/8dFWX/HhSA/yIap/8bGaz/Gx2m/x8bpf8iF6z/Hhit/xsa - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Z - qv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Z - qv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Z - qv8fG6f/IByk/yAcpf8fG6f/Hhmo/x0Yqf8cF6z/HRix/x0Xr/8cFpr/QkST/8PJ4v/v7/X/9u3z//bu - 7v/y8uj/7fPp/+zw7v/u7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v - 7//v7+//7+/v/+/v7//v7+//7+/v//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/9PDx//Xt - 8f/v8O7/6fPz/7e18/87Lbr/IBuj/x8dqP8cGbD/HRmt/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Z - qv8eGar/Hhqp/x4aqf8eGqv/Hhqq/x4ap/8iH5n/b26O/4qKif9PT0//PDw8/zo6Ov8vLy//IiIi/yIi - Iv8hISH/ICAg/yAgIP8fHx//HR0d/xwcHP8bGxv/FxcX/xMTE/8RERH/Dw8R/xYUVv8ZFnX/GxeP/x4Z - p/8eGar/Hhmt/x4Zq/8eGar/Hhmq/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0Z - qP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/Hxmm/x8Zpv8fGab/Hxmm/x8Z - pv8fGab/Hxmm/x8Zpv8fGab/Hxmm/x8Zpv8fGab/Hxmm/x8Zpv8fGab/Hxmm/x8Zpv8eGaT/HRii/x0Y - ov8dGKL/HRii/x0Yov8dGKL/HRii/x0XpP8bFqb/Hhmg/x4Yof8cGKT/GRqg/xwYn/8xJpn/nZrH/8fN - ypfCxtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwtQAyczbJKCevOs3LWr/IBRi/x8W - Zf8fFmX/HxZl/x8WZf8fFmX/HxZl/x8WZf8fFmX/HhVl/x4UgP8iGqf/Gxms/xsdpv8fG6X/Ihes/x4Y - rf8bGqn/Hhqp/x4Zqv8eGar/Hhmq/x4aqv8fGqr/Hxqq/x8aqv8fGqr/Hxqq/x8aqv8fGqr/Hxqq/x8a - qv8fGqr/Hxqq/x8aqv8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Z - q/8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Z - q/8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Z - q/8fGav/Ihiu/yMXrv8jGav/Ihqp/yAbqP8eG6r/HRqu/xoWsf8cGbT/Gxup/xoZkP9TUKD/1dHv//Tw - 8//18+n/8/Pp/+3x7P/u8vH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw - 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Pw - 7//38PD/8vDw/+zz8P/h6Pj/fnPZ/yUap/8dGaj/Gxqt/x0arP8fGav/Hxmr/x8Zq/8fGav/Hxmr/x8Z - q/8fGav/Hxmr/x8aq/8fG6v/Hxur/x8bq/8eGqr/JB+s/5qYyP/Nzcr/s7Oz/6Ojo/+VlZX/d3d3/1ZW - Vv9OTk7/RUVF/zw8PP80NDT/Kysr/yIiIv8ZGRn/EBAQ/wYGBv8BAQH/AQEB/wIBBv8WEn7/Hxqw/x4Z - q/8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8dGaj/HBin/xwYp/8cGKf/HBin/x4Ypf8eGKX/Hhil/x4Y - pf8fGab/Hxmm/x8Zpv8fGab/Hxmm/x8Zpv8fGab/Hxmm/x8Zpv8fGab/Hxmm/x8Zpv8fGab/Hhik/x0Y - o/8dGKP/HRij/x0Yo/8eGaT/Hhmk/x4ZpP8eGKX/HRen/yAaof8gGaL/HRml/xobof8dGaD/Miea/56b - yP/IzsuXw8fSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMLUAMnM2ySgnrzrNy1q/yAU - Y/8fFmb/HxZm/x8WZv8fFmb/HxZm/x8WZv8fFmb/HxZm/x4VZv8eFID/Ihqn/xsZrP8bHab/Hxul/yIX - rP8eGK3/Gxqq/x4Zqv8eGKv/Hhir/x4Yq/8fGav/Hxqs/x8arP8fGqz/Hxqs/x8arP8fGqz/Hxqs/x8a - rP8fGqz/Hxqs/x8arP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8Z - rP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8Z - rP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8Z - rP8fGaz/Hxms/yIWs/8kE7f/Ixay/yIZrf8gG6r/Hxuq/xwaq/8bGa7/Ghqt/xkcp/8eGaz/Ixab/29n - sf/j5fH/8fXt//Dx7f/x8fL/7/Dw//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx - 8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx - 8f/z8u7/9fLu//Tv9f/w8vD/7Pbt/8TC8/9DNLv/Hhin/xobqf8dGq3/Hxms/x8ZrP8fGaz/Hxms/x8Z - rP8fGaz/Hxms/x8ZrP8fGqz/Hxqs/x8arP8fGqz/Hxms/yQfrf+Ylsb/y8vI/7m5uf+rq6v/nJyc/4+P - j/+BgYH/cnJy/2NjY/9UVFT/RkZG/zc3N/8oKCj/GRkZ/woKCv8AAAD/AAAA/wAAAP8BAQb/FhJ8/x8Z - rf8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/HRmo/xsXpv8bF6b/Gxem/xwXpv8dF6b/HRel/x0X - pf8dF6X/Hhim/x8Zp/8fGaf/Hxmn/x8Zp/8fGaf/Hxmn/x8Zp/8fGaf/Hxmn/x8Zp/8fGaf/Hxmn/x4Y - pf8dF6P/HRij/x0Xo/8eGKT/Hxqm/x8apv8fGqX/Hxmn/x4YqP8hG6L/IBqj/x4apv8aHKL/Hhqh/zMn - mv+fnMn/yc/Ml8TI0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDC1ADJzNskoJ686zct - av8gE2P/HxZn/x8WZv8fFmb/HxZm/x8WZv8fFmb/HxZm/x8WZv8eFWb/HhSA/yIap/8bGaz/Gx2m/x8b - pf8iF6z/Hhit/xsaqv8eGar/Hhir/x4Yq/8eGKv/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8Z - rP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8Zrf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Z - rf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Z - rf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Z - rf8fGa3/Hxmt/x8Zrf8hFrL/IhS1/yIVs/8hGK//IBmt/x8arP8dGqv/HBqr/xwbq/8eHqz/IRi2/yQV - sP8oH43/i47A/+fu+v/s7vP/8/Hz//Ty8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx - 8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx - 8f/x8fH/8fLv//Hy8P/z7/X/8/Lu//D36P/o7vf/hXne/yMcpf8bGqn/HRqt/x8Zrf8fGa3/Hxmt/x8Z - rf8fGa3/Hxmt/x8Zrf8fGa3/Hhir/x4Yq/8eGKv/Hhir/x4YrP8kHq3/mJbG/8vMyf+6urr/q6ur/52d - nf+Ojo7/f39//3Fxcf9jY2P/VFRU/0ZGRv83Nzf/KSkp/xoaGv8LCwv/AQEB/wAAAP8AAAD/AQEG/xYR - fP8fGa3/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8cGKf/HBin/xwYp/8dGKf/Hhin/x4Y - p/8eGKf/Hhin/x8ZqP8fGaj/Hxmo/x8ZqP8fGaj/Hxmo/x8ZqP8fGaj/Hxmo/x8ZqP8fGaj/Hxmo/x8Z - qP8eGKX/HRek/x0XpP8dF6T/Hhil/x8Zpv8fGab/Hxmm/x8Zp/8eGKj/IRui/yAao/8eGqb/Ghyi/x4a - of8zJ5r/n5zJ/8nPzJfEyNIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwtQAyczbJKCe - vOs3LWr/IBNj/x8WZ/8fFmf/HxZn/x8WZ/8fFmf/HxZn/x8WZ/8fFmf/HhVm/x4UgP8iGqf/Gxms/xsd - pv8fG6X/Ihes/x4Yrf8bGqr/Hhmq/x4Yq/8eGKv/Hhir/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8Z - rP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGa3/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/IBmu/yAYrv8gGK//IBiv/x8Yr/8fGK//Hxmu/x4Zrf8fGa7/Ixm1/yEY - s/8kHbD/IRyc/y8vi/+ssNr/7/L7//b08v/28vD/8vHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx - 8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx - 8f/x8fH/8fHx/+/x8f/u8fP/8fHx//Ty7f/09Or/7fPx/8jG9/9EO7z/Gxer/x4arv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/JB6t/5mXx//MzMn/urq6/6ys - rP+dnZ3/j4+P/4CAgP9xcXH/Y2Nj/1RUVP9GRkb/Nzc3/ykpKf8aGhr/DAwM/wEBAf8AAAD/AAAA/wEB - Bv8WEXz/Hhmt/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/HRmo/x0ZqP8dGaj/Hhmo/x8Z - qP8fGaj/Hxmo/x8ZqP8fGaj/Hxmo/x8ZqP8fGaj/Hxmo/x8ZqP8fGaj/Hxmo/x8ZqP8fGaj/Hxmo/x8Z - qP8fGaj/Hhim/x0Xpf8dF6X/HRel/x4Ypf8fGaf/Hxmn/x8Zp/8fGaj/Hhio/yEbov8gGqP/Hhqm/xoc - ov8eGqH/Myea/5+cyf/Jz8yXxMjSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMLUAMnM - 2ySgnrzrNy1q/x8TY/8fFmf/HhZn/x4WZ/8eFmf/HhZn/x4WZ/8eFmf/HxZn/x4VZ/8eFYH/Ihqp/xsZ - rv8bHKj/Hxqo/yIXrv8fGK7/HBqq/x4Zq/8eGKz/Hhis/x4YrP8fGaz/Hxmt/x8Zrf8fGa3/Hxmt/x8Z - rf8fGa3/Hxmt/x8Zrf8gGq3/IBqt/yAarf8gGq3/IBqu/yAar/8gGq//IBqv/yAar/8gGq//IBqv/yAa - r/8fGq//Hxqv/x8ar/8fGq//Hxqv/x8ar/8fGq//Hxqv/x8ar/8fGq//Hxqv/x8ar/8fGq//Hxqv/x8a - r/8fGq//Hxqv/x8ar/8fGq//Hxqv/x8ar/8fGq//Hxqv/x8ar/8fGq//Hxqv/x8ar/8fGq//Hxqv/x8a - r/8fGq//Hxmu/x4Zrv8eGa7/Hhmu/x8arP8fG6v/Hxqt/x8Zr/8fGLH/Hxix/x8YsP8fGa//Hxiw/yEU - tf8hGbD/Hx2q/yAeqv8eGpr/RkSb/87P7v/z9PL/9PXt//Dw8f/x8PT/7+/0//Dw8//x8fH/8fLw//Hy - 8P/y8fH/8vHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx8f/x8fH/8fHx//Hx - 8f/x8fH/8fHx//Hx8f/u8PT/7fH0//H07P/08+3/9fLv/+7x8v/n7f3/ioPg/yMaqf8hGqv/Hxiv/xwY - r/8dG6z/Hhmu/yAXsf8fGa3/HRqr/xwZrv8fGq7/IBqt/yAarf8gGq3/Hxmt/yQerv+Zl8f/zM3K/7u7 - u/+srKz/np6e/4+Pj/+AgID/cnJy/2RkZP9VVVX/R0dH/zg4OP8qKir/Gxsb/wwMDP8BAQH/AAAA/wAA - AP8BAQb/FhJ9/x8Zrv8eGav/Hhmr/x4Zq/8eGav/Hhir/x4Yq/8eGKv/Hhmq/x4Zqv8eGar/Hhmq/x4Z - qv8eGar/Hhmq/x4Zqv8eGar/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqo/x4aqP8eGqj/Hhqo/x4aqP8eGqj/Hhqo/x4a - qf8fGqn/Hxqp/x8aqf8fGqn/Hxmp/x8Zqf8fGan/Hxmp/x8ZqP8fGaj/Hxmo/x8ZqP8fGaj/Hhmo/x4Z - qP8eGaj/Hhmo/x0Yp/8cF6b/HBem/xwXpv8dGKf/Hhin/x4Yp/8eGKf/Hhio/x0Yqf8hG6L/IBqk/x4Z - p/8aG6P/Hhmi/zMnm/+fnMn/yc/Ml8TI0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDC - 1ADJzNskoJ686zctav8fFGP/HRZn/x0WZ/8dFmf/HRZn/x0WZ/8dFmf/HRZn/x0WZ/8eFmf/IBWC/yMa - q/8cGbH/HBur/yAaq/8jF7H/Hxiv/xwbq/8fGa3/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEb - sP8hG7D/IRuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x0Zrv8dGa7/HRmu/x0Zrv8eGq//Hxuv/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8a - sf8fF7L/Hhmu/xwarP8dGLD/Ihiv/yIYlv9wbLP/4+r1/+317f/w8fT/8fD4/+/v+f/v8Pf/8PLy//H0 - 7//y8+//8/Ly//Py8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly - 8v/y8vL/8vLy//Ly8v/y8vL/8PH1/+/y9P/x9ez/9PTu//Pw8//w8vP/6vL3/8zM9P9OQbX/JBmm/yAZ - sv8ZGLH/GBqr/x0Zr/8hFrP/IBms/xscqf8YGq//HRmu/x8Zrv8fGa7/Hxmu/x8Yrv8kHq//mpjI/83N - yv+7u7v/ra2t/56env+QkJD/gYGB/3Jycv9kZGT/VlZW/0dHR/85OTn/Kioq/xwcHP8NDQ3/AgIC/wAA - AP8AAAD/AQEG/xYSf/8gGbH/Hxmu/x8Zrv8fGa7/Hhit/x4Yrf8eGK3/Hhit/x8Zrf8fGa3/Hxmt/x8Z - rf8fGa3/Hhis/x4YrP8eGKz/Hhis/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqo/x4bp/8eG6f/Hhun/x4bp/8eG6f/Hhun/x4b - p/8eGqj/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhqp/x4aqf8eGqn/Hhqp/x0Z - qP8dGaj/HRmo/x0ZqP8cGKf/Gxem/xsXpv8bF6b/Gxem/xsXpv8bF6b/Gxem/xsXp/8dGKn/IRuj/yAZ - pv8eGKn/Ghmm/x4YpP8zJ53/n5zJ/8nPzJfEyNIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADAwtQAyczbJKCevOs3LWr/HxRj/x0WZ/8dFmf/HRZn/x0WZ/8dFmf/HRZn/x0WZ/8dFmf/HhZn/yAV - gv8jGqv/HBmy/xwbrP8gGqz/Ixex/x8Yr/8cG6v/Hxmt/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8dGa7/HRmu/x0Zrv8dGa7/Hhqv/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fGrH/IBey/x4Yr/8bGq3/HBiw/yAYsv8mHKX/KyaG/52hzP/r8fr/8fLz//Ty9v/y8Pf/8vH2//Ly - 8//y8/H/8vPw//Lz8f/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly - 8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Dx9P/v8vP/8fTu//Ty8f/28Pb/8fHx/+zx8v/n6f7/kofY/ykc - pv8gG7D/Ghqx/xkYtP8eGbH/IRqr/yIZrf8cGK//Ghqt/x4Zrv8fGa7/Hxmu/x8Zrv8eGK7/JB6v/5qY - yP/Ozsv/vLy8/62trf+fn5//kJCQ/4GBgf9zc3P/ZWVl/1ZWVv9ISEj/OTk5/ysrK/8cHBz/DQ0N/wIC - Av8AAAD/AAAA/wEBBv8WEn//IBmx/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x4Yrf8eGK3/Hhit/x4Yrf8eGKv/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Z - qv8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/HRmo/xwYp/8cGKf/HBin/xwYp/8cGKf/HBin/xwYp/8cGKj/HRip/yEb - o/8gGab/Hheq/xoZpv8eGKT/Myed/5+cyf/Jz8yXxMjSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAwMLUAMnM2ySgnrzrNy1q/x8UY/8dFmf/HRZn/x0WZ/8dFmf/HRZn/x0WZ/8dFmf/HRZn/x4W - Z/8gFYL/Ixqr/xwZsv8cG6z/IBqs/yMXsf8fGK//HBur/x8Zrf8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8hG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/HRmu/x0Zrv8dGa7/HRmu/x4ar/8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxqx/yEWs/8fF7H/HBmu/xsZr/8dGLL/Ihqs/yUgl/9CQpb/zM7u//b19f/y8PD/9PHz//Pv - 8//08PX/8/H0//Ly8v/y8/H/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly - 8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/v8vP/7vLz//Hz8f/08fT/9u/2//fz8v/y9O//7u/6/9PL - 9v9IPLj/HBip/xoasP8bFrv/HBex/yIdpf8jGK3/HxW1/xsZrf8eGa3/Hxmu/x8Zrv8fGa7/Hhiu/yQe - r/+amMn/zs7M/7y8vP+urq7/n5+f/5GRkf+CgoL/dHR0/2VlZf9XV1f/SEhI/zo6Ov8rKyv/HR0d/w4O - Dv8CAgL/AAAA/wAAAP8BAQb/FhJ//yAZsf8fGa7/Hxmu/x8Zrv8gGq//IBqv/yAar/8gGq//IBqv/x8Z - rv8fGa7/Hxmu/x8Zrv8eGK3/Hhit/x4Yrf8eGK3/Hhir/x4Yq/8eGKv/Hhir/x4Yq/8eGKv/Hhir/x4Y - q/8eGKr/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGqn/Hhqp/x4a - qf8eGqn/Hxuq/x8bqv8fG6r/Hxuq/x4aqf8dGaj/HRmo/x0ZqP8dGaj/HRmo/x0ZqP8dGaj/HRip/x0Y - qf8hG6P/IBmm/x4Xqv8aGab/Hhik/zMnnf+fnMn/yc/Ml8TI0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMDC1ADJzNskoJ686zctav8fFGP/HRZn/x0WZ/8dFmf/HRZn/x0WZ/8dFmf/HRZn/x0W - Z/8eFmf/IBWC/yMaq/8cGbL/HBus/yAarP8jF7H/Hxiv/x0bq/8fGa3/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8hG7D/IRuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x0Zrv8dGa7/HRmu/x0Zrv8eGq//Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8asf8hFrT/Hxey/x0Zrv8aGa//Gxey/x8Zsv8hHKn/HBmU/3BvuP/u7Pj/9PL0//Xy - 8//28vP/9fD1//Tw9v/y8fT/8fPx//Hz8f/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly - 8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8PLy/+/z8v/x8fT/9O/3//bv9v/38u//9fTr//Ly - 8f/u6vv/iYHd/yMdp/8bGK7/GhW5/x0Ysv8jHKf/JBmr/yEWs/8eF7H/Hxmv/x8Zrv8fGa7/Hxmu/x8Z - rv8kHq//mpjJ/8/PzP+9vb3/r6+v/6CgoP+RkZH/g4OD/3R0dP9mZmb/V1dX/0lJSf86Ojr/LCws/x0d - Hf8ODg7/AwMD/wAAAP8AAAD/AQEG/xYSf/8gGbH/Hxmu/x8Zrv8fGa7/IBqv/yEbsP8hG7D/IRuw/yAa - r/8fGa7/Hxmu/x8Zrv8fGa7/Hhit/x4Yrf8eGK3/Hhit/x4YrP8eGKv/Hhir/x4Yq/8eGKv/Hhir/x4Y - q/8eGKv/Hhir/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhqp/x4a - qf8eGqn/Hhqp/x8bqv8fG6r/Hxuq/x8bqv8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4Z - qv8eGKn/IRuj/yAZpv8eGKr/Gxmm/x4Ypf8zJ53/n5zJ/8nPzJfEyNIAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADAwtQAyczbJKCevOs3LWr/HxRj/x0WZ/8dFmf/HRZn/x0WZ/8dFmf/HRZn/x0W - Z/8dFmf/HhZn/yAVgv8jGqv/HBmy/x0brP8iG63/JBiz/yEasf8eHKz/IBuv/yEbsP8hG7D/IRuw/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fGrH/IRi0/yAZs/8eGrH/HBqx/x0atP8dGbX/Hhmz/x0YrP8rJpH/trLV//Lw - /v/z8fX/9vLx//Xw8//08Pb/8vH0//Dz8f/x8/H/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly - 8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Hz8f/v8vL/8e/3//Tv+P/28fP/9vLu//bz - 7f/18+3/8/Py/8bD9f9CO7X/HReq/xsZsv8dGLP/JBmx/yYcqv8jG67/IRe2/yEasf8hG7D/IRuw/yEb - sP8gGrD/JiCx/5uZyv/Pz83/vb29/6+vr/+goKD/kpKS/4ODg/91dXX/ZmZm/1hYWP9JSUn/Ozs7/yws - LP8eHh7/Dw8P/wMDA/8AAAD/AAAA/wEBBv8WEn//IBmx/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8ZrP8eGKv/Hhir/x4Yq/8eGKv/Hhir/x4Yq/8eGKv/Hhir/x8Zq/8fGqv/Hxqr/x8a - q/8fGqv/Hxqr/x8aq/8fGqv/Hxqr/x8aq/8fGqv/Hxqr/x8aq/8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGar/Hhmq/yEcpP8hGqf/Hxiq/xwaqP8fGab/NCie/6Cdy//K0M2XxcjTAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAwMLUAMnM2ySgnrzrNy1q/x8UY/8dFmf/HRZn/x0WZ/8dFmf/HRZn/x0W - Z/8dFmf/HRZn/x4WZ/8gFYL/Ixqr/xwZsv8dG63/Ihyu/yUZs/8hGrH/Hh2t/yEbr/8hG7D/IRuw/yEb - sP8gGq//Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8hG7D/IRuw/yEbsP8hG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/yEasv8gGrP/Hxqz/x4as/8eG7X/Hhq1/x0Ztf8eGbb/Hxia/11V - n//e2/j/7vD6//Hy7v/08vD/9PD1//Lx9f/w8/H/8fPx//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly - 8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/x8/D/8PLy//Lu+f/z8Pb/9PTv//T0 - 7f/18vL/9PLx//P17f/n6vv/fXnP/yMco/8dGa3/Hxe2/yQXt/8lHqn/Ih6p/x8Ytv8hGrL/IRuw/yEb - sP8hG7D/IRuw/yYgsf+cmsv/0NDN/76+vv+wsLD/oaGh/5KSkv+EhIT/dXV1/2dnZ/9YWFj/SkpK/zs7 - O/8tLS3/Hh4e/w8PD/8DAwP/AAAA/wAAAP8BAQb/FhJ//yAZsf8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa3/Hhis/x4Yq/8eGKv/Hhir/x4Yq/8eGKv/Hhir/x4Yq/8fGaz/Hxms/x8Z - rP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGqv/Hxqr/x8aq/8fGqv/Hhmq/x4Zqv8eGar/Hhmq/x4Z - qv8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhmq/x4Zqv8iHKT/IRqn/x8Yq/8cG6j/Hxmm/zQpnv+gncv/ytDNl8XJ0wAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDC1ADJzNskoJ686zctav8fFGP/HRZn/x0WZ/8dFmf/HRZn/x0W - Z/8dFmf/HRZn/x0WZ/8eFmf/IBWC/yMaq/8cGbL/HRut/yIcrv8lGbP/IRqx/x4drf8hG6//IRuw/yEb - sP8hG7D/IBqv/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/IRuw/yEbsP8hG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fHK7/Hxqx/x8as/8fGbT/IBqz/x8ZsP8dGK//HRiy/yYd - r/8oHZL/lZPP/+rw/P/t8+7/8/Xt//Ty8v/y8fT/8fLy//Hy8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly - 8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vPx//Lx9P/y7vr/8vH0//H3 - 6v/x9ez/8e/3//Hv+P/w9O7/7fP1/7+/7v87Naf/Hheu/yAWuv8iF7b/Ih2q/x8eqv8dGrL/IBux/yEb - sP8hG7D/IRuw/yEasP8mILH/npzL/9PTzv/Bwb//srOw/6Okof+VlZP/hoaE/3d2df9pZ2f/WlhY/0xK - Sv89Ozv/Liws/x8fHP8QEA3/AwMB/wAAAP8AAAD/AAAD/xYSfv8gGbH/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Yr/8fGK//Hxiv/x8Y - r/8fGK//Hxiv/x8Yr/8fGK//Hxmv/yAarv8gGq7/IBqu/yAarv8gGq7/IBqu/yAarv8gGq7/Hxmt/x8Z - rP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxqr/x8aq/8fGqv/Hxqr/x4Zqv8eGar/Hhmq/x4Z - qv8eGar/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4Zqv8eGar/Ihyk/yEap/8fGKv/HBuo/x8Zpv80KZ7/oJ3L/8rQzZfFydMAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwtQAyczbJKCevOs3LWr/HxNj/x0WZ/8dFmf/HRZn/x0W - Z/8dFmf/HRZn/x0WZ/8dFmf/HhZn/yAVgv8jGqv/HBmy/x0brf8iHK7/JBmz/yEasf8eHa3/IRuv/yEb - sP8hG7D/IRuw/yAar/8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/yEbsP8hG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yAbsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG6//Hh2t/x8br/8gGbT/Ihi1/yQbtP8iG67/Ixyu/yEb - rv8jGbL/Ixan/0RBnP/O1e3/8Prz//H26v/08/D/8vH0//Hy8v/x8vL/8vLy//Ly8v/y8vL/8vLy//Ly - 8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Ly8v/y8vL/8vLy//Pz8f/z8fT/8u76//Dy - 8v/v+Of/7/Xs/+/u+//v7P7/7/Py/+/28P/j6fr/cG7I/yIWsv8fE73/IRqx/yAdrP8dHK//HB2t/yAb - r/8hG7D/IRuw/yEbsP8gGrD/JR+x/4F+xf+pqMj/m5q7/5CPsP+Fg6X/eXia/25sjv9eb3z/UW5t/0Vi - Yv86V1f/L0xL/yU7Q/8eHj//ExIz/wkIKf8GBSf/BgUm/wcGK/8YE4n/IBmx/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa3/Hxmt/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGK//Hxiv/x8Y - r/8fGK//Hxiv/x8Yr/8fGK//Hxiv/x8Zr/8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yAa - rf8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8aq/8fGqv/Hxqr/x8aq/8eGar/Hhmq/x4Z - qv8eGar/Hhmq/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGar/Hhmq/yEcpP8hGqf/Hxir/xwbqP8fGab/NCme/6Cdy//K0M2XxcnTAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwcPVAMvO3CShn73rOC5r/yAUZP8eFmj/HhZo/x4W - aP8eFmj/HhZo/x4WaP8eFmj/HhZo/x0WaP8eFoP/Ihqs/xwYs/8cG67/IRuv/yMYtf8gGbT/Hhyv/x8b - sP8gGrH/IBqx/yAasf8fGrD/Hxqw/x8asP8fGrD/Hxqw/x4asP8eGrD/Hhqw/x4asP8fG7H/Hxux/x8b - sf8fG7H/IBqx/yAasf8gGrH/IBqx/yAasf8gGrH/IBqx/yAasf8fGrH/Hhux/x4bsf8eG7H/Hhux/x4b - sf8eHLH/Hhyx/x4csf8dGrH/HBmx/xwZsf8cGbH/HRmy/x4as/8eGrP/Hhqz/x4as/8eGrP/Hhqz/x4a - s/8eGrP/Hhqz/x4as/8eGrP/Hhqz/x8as/8gGrP/IBqz/yAas/8gGrP/IBqz/yAas/8gGrP/IBqz/yAa - s/8gGrP/IBqz/yAas/8gGrP/IBqz/yAas/8gGrP/IBuz/x8csf8fG7P/IBm1/yAZtf8iG7X/Ihuz/yMc - sv8hHLL/IRuy/yMYs/8lGKP/g4LE/+r38//u9+n/9PH3//Pu9//y8fL/8/Ty//Pz8//z8/P/8/Pz//Pz - 8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//08/P/9PP0//Py - 9//z8/P/8vbu//H18f/x8fj/8fD5//Lz9P/y9PT/7/f3/7K05/80JrT/IA7A/x4Ysf8cHan/Gxqw/xoZ - sv8bGbH/Gxmx/xsZsf8bGbH/Gxqy/xwasv8fHbL/IB+z/x8esv8eHbH/Hhyw/x0csP8eGrD/EFGX/wOA - f/8Cf3//An9//wGAff8HZon/Ghus/xoZrf8aGKz/GRis/xkYrP8ZGKz/HBew/yIWsv8jGK7/Ihms/yIZ - rf8jGaz/Ixuq/yQbqv8lGa3/IRiv/x4Yr/8eGK//Hhiv/x4Yr/8eGK//Hhiv/x4Yr/8eGK//Hhmu/x4Z - rv8eGa7/Hhmu/x4Zrv8eGa7/Hhmu/x4Zrv8eGa7/IBqv/yAar/8gGq//IBqv/yAar/8gGq//IBqv/yAa - r/8fGa7/Hxmt/x8Zrf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Zrf8fGa3/Hxmt/x8Zrf8fGa3/Hhms/x4Y - rP8eGKz/Hhis/x4Zq/8fGaz/Hxms/x8ZrP8fGav/Hhir/x4Yq/8eGKv/Hhir/x4Zqv8eGqn/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhmq/x4Zqv8gHKT/IBqn/x4Yq/8bG6n/Hxqn/zMonv+enMv/yM7Ml8PI - 0wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLE1gDLzt0koqC+6zgubP8hFWX/HhZp/x4W - af8eFmn/HhZp/x4Waf8eFmn/HhZp/x4Waf8dF2j/HRaD/yIarP8bGLT/HBuv/yAbsP8jF7b/Hxi1/x0b - sP8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x4asf8dG7H/HRux/x0bsf8dG7H/HRux/x0b - sf8dG7H/HRux/x8asf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x0bsf8dG7H/HRux/x0b - sf8eHLL/Hhyy/x4csv8eHLL/HRqy/xsXsv8bGLL/Gxiy/xwYs/8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4a - tf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8fGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAa - tf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAa - tf8gGrX/IBq1/yAdsf8gGrP/JhS4/z83nv/I0eT/7/fy//Hv9//07/f/+PX0//X18//09PT/9PT0//T0 - 9P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T0 - 9P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PX/9PL6/+/19P/c4/j/YljH/yERuP8eGrL/HCKk/xwe - rP8dGbb/IBm1/yAZtf8gGbX/IBm1/yAZtf8gGbT/IBm0/yAZtP8gGbX/IBm1/yAZtf8gGbX/IRi1/xou - qv8CeYP/AICA/wCAgP8AgYD/BHOH/xoqrP8gGLX/IBm1/yAZtf8gGbX/IBm1/yEYtv8jGLb/Ixqy/yMa - sf8iGbL/IBew/yAXr/8jGLH/JRe1/yEXtP8dGK//HRiv/x0Yr/8dGK//HRiv/x0Yr/8dGK//HRiv/x0Z - rv8dGa7/HRmu/x0Zrv8dGa7/HRmu/x0Zrv8dGa7/Hhmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x4Y - rf8eGK3/Hhit/x4Yrf8eGK3/Hxmu/x8Zrv8fGa7/Hxmu/x4Yrf8eGK3/Hhit/x4YrP8eGar/Hhqp/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4Zqv8dGar/IByk/x8ap/8dGKv/HBup/x8ap/8yJ5//nZvL/8fN - zJfCx9MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCxNYAy87dJKKgvus4Lmz/IRVl/x4W - af8eFmn/HhZp/x4Waf8eFmn/HhZp/x4Waf8eFmn/HRdo/x0Wg/8iGqz/Gxi0/xsbr/8gG7D/Ixe2/x8Y - tf8dG7D/Hxqx/x8asf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8asf8eGrH/HRux/x0bsf8dG7H/HRux/x0b - sf8dG7H/HRux/x0bsf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8asf8dG7H/HRux/x0b - sf8dG7H/Hhyy/x4csv8eHLL/Hhyy/x0as/8dGbT/HRm0/x0ZtP8dGbT/Hhq1/x4atf8eGrX/Hhq1/x4a - tf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hxq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAa - tf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAa - tf8gGrX/IBq1/yAatf8fHLP/Hx2z/yQZs/8oH5r/fHu4/+rv+v/v8vL/9vPz//n08v/29PL/9PT0//T0 - 9P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T0 - 9P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT1//Tw+v/w8/f/6fH6/56e5P8qH7D/Hxi0/xwf - qf8cHqv/HRi2/yMZsv8kGrH/JBmx/yQZsf8kGbD/JBmw/yQZsP8kGbD/JBmx/yQasf8kGbH/JBmx/yQY - sf8fJ6r/A3eE/wCBgP8AgID/AICA/wCAgP8YPKD/JBex/yQZsf8kGrH/JBmx/yQZsf8iGrD/HBuw/xwb - sP8cG7H/HBqx/xoYr/8aF7D/HBmz/x4ZtP8eGbL/HRiv/x0Yr/8dGK//HRiv/x0Yr/8dGK//HRiv/x0Y - r/8dGa7/HRmu/x0Zrv8dGa7/HRmu/x0Zrv8dGa7/HRmu/x4Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8eGK3/Hhit/x4Yrf8eGK3/Hhmq/x4a - qf8eGqn/Hhqp/x4aqf8eGqn/Hhqp/x4aqf8eGar/HRmr/yAcpf8fGqn/HRis/xwbqf8fGqj/Mief/52b - y//HzcyXwsfTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwsTWAMvO3SSioL7rOC5s/yEV - Zf8eFmn/HhZp/x4Waf8eFmn/HhZp/x4Waf8eFmn/HhZp/x0XaP8dFoP/Ihqs/xsYtP8bG6//IBuw/yMX - tv8fGLX/HRuw/x8asf8fGrL/Hxqy/x8asv8fGrL/Hxqy/x8asv8fGrL/Hhqy/x0bsv8dG7L/HRuy/x0b - sv8dG7L/HRuy/x0bsv8dG7L/Hhqy/x8asv8fGrL/Hxqy/x8asv8fGrL/Hxqy/x8asv8fGrL/HRuy/x0b - sv8dG7L/HRuy/x4bs/8eHLP/Hhyz/x4cs/8eG7T/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4a - tf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x8atf8gGrX/IBq1/yAatf8gGrX/IBq1/yAa - tf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAa - tf8gGrX/IBq1/yAatf8gGrX/Hhu1/x4fsv8gHa3/Jhqq/zswn//Dxen/7/by//X27//59PD/9vPy//T0 - 9P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T0 - 9P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09f/08Pf/8vP2/+z29//Q1/f/TkW+/yIS - uv8gF7b/Hhi3/x0Sw/8dFrr/HRi3/x0Xt/8dF7f/HRe3/x0Xt/8dF7f/HRe3/x0Xt/8dF7f/HRe3/x0X - t/8dF7f/HBy1/wldk/8AgX//AICA/wCAgP8AgX//DlCY/x0Ytv8dF7f/HRe3/x0Xt/8dF7f/HBi2/xsZ - tv8bF7n/Gxe5/x0as/8dHLH/HRuz/xsbs/8aHa3/Gxut/x0Yr/8dGK//HRiv/x0Yr/8dGK//HRiv/x0Y - r/8dGK//HRmu/x0Zrv8dGa7/HRmu/x0Zrv8dGa7/HRmu/x0Zrv8eGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/IBqv/yAar/8gGq//IBqv/yAar/8fGa7/Hxmu/x8Zrv8fGa7/Hhit/x4Yrf8eGK3/Hhit/x4Y - q/8eGar/Hhmq/x4Zqv8eGar/Hhmq/x4Zqv8eGar/Hhir/xwZq/8fHKX/Hxqp/x0Yrf8cG6v/Hxmo/zIn - oP+dm8v/x83Ml8LH0wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHD1QDLztwkoqC+6zgu - bP8hFWX/HhZp/x4Waf8eFmn/HhZp/x4Waf8eFmn/HhZp/x4Waf8dF2j/HhaD/yIarf8cGbT/HBuv/yAb - sP8jGLb/IBi1/x0csf8fG7L/Hxqz/x8as/8fGrP/Hxqz/x8as/8fGrP/Hxqz/x4as/8dGrP/HRqz/x0a - s/8dGrP/HRqz/x0as/8dGrP/HRqz/x8as/8fGrP/Hxqz/x8as/8fGrP/Hxqz/x8as/8fGrP/Hxqz/x0a - s/8dGrP/HRqz/x0as/8eG7T/Hhu0/x4btP8eG7T/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4a - tf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8fGrX/IBq1/yAatf8gGrX/IBq1/yAa - tf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAa - tf8gGrX/IBq1/yAatf8gGrX/IBq1/x4atv8cHrH/HSCp/yEWt/8lFKv/eHa+/+jy9v/x9e//+Pbx//bz - 8v/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T0 - 9P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9/T1//b29P/v+vD/5vL4/42J - 3P85J73/Nym//zQqvf8yJMr/LyjG/y4pxf8uKcX/LinF/y4pxf8uKcT/LinE/y4pxP8uKcT/LinE/y4p - xP8uKcT/LinE/y8nxv8XVaL/AIJ//wCAgP8AgID/AIF//whwjP8rLcH/LinF/y4pxf8uKcX/LinF/zAq - w/80KcH/NSXI/zYmxv82K7z/NS26/yogu/8fF7n/Gxqy/x0br/8eGbD/Hhmw/x4ZsP8eGbD/Hhmw/x4Z - sP8eGbD/Hhmw/x4ar/8eGq//Hhqv/x4ar/8eGq//Hhqv/x4ar/8eGq//Hhqv/yAar/8gGq//IBqv/yAa - r/8gGq//IBqv/yAar/8gGq//IBqv/yAar/8gGq//IBqv/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/IBqv/yAa - r/8gGq//IBqv/yEbsP8hG7D/IRuw/yEbsP8gGq//Hxmu/x8Zrv8fGa7/Hxmu/x4Yrf8eGK3/Hhit/x4Y - rf8eGKz/Hhmr/x4Zq/8eGav/Hhmr/x4Zq/8eGav/Hhmr/x4YrP8dGaz/IBym/yAaqv8eGK7/HBur/x8Z - qf8yJ6D/nZvM/8fNzJfCxtQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwtQAyczbJKKg - vus5L2z/IRZm/x4Waf8eFmn/HhZp/x4Waf8eFmn/HhZp/x4Waf8eFmn/Hhdp/x4XhP8jG67/HRq1/x0d - sP8hHLH/JBi3/yAZtv8eHLL/IBuz/yAbtP8gG7T/IBu0/yAbtP8gG7T/IBu0/yAbtP8fG7T/Hhu0/x4b - tP8eG7T/Hhu0/x4btP8eG7T/Hhu0/x4btP8gG7T/IBu0/yAbtP8gG7T/IBu0/yAbtP8gG7T/IBu0/yAb - tP8eG7T/Hhu0/x4btP8eG7T/Hhu0/x4btP8eG7T/Hhu0/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4a - tf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hxq1/yAatf8gGrX/IBq1/yAa - tf8gGrX/IBq1/yAatf8gGrX/IRu2/yEbtv8hG7b/IRu2/yEbtv8hG7b/IRu2/yEbtv8hG7b/IRu2/yEb - tv8hG7b/IRu2/yEbtv8hG7b/IRu2/yEbtv8fGrf/HR2x/x0gqv8fF7z/IxK8/zcymv/ByOb/8vf6//X1 - 9P/39fT/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X1 - 9f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//j09f/39vP/8vvq/+37 - 7//Z3ff/tK3u/6+s7v+rru3/rKzw/7Gu8P+yrvD/sq7w/7Ku8P+yrvD/sq7w/7Ku8P+yrvD/sa7w/7Ct - 8P+wrfD/sK3w/7Ct8P+yrfH/kKzY/w+Gif8AgH//AICA/wCAgP8GfoX/eJfO/7Ou8v+wrfD/sK3w/7Ct - 8P+wr+//srHt/7Or8P+zqvD/sq/u/62r7/9fVsz/JBev/yIcsf8gHa//Hxqx/x8asf8fGrH/Hxqx/x8a - sf8fGrH/Hxqx/x8asf8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/yAbsP8hG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IB2y/yEcsf8gGq//Hxmu/x8Zrv8fGa7/Hxmu/yEb - sP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IBqv/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmt/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGa3/Hhmu/yEbqP8gGqv/Hhiv/xwa - rP8fGKr/Mieh/52bzf/HzM6XwsbVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMLUAMnM - 2ySioL7rOS9s/yEWZv8eFmn/HhZp/x4Waf8eFmn/HhZp/x4Waf8eFmn/HhZp/x4Xaf8eF4T/Ixuu/x0a - tf8dHbD/IRyx/yQYt/8gGbb/Hhyy/yAbtP8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/Hxq1/x4a - tf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAa - tf8gGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4a - tf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x8atf8gGrX/IBq1/yAa - tf8gGrX/IBq1/yAatf8gGrX/IBq1/yEbtv8hG7b/IRu2/yEbtv8hG7b/IRu2/yEbtv8hG7b/IRu2/yEb - tv8hG7b/IRu2/yEbtv8hG7b/IRu2/yEbtv8hG7b/IRq2/x8bs/8dHq7/HRm4/yAWvf8iG5//dXi4/+rw - /v/z9ff/9vb2//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X1 - 9f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/49Pb/+PX0//X6 - 7P/y++v/8fjz//D1+f/t9/n/6/n0/+768//49/X/+vb2//r29v/69vb/+vb1//r29f/69vX/+vb1//n1 - 9f/59fX/+fX1//n19f/59fX/+vX1/+Xr6/8rlJT/AH9//wCAgP8AgID/AH9+/3u6uv/49PT/9/Pz//fz - 8//38/P/9ffv//H76//x9Pf/8fL5/+739P/o7/z/enTJ/yMWp/8jGrL/IByw/x8asf8fGrH/Hxqx/x8a - sf8fGrH/Hxqx/x8asf8fGrH/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8gG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IByx/xU1zP8dI7j/IRqv/x8Zrv8fGa7/Hxmu/x8Z - rv8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yAar/8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrf8fGaz/Hxms/x8ZrP8fGaz/Hxms/x8ZrP8fGaz/Hxmu/x4Yr/8hG6n/IBms/x4Y - sP8cGqz/Hxir/zImov+dms7/x8zOl8LF1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDC - 1ADJzNskoqC+6zkvbP8hFmb/HhZp/x4Waf8eFmn/HhZp/x4Waf8eFmn/HhZp/x4Waf8eF2n/HheE/yMb - rv8dGrX/HR2w/yEcsf8kGLf/IBm2/x4csv8gGrT/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/x8a - tf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBq1/yAa - tf8gGrX/IBq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4a - tf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8fGrX/IBq1/yAa - tf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8hG7b/IRu2/yEbtv8hG7b/IRu2/yEbtv8hG7b/IRu2/yEb - tv8hG7b/IRu2/yEbtv8hG7b/IRu2/yEbtv8hG7b/IRu2/yIbtv8iGrX/Hhuz/xwdsP8dG7X/Ihuy/zk2 - nf/Fyun/8vj6//P19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X1 - 9f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9/T2//n2 - 8//49fX/9/P4//b18P/0+uv/9Pjv//L47f/0++n/+Pbv//j18f/49fH/+PXx//n18f/59fH/+fXx//n1 - 8f/49fH/9/Pv//fz7//38+//9/Pv//f08P/38/D/dre1/wB+fv8AgID/AICA/wB/f/8qlJP/4+rm//by - 7f/08e3/9PHt//X06P/29ub/9u72//Tv9f/v9uj/6vL3/3lzx/8kFrD/HRS6/x4atf8fGrH/Hxqx/x8a - sf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/IBuw/yEb - sP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRqv/xoqwP8FWfH/HCe9/yEarv8fGa7/Hxmu/x8Z - rv8fGa7/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8gGq//Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Yr/8eGK//IRup/yAZ - rP8eF7D/HBqt/x8Yq/8yJqL/nZrO/8fMzpfCxdYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADCwtQAy8zbJKKfvus4L2z/IBVm/x4Waf8eFmn/HhZp/x4Waf8eFmr/HhZq/x4Wav8eF2n/Hhdp/x4W - hP8jG67/HBq2/x0csf8hHLL/Ixi3/yAZt/8eHLL/Hxq1/yAZtv8gGbb/IBm2/yAZtv8gGbb/IBm2/yAZ - tv8fGrb/Hhq2/x4atv8eGrb/Hhq2/x4atv8eGrb/Hhq2/x4atv8fGbb/IBm2/yAZtv8gGbb/IBm2/yAZ - tv8gGbb/IBm2/x8Ztv8eGrb/Hhq2/x4atv8eGrb/Hhq2/x4atv8eGrb/Hhq2/x4atv8eGrX/Hhq1/x4a - tf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hxq1/yAa - tf8gGrX/IBq1/yAatf8gGrX/IBq1/yAatf8gGrX/IBu2/yEbtv8hG7b/IRu2/yEbtv8hG7b/IRu2/yEb - tv8hG7b/IRu2/yEbtv8hG7b/IRu2/yEbtv8hG7b/IRu2/yEbtv8iG7T/Ihq1/x4Zt/8aH6//Gh6w/yEa - uf8lHZ7/g4O+/+30/P/y9vf/9PX1//X29P/19fT/9PX2//T19f/09vT/9fX1//b09//19fb/9fX1//X1 - 9f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//b1 - 9P/49vL/+fH6//nt///68vr/+vfy//jx+P/47/z/9/P3//L1+P/w9fj/8PX4//D1+P/w9fj/8PT4//D0 - +P/w9Pj/8PT3/+/z9//v8/f/7/P3/+/z9//v8/b/8vX4/6vS1f8Nhof/AH9//wCAgP8AgID/CoWF/6LO - 0P/x8/f/7fH1/+3x9f/w8fL/9+/z//jo/f/17Pj/8fbn/+j18v93dcT/Ihmr/xsbtv8aGrH/Hxqy/x8a - sv8fGrL/Hxqy/x8asv8fGrL/Hxqy/x8asv8fG7H/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8b - sP8gG7D/IBuw/yAbsP8gG7D/IBuw/yAbsP8gG7D/IRuw/yAcsf8NR9//AmL7/xsnvf8hGa//Hxmv/x8Z - r/8fGa//Hxmv/yEbsP8hG7D/IRuw/yEbsP8hG7D/IRuw/yEbsP8hG7D/IBqv/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGK//Hhiw/yEb - qf8gGaz/Hhex/xwZrv8fGKv/Miaj/52azv/HzM6Xw8XWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAx8LVANHM3CSknr/rNi9u/x0VZ/8eFWv/HhVr/x4Va/8eFWv/IBdt/yAXbf8gF23/IBhs/x0W - av8dFYb/Ihuw/xwZuP8cHLP/IBuz/yIYuf8fGbj/HRu0/x4atf8eGrb/Hhq2/x4atv8fG7f/Hxu3/x8b - t/8fG7f/Hxq2/x4atf8eGrX/Hhq1/x4atf8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8a - tv8eGrX/Hhq1/x4atf8eGrX/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8b - tv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8b - tv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8b - tv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hh2y/xwesv8aGrr/GBu5/xod - tf8hHLr/Jhiv/0c/ov/O0u//7/X9//P29v/2+O7/9/fy//T1+f/x9vf/8vny//f29f/68vz/9/X4//b2 - 9v/29vb/9vb2//X19f/19fX/9fX1//X19f/19fX/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/19fX/9fX0//b09//28/n/9vT3//b19f/29Pf/9vP4//X09v/09fb/8/X2//P19v/z9fb/8/X2//T1 - 9v/09fb/9PX2//P19v/z9fb/8/X2//P19v/z9PX/8vT1//P09f/k7e7/MZeX/wB/f/8AgID/AICA/wB+ - fv9Xqar/6+/w//Hy8//w8vP/8vLz//Xx8v/27/X/9e/2//Lz7//q9PL/eHHL/yIWrv8dHLT/Gxyz/x4a - tP8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrT/Hhuz/x4csv8eHLL/Hhyy/x4csv8eHLL/Hhyy/x4c - sv8eHLL/HRux/x4bsf8eG7H/Hhux/x4bsf8eG7H/Hhux/x4asP8YKsL/A2D5/wJi+/8aJr//IBmx/x8a - sv8fGrL/Hxqy/x8asv8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8ZsP8dGK//HRiv/x0Y - r/8dGK//HRiv/x0Yr/8dGK//HRiv/x4Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxiv/x4X - sf8hGqv/IBmt/x4Xsf8cGq7/IBmt/zQppf+fnM//yM3Nl8PG1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMjB1gDSy90kpZ6/6zYvbv8cFWf/HhVr/x4Va/8eFWv/HhVr/x8WbP8fFmz/HxZs/x8W - a/8cFmr/HRWG/yIasf8cGbn/HB2z/x8bs/8iF7n/Hhm4/xwbtf8eGrX/Hhq2/x4atv8eGrb/Hxu3/x8b - t/8fG7f/Hxu3/x8btv8eGrX/Hhq1/x4atf8eGrX/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8b - tv8fG7b/Hhq1/x4atf8eGrX/Hhq1/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8ctP8dHbP/Gxq7/xoa - u/8bHLf/Hhm3/ygat/8rIJj/kpPJ/+7z///y9PL/+frr//z58//49v3/8fb5//H68f/19/T/+vP7//f1 - +P/29vb/9vb2//b29v/19fX/9fX1//X19f/19fX/9fX1//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X1 - 9f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//T09P/09PT/9vX1/4vCwv8Af3//AICA/wCA - gP8Af3//FYqK/8Pc3P/18/P/8vLy//Ly8v/08vH/9vHy//Xw9f/y8/H/6/Ty/3hvzf8jFbD/HRu0/xwb - s/8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4bs/8eHLL/Hhyy/x4csv8eHLL/Hhyy/x4c - sv8eHLL/Hhyy/x0bsf8dG7H/HRux/x0bsf8dG7H/HRux/x0bsf8cHLL/C0nh/wBn//8CYfr/Gia//x8Z - sv8fGrP/Hxqz/x8as/8fGrP/Hxqx/x8asf8fGrH/Hxqx/x8asf8fG7L/Hxuy/x8asf8eGbD/HRiv/x0Y - r/8dGK//HRiv/x0Yr/8dGK//HRiv/x0Yr/8eGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Y - r/8eF7L/IRqs/yAZrv8eF7H/HBqu/yAZrf81KaX/n5zO/8jNzJfDx9QAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADIwdYA0svdJKWev+s2L27/HBVn/x4Va/8eFWv/HhVr/x4Va/8eFWv/HhVr/x4V - a/8eFmv/HBZq/x0Vhv8iGrH/HBm5/xwds/8fG7P/Ihe5/x4ZuP8cG7X/Hhq1/x4atv8eGrb/Hhq2/x8b - t/8fG7f/Hxu3/x8bt/8fG7b/Hhq1/x4atf8eGrX/Hhq1/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8b - tv8fG7b/Hxu2/x4atf8eGrX/Hhq1/x4atf8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7b/IBu3/x4Z - u/8cG7n/HBy1/x8auP8mGrv/KB2l/1BOp//a3Pb/9/fz//z87P/79u//+fP9//P0+//x+fP/9fjy//r1 - +P/39vf/9vb2//b29v/29vb/9fX1//X19f/19fX/9fX1//X19f/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X1 - 9f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/09PT/9PT0//f19f/E3d3/GIuL/wB/ - f/8AgID/AICA/wB/f/9rs7P/8vLy//Ly8v/y8vL/9PLx//bx8v/18Pb/8vPx/+v08v94cM3/IxWw/x0b - tP8cG7P/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eHLT/Hhux/x4csv8eHLL/Hhyy/x4c - sv8eHLL/Hhyy/x4csv8dG7H/HRux/x0bsf8dG7H/HRux/x0bsf8dGrD/Fi3E/wJh+f8AZ///AmH6/xom - v/8fGbL/Hxqz/x8as/8fGrP/Hxqz/x8asf8fGrH/Hxqx/x8ZsP8dHrb/DkTc/xI60v8fGrH/Hhmw/x0Y - r/8dGK//HRiv/x0Yr/8dGK//HRiv/x0Yr/8dGK//Hhmu/x8Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGK//Hhey/yEarP8gGa7/Hhex/xwarv8gGa3/NSml/5+czv/IzcyXw8fVAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAyMHWANLL3SSlnr/rNi9u/xwVZ/8eFWz/HhVs/x4VbP8eFWz/IBdu/yAX - bv8gF27/IBdu/x0Wa/8dFYb/Ihqx/xwZuf8cHbP/Hxuz/yIXuf8eGbj/HBu1/x4atf8eGrb/Hhq2/x4a - tv8fG7f/Hxu3/x8bt/8fG7f/Hxu2/x4atv8eGrb/Hhq2/x4atv8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8btv8eGrb/Hhq2/x4atv8eGrb/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/IRm5/yMY - u/8hGbr/Hhu3/x4ctv8fGrn/Ihi8/yUbs/8oIp7/pKLZ//j4+f/6+uv//vnx//vz/f/08/z/8vjz//b5 - 8P/59vX/9/b2//b29v/29vb/9vb2//X19f/19fX/9fX1//X19f/19fX/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//b29v/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X1 - 9f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9PT0//T09P/09PT/8vPz/1qq - qv8Afn7/AICA/wCAgP8Af3//GoyM/8Lb2//19PT/8vLy//Ty8f/28fL/9fD2//Lz8f/r9PL/eHDN/yMV - sP8dG7T/HBuz/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8dHbj/ETrT/xgqwv8eG7P/Hhuz/x4b - s/8eG7P/Hhuz/x4btP8eG7P/HRqy/x0asv8dGrL/HRqy/x0asv8dGrL/HB21/wpM5f8AZ///AGb//wJh - +v8aJr//Hxmy/x8as/8fGrP/Hxqz/x8as/8fGrH/Hxqx/x8ZsP8XLsX/CFLr/wBm//8DX/j/FjDI/x8Z - sP8dGK//HRiv/x0Yr/8dGK//HRiv/x0Yr/8dGK//HRiv/x4Zrv8fGa7/Hxmu/x8Zrv8fGa7/Hxmu/x8Z - rv8fGa7/Hxiv/x4Xsv8hGqz/IBmu/x4Xsf8cGq7/IBmt/zUppf+fnM7/yM3Ml8PH1QAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjB1gDSy90kpZ6/6zYvbv8cFWj/HhVs/x4VbP8eFWz/HhVs/yAX - bv8gF27/IBdu/yAXbv8eGGz/HheI/yIbsf8cGrn/HB20/yActP8iGLr/Hxm5/x0ctf8eG7b/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8auP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8a - uP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8a - uP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8auP8gG7n/IBy6/yAc - uv8gHLr/IBy6/yAcuv8gHLr/IBy6/yAcuv8gHLr/IBy6/yAcuv8gHLr/IBy6/yAcuv8gHLr/IBy6/yIZ - vP8kF73/Ixm5/yAbtv8fGrj/Hhi6/yAZvP8iGbn/Ihmv/2Ncsv/p6Pj/+Pny//358//79P3/9PP9//L3 - 9P/2+fD/+Pf0//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//j2 - 9v+62dn/DoeH/wB/f/8AgID/AICA/wB/f/9Xqan/6u/v//Tz9P/08vH/9vHy//Xw9v/y8/H/7PXz/3lx - z/8kFrH/Hhy1/xwcs/8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/xA91/8DXvf/FTLL/x4b - tP8eG7T/Hhu0/x4btP8eG7T/Hhu0/x4btP8eG7T/Hhu0/x4btP8eG7T/Hhqz/xUwyf8BYvv/AGb//wBm - //8CYvv/GSjB/yAas/8gG7T/IBu0/yAbtP8gG7P/IBmw/x0gt/8OQtr/A1/4/wBn//8AZv//AGj//wxH - 4P8fGbH/Hhmw/x4ZsP8eGbD/Hhmw/x4ZsP8eGbD/Hhmw/x4ZsP8gGrD/IBqv/yAar/8gGq//IBqv/yAa - r/8gGq//IBqv/yAZsP8eF7L/IRqs/yAZrv8eF7H/HBqu/yAZrf81KaX/n5zO/8jNzJfDx9UAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADIwdYA0svdJKWev+s2L27/HRZo/yAWb/8gFm//IBZv/yAW - b/8gFm//IBZv/yAWb/8gF2//Hxht/x8Yif8jHLL/HBq5/xwdtP8gHLT/Ixi6/x8auf8dHLb/Hxu2/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7j/Hxq4/x8auP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8a - uP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8auf8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Z - uv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Z - uv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/IBu7/yEb - vP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEb - vP8iGb7/Ixe9/yIbt/8hG7b/Hxm7/x8YvP8fGrj/IBq5/yAXvP8yKZ7/uLbe//X3+v/59/T/+vT7//Tz - /P/y9/b/9vjx//j39P/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//b29v/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X1 - 9f/19fX/8vT0/1apqf8Afn7/AICA/wCAgP8AgID/BoKC/6jQ0P/49vb/9PLx//bx8v/18Pb/8/Px/+z1 - 8/96cc//JBax/x8ctf8cHLP/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4ZtP8WLsj/AWL8/wJg - +f8NQ93/HCC6/x4ZtP8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq0/x0dt/8JT+n/AGf//wBm - //8AZv//AWP8/xcwyf8gGrP/IBu0/yAbtP8gG7T/IBqz/xcvx/8JUen/AGf//wBm//8AZv//AGf//wNe - 9/8XLcX/Hxmw/x8asf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8asf8fGrH/IBuw/yEbsP8hG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8gGrH/Hhey/yEarP8gGa7/Hhex/xwarv8gGa3/NSml/5+czv/IzcyXw8fVAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyMHWANLL3SSlnr/rNi9u/x0Waf8hF3H/IRdx/yEX - cf8hF3H/IBZw/yAWcP8gFnD/IBZv/x8Ybf8fGIj/Ixyy/xwauf8cHbT/IBy0/yMYuv8fGrn/HRy2/x8b - tv8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu4/x8auf8fGrn/Hxq5/x8auf8fGrn/Hxq5/x8a - uf8fGrn/Hxq5/x8auf8fGrn/Hxq5/x8auf8fGrn/Hxq5/x8auf8fGrn/Hxm6/x8Zuv8fGbr/Hxm6/x8Z - uv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Z - uv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/yAa - u/8hG7z/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEb - vP8hG7z/IRm+/yAYvf8gHLT/IBu2/x8Xvv8fF77/Hxy0/x8ctP8gF7//Iheo/3BsvP/r7vz/9vj4//X0 - 9//y9Pr/8vf1//b38//49vb/9/b2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//b29v/29vb/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X1 - 9f/19fX/9fX1//j29v+/29v/EYiI/wB/f/8AgID/AICA/wB/f/8ok5P/zuHh//fz8//28fL/9fD2//Pz - 8f/s9fP/enHP/yQWsf8fHLX/HByz/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/HR24/wZV - 7/8AaP//AGf//wpN5/8ZJcD/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4ZtP8VMcv/AWP8/wBm - //8AZv//AGb//wBm//8QQdr/IBqz/yAbtP8hGrP/HSK7/xBA2f8DYPn/AGf//wBm//8AZv//AGf//wNf - 9/8WMcj/Hxmw/x8asf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8asf8fGrH/Hxqx/yAbsP8hG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8hG7D/IBqx/x4Xsv8hGqz/IBmu/x4Xsf8cGq7/IBmt/zUppf+fnM7/yM3Ml8PH - 1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjB1gDSy90kpZ6/6zYvbv8dFmj/IBZv/yAV - cP8gFnD/IBZw/yAWcP8gFnD/IBZw/yAWb/8fGG3/HxiI/yMcsv8cGrn/HB20/yActP8jGLr/Hxq5/x0c - tv8fG7b/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8buP8fGrn/Hxq5/x8auf8fGrn/Hxq5/x8a - uf8fGrn/Hxq5/x8auf8fGrn/Hxq5/x8auf8fGrn/Hxq5/x8auf8fGrn/Hxq5/x8Zuv8fGbr/Hxm6/x8Z - uv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Z - uv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Z - uv8gGrv/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEb - vP8hG7z/IRu8/yAZvv8eGbv/Hx2y/x8btv8fFcL/IBa//yAesP8fH6//Hxi9/yAUuf85NKP/x8zs//T6 - +//z9vf/8vX4//L39f/19/T/+PX3//f29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//b29v/29vb/9vb2//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X1 - 9f/19fX/9fX1//X19f/19fX/8/T0/3m5uf8AgID/AICA/wCAgP8AgID/AH9//2exsf/v8O//9/Ly//Xw - 9f/y8/H/7PXz/3pxz/8kFrH/Hxy1/xwcs/8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4a - tf8OQtz/AGf//wBm//8AZv//BFz2/xM1z/8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8dHbn/CVDq/wBn - //8AZv//AGb//wBm//8AZ///DErj/yEas/8gG7T/GC7H/wlR6v8AZv//AGb//wBm//8AZv//AGb//wBm - //8RPNT/Hxmw/x8asf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8asf8fGrH/Hxqx/x8asf8gG7D/IRuw/yEb - sP8hG7D/IRuw/yEbsP8hG7D/IRuw/yAasf8eF7L/IBqs/yAYrv8eF7H/HBqu/yAZrf81KaX/n5zO/8jN - zZfDx9UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGwtEA0MzYJKSfu+s1MG7/HBVr/x8V - b/8fFW//HxVv/x8Vb/8gFnD/IBZw/yAWcP8hF3D/Hxhu/x8Xif8jG7L/HBq6/xwctf8gG7X/Ixi8/x8Z - uv8dHLb/Hxu4/x8auP8fGrj/Hxq4/x8auP8fGrj/Hxq4/x8auf8fGrr/IBq7/yAau/8gGrv/IBq7/yAa - u/8gGrv/IBq7/yAau/8gGrv/IBq7/yAau/8gGrv/IBq7/yAau/8gGrv/IBq7/yAau/8gGbz/IBm8/yAZ - vP8gGbz/IBm8/yAZvP8gGbz/IBm8/yAZvP8gGbz/IBm8/yAZvP8gGbz/IBm8/yAZvP8gGbz/IBm8/yAZ - vP8gGbz/IBm8/yAZvP8gGbz/IBm8/yAZvP8gGbz/IBq7/yAau/8gGrr/IBq6/yAauv8gGrr/IBq6/yAa - uv8gGrr/IBq8/yEbvf8hG73/IRu9/yEbvf8hG73/IRu9/yEbvf8hG73/IRu9/yEbvf8hG73/IRu9/yEb - vf8hG73/IRu9/yEbvf8gGr7/Hxq8/x8ct/8gG7n/IBfB/yEYv/8hHbX/IB6z/yAZvP8iF8H/JBqp/4iM - yv/s9/r/8/f2//j29//49/X/9/j0//b2+P/29vj/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f3 - 9//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//29vb/9vb2//b2 - 9v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X1 - 9f/19fX/9fX1//X19f/19fX/9fX1//f29v/a6Oj/M5iY/wB/f/8AgID/AICA/wCAgP8EgoL/eLi3/+3x - 8P/z8vf/9fPy/+708/93cM//Hxax/x4ctv8dG7T/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4a - tf8fGbX/Fy7J/wFk/f8AZv//AGb//wBn//8CYfr/DkLc/xsivf8fGbX/Hhq2/x4atv8fGbX/FTPN/wFj - /P8AZf//AHb//wCA//8AZf//AGj//wxJ4v8dIbr/ET7X/wJg+f8AZ///AGb//wBm//8AZv//AGb//wBn - //8KS+X/HB+4/x8as/8fGrP/Hxqz/x8as/8fGrP/Hxqz/x8as/8fGrP/Hxqz/x8as/8fGrP/Hxux/x8b - sP8fG7D/Hxuw/x8bsP8fG7D/Hxuw/x8bsP8fGrL/Hhiz/yAarf8hGa//Hhiy/xwar/8gGq7/NCml/56b - z//HzM6XwsbWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMPNAM7N1CSiobjrMzBt/xwV - bv8hF3H/IRdx/yEXcf8hF3H/IRdx/yEXcf8hF3H/IRdw/x8XcP8fFov/Ixu0/xwZvP8cG7b/IBq3/yMX - vf8fGLz/HRu3/x8auf8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/IBq8/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEbvf8hHLv/IRy7/yEcu/8hHLv/IRy7/yEc - u/8hHLv/IRy7/yEbvf8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq9/yEbvf8hGr7/IRi8/yMV - uf9KSqz/1uTy//f7+v/+9/f//vnz//n69P/z+fn/9/j4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/9/f3//b2 - 9v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9fX1//X19f/19fX/9fX1//X19f/19fX/+ff3/7XW1v8Ohob/AH9//wCAgP8AgID/AH9//wOC - gf90ubn/6vH1//n09P/x8vP/c3DP/xkWsv8dGrf/Hxu1/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8b - tv8fG7b/Hxu2/x0fuv8HVO7/AGf//wBm//8AZf//AGb//wBn//8JUev/GijC/x8btv8fG7b/HR+6/whS - 7P8AZ///AGT//wCp//8Ap///AGT//wBn//8HVO3/CFHr/wBm//8AZv//AGT//wBn//8AZv//AGb//wBm - //8JTuj/HCC6/x4ZtP8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x0b - s/8dG7H/HRux/x0bsf8dG7H/HRux/x0bsf8dG7H/HRqz/x4Ztf8hG6//IRqx/x8ZtP8dG7H/Hxqv/zMp - pv+cms//xczNl8DF1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTDzQDOzdQkoqG36zMw - bv8cFW//IRdx/yEXcf8hF3H/IRdx/yEXcf8hF3H/IRdx/yEXcP8fF3D/HxaL/yMbtP8cGbz/HBu2/yAa - t/8jF73/Hxi8/x0bt/8fGrn/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/yAZvP8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr3/IRu8/yEcu/8hHLv/IRy7/yEc - u/8hHLv/IRy7/yEcu/8hG73/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yIa - uv8lGbn/KiSh/6Wr2f/1+/v//fj3///68f/5+fb/9Pj5//f4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//f3 - 9//29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//X19f/19fX/9fX1//X19f/19fX/9fX1//b19f/x8/P/fbu7/wWCgv8AgID/AICA/wCA - gP8Af3//A4GC/3S3uf/z8fH/9fT1/3Rxz/8ZF7P/Hhu4/yAbtv8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/DUXg/wBm//8AZv//AHD//wBp//8AZf//AGf//wRd9v8TONP/Hxq1/xQ2 - 0P8BZP3/AGX//wB3//8A5f//AM3//wBr//8AZv//AGb//wBn//8AZP//AGz//wCM//8AfP//AGX//wBm - //8BY/z/Fi7J/x8Ys/8eGbT/Hhm0/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4a - tf8dG7P/HRux/x0bsf8dG7H/HRux/x0bsf8dG7H/HRux/x0as/8dGbX/IRuv/yAasf8eGbT/HBux/x8a - r/8zKab/nJrP/8XMzZfAxdUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEw80Azs3UJKKh - t+szMG7/HBVu/yEXcf8hF3H/IRdx/yEXcf8hF3H/IRdx/yEXcf8hF3D/Hxdw/x8Wi/8jG7T/HBm8/xwb - tv8gGrf/Ihe9/x8YvP8dG7f/Hxq5/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8gGbz/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq9/yEbvP8hG7z/IRu8/yEb - vP8hG7z/IRu8/yEbvP8hG7z/IRq9/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vf8iHLf/JBy2/yQYsP9kYrn/6PD5//v59//++vH/+fn2//T4+v/3+Pn/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/39/f/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//b29v/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9vb2//Dz8/9psrL/AICA/wCA - gP8AgID/AICA/wCAgP8DgYH/dLa0/9ro6f93ctH/Ghe0/x8cuf8gHLb/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxq2/xctyP8BZf7/AGX//wB8//8AqP//AHX//wBk//8AZ///AWL7/w1G - 4P8GVvD/AGf//wBl//8Aq///AP///wDn//8Acf//AGX//wBm//8AZP//AHf//wC3//8Aqv//AGj//wBl - //8AZv//AGX+/wdU7v8NRN//FyvG/xshvP8eGbT/Hhm0/x4ZtP8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4a - tf8eGrX/HRqz/x0bsf8dG7H/HRux/x0bsf8dG7H/HRux/x0bsf8dGrP/HRm1/yEbr/8gGrH/Hhm0/xwb - sf8fGq//Mymm/5yaz//FzM2XwMXVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMPNAM7N - 1CSjobfrMzBu/x0Vb/8hF3H/IRdx/yEXcf8hF3H/IRdx/yEXcf8hF3H/IRdw/x8XcP8fFov/Ixu0/x0Z - vP8dG7f/IBu3/yMXvf8gGbz/Hhy3/x8auv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/IBq8/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hG7z/IRu8/yEb - vP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEavf8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr3/Ih22/yIctv8iFL//Ny+r/8DG5v/4+/r//Pn2//n69P/29/v/9/j5//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/9/f3//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//b29v/29vb/9fX1//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/39vb/2ujo/z6d - nf8Afn7/AICA/wCAgP8AgID/AICA/wGAgP8vlpj/SGi1/xwdtP8gG7r/IRy3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8at/8cIr7/Blbw/wBm//8Abv//ANj//wDf//8Ah///AGP//wBm - //8AZv//AGb//wBl//8AeP//AOX//wD///8A6f//AHH//wBk//8Aav//AJL//wDj//8A9v//AKH//wB6 - //8AZ///AGT//wBl//8AZ///AGf//wFk/f8GVe//DEbg/xYuyf8bIr3/Hxm0/x8ZtP8eGrX/Hhq1/x4a - tf8eGrX/Hhq1/x0atP8dGrP/HRqz/x0as/8dGrP/HRqz/x0as/8dGrP/HRm0/x0Ztf8hG6//IRqx/x8Z - tP8dG7H/Hxqv/zMppv+cms//xczNl8DF1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMXE - zgDPztQko6K46zQxb/8dFnD/IRdx/yEXcf8hF3H/IRdx/yEXcf8hF3H/IRdx/yEXcP8fF3D/HxaL/yQc - tf8fG77/Hx25/yIcuf8kGb7/IRq9/x8duf8hG7v/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEa - vf8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq9/yIduP8gG7n/IhfE/yYbsf+Fhsj/8vf9//n3+//7/PT/9/b7//j3+v/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/39/f/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9fX1//f2 - 9v/L4eH/NpmZ/wB/f/8AgID/AICA/wCAgP8AgID/AH9//wN8gv8KWpX/GTGt/yAdtv8fGbr/Hxq5/x8a - uf8fGrn/Hxq5/x8auf8fGrn/Hxq5/x8auf8fGrn/Hxm4/w1H4v8AZ///AGT//wCo//8A////AOn//wCk - //8AbP//AGX//wBm//8AZf//AK///wD///8A////AOj//wBw//8AdP//AL7//wD3//8A////AP///wD7 - //8A7///AML//wCk//8Aef//AGz//wBj//8AZf//AGb//wBn//8BY/z/BVnz/w5E3v8UNM7/HCO9/x4c - tv8eGbT/Hhq1/x4atf8eG7T/Hhu0/x4btP8eG7T/Hhu0/x4btP8eG7T/Hhu0/x4atf8eGrb/IRyw/yEb - sv8fGrX/HRuy/x8ar/8zKab/nJrP/8XMzZfAxdUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADFxM4Az87VJKOiuOs0MW//HRZw/yEXcf8hF3H/IRdx/yEXcf8hF3H/IRdx/yEXcf8hF3D/Hxdw/x8W - i/8kHLb/Hxu+/x8euf8iHLn/JRm//yEavv8fHbn/IRy7/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEb - vP8hG73/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8iG77/IBy+/yAbv/8jGbr/TEiw/9rd8//49v3//Pz3//j2/P/49/r/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/9/f3//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/19fX/+Pb2/9Hk5P9Wqan/BIKC/wCAgP8AgID/AICA/wCAgP8AgID/AIF//wN3hf8MWJb/Fjaq/x0f - t/8fGbr/IBe7/x8Zuv8fGbr/Hxm6/x8Zuv8fGbr/Hxm6/x8Yuf8YK8r/AWP8/wBl//8Ahf//APD//wD/ - //8A/f//AL7//wBz//8AZP//AHz//wDo//8A////AP///wDp//8Anv//AOD//wD///8A////AP///wD/ - //8A////AP///wD///8A/P//AO///wDN//8Ap///AH///wBt//8AZf//AGb//wBn//8AaP//AWP8/wRc - 9v8MSOL/FDLN/x0duP8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrb/Hhq2/yIc - sP8hG7L/Hxq1/x0bsv8fGq//Mymm/5yaz//FzM2XwMXVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAxcTOAM/O1SSjorjrNDFv/x0WcP8hF3H/IRdx/yEXcf8hF3H/IRdx/yEXcf8hF3H/IRdw/x8X - cP8fFov/JBy2/x8bvv8fHrn/Ihy5/yUZv/8hGr7/Hx25/yEcu/8hG7z/IRu8/yEbvP8hG7z/IRu8/yEb - vP8hG7z/IRu9/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr//IRq//yEav/8hGr//IRq//yEav/8hGr//IRq//yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr//IRbF/x8bv/8aH7P/IRy+/y4jrf+rqNv/+fr+//n2+//69/v/+Pf4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//f39//29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9fX1//X19f/39vb/7fDw/366uv8Gg4P/AH9//wCAgP8AgID/AICA/wCAgP8AgYD/AIJ//wJ6 - g/8FbYr/EEue/xY4qP8dH7b/Hhy4/x8Zuv8gF7v/IBe7/x8Yu/8fGLn/HCHB/wZY8v8AZv//AGv//wDb - //8A////AP///wD+//8A3///AI7//wC2//8A////AP///wD///8A+///APf//wD///8A////AP///wD/ - //8A////AP///wD///8A////AP///wD///8A////AP///wDv//8A2P//AIv//wBl//8AZv//AGb//wBn - //8BZf7/CU/p/xgqxP8eG7b/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq1/x4atf8eGrX/Hhq2/x4a - tv8iHLD/IRuy/x8atf8dG7L/Hxqv/zMppv+cms//xczNl8DF1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMXEzgDPztUko6K46zQwb/8dFnD/IRdx/yEXcf8hF3H/IRdx/yEXcf8hF3H/IRdx/yEX - cf8fF3D/HxaL/yQctv8eG77/Hx65/yIcuf8kGb//IRq+/x8duf8hHLv/IRu8/yEbvP8hG7z/IRu8/yEb - vP8hG7z/IRu8/yEbvf8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq//yEav/8hGr//IRq//yEav/8hGr//IRq//yEav/8hGr//IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq//yIVy/8eHL7/GyWw/x8dvf8iE7P/b2m6/+/0+P/59P3/+vb6//n4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/39/f/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b2 - 9v/29vb/9vb2//X19f/19fX/9fX1//n29v/08/L/mMvJ/yyVlv8Af3//AH9//wCAgP8AgID/AICA/wCA - gP8AgYD/AIF//wCCf/8BfIL/BmyL/wdojf8QSZ//FTmo/xU5qP8aK7D/Hhu5/x8Zuf8NRuH/AGf//wBl - //8AqP//AP///wD///8A////AP///wDz//8A+P//AP///wD///8A////AP///wD///8A////AP///wD/ - //8A////AP///wD///8A////AP///wD///8A////AP///wD///8A8f//ALH//wB5//8AZf//AGb//wBn - //8GWPH/EjnT/x0duP8eGbT/Hhq1/x4atf8eGrb/Hhq2/x4atv8eGrb/Hhq2/x4atv8eGrb/Hhq2/x4a - tv8eGrb/IRyw/yEbsv8fGrX/HRuy/x8ar/8zKab/nJrP/8XMzZfAxdUAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADExc0Azc/TJKKjues1MXH/HRZy/x8Xcv8fF3L/Hxdy/x8Xcv8fF3L/Hxdy/x8X - cv8fF3H/Hhdw/x8Wi/8jHLb/HRy+/x4euf8hHbn/Ixm//yEavv8fHbr/IBu8/yAbvv8gG73/IBu9/yAb - vf8gG73/IBu9/yAbvf8gG77/IBu+/yAbvv8gG77/IBu+/yEbv/8hG7//IRu//yEbv/8hG7//IRu//yEb - v/8hG7//IRu//yEbv/8hG7//IRu//yEbv/8iG7//Ihu//yIbv/8iG7//Ihu//yIbv/8iG7//Ihu//yIb - v/8iG7//Ihu//yIbv/8iG7//Ihu//yIbv/8iG7//Ihu//yEbv/8hG7//IRu//yEbv/8hG7//IRu//yEb - v/8hG7//IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yIawP8iGsD/IhrA/yIa - wP8iGsD/IhrA/yIawP8iGsD/IRu//yEbv/8hG7//IRu//yEbv/8hG7//IRu//yEbv/8hG7//Ihu//yIb - v/8iG7//Ihu//yIbv/8iG7//Ihu//yIbwP8gGsT/Hx29/x8htv8gHMD/IBPD/zs4rP/N2er/+fr4//3z - /f/89/v/+vn5//r5+f/6+fn/+vn5//r5+f/6+fn/+vn5//r5+f/6+fn/+vn5//r5+f/6+fn/+vn5//r5 - +f/6+fn/+vn5//r5+f/6+fn/+vn5//r5+f/6+Pj/+ff3//n4+P/5+Pj/+fj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj3//f49//3+Pf/9/j3//f49v/29/X/9vf1//b39f/29/X/9vb2//b2 - 9v/29vb/9vb2//b29v/29vb/9vb2//b29v/49fX/+fX0//L49v/P5en/brO0/w2Ghv8AgH//AIGA/wCA - gP8AgID/AICA/wCAgP8AgID/AICA/wCBf/8AgX//AIGA/wCAgP8AgID/BHOH/whmj/8IZI7/BGys/wBo - +f8AZP//AI3//wD2//8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/ - //8A////AP///wD///8A////AP///wD///8A////AP///wD4//8Azf//AIb//wBm//8AZf//AGf//wJh - +/8ORN//HCO+/x8atf8fGrX/Hxu2/x8btv8fG7b/Hxu2/x8bt/8fG7f/Hxu3/x4atv8eGrb/Hhq2/x4a - tv8eGrb/Hhm3/yAcsf8gGrT/Hhi4/x4atv8hGbL/Nimp/52az//HzM6XwsXVAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAw8XNAM3P0ySio7nrNDJy/x0Wc/8eF3L/Hhdy/x4Xcv8eF3L/Hhdy/x4X - cv8eF3L/Hhdy/x0XcP8eFoz/Ixy2/x0bvv8dHrn/IR25/yMZv/8gGr//Hxy6/yAbvf8gG77/IBu+/yAb - vv8gG77/IBu+/yAbvv8gG77/IBu+/yAbvv8gG77/IBu+/yAbvv8hHL//IRy//yEcv/8hHL//IRvA/yEb - wP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIb - wP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEb - wP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yIawf8iGsH/IhrB/yIa - wf8iGsH/IhrB/yIawf8iGsH/IhrB/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yIb - wP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/Hxy//x4dvf8gHrv/IBvA/x8XyP8iIKn/mqXR//f9 - +P/+9P3//ff7//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//r4+P/6+Pj/+vj4//r4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+ff/+Pn3//j59//4+ff/9vf1//b39f/29/X/9vf1//b2 - 9v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/+Pb2//n18//v9/T/8vX6//bz9P+11tb/NYih/wF1 - g/8AgX//AIF//wCAgP8AgID/AICA/wCAgP8AgID/AICA/wCAgP8AgID/AIB//wCBfv8Agn3/AICG/wB5 - pP8AaPb/AGb//wBq//8A2///AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/ - //8A////AP///wD///8A////AP///wD///8A////AP///wDf//8Amf//AGj//wBk//8AZ///AGX+/wpO - 6P8XLsj/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hhq2/x4a - tv8eGrb/Hhq2/x0Zt/8gHLL/IBq2/x4Xuv8eGrf/Ihm0/zcpqv+fmtD/yMzPl8PE1gAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPFzQDNz9MkoqO56zQycv8dFnP/Hhdy/x4Xcv8eF3L/Hhdy/x4X - cv8eF3L/Hhdy/x4Xcv8dF3H/HhaM/yMbtv8dG7//HR66/yEcuv8jGcD/IBq//x8cuv8gG73/IBu+/yAb - vv8gG77/IBu+/yAbvv8gG77/IBu+/yAbvv8gG77/IBu+/yAbvv8gG77/IRy//yEcv/8hHL//IRy//yEb - wP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIb - wP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/IRvA/yEbwP8hG8D/IRvA/yEb - wP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8iGsH/IhrB/yIa - wf8iGsH/IhrB/yIawf8iGsH/IhrB/yIawf8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEb - wP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/IhvA/x8cv/8fHMD/IRy9/yAcvv8fGMX/IBuz/2Nm - tP/s8Pn//fj2//z5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pn3//j59//4+ff/+Pn3//b39f/29/X/9vf1//b3 - 9f/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//j29v/59fP/7/f0//D0+f/59PX/9/b3/3Vz - 0v8ULar/EEug/wZuiv8CeoP/AIJ//wCBf/8AgYD/AICA/wCAf/8AgH//AIB+/wB+jP8Aepz/AHLE/wBt - 3f8AZ/r/AGb//wBm//8AZP//AKv//wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/ - //8A////AP///wD///8A////AP///wD///8A////AO///wCu//8Adv//AGT//wBm//8AZv//BVrz/xM4 - 0/8dH7v/IBq1/x8btv8fG7b/Hxu2/x8btv8fG7b/Hxu2/x8btv8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x4a - tv8eGrb/Hhq2/x4atv8dGbf/IByy/yAatv8eF7r/Hhq3/yIZtP83Kar/n5rQ/8jMz5fDxNYAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDxc0Azc/TJKKjues0MnL/HRZz/x4Xcv8eF3L/Hhdy/x4X - cv8eF3L/Hhdy/x4Xcv8eF3L/HRdy/x4WjP8jG7f/HRvA/x0du/8hHLv/IhnA/yAZwP8fHLv/IBu+/yAa - v/8gGr7/IBq+/yAavv8gGr7/IBq+/yAavv8gGr7/IBq+/yAavv8gGr7/IBu//yEbv/8hG8D/IRvA/yEb - wP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIb - wP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/IhvA/yEbwP8hG8D/IRvA/yEb - wP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IhrB/yIa - wf8iGsH/IhrB/yIawf8iGsH/IhrB/yIawf8iGsH/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEb - wP8hG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8gG8D/IBrC/yEbwP8hHbz/IBrC/yIZ - wP86M6r/ysvp//v98//7+vf/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn//Pr6//z6+v/8+vr/+/r6//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j59//4+ff/+Pn3//j59//29/X/9vf1//b3 - 9f/29/X/9vb2//b29v/29vb/9vb2//b29v/29vb/9vb2//b29v/49vb/+fXz/+/39P/w9Pn/+fT1//T0 - 9v92cdP/GxW4/x8avf8fIbj/Fzis/xBOnv8GbYv/A3aF/wF7g/8Afor/AHmi/wByw/8Aa+b/AGf4/wBm - //8AZv//AGb//wBl//8Aav//AHX//wCy//8A////AP///wD///8A////AP///wD///8A////AP///wD/ - //8A////AP///wD///8A////AP///wD///8A////APj//wCZ//8AY///AGX//wBm//8BY/z/DkTe/xwj - v/8fGrb/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8eGrb/Hhq2/x4atv8eGrb/HRm3/yAcsv8gGrb/Hhe6/x4at/8iGbT/Nymq/5+a0P/IzM+Xw8TWAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw8XNAM3P0ySio7nrNDJy/x0Wc/8eF3P/Hhdy/x4X - cv8eF3L/Hhdy/x4Xcv8eF3L/Hxhy/x0Xcv8fFo7/JBy5/x0bwf8dHbv/IRy8/yMZwv8hGsH/IBy8/yAb - v/8gGsD/IBrA/yAawP8gGsD/IBrA/yAawP8gGsD/IBrA/yAawP8gGsD/IBrA/yEawP8hG8D/IRvA/yEb - wP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IhvA/yIbwP8iG8D/IhvA/yIb - wP8iG8D/IhvA/yIbwP8iG8D/IxzB/yMcwf8jHMH/IxzB/yMcwf8jHMH/IxzB/yMcwf8iHMH/IhzB/yIc - wf8iHMH/IhzB/yIcwf8iHMH/IhzB/yIcwf8iHMH/IhzB/yIcwf8iHMH/IhzB/yIcwf8iHMH/IhzB/yIb - wf8jG8L/IxvC/yMbwv8jG8L/IxvC/yMbwv8jG8L/IxvC/yIcwf8iHMH/IhzB/yIcwf8iHMH/IhzB/yIc - wf8iHMH/IhzB/yMcwf8jHMH/IxzB/yMcwf8jHMH/IxzB/yMcwf8jHMH/IRvC/yEaxf8jG8L/Ix68/yId - wf8jGcr/KRuy/5WS0f/1/fb/+vr2//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//z6+v/8+vr//Pr6//v6 - +v/5+fn/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j5+P/4+ff/+Pn3//j59//4+ff/9/j2//f4 - 9v/3+Pb/9/j2//b39v/29vb/9vb2//b29v/29vb/9vb2//b29v/29vb/+fb2//n28//v9/T/8PT6//n1 - 9f/19vf/d3PU/xwXuf8gG77/Ihq9/yEZv/8hGb//HiO5/xM8yP8FYcz/AGzr/wBo+P8AZv//AGb//wBm - //8AZv//AGb//wBl//8Afv//ALr//wDp//8A/f//AP///wD///8A////AP///wD///8A////AP///wD/ - //8A////AP///wD///8A////AP///wD///8A////AP///wD///8Az///AHT//wBk//8AZ///AmD6/xcv - y/8hGrf/IBu5/yAbuP8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8b - t/8fG7f/Hhq2/x4atv8eGrb/Hhq3/x4at/8gHLL/IBq2/x8Yu/8eGrf/Ihm0/zcpqv+fmtD/yMzPl8PE - 1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPFzQDNz9MkoqO56zQycv8dFnP/Hxhz/x8Y - c/8fGHP/Hxhz/x8Yc/8fGHP/Hxhz/x8Yc/8dF3L/IBeP/yYeu/8eHMP/Hh28/yIcvf8kGcP/IRrC/yAd - vv8hG8D/IRrB/yEawf8hGsH/IRrB/yEawf8hGsH/IRrB/yEawf8hGsH/IRrB/yEawf8hGsH/IRrB/yEa - wf8hGsH/IRrB/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yIbwP8iG8D/IhvA/yIb - wP8iG8D/IhvA/yIbwP8iG8D/IxzB/yQdwv8kHcL/JB3C/yQdwv8kHcL/JB3C/yQdwv8kHcL/Ix3C/yMd - wv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMd - wv8kHMP/JBzD/yQcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yQcw/8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMd - wv8jHcL/Ix3C/yMdwv8kHcL/JB3C/yQdwv8kHcL/JB3C/yQdwv8kHcL/JB3C/yMbxv8jG8b/Jh3C/yUf - vv8iHsH/IhjL/yUVv/9dV7j/4+z2//n6+f/7+fn/+/n5//v5+f/6+Pj/+vj4//r4+P/6+Pj/+/n5//v5 - +f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/4+fj/+Pn3//j59//4+ff/+Pn3//j5 - 9//4+ff/+Pn3//j59//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//n29v/59vP/7/f0//D0 - +f/59fX/9vf3/3h01f8cGLn/IBu9/yIavP8hGr7/IRq+/yEav/8dI8f/ET7f/wxK6f8FWvX/AWT9/wBm - //8AZ///AGb//wBm//8AZv//AHH//wCA//8Am///AMb//wDb//8A+f//AP7//wD///8A////AP///wD/ - //8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wDR//8AdP//AGT//wBn - //8EXPb/GS7M/yIbu/8gG7r/Hxu4/x8buP8fG7j/Hxu4/x8buP8fG7j/Hxu4/x8buP8fG7f/Hxu3/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8eGrj/IR2z/yEbt/8fGbv/Hhq3/yIZtP83Kar/n5rQ/8jM - z5fDxNYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDxc0Azc/TJKKjues0MnL/HRZz/x8Y - c/8fGHP/Hxhz/x8Yc/8fGHP/Hxhz/x8Yc/8fGHP/HRZz/yAWkf8mHbz/HhzD/x4dvf8iHL7/JBnE/yEa - w/8gHL7/IRvA/yEawf8hGsH/IRrB/yEawf8hGsH/IRrB/yEawf8hGsH/IRrB/yEawf8hGsH/IRrB/yEa - wf8hGsH/IRrB/yEawf8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8iG8D/IhvA/yIb - wP8iG8D/IhvA/yIbwP8iG8D/IhvA/yMcwf8kHcL/JB3C/yQdwv8kHcL/JB3C/yQdwv8kHcL/JB3C/yMd - wv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMd - wv8jHcL/JBzD/yQcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yQcw/8kHMP/Ix3C/yMdwv8jHcL/Ix3C/yMd - wv8jHcL/Ix3C/yMdwv8jHcL/JB3C/yQdwv8kHcL/JB3C/yQdwv8kHcL/JB3C/yQdw/8jGsj/JRvF/yce - v/8lHcD/JB7E/yAax/8jFsX/NS2o/7zA5f/6+v3/+/n5//v5+f/7+fn/+vj4//r4+P/6+Pj/+vj4//r4 - +P/6+Pj/+vj4//r4+P/6+Pj/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+/n5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn4//n6+P/5+vj/+fr4//n6 - +P/5+vj/+fr4//n6+P/5+vj/+Pj4//f39//39/f/9/f3//f39//39/f/9/f3//f39//69/f/+vf0//D4 - 9f/x9fr/+vX2//X29v93ctP/Gxe4/x8avP8hGrz/IRq+/yEavv8hGr7/IRm9/yEZvf8hGr7/HSTH/xks - zf8PQuH/Ck/r/wNe+P8AZv//AGf//wBm//8AZP//AGT//wBk//8Acf//ALD//wD7//8A////AP///wD/ - //8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ANH//wB0 - //8AZP//AGf//wRc9v8ZLs3/IRq6/x8auf8fGrn/Hxq5/x8auf8fGrn/Hxq5/x8auf8fGrn/Hxu4/x8b - t/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hhq4/yEds/8hG7f/Hxi7/x4at/8iGbT/Nymq/5+a - 0P/IzM+Xw8TWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw8XNAM3P0ySio7nrNDJy/x0W - c/8fGHP/Hxhz/x8Yc/8fGHP/Hxhz/x8Yc/8fGHP/Hxhz/x0Wc/8gFpH/Jh28/x4bxP8eHL7/Ihy+/yQY - xP8hGsP/IBy+/yEawf8hGsL/IRrB/yEawf8hGsH/IRrB/yEawf8hGsH/IRrB/yEawf8hGsH/IRrB/yEa - wf8hGsH/IRrB/yEawv8hGsH/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IhvA/yIb - wP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8jHMH/JB3C/yQdwv8kHcL/JB3C/yQdwv8kHcL/JB3C/yQd - wv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMd - wv8jHcL/Ix3C/yQcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yMdwv8jHcL/Ix3C/yMd - wv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yQdwv8kHcL/JB3C/yQdwv8kHcL/JB3C/yQdwv8kHcP/IxnK/yUc - w/8nH7z/JxzD/yIbxP8eHML/IhnE/yccq/+Egcj/9fP8//z5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+/n5//v5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//r7+f/6+/j/+vv4//r7 - +P/6+/j/+vv4//r7+P/6+/j/+vv4//n5+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+/j3//v4 - 9P/x+fX/8vb7//z39//4+Pj/eHTU/xsXuf8fG73/IRq8/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEZ - vf8hGb3/IRq+/yEavv8bKMr/FzHR/w1H5f8HVfD/AWP9/wBm//8AZP//AHr//wDk//8A////AP///wD/ - //8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/ - //8A0f//AHX//wBk//8AZ///BF33/xguzP8fGbj/Hxq5/x8auf8fGrn/Hxq5/x8auf8fGrn/Hxq5/x8b - uP8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x8bt/8fG7f/Hxu3/x4auP8hHbP/IRu3/x8Yu/8eGrf/Ihm0/zcp - qv+fmtD/yMzPl8PE1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPFzQDNz9MkoqO56zQx - cv8dFnT/Hxdz/x8Yc/8fGHP/Hxhz/x8Yc/8fGHP/Hxhz/x8Yc/8dFnP/IBaR/yYdvP8eG8T/Hh2+/yIc - vv8kGMT/IRrD/yAcv/8hG8L/IRrD/yEaw/8hGsP/IRrD/yEaw/8hGsP/IRrD/yEaw/8hGsP/IRrD/yEa - w/8hGsP/IRrD/yEaw/8hGsP/IRrC/yEbwf8hG8H/IRvB/yEbwf8hG8H/IRvB/yEbwf8hG8H/IhvB/yIb - wf8iG8H/IhvB/yIbwf8iG8H/IhvB/yIbwf8iG8H/IxzB/yQdwv8kHcL/JB3C/yQdwv8kHcL/JB3C/yQd - wv8kHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdwv8jHcL/Ix3C/yMdw/8jHcP/Ix3D/yMd - w/8jHcP/Ix3D/yMcw/8jHMP/JBzD/yQcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yQcw/8jHMP/Ix3D/yMd - w/8jHcP/Ix3D/yMdw/8jHcP/Ix3D/yMdw/8kHcP/JB3D/yQdw/8kHcP/JB3D/yQdw/8kHcP/JBzD/yMZ - yf8kHcL/Jh+9/yYbxP8jHMb/HRu+/yEbwv8lG7j/Tkmv/+Hg8//6+fv//Pr4//z4+v/9+vv//Pz5//z6 - /P/9+vz//fv5//v6+f/7+vr/+/r6//v6+v/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+/n5//v5+f/6+fn/+fn5//n5+P/5+fn/+fn5//n5+f/5+Pr/+fj7//f1+v/j4e7/29vr/9rc - 6v/a3Or/2t3p/9vc6v/b2+v/3Nzq/9zc6v/b2+r/2tvq/9rb6v/a2+r/2tvq/9rb6v/a2+r/2tvq/9va - 6v/b2en/09rp/9PY7P/Z1+v/1Nbt/2poz/8dG7j/IB2+/yIbvv8hGr7/IRq+/yEavv8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/Ihm+/yIZvf8hG7//Ejzb/wFk/f8AZf//AGz//wDE//8A////APf//wDD - //8Awv//AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/ - //8A////AP///wDV//8Ae///AGX//wBn//8EXff/Fi/N/yAZuf8fGrr/Hxq6/x8auv8fGrr/Hxq6/x8a - uv8fG7n/Hxu4/x8buP8fG7j/Hxu4/x8auP8fGrj/Hxq4/x8auf8eGrj/IB2z/yEbt/8fGbv/Hhu3/yEa - s/82Kar/nprP/8jMzpfDxdUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDxM4Azc7UJKKi - uus0MHT/HRV1/x4WdP8eFnP/HhZz/x4Wc/8eFnP/HhZz/x4Wc/8eFnP/HRZ0/yAWkf8lG7z/HhvE/x8d - v/8iG7//JBjE/yEZxP8gHMD/IxzC/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcxP8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzD/yMcwv8jHMP/IxzE/yEbwv8jHMP/IxzD/ykkrf+qrdr/9/v+//z99//+9/z//Pr5//j9 - 9f/39/3/+vj7//v99P/6+vn/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6 - +v/6+vr/+fn5//n5+f/5+fn/+fn5//n6+P/5+vf/+fr3//n6+P/8+/z/+vj9//n1/v/y7Pv/gny3/zMw - j/8zMZD/MjGR/zE0if8yMoz/NC+S/zYxjf82MY7/NDGN/zMyjf8zMo3/MzKN/zMxjf8yMYz/MjGM/zIx - jP8zMYz/NDGM/zIyjP8vMY7/LjCR/ysvmv8kJqn/ICC4/x8ewP8gHMH/IRvA/yEbwP8hG8D/IRvA/yEb - wP8hG8D/IRvA/yEbwP8iG8D/IhvA/yIbwP8iGr//FTbX/wFj/P8AZv//AGj//wC7//8A/P//ANr//wCU - //8AZ///AKH//wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/ - //8A////AOT//wC0//8A5///AMH//wB0//8AZv//AGf//wNe+P8WMtL/IRu+/yEavf8hGr3/IRq9/yEa - vf8hGr3/IRu8/yEbvP8hG7z/IRu8/yAau/8fGbr/Hxm6/x8Zuv8fGbr/Hhq5/x8ds/8gG7f/Hxm7/x4c - uP8hG7T/NSqo/5yazP/HzcyXwcXSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw8TOAM3O - 1CSiorrrNDB0/x0Vdf8eFnT/HhZz/x4Wc/8eFnP/HhZz/x4Wc/8eFnP/HhZz/x0WdP8gFZL/JRu8/x4b - xP8fHb//Ihu//yQYxf8hGcT/IBzA/yMcwv8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcxP8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzE/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcxP8fGa//bWu6/+vx+//6/Pf//vr8//z7 - 9//3+/n/9/j9//r6+f/7/Pb/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6 - +v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/5+fn/+fr4//n6+P/5+vj/+vr7//r4/f/38/7/+vX//6um - 4/8pIqv/HxS0/x8Vt/8eF7H/Hxmv/yAXsv8iFbb/Ixey/yEXsP8gFrH/IBax/yAWsf8hFrH/IRey/yEX - sv8hF7L/Ihex/yUYrv8kGaz/Ihqr/yAbq/8cGa7/Hhu2/yAcwf8fG8f/IBrE/yEbwP8hG8D/IRvA/yEb - wP8hG8D/IRvA/yEbwP8hG8D/IhvA/yIbwP8iGr//HSbJ/wZZ9P8AZ///AGX//wCO//8A1P//AKH//wBw - //8AZf//AGP//wCc//8A/f//AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/ - //8A////AP///wDS//8AZ///AHH//wBz//8Abv//AGf//wBm//8AZ///A2D6/xM62v8gHMD/IRq+/yEa - vv8hGr7/IRq+/yEbvf8hG7z/IRu8/yEbvP8gGrv/Hxm6/x8Zuv8fGbr/Hhm6/x0auv8fHbP/IBq3/x8Z - u/8eHLj/IRu0/zUqqP+cmsz/x83Ml8HF0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPE - zgDNztQkoqK66zQwdP8dFXX/HhZ0/x4Wc/8eFnP/HhZz/x4Wc/8eFnP/HhZz/x4Wc/8dFnT/IBWS/yUb - vP8eG8T/Hx2//yIbv/8kGMX/IRnE/yAcwP8jHML/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMT/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxP8jHMP/IxzD/yMcw/8jHMP/IxzE/yQdxP8jHMT/Ixq7/z00qf/Hzer/+v37//38 - +f/8/Pn/+Pj9//f6+v/6/Pb/+/r6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6 - +v/6+vr/+vr6//r6+v/7+/v/+/v7//v7+//7+vv/+fj7//n4+v/5+fn/+fn5//n5+v/5+Pz/+vf9//j1 - /v/b3/z/VlfK/yEWwv8kGs//IBvM/x4ewv8fHsH/IRfN/yIbxP8iHML/IRrF/yEaxf8hGsX/IhrF/yIa - xf8iGsX/IhvF/yMZx/8mF8v/JhjJ/yUaxf8kHML/Ihy//yEbwP8gG8P/IBvF/yEbw/8hG8D/IRvA/yEb - wP8hG8D/IRvA/yEbwP8hG8D/IRvA/yIbwP8iGsD/HiPH/wlS7v8AZ///AGb//wBq//8Ajf//AHP//wBk - //8AZv//AGb//wBl//8Aff//AOr//wD///8A////AP///wD+//8A+v//AP///wD///8A////AP///wD/ - //8A////AP///wD///8A1P//AGj//wBl//8AZf//AGb//wBm//8AZv//AGb//wBn//8BY/z/D0Pi/x8e - wf8hGb7/IRq+/yEavv8hG73/IRu8/yEbvP8hG7z/IBq7/x8Zuv8fGbr/Hxm6/x4Zuv8dGrr/Hx20/yAa - uP8fGLz/Hhy5/yEbtP81Kqj/nJrN/8fMzJfBxdMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADDxM4Azc7UJKKiuus0MHT/HRV1/x4WdP8eFnP/HhZz/x4Wc/8eFnP/HhZz/x4Wc/8eFnP/HRZ0/yAV - kv8lG7z/HhvE/x8dv/8iG7//JBjF/yEZxP8gHMD/IxzC/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMT/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMb - xv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMb - xv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMb - xv8jG8b/IxvG/yMbxv8jHMX/IxzF/yMcxf8jHMX/IxzF/yQdxf8kHcX/IxzF/yYdxv8oG7H/iYvI//P6 - /f/6/Pf/+/r7//j4/v/3/Pf/+vz2//v6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6 - +v/6+vr/+vr6//r6+v/7+/v//Pz8//z8/P/8/Pz/+/v8//n4/P/5+Pv/+fj6//n4+v/5+Pr/+Pf6//f2 - +f/5+fz/7Pf+/5qm5P8uKLj/IRjF/xwaw/8aIbn/GiG5/xsbxP8dH73/Hx+8/x8ev/8fHr7/Hx6+/x8e - vv8fHr7/Hx6+/x8evv8fHML/HxjI/yAZx/8gG8P/IB2//x4cuv8eHbr/IB28/yIevf8hHb//IRvA/yEb - wP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8iG8D/IhvA/w9E4v8AZ///AGb//wBm//8AZv//AGX//wBl - //8AZ///AWT9/wBl/v8AZv//AGv//wDg//8A////AP///wD///8A7///AJv//wDS//8A/v//AP///wD/ - //8A////AP///wD///8A////AOz//wCB//8AZP//AGb//wFk/f8AZf7/AGf//wBn//8AZ///AGb//wBl - /v8ORuT/Hx7B/yEZvf8hGr7/IRu9/yEbvP8hG7z/IRu8/yAau/8fGbr/Hxm6/x8Zuv8eGbr/HRq6/x8d - tP8gGrj/Hxi9/x4cuf8hG7T/NSqp/5yazv/HzM2XwcTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAw8TOAM3O1CSiorrrNDB0/x0Vdf8eFnT/HhZz/x4Wc/8eFnP/HhZz/x4Wc/8eFnP/HhZz/x4W - dP8hF5P/Jx2+/x8cxf8fHb//Ix3A/yUZxv8jGsb/Ih3B/yMdwv8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzE/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/JB3G/yQdxv8kHcb/JB3G/yQdxv8kHcb/JB3G/yQdxv8kHcb/JB3G/yQd - xv8kHcb/JB3G/yQdxv8kHcb/JB3G/yQdxv8kHcb/JB3G/yQdxv8kHcb/JB3G/yQdxv8kHcb/JB3G/yQd - xv8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQc - x/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQc - x/8kHMf/JBzH/yQcx/8kHMf/JBzG/yQdxv8kHcb/JB3G/yQdxv8kHcb/JB3G/yQdxv8kHMn/Ihe//0pG - r//c4fX/+/38//r4/f/5+/z/+f74//v9+f/9/Pv//Pz8//z8/P/8/Pz/+/v7//r6+v/6+vr/+vr6//r6 - +v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+//6+fz/+vn9//r5/P/6+fv/+fj6//n5 - +v/5+fn/+fr5//L6+//Z4fn/YljH/ycUwf8iGcT/Hx6//x4dwv8fHcL/IRzD/yIcxP8jHMT/IxzE/yMc - xP8jHMT/IhvE/yIbxP8jG8T/IRzD/x0ewf8dHsD/Hh++/x8gvP8fH7z/Hx67/yAcvP8iHb7/IhzA/yEb - wP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IhvA/xU32P8CYvz/AGb//wBm//8AZv//AGb//wBn - //8CYvz/DEvn/xgx0f8IU+7/AGf//wBs//8A4P//AP///wD///8A/v//ALH//wBl//8AcP//AJ///wDr - //8A////AP///wD///8A////AP///wD+//8Akv//AGT//wNf+f8XMdH/FDbW/wpN6v8KT+v/BVr1/wBl - //8AZv//AGb//wxJ5/8fH8L/IRq+/yEbvf8hG7z/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IBq8/x8b - vP8gHrf/Ihu7/yAavv8fHLv/Ihu2/zYrrP+dm9D/yMzOl8LE1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMPEzgDNztQkoqK66zQwdP8dFXX/Hxd0/x8XdP8fF3T/Hxd0/x8XdP8fF3T/Hxd0/x8X - dP8eF3X/IheT/ycevv8fHMX/Hx7A/yQdwf8mGsf/IxvG/yIdwv8jHcL/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcxP8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMb - xv8jG8b/IxvG/yMbxv8jG8b/IxvG/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQc - x/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQc - x/8kHMf/JBvI/yQbyP8kG8j/JBvI/yQbyP8kG8j/JBvI/yQbyP8kG8j/JBvI/yQbyP8kG8j/JBvI/yQb - yP8kG8j/JBvI/yQbyP8kG8j/JBvI/yQbyP8kG8j/JBvI/yQbyP8kG8j/JBvI/yQbyP8kG8j/JBvI/yQb - yP8kG8j/JBvI/yQbyP8kG8j/JBvI/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/IhvH/x8a - xf8nHq7/p6bc//j5///7+f//+v35//n++f/8/P3//f36//z8/P/8/Pz//Pz8//z8/P/6+vr/+vr6//r6 - +v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r5+//6+fz/+vn8//n4 - +//5+fn/+fr4//n69//3+ff/9vb9/7aq7f89JcH/KxjG/yUZyP8jGcr/JB3B/yYYyv8mGMr/JhnI/ycZ - yP8nGcj/JxnI/ycZyP8nGcj/JxnI/yUax/8gHsL/Hx7C/x8dw/8gHcT/IBvE/yAZxv8hGMn/IhfK/yEZ - xf8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRq//xgv0f8CYfv/AGf//wBm//8AZv//AGf//wBl - /v8JUu7/GDHS/yAdwP8iGr3/D0Ti/wBn//8Aa///ANn//wD///8A////ANv//wB0//8AZf//AGX//wBk - //8Afv//AMH//wDz//8A////AP///wD///8A////AJP//wBk//8CYPr/GSvN/yIYvf8hGr7/IRq+/xwl - x/8YL9D/FzDR/w5G5P8IVPD/EznZ/yAbv/8hG73/IRu8/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yAb - vf8fG77/IR64/yIbvP8hGsD/Hx28/yIbtv83K6z/nprR/8jMz5fCxNYAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADDxM4Azc7UJKKiuus0MHT/HRV2/yAYdf8gGHX/IBh1/yAYdf8gGHX/IBh1/yAY - df8gGHX/Hhd1/yIXk/8nHr7/HxzF/x8ewP8kHcH/JhrH/yMbxv8iHcL/Ix3C/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMT/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMb - xv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQc - x/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQc - x/8kHMf/JBzI/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQb - yf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQb - yf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kHMj/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yEd - xf8bH8L/IBW9/2RZvv/r6fz/+v37//r++f/6/fv//Pz8//38+//8/Pz//Pz8//z8/P/8/Pz/+vr6//r6 - +v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vv5//r7+P/6+/j/+vr6//r5 - /f/5+Pz/+fj6//n5+f/5+vf/+/v1//v69f/q5fz/c2XO/y4cwP8nGMr/JB3D/yUgu/8mGsf/JhrG/yUc - wv8lHML/JRzC/yUcwv8lHML/JRzC/yUcwv8lHMP/IxvF/yIbxv8iGsj/IhrJ/yIZyv8iF8z/IhfN/yIX - zv8hGcf/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yAcwf8NSuf/AGf//wBm//8AZ///AGX+/wdW - 8v8VN9f/IB/E/yIav/8hHL//Ihu+/w9F4v8AZ///AGb//wCt//8A////APv//wCZ//8AY///AGb//wBn - //8AZ///AGT//wBn//8Aj///ANn//wD+//8A////AP///wCT//8AY///AGf//xE+3f8iGb3/IRq+/yEa - vv8hGb3/Ihm9/yIZvf8hGr7/IBu//x8ewv8gHMD/IRu9/yEbvP8hG7z/IRu8/yEbvP8hG7z/IRu8/yEb - vP8gG73/Hxu+/yEduP8iG7z/IRnA/x8cvP8iGrf/Nyut/52a0f/IzNCXwsTWAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAw8TOAM3O1CSiorrrNDB0/x4Vdv8hGXb/IRl2/yEZdv8hGXb/IRl2/yEZ - dv8hGXb/IRl1/x4Xdf8iF5P/Jx6+/x8cxf8fHsD/JB3B/yUax/8jG8b/Ih3C/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzE/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMb - xv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQc - x/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQc - x/8kHMf/JBzH/yQcyP8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQb - yf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQb - yf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBzI/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQc - x/8hH8P/GCK8/yEXyP86JbP/wr3j//z/+P/6/Pv/+vz7//z9+v/9+/3//Pz8//z8/P/8/Pz//Pz8//r6 - +v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r7+f/6/Pb/+vz2//r7 - +f/6+fz/+fj8//n4+//5+fn/+fr4//379v/7+vP/9fj6/7e28f88K8z/JBTP/yIfvv8iILz/IxrI/yIb - xf8hHcH/IR3C/yEdwf8hHcH/IR3B/yEdwv8hHcL/Ih3C/yUcw/8lHMT/JBzE/yQcxP8kHMX/JBzF/yMd - xP8iHsP/IRzB/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/Gi3P/wNe+f8AZv//Bljz/xQ5 - 2f8fIMT/Ihq//yIbwP8iG8D/IRy//yIbvv8PQ+H/AGf//wBj//8AmP//AP///wDN//8Aa///AGb//wNf - +v8RP+D/CFXx/wBl/v8AZ///AGX//wBw//8Apv//AOj//wD///8Al///AGP//wBo//8QQeD/Ihm9/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr7/IRq+/yEbvf8hG7z/IRu8/yEbvP8hG7z/IRu8/yEb - vP8hG7z/IBu9/x8bvv8hHbn/Ihu8/yEZwf8fHL3/Ihq4/zcqrf+dmtH/yMzQl8LE1wAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLDzQDMzdQkoqK66zUxdP8eFnf/IBl4/yAZd/8gGXf/IBl3/yAZ - d/8gGXf/IBl3/yAZd/8eGHb/IBeT/yYdvv8fHMb/IB7B/yMewv8lGsj/IxvH/yIewv8jHMX/JBzG/yQc - xv8kHMb/JBzG/yQcxv8kHMb/JBzG/yMcxv8iHMb/IhzG/yIcxv8iHMb/IhzG/yIcxv8iHMb/IhzG/yIb - x/8iG8j/IhvI/yIbyP8iG8j/IhvI/yIbyP8iG8j/IxvI/yMcx/8jHMf/IxzH/yMcx/8jHMf/IxzH/yMc - x/8jHMf/IxzH/yMcx/8jHMf/IxzH/yMcx/8jHMf/IxzH/yMcx/8jHMf/IxzH/yMcx/8jHMf/IxzH/yMc - x/8jHMf/IxzH/yMcx/8jHMj/IxzJ/yMcyv8jHMr/IxzK/yMcyv8jHMr/IxzK/yMcyv8jHMr/IxzK/yMc - yv8jHMr/IxzK/yMcyv8jHMr/IxzK/yMcyv8jHMr/IxzK/yMcyv8jHMr/IxzK/yMcyv8jHMr/IxzK/yMc - yv8jHMr/IxzK/yMcyv8jHMr/IxzK/yMcyv8jHMr/IxzK/yMcyP8jHcf/Ix3I/yQdyP8jHMf/IxzH/yMc - x/8jHMf/IR7C/yAjvP8jGNH/KBe+/3h3vv/w9fv/+/n8//z7+P/8/fr/+/n///z8/P/8/Pz//Pz8//z8 - /P/7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/r/+vv4//r7 - +P/6+vr/+vr7//r5+//6+fv/+vn6//r6+f/7+vj//Pj6//n5+f/q7vv/em/i/yYV0v8dHMT/Hx+9/yUc - xv8jG8f/IRzG/yEdxP8hHsP/IB3D/yAdw/8gHMT/IBzF/yIcxf8kHMP/JBzD/yQcwv8kHcL/JB3C/yQe - wv8jH8D/Ix/A/yIdwf8iHMH/IhzC/yIcwv8iHML/IhzC/yIcwv8iHML/IhvC/yIcwv8UO9z/EUHh/x8k - yP8jG8H/IxvB/yMcwv8jHML/IhzB/yIcwf8iG8D/FzLU/wJi/P8AY///AJn//wDv//8Ahf//AGX//wBn - //8PQ+P/IhnA/x8gxv8SPt7/A175/wBn//8AZv//AGT//wCC//8Aw///ALT//wBn//8AZ///EEHg/yIZ - vv8hG7//IRu//yEbv/8hG7//IRq//yEav/8gGr//IBq//yAavv8hG73/IRu8/yEbvP8hG7z/IRu8/yEb - vP8hG7z/IRu8/yAbvf8fGr7/IR25/yIbvf8hGcH/Hxy9/yIauP83Kq7/nZrS/8jM0JfCxNgAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCw80AzM3TJKKiuus1MXX/HhZ4/x8ZeP8fGXj/Hxl4/x8Z - eP8fGXj/Hxl4/x8ZeP8fGXj/HRh3/x8Xk/8lHL7/IBzH/yAfwv8jHsP/JRvJ/yMcx/8hHsP/JBzI/yQb - yf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8jHMj/Ih3H/yIdxv8iHcb/Ih3G/yIdxv8iHcb/Ih3G/yIc - x/8iHMn/IhvK/yIbyv8iG8r/IhvK/yIbyv8iG8r/IhvK/yIcyf8iHMj/IhzH/yIcx/8iHMf/IhzH/yIc - x/8iHMf/IhzH/yIcx/8iHMf/IhzH/yIcx/8iHMf/IhzH/yIcx/8iHMf/IhzH/yIcx/8iHMf/IhzH/yIc - x/8iHMf/IhzH/yIcx/8iHMf/IhzI/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMd - yv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMd - yv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcn/Ix3I/yMdyP8jHcj/Ix3I/yIc - x/8iHMf/IhzH/yMdxP8mIMD/IxjR/yAYx/86O6r/y8zs//77/////Pj//Pr6//v7/v/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//r6 - +v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+fr7//r5+//8+fT/+vr1/8vH+f9HO9L/HxnJ/x4e - vf8lHcH/JBvH/yQcyP8kHcX/JB7D/yMewv8jHcL/IxzE/yMcxf8jG8b/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMT/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/Ix3E/yMc - w/8jG8P/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/x8lyv8DX/n/AGT//wCT//8As///AGb//wBn - //8FW/b/HSXK/yIZwP8iGsH/IhrB/xwozf8MSej/AWP8/wBn//8AZP//AGr//wB8//8AZ///AGf//xBC - 4f8hGr//IRvA/yEbwP8hG8D/IRvA/yEbwP8gGr//IBq//yAav/8gGr//IRu+/yEbvP8hG7z/IRu8/yEb - vP8hG7z/IRu8/yEbvP8gG73/Hxq//yEduf8iG73/IRnB/x8cvf8iGrj/Nyqu/52a0v/IzNCXwsTYAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwsPNAMzN0ySiorrrNTF1/x4WeP8fGXj/Hxl4/x8Z - eP8fGXj/Hxl4/x8ZeP8fGXj/Hxl4/x0Yd/8fF5P/JRy+/yAbx/8gH8L/Ix7D/yUbyf8jHMj/IR7E/yQc - yP8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/IxvI/yIcx/8iHMf/IhzH/yIcx/8iHMf/IhzH/yIc - x/8iHMf/IhvJ/yIbyv8iG8r/IhvK/yIbyv8iG8r/IhvK/yIbyv8iG8r/IhzI/yIcyP8iHMj/IhzI/yIc - yP8iHMj/IhzI/yIcyP8iHMj/IhzI/yIcyP8iHMj/IhzI/yIcyP8iHMj/IhzI/yIcyP8iHMj/IhzI/yIc - yP8iHMj/IhzI/yIcyP8iHMj/IhzI/yIcyP8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMd - yv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMd - yv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyf8jHcn/Ix3J/yMd - yP8iHMj/IhzI/yIcyP8jHMj/IxzG/yMfy/8jH8v/JR+s/4mGyP/49f7//vr8//37+//7/Pr//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//j5/P/3+vT//Prw//vz/P/y7///lZTj/ykh - wf8hG8v/IhzI/yUbyv8kGsr/JBzI/yQdxf8kHcT/IxzE/yMcxP8jHMX/IxvG/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzE/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMbw/8fJMr/BF/5/wBm//8Abv//AGz//wBm - //8BZP3/FDja/yIawf8iGsH/IhrB/yIawf8iGcD/IRvC/xU22P8HVvH/AGb//wBm//8AZf//AGb//wBn - //8LTer/IB7D/yEbwP8hG8D/IRvA/yEbwP8hG8D/IBq//yAav/8gGr//IBq//yEavv8hG73/IRu9/yEb - vf8hG73/IRu9/yEbvf8hG73/IBq+/x8av/8hHbn/Ihu9/yEZwf8fHL3/Ihq4/zcqrv+dmtL/yMzQl8LE - 2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLDzQDMzdMkoqK66zUxdf8eFnj/Hxl4/x8Z - eP8fGXj/Hxl4/x8ZeP8fGXj/Hxl4/x8ZeP8dGHj/HxaV/yUcv/8gG8j/IB7D/yMexP8lG8n/IxzJ/yEe - xP8kHMj/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yMbyP8iHMf/IhzH/yIcx/8iHMf/IhzH/yIc - x/8iHMf/IhzH/yIbyf8iG8r/IhvK/yIbyv8iG8r/IhvK/yIbyv8iG8r/IhvK/yIcyf8iHMn/IhzJ/yIc - yf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIc - yf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIcyf8iHMr/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMdyv8jHcr/Ix3K/yMd - yv8jHcr/IhzJ/yIcyf8iHMn/IhvK/yAbzP8gIsX/HxzI/yYawf9JQav/19Xx//36/v/+/Pr//f34//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/4+v3/+f74//388///9f7/+fT9/93k - +f9lYtL/IxfO/yAaz/8iGsv/JBnM/yQayv8kG8n/JBvH/yMcxf8jHMX/IxzF/yMbxv8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMT/IxzE/yMcxP8jHMT/IxzE/yMcxP8jHMT/IxzE/yMc - w/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jG8P/HyTJ/wRd9/8AZ///AGb//wBm - //8AZ///CVHu/yAexP8iGsH/IhrB/yIawf8iGsH/IhrB/yIawf8iGcD/HiLG/xBB4P8CYfv/AGf//wBm - //8AZv//BF33/x0kyP8hGr//IRvA/yEbwP8hG8D/IRvA/yAav/8gGr//IBq//yAav/8hGr7/IRq+/yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yAav/8fGr//IR25/yIbvf8hGcH/Hxy9/yIauP83Kq7/nZrS/8jM - 0JfCxNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCw80AzM3TJKKiuus1MXX/HhZ4/x8Z - eP8fGXj/Hxl4/x8ZeP8fGXj/Hxl4/x8ZeP8fGXj/HRd4/yAXlf8mHMD/IBvI/yAew/8jHcT/JRrK/yMc - yf8hHsT/JBzI/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8jHMn/IhzI/yIcyP8iHMj/IhzI/yIc - yP8iHMj/IhzI/yIcyP8iG8r/IhvK/yIbyv8iG8r/IhvK/yIbyv8iG8r/IhvK/yIbyv8iHMn/IhzJ/yIc - yf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIc - yf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIcyf8iHMn/IhzK/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/Ix3K/yMd - yv8jHcr/IxzK/yIcyf8iHMn/IhzJ/yEby/8fG8//HR7G/yAdyv8oG87/LCCu/5OP0f/19v7/+/v3//78 - +f/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//v7+//6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/9/r8//n8+//+/PX///n3//34 - +//3/Pn/vMDy/z8z0P8fFsv/IRjM/yQZzf8lGsz/JBrK/yMayf8jGsj/IxvG/yMcxf8jHMX/IxvG/yMb - xv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jHMb/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yIexf8NS+n/AGf//wBm - //8AZv//AmP8/xgw1P8jGcH/IhrB/yIawf8iGsH/IhrB/yIawf8iGsH/IhvB/yIbwP8hG8D/GizO/wtN - 6v8BZP7/AGf//wJg+v8cJsn/IRq//yEbwP8hG8D/IRvA/yEbwP8gGr//IBq//yAav/8gGr//IRq//yEa - vv8hGr7/IRq+/yEavv8hGr7/IRq+/yEavv8hGr//Hxq//yEduf8iG73/IRnB/x8bvf8iGrj/Nyqu/52a - 0v/IzNCXwsTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwsPNAMzN0ySiorrrNTF1/x4W - eP8fGXj/Hxl4/x8ZeP8fGXj/Hxl4/x8ZeP8fGXj/Hxl4/x0Xef8hF5f/KB7C/yEcyv8gHsT/Ix3F/yUa - y/8jG8r/IR3F/yQcyP8kG8n/JBvJ/yQbyf8lHMr/JRzK/yUcyv8lHMr/JBzK/yMdyv8jHcr/Ix3K/yMd - yv8jHcr/Ix3K/yMdyv8jHcr/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jG8z/IxvM/yMbzP8jG8z/IxvM/yMb - zP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMb - zP8kHMz/JBzN/yQczf8kHM3/JBzN/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8iHMv/HhzM/x4bzv8hHMz/JRvO/yYZwv9KRbH/1dr0//n6 - +//9+fz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/+/v7//r6+v/6+vr/+vr6//n5/P/4+vv//P30///9 - 8v//+/b//f33//Dz//+Rjeb/KyHB/yMZyf8jGcn/JBrK/yMZyv8iGMn/JBvJ/yQbyP8kHMf/JB3G/yQc - x/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQcx/8kHMf/JBzH/yQdxv8kHcb/JB3G/yQdxv8kHcb/JB3G/yQd - xv8kHcb/IxzE/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8kG8L/Ej/f/wBn - //8AZv//AGf//w9H5v8jHcT/JBzD/yQcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yQcw/8jHcL/Ix3C/yQc - wf8hIMX/FTjZ/wVZ9P8DYPr/HCbJ/yEav/8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yIb - wP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/IRvA/x8av/8hHbn/Ihu9/yEYwf8fG7z/Ixq5/zcr - r/+dmtL/x8zPl8LE2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLDzQDMzdMkoqK66zUx - df8eFnj/Hxl4/x8ZeP8fGXj/Hxl4/x8ZeP8fGXj/Hxl4/x8ZeP8dF3n/IReY/ygdw/8hHMv/IB7F/yMd - xf8lGcv/IxvK/yEdxf8kHMj/JBvJ/yQbyf8kG8n/JRzK/yUcyv8lHMr/JRzK/yQcyv8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxvM/yMbzP8jG8z/IxvM/yMb - zP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMb - zP8jG8z/IxvM/yIazP8iGsz/IhrM/yMazP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMb - zP8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/Ih3K/x8eyP8hGdH/IxrP/yMbzf8iGs3/JCGs/5CU - z//39////fr+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//v7+//6+vr/+vr6//r6+v/7+fv/+/v4//n8 - 9v/7+/f//v30///8+f/7+P3/4uT9/3Bn1v8oH7//JB3H/yIaxv8lG8r/JBrK/yQayv8kG8n/JBzH/yQc - x/8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQcyP8kHMf/JBzH/yQcx/8kHMf/JBzH/yQc - x/8kHMf/JBzG/yMcxP8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/JBvC/xM/ - 3/8AZ///AGf//wVc9/8eJ8z/JBvD/yQcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yQcw/8kHMP/Ix3C/yMd - wv8jHcL/Ix3C/yIbwP8eIsb/EUDf/x0jx/8hGsD/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEb - wP8iG8D/IhvA/yIbwP8iG8D/IhvA/yIbwP8iG8D/IhvA/yEawf8fGsD/IR25/yIbvf8hGMH/Hxu8/yMa - uf83K6//nZrS/8fLz5fCxNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCw80AzM3TJKKi - uus1MXX/HhZ4/x8ZeP8fGXj/Hxl4/x8ZeP8fGXj/Hxl4/x8ZeP8fGXj/HRd5/yEXmP8oHcT/IRvL/yAd - xf8jHcb/JRnL/yMay/8hHcb/JBzI/yQbyf8kG8n/JBvJ/yUcyv8lHMr/JRzK/yUcyv8kHMr/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMb - zP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMazv8jGs7/IxrO/yMa - zv8jGs7/IxrO/yMazv8jGs7/IxrO/yMazv8jGs7/IxrO/yMazv8jGs7/IxrO/yMazv8jGs7/IxrO/yMa - zv8jGs7/IxrO/yMazv8jGs3/IxrN/yMazf8jGs7/IxrO/yMazv8jGs7/IxrO/yMazv8jGs7/IxrO/yMa - zv8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yIcy/8hHsf/JBrO/yUY0f8hGtD/HBzL/x4f - uf9FRan/2Nbz//37/v/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/7+/v/+vr6//r6+v/6+vr//fv3//37 - 9v/2+fz/9Pr8//n89P/++vj//vj8//r5/f/NyvX/TUjL/yAavv8lH8X/Jh7J/yUbyv8kGsr/JBvJ/yQc - yP8kHMj/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kHMj/JBzH/yQcx/8kHMf/JBzH/yQc - x/8kHMf/JBzH/yQcx/8jHMT/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yQb - wv8TPt7/AGf//wBl//8SP+D/IxvC/yQcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yMd - wv8jHcL/Ix3C/yMdwv8iHMH/IRvA/yEcwf8hHMH/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEb - wP8hG8D/IhrB/yIawf8iGsH/IhrB/yIawf8iGsH/IhrB/yIawf8hGsH/HxrA/yEduf8iG73/IRjB/x8b - vP8jGrn/Nyuv/52a0v/Hy8+XwsTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwsPNAMzN - 0ySiorrrNTF1/x4WeP8fGXj/Hxl4/x8ZeP8fGXj/Hxl4/x8ZeP8fGXj/Hxl4/x0Xef8gF5j/KB3E/yAb - zP8fHcb/Ix3G/yUZzP8jGsv/IR3H/yMcyP8kG8n/JBvJ/yQbyf8lHMr/JRzK/yUcyv8lHMr/JBzK/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMb - zP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzf8jGs7/IxrO/yMa - zv8jGs7/IxrO/yMazv8jGs7/IxrO/yMazv8jGs7/IxrO/yMazv8jGs7/IxrO/yMazv8jGs7/IxrO/yMa - zv8jGs7/IxrO/yMazv8jG8//JBvP/yQbz/8kG8//JBvP/yMazv8jGs7/IxrO/yMazv8jGs7/IxrO/yMa - zv8jGs7/IxvN/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/Ix3J/yYdyf8mGdD/IRnS/xwe - y/8cIMH/JCGl/5OQzv/4+f///P38//z8/f/8/P3//Pz9//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/+/v7//r6+v/6+vr/+vr6//79 - 8//++/b/9fb///D6/f/2/Pj//Pr3///4+f/99v3/9PX+/6Wn9f81Msb/JB7A/yMcxf8jHMr/IxvL/yMa - y/8lG8n/JBzG/yQcyP8kHMj/JBvJ/yQbyf8kG8r/JBvJ/yQbyf8kHMj/JBzI/yQcx/8kHMf/JBzH/yQc - x/8kHMf/JBzH/yQcyP8kHMf/IxzF/yMcxP8jHMT/IxzE/yMcxP8jHMT/IxzE/yMcxP8jHMT/IxzD/yMc - w/8jG8P/GyzQ/wNg+v8IVfH/ICLI/yMcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yQc - w/8jHcL/Ix3C/yMdwv8jHcL/IhzB/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEbwP8hG8D/IRvA/yEb - wP8hG8D/IRvA/yIawf8iGsH/IhrB/yIawf8iGsH/IhrB/yIawf8iGsH/IRrB/yAawP8hHbn/Ihu9/yAZ - wv8eG73/Ihq5/zcrr/+emtL/x8zPl8LE2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTE - zwDOztYkoaG76zUwdv8eF3n/IBp5/yAaef8gGnn/IBp5/yAaef8gGnn/IBp5/yAaef8dGHn/HxeX/yYe - w/8fHMr/Hx7G/yMdyP8lGs7/IhrN/yEdyf8jHMr/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8iHMv/IRzL/yEcy/8hHMv/IRzL/yEcy/8hHMv/IRzL/yEbzP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEb - zP8hG8z/IRvM/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8iHM//IxzQ/yMc0P8jHND/IxzQ/yMc0P8jHND/IxzQ/yMc - 0P8jHND/IxzQ/yMc0P8jHND/IhzP/yIbzv8iG87/IhvO/yIbz/8jHND/IxzQ/yMc0P8jHM//IhvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IhvO/yMbzP8jHsf/IR7I/x8c - zf8dGdD/IBvO/yAcs/9AQqn/z9Xz//v9/f/7+v7//Pj///35///8/Pz//P74//v9+//6+v7//Pv+//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pj/+/r5//j4/f/3+vv/+fr6//v6+f/8+fr//Pn7//j6+v/o8Pz/lpLl/zMow/8iHcv/HB3L/xwc - zf8hGs//JxvJ/ygew/8kH8L/Ix/F/yMcyf8jG8z/IxrN/yMbzP8jHcn/Ix7G/yMdyP8iG8n/IhvJ/yIb - yf8iG8n/IhvJ/yIbyf8iG8n/IhvJ/yIcyP8iHMf/IhzH/yIcx/8iHMf/IhzH/yIcx/8iHMf/IxzH/yQd - xv8kHcX/JB3F/yEiyv8GWPT/GDHW/yQbxP8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMT/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHML/IxzC/yMcwv8jHML/IxzC/yMcwv8jHML/IhzC/yEa - wf8hGsH/IRrB/yEawf8iGsH/IhrB/yIawf8iGsH/IhrB/yIawf8iGsH/IhrB/yIZwv8hGsL/Ih28/yEb - wP8eGcT/GxzA/yAbvP83K7L/n5rV/8jL0ZfDxNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADExNAAzs7WJKGhu+s1MHf/Hhd5/yAaef8gGnn/IBp5/yAaef8gGnn/IBp5/yAaef8gGnn/HBh5/x8Y - l/8mHsP/HxzL/x4exv8iHcj/JBrO/yIbzv8gHcn/IxzK/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8iHMv/IRzL/yEcy/8hHMv/IRzL/yEcy/8hHMv/IRzL/yEcy/8hG8z/IRvM/yEbzP8hG8z/IRvM/yEb - zP8hG8z/IRvM/yEbzP8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IhzP/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd - 0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yIcz/8hG87/IRvO/yEbzv8iHM//Ix3Q/yMd0P8jHdD/Ix3Q/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEaz/8jGdD/IRzL/x8e - x/8fHMz/IBnW/yMZ1v8mIMX/ISKn/4SGzf/19f7/+Pn9//z7/f/++v///vv9//3/9//8/fr/+/n///z7 - /v/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz/+/v7//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/5+vr/9fr9/+Xs/P+BfN3/LCDL/x8Z - 0P8cHcn/ICHG/yQeyP8mHcr/JB/F/yMex/8jHcr/IxvM/yMbzP8jG8z/Ix3K/yMdyP8iHMn/IhvK/yIb - yv8iG8r/IhvK/yIbyv8iG8r/IhvK/yIbyv8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yMc - yP8kHMf/JBzH/yQcx/8hIsv/EkDi/yIeyP8jG8b/IxvG/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8hGsH/IRrB/yEawf8hGsH/IhrB/yIawf8iGsH/IhrB/yIawf8iGsH/IhrB/yIawf8iGcL/IRrD/yId - vf8gG8H/HRnF/xocwP8gG73/OCuz/5+a1v/Jy9KXxMPaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAxMTQAM7O1iShobvrNTB3/x4Xef8gGnn/IBp5/yAaef8gGnn/IBp5/yAaef8gGnn/IBp5/xwY - ef8fGJf/Jh7E/x8bzP8eHsb/Ih3I/yQZz/8iGs//IB3K/yMcy/8jG8z/IxvM/yMbzP8jG8z/IxvM/yMb - zP8jG8z/IhvM/yEbzP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEb - zP8hG8z/IRvM/yEbzP8hG8z/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yIcz/8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd - 0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8iHM//IRvO/yEbzv8hG87/IhzP/yMd0P8jHdD/Ix3Q/yMd - 0P8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hGtD/IxfU/yEa - z/8fHcr/HxzN/x8Y1f8iFtf/JBrO/yQfvf9BPKr/zsnt//j8/P/6//X//v38///7/f///vf//v34//35 - /v/8+v7//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//v7+//6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+fr6//X6+f/y+/v/3uX7/3hv - 3/8xHtD/Jh3L/x8iwP8dIMX/IR7S/yMbzf8jG8z/IxzL/yMcyv8jHcr/Ix3K/yMcy/8jHMv/IhzK/yIb - yv8iG8r/IhvK/yIbyv8iG8r/IhvK/yIbyv8iG8r/IhzJ/yIcyf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIc - yf8jHMj/JBzH/yQcx/8kHMf/Ix3I/yAhy/8jG8b/IxvG/yMbxv8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMc - w/8jHMP/IRrB/yEawf8hGsH/IRrB/yIawf8iGsH/IhrB/yIawf8iGsH/IhrB/yIawf8iGsH/IhnC/yEa - w/8iHb3/IBvB/x0Zxf8aHMD/IBu9/zgrs/+fmtb/ycvSl8TD2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMTE0ADOztYkoaG76zUwd/8eFnn/IBl6/yAZev8gGXr/IBl6/yAZev8gGXr/IBl6/yAZ - ev8cF3r/HxeY/yYdxP8fG8z/Hh3H/yIdyf8lGc//IhrP/yAcy/8jG8z/IxvM/yMbzP8jG8z/IxvM/yMb - zP8jG8z/IxvM/yIbzP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEb - zP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8iHM//Ix3Q/yMd0P8jHdD/Ix3Q/yMd - 0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/IhzP/yEbzv8hG87/IRvO/yIcz/8jHdD/Ix3Q/yMd - 0P8jHdD/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRrQ/yIX - 1f8hGdH/IB3K/yAdyv8iG9L/IxjX/yEW0/8lHM7/KByv/391xP/u8/z/9//x//z+9///+/7///34///9 - +P//+f7//fr+//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/7+/v/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/3+ff/9fn1//P5 - +f/d3vz/fW7i/zEdyf8iHMn/GR/J/xkczv8hGdH/IxrP/yMbzP8jHcn/Ix3I/yMdyv8jG8z/IxrO/yIa - zP8iG8r/IhvK/yIbyv8iG8r/IhvK/yIbyv8iG8r/IhvK/yIcyf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIc - yf8iHMn/IxzI/yQcx/8kHMf/JBzH/yQcx/8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMb - xv8jG8b/IxvG/yMbxv8jHMX/IxzF/yMcxP8jHMT/IxzE/yMcxP8jHMT/IxzE/yMcxP8jHMT/IxzD/yMc - w/8jHMP/IxzD/yEawf8hGsH/IRrB/yEawf8iGsH/IhrB/yIawf8iGsH/IhrB/yIawf8iGsH/IhrB/yIZ - wv8hGsP/Ih29/yAbwf8dGcX/GhzA/yAbvf84K7P/n5rW/8nL0pfEw9oAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADFxdEAz8/XJKKivOs2MXj/Hxd6/yAZe/8gGXr/IBl6/yAZev8gGXr/IBl6/yAZ - ev8gGXr/HRh7/yAYmf8nHsX/IBzN/x8dyP8iHMn/JBjQ/yEZz/8gHMv/IxvM/yMazf8jGs3/IxrN/yMa - zf8jGs3/IxrN/yMazf8iG83/IRvN/yEbzf8hG83/IRvN/yIczv8iHM7/IhzO/yIczv8iHM3/IhzN/yIc - zf8iHM3/IhzN/yIczf8iHM3/IhzN/yIczv8iHM//IhzP/yIcz/8iHM//IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IhzP/yIcz/8iHM//IhzP/yEbzv8hG87/IRvO/yEbzv8iHM//IhzP/yIc - z/8iHM//IhzP/yIcz/8iHM//IhzP/yIcz/8hG87/IRvO/yEbzv8hG87/IhzP/yIcz/8iHM//IhzP/yIc - z/8iHM//IhzP/yIcz/8iHM//IhzP/yIcz/8iHM//IhzP/yEbzv8hG87/IRvO/yEbzv8hG87/IhzP/yIc - z/8iHM//IhzP/yIcz/8iHM//IhzP/yIcz/8hG87/IRvO/yEbzv8hG87/IRvO/yIcz/8iHM//IhzP/yIb - 0P8iGtP/IhzP/yIfyP8iIMf/Ih7L/yEZ0P8hGdT/IRnT/ygbxf87MKX/vcLl//X/+f/5/ff///v9///8 - +////fr///r+//77/v/9/f3//f39//39/f/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//v7+//7+/v/+/v7//v7+//6+vr/+vr6//r6+v/6+vr//Pr8//z7 - +f/8+/j/+Pn8/97c/f99cOH/LBzM/x0cz/8bHs3/IhrS/yIYz/8iGsz/IxzJ/yMdyP8jHcr/IxvM/yMa - z/8jGs3/IxvL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMr/Ix3K/yMdyv8jHcr/IhzJ/yIc - yf8iHMn/IhzJ/yMcyf8kG8j/JBvI/yQbyP8kG8j/JBvI/yQbyP8kG8j/JBvI/yQbx/8kHMf/JBzH/yQc - x/8kHMf/JBzH/yQcx/8kHMf/JBzG/yQcxv8kHcb/JB3G/yQdxv8jHMX/IxzF/yMcxf8jHMX/IxzE/yMc - w/8jHMP/IxzD/yMcw/8iG8L/IhvC/yIbwv8iG8L/IxvC/yMbwv8jG8L/IxvC/yMbwv8jG8L/IxvC/yMb - wv8jGsP/IRrD/yIdvf8gG8H/HRnF/xscwf8gHL3/Nyuz/5+Z1f/IytGXw8LZAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAxcXRAM/P1ySjor3rNzJ4/x8Xev8gGHv/IBl7/yAZe/8gGXv/IBl7/yAZ - e/8gGXv/IBl7/x4Yff8gGJr/KB7H/yAcz/8fHcn/IRvJ/yQY0P8hGND/IBvL/yMbzf8jGs7/IxrO/yMa - zv8jGs7/IxrO/yMazv8jGs7/IhrO/yEbzv8hG87/IRvO/yEbzv8jHdD/Ix3Q/yMd0P8jHdD/Ix3P/yMd - zv8jHc7/Ix3O/yMdzv8jHc7/Ix3O/yMdzv8jHc7/Ix3Q/yMd0P8jHdD/Ix3Q/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yMd0P8jHdD/Ix3Q/yMd0P8hG87/IRvO/yEbzv8hG87/IhzP/yMd - 0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8jHdD/Ix3Q/yMd0P8jHdD/IhzP/yEbzv8hG87/IRvO/yIcz/8jHdD/Ix3Q/yMd - 0P8jHdD/Ih3P/yMezf8jIMn/JCLH/yIfx/8gHMr/HxvP/x0a0f8kHM7/Jh6w/2Nmtf/k7Pz/+f39//79 - /P///P3///z+///8/v/+/P7//f39//39/f/9/f3//f39//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/+vr6//r6+v/6+vr/+vr6//38 - +v//+f3///f9//z3/P/4+vz/3uH8/4F65f8wJMv/IxzK/yMbzP8kHM3/IRnJ/yMcyv8kHcz/IxvM/yMb - zP8jGs7/IxvM/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/Ix3K/yMdyv8jHcr/Ix3K/yIc - yf8iHMn/IhzJ/yIcyf8jHMn/JBrK/yQayv8kGsr/JBrK/yQbyv8kG8r/JBvK/yQbyf8kG8n/JBzI/yQc - yP8kHMj/JBzI/yQcyP8kHMj/JBzI/yQcyP8kHMf/JB3H/yQdx/8kHcf/IxzG/yMbxf8jHMX/IxzG/yMc - xP8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yQcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yQc - w/8kHMP/JBvE/yEaw/8iHb3/IBvB/x0Zxf8bHcL/IBy+/zcrs/+emdX/x8nQl8PC2QAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMXF0QDPz9cko6K96zcyeP8fF3v/IBh8/yAYfP8gGHz/IBh8/yAY - fP8gGHz/IBh8/yAYfP8eGH3/IBib/yceyP8gHND/Hx3K/yMcy/8lGdL/IhnR/yEczP8jGs7/IxrO/yMa - zv8jGs7/IxrO/yMazv8jGs7/IxrO/yIazv8hG87/IRvO/yEbzv8hG8//IxzQ/yMd0P8jHdD/Ix3Q/yMd - z/8jHc7/Ix3O/yMdzv8jHc7/Ix3O/yMdzv8jHc7/Ix3O/yMd0P8jHdD/Ix3Q/yMd0P8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8jHdD/Ix3Q/yMd0P8jHdD/IRvO/yEbzv8hG87/IRvO/yIc - z/8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/Ix3Q/yMd0P8jHdD/Ix3Q/yIcz/8hG87/IRvO/yEbzv8iHM//Ix3Q/yMd - 0P8jHdD/Ix3Q/yEezv8iHs7/Ix7N/yUezP8iHsn/IB7I/x0dy/8aHM7/HRzO/yQfxv8pJqj/o6Tb//X7 - ///8//n///v+///5/////f3//f38//39/f/9/f3//f39//39/f/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//r6+v/6+vr/+vr6//r6 - +f/7/vb//fn9//3z///89vv/+fv2//L69//l6v3/mI3p/0Exyv8iHcH/Ih3G/yMcyv8iGs3/IxrQ/yMa - z/8jG83/IxzL/yMcyv8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMdyv8jHcr/Ix3K/yMd - yv8iHMn/IhzJ/yIcyf8iHMn/IxvJ/yQayv8kGsr/JBrK/yQayv8kGsr/JBrK/yQayv8kGsr/JBvJ/yQb - yf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBzH/yQcx/8kHMf/JBzH/yMbxv8jG8b/IxvG/yMb - xv8jHMX/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8kHMP/JBzD/yQcw/8kHMP/JBzD/yQc - w/8kHMP/JBzD/yQbxP8hGsP/Ih29/yAbwf8dGcX/Gx3C/yAcvv83K7P/npnV/8fJ0JfDwtkAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFxdEAz8/XJKOives3Mnj/HxZ7/yAYff8gGHz/IBh8/yAY - fP8gGHz/IBh8/yAYfP8gGHz/Hhh+/yAXnP8oHsf/IBzQ/yAdy/8kHc3/JhrT/yMa0/8hHM7/IxrO/yMa - z/8jGs//IxrP/yMaz/8jGs//IxrP/yMaz/8iGs//IRrP/yEaz/8hGs//IRrP/yMc0f8jHNH/IxzR/yMc - 0f8jHc//Ix3O/yMdzv8jHc7/Ix3O/yMdzv8jHc7/Ix3O/yMdzv8jHdD/Ix3Q/yMd0P8jHdD/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/Ix3Q/yMd0P8jHdD/Ix3Q/yEbzv8hG87/IRvO/yEb - zv8iHM//Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzv8hG87/IRvO/yMd0P8jHdD/Ix3Q/yMd0P8iHM//IRvO/yEbzv8hG87/IhzP/yMd - 0P8jHdD/Ix3Q/yId0P8hHdD/IRzT/yQa1f8lGtX/IxvP/yAdy/8dHcv/GR3M/xkezv8fH9L/IRjC/0tF - rv/a4PH/+//3//77/f/++P///f36//3++v/9/f3//f39//39/f/9/f3//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/6+vr/+vr6//r6 - +v/6+vr/+v34//n8+f/6+Pz/+fj6//n79v/3+/X/9fn4//Ht/P+xp/L/SEjR/yIgwP8iHcj/IhjP/yMY - 1P8jGNL/IxvN/yMeyP8jHcj/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHcr/Ix3K/yMd - yv8jHcr/IhzJ/yIcyf8iHMn/IhzJ/yMbyf8kGsr/JBrK/yQayv8kGsr/JBrK/yQayv8kGsr/JBrK/yQb - yf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQcx/8kHMf/JBzH/yQcx/8jG8b/IxvG/yMb - xv8jG8b/IxzF/yMcw/8jHMP/IxzD/yMcw/8jHMP/IxzD/yMcw/8jHMP/JBzD/yQcw/8kHMP/JBzD/yQc - w/8kHMP/JBzD/yQcw/8kG8T/IRrD/yIdvf8gG8H/HRnF/xsdwv8gHL7/Nyuz/56Z1f/HydCXw8LZAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxcXSAM/P2CSjor3rNjJ5/x4WfP8fGH3/Hxh9/x8Y - ff8fGH3/Hxh9/x8Yff8fGH3/Hxh9/x0Xfv8gF5z/Jx7I/yAb0P8fHcz/JB3O/yUa1P8jG9T/IR3P/yIb - z/8iG8//IhvP/yIbz/8iGs//IhrP/yIaz/8iGs//IRrP/yAaz/8gGs//IBrP/yEbz/8iHND/IhzQ/yIc - 0P8iHND/IhzP/yIcz/8iHM//IhzP/yIdz/8iHc//Ih3P/yIdz/8iHdD/Ih3Q/yId0P8iHdD/Ih3Q/yEb - z/8gG87/IBvO/yAbzv8gG87/IBvO/yAbzv8gG87/IRvP/yId0P8iHdD/Ih3Q/yId0P8hHM//IRvP/yEb - z/8hG8//IhzQ/yId0f8iHNH/IhzR/yIc0f8iHNH/IhzR/yIc0f8iHNH/IRvQ/yEb0P8hG9D/IRvQ/yEb - 0P8hG9D/IRvQ/yEb0P8hG9D/IRvQ/yEb0P8hG9D/IRvQ/yEb0P8hG9D/IRvQ/yEb0P8hG9D/IRvQ/yEb - 0P8hG9D/IRvQ/yEb0P8hG9D/IRvQ/yEb0P8iHNH/IhzR/yIc0f8iHNH/IRvQ/yEb0P8hG9D/IRvQ/yIb - 0P8iHNH/IhzR/yIc0f8iHNH/IRzS/yEb1P8jGdf/JBnX/yIZ0v8gG87/HRzM/xsczf8YH8r/Gh7Q/yMV - 2f8pG7L/iorF//L5+v/6/P3//Pn+//z9+//9/vv//fz+//38/v/9/P7//fz9//z8/f/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/+/v7//v7 - +//7+/v/+/v7//r8+//4/ff/+P31//j6+P/5+vr/+vv3//n59//69/n/9PX8/8HF/P9ybt//NSjF/ykY - z/8mFtX/IxnR/yAdyv8eIMX/IB/G/yMdy/8iHMr/IxzK/yMbyv8kHMr/JRzI/yUdx/8lHcj/JRvL/yUc - yf8lHsj/JBzK/yMby/8iHcf/Ih7E/yIcyv8jGs3/JBvL/yQbyv8kG8r/JBvK/yQbyv8kG8r/JBvK/yQb - yv8kG8r/JBvK/yQbyv8kG8r/JBvJ/yMbyf8jG8n/IxvJ/yMbyf8jHMj/IxzI/yMcyP8jHMj/IxzH/yMb - x/8jG8f/IxvH/yMcxv8jHMT/IxzE/yMcxP8jHMT/IxzE/yMcxP8jHMT/IxzE/yMcxP8kHMT/JBzE/yQc - xP8kHMT/JBzE/yQcxP8kHMT/IxvF/yIaxP8iHb7/IRvC/x0axv8bHcL/IRy9/zcss/+emdT/x8rQl8PC - 2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTF0wDOz9kkoaK+6zQyef8cFnz/Hhh9/x4Y - ff8eGH3/Hhh9/x4Yff8eGH3/Hhh9/x4Yff8cF37/Hxed/yYdyf8fG9H/Hh3M/yMezv8lGtT/IhvU/yEe - z/8hHdD/IR3Q/yEd0P8hHdD/IBzP/x8bzv8fG87/HxvO/x8bzv8fG87/HxvO/x8bzv8fG87/HxvO/x8b - zv8fG87/HxvO/x8az/8fGs//HxrP/x8az/8gG9D/IRzR/yEc0f8hHNH/IRzR/yEc0f8hHNH/IRzR/yEc - 0f8gG9D/HxrP/x8az/8fGs//HxrP/x8az/8fGs//HxrP/yAb0P8hHNH/IRzR/yEc0f8hHNH/IRzS/yEc - 0/8hHNP/IRzT/yEc0/8hHNP/IRzT/yEc0/8hHNP/IRvT/yEb0/8hG9P/IRvT/yEb0/8hG9P/IRvT/yEb - 0/8hG9P/IRvT/yEb0/8hG9P/IRvT/yEb0/8hG9P/IRvT/yEb0/8hG9P/IRvT/yEb0/8hG9P/IRvT/yEb - 0/8hG9P/IRvT/yEb0/8hG9P/IRvT/yEb0/8hG9P/IRvT/yEb0/8hG9P/IRvT/yEb1P8hG9T/IRvU/yEb - 1P8hG9T/IRvU/yEb1P8hG9T/IRzT/yEc0v8hHNL/IRzS/yEc0v8gG9D/HxrP/x8az/8fG8//HSDI/x4i - zP8kFeD/KhXT/zowqP+8weX/9P3+//v++//+/v3//f3+//38///9/P///fz///38///9/P7//fz+//39 - /f/9/f3//Pv9//z7/f/8+/3//Pv9//z7/f/8+/3//Pv9//z7/f/8+/3//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/6+vr/+vr6//r6+f/6+vr/+vr6//r6+v/5+fn/+fj4//f59//z9/f/6Ob8/62i - 8P9fTdb/Mh/K/yQXz/8fG9D/Gx/M/x4gy/8hHsz/IRzM/yIazP8iGcz/IxnM/yMay/8jG8n/JBvJ/ycZ - z/8mHcf/JR/D/yQcy/8jGs7/Ix/E/yMiv/8jHMv/IxfV/yMczP8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMd - yv8jHcr/IxzL/yMcy/8jHMv/IxzL/yMcy/8iG8r/IhvK/yIbyv8iG8r/IhzJ/yIcyf8iHMn/IhzJ/yIc - yf8iHMn/IhzJ/yIcyf8jHMj/JB3G/yQdxv8kHcb/JB3G/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMbxv8jG8b/JB7A/yIcw/8fG8f/HB3C/yEdvf83LLL/npnT/8fK - 0JfCwdcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADExdMAzs/ZJKGivus0Mnn/HBZ8/x4Y - fv8eGH3/Hhh9/x4Yff8eGH3/Hhh9/x4Yff8eGH3/HBd+/x4Xnf8mHcn/HxvR/x4dzP8iHs7/JBrU/yIb - 1P8gHs//IR3Q/yEd0P8hHdD/IR3Q/yAcz/8fG87/HxvO/x8bzv8fG87/HxvO/x8bzv8fG87/HxvO/x8b - zv8fG87/HxvO/x8bzv8fGs//HxrP/x8az/8fGs//IBvQ/yEc0f8hHNH/IRzR/yEc0f8hHNH/IRzR/yEc - 0f8hHNH/IBvQ/yAb0P8gG9D/IBvQ/yAb0P8gG9D/IBvQ/yAb0P8gG9D/IRzR/yEc0f8hHNH/IRzR/yEc - 0/8hHNP/IRzT/yEc0/8hHNP/IRzT/yEc0/8hHNP/IRzT/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8hG9T/IRvU/yEb - 1P8hG9T/IRvU/yEb1P8hG9T/IRvU/yEc0/8hHNL/IRzR/yEc0f8hHNH/IBvQ/yAb0P8gG9D/IBvQ/yAe - zv8hIM//IxrW/yga1P8nHLP/Xl6v/+Lq9//5//j//f35//78/f/9/f7//fz+//38/v/9/P7//f39//39 - /f/9/f3//f39//z7/f/8+/3//Pv9//z7/f/8+/3//Pv9//z7/f/8+/3//Pv9//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+fn5//j4+P/49/b/9/ny//f+ - 8//x/Pf/1dv5/5WQ5/9OQNf/Lh3V/yYX1/8hGdH/IRvN/yIc0f8eGND/HxfT/x8Y1P8dGNT/HBjT/x0Z - 0v8gGdL/Ih3J/yEfxf8hGs7/IRnS/yEdyf8hIcL/IRzL/yIY0/8jHMv/Ix3K/yMdyv8jHcr/Ix3K/yMd - yv8jHcr/Ix3K/yMcy/8jHMv/IxzL/yMcy/8jHMv/IhvK/yIbyv8iG8r/IhvK/yIcyf8iHMn/IhzJ/yIc - yf8iHMn/IhzJ/yIcyf8iHMn/IxzI/yQcx/8kHMf/JBzH/yQcx/8jG8b/IxvG/yMbxv8jG8b/IxzF/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jG8b/IxvG/yQewP8iHMP/HxvI/xwdwv8hHb3/Nyyy/56Z - 0//HytCXwsHXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMXTAM7P2SShor7rNDJ5/xwW - fP8eGH7/Hhh9/x4Yff8eGH3/Hhh9/x4Yff8eGH3/Hhh9/xwXfv8eF53/Jh3J/x8b0f8eHcz/Ih7O/yQa - 1P8iG9T/IR7P/yEd0P8hHdD/IR3Q/yEd0P8gG8//HxvO/x8bzv8fG87/HxvO/x8bzv8fG87/HxvO/x8b - zv8fG87/HxvO/x8bzv8fG87/HxrP/x8az/8fGs//HxrP/yAb0P8hHNH/IRzR/yEc0f8hHNH/IRzR/yEc - 0f8hHNH/IRzR/yEc0v8iHdL/Ih3S/yId0v8iHdL/Ih3S/yId0v8iHdL/IRzS/yEc0f8hHNH/IRzR/yEc - 0f8hHNP/IRzT/yEc0/8hHNP/IRzT/yEc0/8hHNP/IRzT/yEc1P8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd - 1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd - 1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/IhzV/yEb - 1P8hG9T/IRvU/yEb1P8hG9T/IRvU/yEb1P8hG9T/IRzS/yEc0f8hHNH/IRzR/yEc0v8iHdL/Ih3S/yId - 0v8iG9P/IRvQ/yMhz/8hHM7/Jh7M/yompv+UmMz/9fj8//79+f///fr//f78//3+/P/9/vz//f78//39 - /P/9/f3//f39//38/v/8+/3//Pv9//z7/f/8+/3//Pv9//z7/f/8+/3//Pv9//z7/f/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//n5+f/4+Pj/+vj2//z6 - 8//7+vb/9vr6//L6/P/r9fz/0db6/5mT6/9iUN7/OynS/ycdyv8lG8v/IhnM/yIcz/8fHc7/Gx7N/xkg - y/8YIMr/GhvQ/xwdzP8eHcr/HhrR/x8X1v8fG8//Hx7H/x8dy/8gGs7/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yIbyv8iG8r/IhvK/yIbyv8iHMn/IhzJ/yIc - yf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yMcyP8kHMf/JBzH/yQcx/8kHMf/IxvG/yMbxv8jG8b/IxvG/yMc - xf8jHMX/IxzF/yMcxf8jHMX/IxzF/yMcxf8jHMX/IxvG/yMbxv8kHsD/IhzD/x8byP8cHcL/IR29/zcs - sv+emdP/x8rQl8LB1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTF0wDOz9kkoaK+6zQy - ef8cFnz/Hhh+/x4Yff8eGH3/Hhh9/x4Yff8eGH3/Hhh9/x4Yff8cF37/Hhed/yYdyf8fG9H/Hh3M/yIe - zv8kGtT/IhvU/yEdz/8hHdD/IRzR/yEc0f8hHNH/IBvP/x8az/8fGs//HxrP/x8az/8fGs//HxrP/x8a - z/8fGs//HxrP/x8az/8fGs//HxrP/x8a0f8fGtH/HxrR/x8a0f8gG9L/IRzT/yEc0/8hHNP/IRzT/yEc - 0/8hHNP/IRzT/yEc0/8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8hHNP/IRzT/yEc - 0/8hHNP/IRvU/yEb1P8hG9T/IRvU/yEb1P8hG9T/IRvU/yEb1P8iHNX/Ix3W/yMd1v8jHdb/Ix3W/yMd - 1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd - 1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yMd1v8jHdb/Ix3W/yIc - 1f8hG9T/IRvU/yEb1P8hG9T/IRvU/yEb1P8hG9T/IRvU/yEc0/8hHNP/IRzT/yEc0/8iHdT/Ih3U/yId - 1P8iHdT/JBvV/yQb0v8iIc//Hx/S/x8c1P8jHb//QDyl/8vJ7f/+/Pz//v36//3++//9/vr//f75//3+ - +v/9/vv//f39//38/v/9/P///Pv9//z7/f/8+/3//Pv9//z7/f/8+/3//Pv9//z7/f/8+/3//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/5+fn/+Pj4//r2 - +f/99fz//fb9//v4+//4+vb/9Pv0//P6+f/v8v3/39z9/7Sr9P9/dOn/VkvU/zouxf8tI8b/Jh3L/yEa - 0P8eGdX/HRvV/xwdzv8dH8j/Hx/H/yAczP8hGdH/IRnR/x8czP8fHcr/Hx3K/yIcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8iG8r/IhvK/yIbyv8iG8r/IhzJ/yIc - yf8iHMn/IhzJ/yIcyf8iHMn/IhzJ/yIcyf8jHMj/JBzH/yQcx/8kHMf/JBzH/yMbxv8jG8b/IxvG/yMb - xv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/IxvG/yMbxv8jG8b/JB7A/yIcw/8fG8j/HB3C/yEd - vv84LLL/npnT/8fK0JfCwtcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADExdMAzs/ZJKGi - vus0Mnn/HBZ8/x4Yfv8eGH3/Hhh9/x4Yff8eGH3/Hhh9/x4Yff8eGH3/HBd+/x4Xnf8mHcn/HxvR/x4d - zP8iHs7/JBrU/yIb1P8hHc//IR3Q/yEc0f8hHNH/IRzR/yAb0P8fGs//HxrP/x8az/8gG9D/IRzR/yEc - 0f8hHNH/IRzR/yEc0f8hHNH/IRzR/yEc0f8hHNP/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId - 1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId - 1P8iHdT/Ih3U/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId - 1P8iHdT/Ih3U/yUc1P8nHNT/Ih3V/xwe1f8cHdX/Ih3R/yketv9rY7j/6ur4//r6/P/8/Pz//Pz7//39 - +f/9/vn//f76//39/f/9/P7//fz///38/v/9/P7//fz+//38/v/8+/3//Pv9//z7/f/8+/3//Pv9//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/+vr6//r6+v/6+vr/+vr6//v7+//7+/v/+vr6//n5 - +f/79/v//vb9//759v/+/e///fzw//z5+P/69f3/+vf7//v99f/0+vT/6PD5/9fc+f+2tvD/lI/j/3Rq - 3/9YSd//RDPd/zkn3v8tHOH/Khnf/yoa1/8pGtH/KBnS/yYZ1f8jHNL/Hh/H/x4fw/8iHMv/IxvM/yMb - zP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMd - yv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/IxzJ/yQbyf8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yQb - yf8kG8n/JBvI/yQcx/8kHMf/JBzH/yQbx/8jG8b/IxvG/yMbxv8jGsf/IxrH/yQewP8iHMP/HxvI/xwe - w/8iHr7/OS6z/5+a1P/JzNGXw8PZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxMXTAM7P - 2SShor7rNDJ5/xwWfP8eGH7/Hhh9/x4Yff8eGH3/Hhh9/x4Yff8eGH3/Hhh9/xwXfv8eF53/Jh3J/x8b - 0f8eHcz/Ih7O/yQa1P8iG9T/IR3P/yEc0v8hHNP/IRzT/yEc0/8gG9L/IBvR/yAb0f8gG9H/IBvS/yEc - 0/8hHNP/IRzT/yEc0/8hHNP/IRzT/yEc0/8hHNP/IhzU/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8lHNP/JhzT/yIb2P8dHNb/HB7T/yAb1v8oG9D/KSCm/5OV0P/z8///+/j9//38 - /f/9/fv//f75//3/+v/9/f3//fz+//38///9/P7//fz+//38/v/9/P7//Pv9//z7/f/8+/3//Pv9//z7 - /f/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//r6+v/6+vr/+vr6//r6+v/7+/v//Pz8//v7 - +//5+fn/+vn4//35+P/9+fj//fn3//369f/+/PL//vzy//769f/++Pj/+/r0//f88f/1+fb/9Pf7//L0 - /f/p7P7/3OD5/87T9P+8wfL/pqrz/5yd8P+Tk+X/iInd/3p33v86Mcn/JBnO/x8cz/8eHsr/IhvM/yMb - zP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMcyv8kGsr/JBrK/yQayv8kGsr/JBrK/yQa - yv8kGsr/JBrK/yQbyf8kG8n/JBvJ/yQbyf8kG8j/IxrI/yMayP8jGsj/IxrI/yMax/8kHsD/IhzD/x8b - yP8dHsP/Ih6+/zkus/+gm9T/yczSl8TD2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTF - 0wDOz9kkoaK+6zQyef8cFnz/Hhh+/x4Yff8eGH3/Hhh9/x4Yff8eGH3/Hhh9/x4Yff8cF37/Hhed/yYd - yf8fG9H/Hh3M/yIezv8kGtT/IhvU/yEdz/8hHNL/IRzT/yEc0/8hHNP/IRzT/yEc0/8hHNP/IRzT/yEc - 0/8hHNP/IRzT/yEc0/8hHNP/IRzT/yEc0/8hHNP/IRzT/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IxzV/yQc1P8jHNT/IR3U/yAc1v8iGdz/IxjW/yYfwf8yMqX/xMHn//74 - ///9+v///f3+//z9+//9/vv//f39//38/v/9/P///fz+//38/v/9/P7//fz+//z7/f/8+/3//Pv9//z7 - /f/8+/3//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/6+vr/+vr6//r6+v/6+vr/+/v7//z8 - /P/7+/v/+fn5//n4+v/59/3/+vb+//r3/f/7+fn/+/vz//z98f/8+/T//Pn5//v49f/69/L/+vj0//r5 - +P/6+Pr/9/f5//f5+P/4+/j/9vv2//L89P/x+/f/8Pn5/+33/f/Y3fr/WFDH/ygay/8gGtX/HRvO/yIa - zf8jGs7/IxrO/yMazv8jGs7/IxrO/yMazv8jGs3/IxvM/yMcy/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHMr/JBrK/yQayv8kGsr/JBrK/yQa - yv8kGsr/JBrK/yQayv8kG8n/JBvJ/yQbyf8kG8n/JBvJ/yMayP8jGsj/IxrI/yMayP8jGsf/JB7A/yIc - w/8fG8j/HR7D/yIevv85LrP/oJvU/8nM0pfEw9kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADExdMAzs/ZJKGivus0Mnn/HBZ8/x4Yfv8eGH3/Hhh9/x4Yff8eGH3/Hhh9/x4Yff8eGH3/HBd+/x4X - nf8mHcn/HxvR/x4dzP8iHs7/JBrU/yIb1P8gHc//IRzT/yEb1P8hG9T/IRvU/yIc1P8iHNX/IhzV/yIc - 1f8iHNT/IRvU/yEb1P8hG9T/IRvU/yEb1P8hG9T/IRvU/yEb1P8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIa2P8jG9f/JCDO/yQfz/8kGdn/JBje/yQb1/8iH8z/Hh67/2Fb - p//o4fH//Pj///z6/v/9/f3//f78//39/f/9/P7//fz///38/v/9/P7//fz+//38/v/8+/3//Pv9//z7 - /f/8+/3//Pv9//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/+vr6//r6+v/6+vr/+vr6//v7 - +//8/Pz/+/v7//n5+f/5+fn/9/r4//f5+f/3+Pv/9/b9//j2/f/59v3/+fj7//n6+P/5+fj/+vf6//r2 - +//79fz//PX9//vz+//79Pn/+vT2//z29//89/f//PX5//r1+P/29vn/3t34/1xRv/8pGsj/IBrT/x4d - zv8iGs7/IxrO/yMazv8jGs7/IxrO/yMazv8jGs7/IxrO/yMbzP8jHMv/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMdyv8jHcr/Ix3K/yMdyv8jHcr/Ix3K/yMdyv8jHcr/IxzK/yQayv8kGsr/JBrK/yQa - yv8kGsr/JBrK/yQayv8kGsr/JBvJ/yQbyf8kG8n/JBvJ/yQbyf8jGsj/IxrI/yMayP8jGsj/IxrH/yQd - wP8iHMP/HxvI/x0ew/8iHr//OS60/6Cb1P/JzNKXxMTZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAxMbQAM7Q1iSho7zrNDJ6/xsWff8dGH3/HRl8/x0ZfP8dGX3/Hhp9/x4afv8eGn7/Hhp9/xsX - fv8eF57/JR7L/x8c1P8fHdD/Ih3S/yQa1/8iG9X/IR7Q/yIc1P8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzU/yId1P8iHdT/Ih3U/yId - 1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId - 1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId - 1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iG9b/IhzV/yMf0P8jHtH/JBvX/yMZ2P8iHNP/Ih7S/yIe - z/8qH6P/iITD/+zv///6+f////z+///+/P/+/v3//P3+//r+/P/8/f3//f39//39/f/9/f3//Pz9//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//r6+v/6+vr/+vr6//r6 - +v/7+/v//Pz8//v7+//5+fn/+fr4//n79v/5+vf/+fn6//n3/P/59v3/+fb9//n4+//6+fn/+Pj5//f2 - +v/49vr/+Pb6//r2+v/69vr/+vb4//n29v/79/j/+/X7//z0+f/89Pn/+PT6/97e+P9XT8H/JRnH/yAb - 0v8fHND/IxzP/yMcz/8jHM//IxzP/yMcz/8jHM//IxzP/yMcz/8iG83/IhvM/yIbzP8iG8z/IhvM/yIb - zP8iG8z/IhvM/yIcy/8iHMv/IhzL/yIcy/8iHMv/IhzL/yIcy/8iHMv/IhzL/yIcy/8jG8v/IxvL/yMb - y/8jG8v/IxvL/yMby/8jG8v/IxvL/yMbyv8jG8r/IxvK/yMbyv8jG8n/IhvJ/yIbyf8iG8n/IxrK/yQa - yv8kHsL/Ix3E/x8byf8dHcf/IhvE/zkst/+gmtX/yczQl8TE2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMTHzwDO0dUkoaS76zQxev8bFn//HBh9/xwYfP8cGH3/HBl9/x4afv8eG3//Hht//x4b - fv8bF3//Hhie/yUezf8fHNf/Hx3T/yMc1P8kGdn/IhvW/yAe0f8iHdT/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNT/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8jHdT/KR/H/y8po/+rrN7/9vn///7++/////3///7+//z9/v/5/f7//P39//39/f/9/f3//f39//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/6+vr/+vr6//r6 - +v/6+vr/+/v7//z8/P/7+/v/+fn5//n5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//n4 - +f/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pf5//X2+P/4+PH/+/X2//b1+v/d4Pj/VVDF/yMa - yf8gG9H/IBvS/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/IhzO/yEbzP8hG8z/IRvM/yEb - zP8hG8z/IRvM/yEbzP8hG8z/IRzL/yEcy/8hHMv/IRzL/yEcy/8hHMv/IRzL/yEcy/8iHMv/IxvM/yMb - zP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8iG8v/IhvK/yIbyv8iG8r/IhvK/yIbyv8iG8r/IhvK/yIa - y/8kGsz/JR7D/yMdxP8gG8r/HRvK/yIZx/84Krj/oJrV/8nMz5fExNgAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADEx88AztHVJKGku+s0MXr/GxZ//xwYfv8cGH3/HBh9/xwYff8eGn//Hhp//x4a - f/8eGn//Gxd//x4Ynv8lHs3/HxzX/x8d0/8iHNT/JBnZ/yIb1v8gHtH/Ih3U/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzU/yce0P8qHcT/Qzyq/8nP6P/5//j//v77///8/v/+/P7//fr///38/v/9/f3//f39//39 - /f/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/+vr6//r6 - +v/6+vr/+vr6//v7+//8/Pz/+/v7//n5+f/5+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/5+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j3+P/19vj/+Pjx//v19f/29fr/3OD4/1VQ - xf8jGsn/IBvR/yAb0v8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yIczv8hG8z/IRvM/yEb - zP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEbzP8hHMv/IRzL/yEcy/8hHMv/IRzL/yEcy/8hHMv/IhvM/yMb - zP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IhvL/yIbyv8iG8r/IhvK/yIbyv8iG8r/IhvK/yIb - yv8iGsv/JBnM/yUew/8jHcT/IBvK/x0byv8iGcf/OCq4/6Ca1f/JzM+XxMTYAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAxMfPAM7R1SShpLvrNDF6/xsWf/8cGH3/HBh9/xwYff8cGH3/Hhp//x4a - f/8eGn//Hhp//xsXf/8eGJ7/JR7N/x8c1/8fHdP/IhzU/yQZ2f8iG9b/IB7R/yId1P8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb - 1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb - 1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8jG9r/JxrZ/yUatf9ZWav/2+Py//n++//9+v7///r////8/f/+/f3//f39//39 - /f/9/f3//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//r6 - +v/6+vr/+vr6//r6+v/7+/v//Pz8//v7+//5+fn/+fn5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+fj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4+P/49/n/9fb4//j48f/79fX/9vX6/9zg - +P9VUMX/IxrJ/yAb0f8gG9L/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8iHM7/IRvM/yEb - zP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEbzP8hG8z/IRvM/yIb - zP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yIby/8iG8r/IhvK/yIbyv8iG8r/IhvK/yIb - yv8iG8r/IhrL/yQZzP8lHsP/Ix3E/yAbyv8dG8r/IhnH/zgquP+gmtX/yczPl8TE2AAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPGzgDN0NQkoaO66zQye/8cFoD/HRl//x0Zfv8dGX7/HRl+/x4a - gP8eGoD/HhqA/x4agP8bF3//Hhie/yUezf8fHNf/Hx3T/yIc1P8kGdn/IhvW/yAe0f8iHdT/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1v8iHNb/IhzW/yIc1v8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1v8iHNb/IhzW/yIc1v8iHNb/IhzW/yIc1v8iHNb/IhzW/yIc1v8iHNb/IhzW/yIc - 1v8iHNb/IhzW/yIc1v8iHNb/IhvX/yIb1/8iG9f/IhvX/yIb1/8iG9f/IhvX/yIb1/8iG9f/IhvX/yIb - 1/8iG9f/IhvX/yIb1/8iG9f/IhvX/yIb1/8iG9f/IhvX/yIb1/8iG9f/IhvX/yIb1/8iG9f/IhvX/yIb - 1/8iG9f/IhvX/yIb1/8iG9f/IhvX/yIb1/8iG9f/IhvX/yIc1v8iHNb/IhzW/yIc1v8iHNb/IhzW/yIc - 1v8iHNb/IhzW/yIc1v8iHNb/IhzW/yIc1v8iHNb/IhzW/yIc1v8iHNb/IhzW/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iG9b/Hxnd/yAb1v8pIsv/JByn/3N0vP/m7fr/9/n9//78/P////b//v77//39 - /f/9/f3//f39//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/7+/v/+/v7//v7+//7+/v/+/v7//v7+//6+vr/+fn5//r5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+/n5//n4+P/4+Pj/+Pj4//j4+P/4+Pj/9/f3//f39//39/f/9/f4//X2+P/4+PH/+/X1//b1 - +v/c4Pj/VVDE/yMayf8gG9H/IBvS/yMd0P8jHdD/Ix3Q/yMd0P8iHM//IhzP/yIcz/8iHM//IhzN/yEb - zP8hG8z/IRvM/yEbzP8iHM3/IhzN/yIczf8iHM3/IRvN/yEbzf8hG83/IRvN/yEbzf8hG83/IRvN/yEb - zf8iG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8v/IhvK/yIbyv8iG8r/IhvK/yIb - yv8iG8r/IhvK/yMay/8kGsz/JR7D/yMdxP8gG8r/HRvK/yIZx/85K7n/oJrV/8nM0JfExNgAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBxMwAy87SJJ+iues1M3z/HReC/x4Zgv8eGoH/HhqB/x4a - gf8eGoH/HhqB/x4agf8eGoH/Gxd//x4Ynv8lHs3/HxzX/x8d0/8iHNT/JBnZ/yIb1v8gHtH/Ih3U/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iG9b/IhvX/yIb1/8iG9f/IhvX/yIb1/8iG9f/IhvX/yIb1/8jHNj/IxzY/yMc2P8jHNj/IhvX/yIb - 1/8iG9f/IhvX/yMc1/8jHNj/IxzY/yMc2P8jHNj/IxzY/yMc2P8jHNj/IxzY/yMc2P8jHNj/IxzY/yMc - 2P8jHNj/IxzY/yMc2P8jHNj/IxzY/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNj/IxzY/yMc2P8jHNj/IxzY/yMc - 2P8jHNj/IxzY/yMc2P8jHNj/IxzY/yMc2P8jHNj/IxzY/yMc2P8jHNj/IxzY/yMc1/8iG9f/IhvX/yIb - 1/8iG9f/IhvX/yIb1/8iG9f/IhvX/x8c2P8fH9H/IyHM/yghy/8lHar/gIDG/+nw+v/5/fb//f70//3+ - +//9/f3//f39//39/f/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//v7+//6+vr/+vr6//r6+v/6+vr/+/n5//v5+f/7+fn/+/n5//v5 - +f/7+fn/+/n5//v5+f/5+Pj/+Pj4//j4+P/4+Pj/+Pj4//b29v/29vb/9vb2//b29//19ff/+Pjx//v1 - 9f/29fr/3eD4/1VPxP8jGsn/IBvS/yAb0v8jHdD/Ix3Q/yMd0P8jHdD/IRvO/yEbzv8hG87/IRvO/yEb - zf8hG8z/IRvM/yEbzP8iHM3/Ix3O/yMdzv8jHc7/Ix3O/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IhvN/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxzL/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jG8z/JBrM/yUew/8jHcT/IBvK/x0byv8iGcf/OSu5/6Ca1f/JzdCXxMTYAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwcTMAMvO0iSfornrNTN8/x0Xgv8eGYL/HhmC/x4Z - gv8eGYL/HhmC/x4Zgv8eGYL/HhmC/xsXgP8eGJ7/JR7N/x8c1/8fHdP/IhzU/yQZ2f8iG9b/IB7R/yId - 1P8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhvX/yIb2P8iG9j/IhvY/yIb2P8iG9j/IhvY/yIb2P8iG9j/IxzZ/yMc2f8jHNn/IxzZ/yIb - 2P8iG9j/IhvY/yIb2P8jHNj/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IhvY/yIb - 2P8iG9j/IhvY/yIb2P8iG9j/IhvY/yIb1/8hHdP/IR7T/yEg0v8hHtH/JBrN/yYdp/+Nkcb/7vb5//r8 - /f/9/f3//f39//39/f/9/f3//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/7+/v/+vr6//r6+v/6+vr/+vr6//v5+f/7+fn/+/n5//v5 - +f/7+fn/+/n5//v5+f/7+fn/+fj4//j4+P/4+Pj/+Pj4//j4+P/29vb/9vb2//b29v/29vf/9fX3//j4 - 8f/79fX/9vX6/93g+P9VT8T/IxrJ/yAb0v8gG9L/Ix3Q/yMd0P8jHdD/Ix3Q/yEbzv8hG87/IRvO/yEb - zv8hG83/IRvM/yEbzP8hG8z/IhzN/yMdzv8jHc7/Ix3O/yMdzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yIbzf8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMcy/8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxvM/yQazP8lHsP/Ix3E/yAbyv8dG8r/IhnH/zkruf+gmtX/yc3Ql8TE - 2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHEzADLztIjn6K56zUzfP8dF4L/HhmC/x4Z - gv8eGYL/HhmC/x4Zgv8eGYL/HhmC/x4Zgv8bF4D/Hhie/yUezf8fHNf/Hx3T/yIc1P8kGdn/IhvW/yAe - 0f8iHdT/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIb1/8iG9j/IhvY/yIb2P8iG9j/IhvY/yIb2P8iG9j/IhvY/yMc2f8jHNn/IxzZ/yMc - 2f8iG9j/IhvY/yIb2P8iG9j/IxzY/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yIb - 2P8iG9j/IhvY/yIb2P8iG9j/IhvY/yIb2P8iG9j/JhzX/yQa1/8iH9j/HB3S/yEd1v8lG8b/LCac/5WV - yP/w8f7//P3+//39/f/9/f3//f39//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8 - /P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/+/v7//r6+v/6+vr/+vr6//r6+v/7+fn/+/n5//v5 - +f/7+fn/+/n5//v5+f/7+fn/+/n5//n4+P/4+Pj/+Pj4//j4+P/4+Pj/9vb2//b29v/29vb/9vb3//X1 - 9//4+PH/+/X1//b1+v/d4Pj/VU/E/yMayf8gG9L/IBrS/yMd0P8jHdD/Ix3Q/yMd0P8hG87/IRvO/yEb - zv8hG87/IRvN/yEbzP8hG8z/IRvM/yIczf8jHc7/Ix3O/yMdzv8jHc7/IRvP/yEaz/8hGs//IRrP/yEa - z/8hGs//IRrP/yEaz/8iG87/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jHMv/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMbzP8kGsz/JR7D/yMdxP8gG8r/HRvK/yIZx/85K7n/oJrV/8nN - 0JfExNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCxcwAy87PMaCiue41Mnz/HReC/x4Z - gv8eGYL/HhmC/x4Zgv8eGYL/HhmC/x4Zgv8eGYL/GxeB/x4Ynv8lHs3/HxvX/x8d0/8iHNT/JBnZ/yIb - 1v8gHtH/Ih3U/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzW/yIc1v8iHNb/IhzW/yIc - 1v8iHNb/IhzW/yIc1v8iG9j/IhvY/yIb2P8iG9j/IhvY/yIb2P8iG9j/IhvY/yIb2P8jHNn/IxzZ/yMc - 2f8jHNn/IhvY/yIb2P8iG9j/IhvY/yMb2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8iG9j/IhvY/yIb2P8iG9j/IhvY/yIb2P8iG9j/IxrZ/ycY3f8mGt3/Ihza/x4c2P8gH9X/JB/Q/yse - w/8tJJv/lJbK//P0/f/7/P///Pz+//7++//9/fr//fz8//z7/f/7/Pv/+/z7//z8/P/7/fv/+/36//v9 - +v/7/Pz//Pz8//z7/f/9/P3//Pz8//z8/P/8/Pz//Pz8//v7+//6+vr/+vr6//r6+v/6+vr/+/n5//v5 - +f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/5+Pj/+Pj4//j4+P/4+Pj/+Pj4//b29v/29vb/9vb2//b2 - 9//19vf/+Pjy//v19f/29fr/3OD4/1VPxP8jGsr/IBvS/yAb0/8iHdD/Ix3Q/yMd0P8jHdD/IRvP/yEb - zv8hG87/IRvO/yEbzv8hG8z/IRvM/yEbzP8hHM3/Ix3O/yMdzv8jHc7/Ih3O/yEbz/8hGs//IRrP/yEa - z/8hGs//IRrP/yEaz/8hGs//IhvO/yMbzf8jG8z/IxvM/yMbzP8jG8z/IxvM/yMbzP8jG8z/IxzL/yMc - y/8jHMv/IxzL/yMcy/8jHMv/IxzL/yMcy/8jG8z/JBrM/yUexP8jHcX/IBvL/x0byv8iGsj/OSu5/5+a - 1P/JzdCXw8TXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxcfMAMvNy4ulp73/NTF//xwV - hP8dGYP/HRmD/x0Zg/8dGYP/HRmD/x0Zg/8dGYP/HRmD/xwYgv8fGZ//JR7N/x8b1v8eHdP/IxzU/yQZ - 2f8iG9b/IB7S/yId1P8iHNX/IhzV/yIc1f8jHdb/Ix3W/yMd1v8jHdb/IxzY/yMb2f8jG9n/IxvZ/yMb - 2f8jG9n/IxvZ/yMb2f8jG9n/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIc2f8iHNn/IhzZ/yIc2f8iHNn/IhzZ/yIc2f8iHNn/IhzZ/yIc2f8iHNn/IhzZ/yIc - 2f8iHNn/IhzZ/yIc2f8iHNn/IhzZ/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8kGtv/JBvb/yMb2v8iHNn/Ih3X/yQe - 1/8mHtT/IRvH/yMhpv+Pj8b/6+z8//j6/P/+/vX//v71//77/P/9+v7/+f36//n9+v/6/Pz/+f/3//j/ - 8//3//T/+P76//v7/v/9+v////v+//78/P/8/Pz//Pz8//z8/P/7+/v/+vr6//r6+v/6+vr/+vr6//v5 - +f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+fj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/9fb3//j38//79vP/9vT7/9zf+P9UTsT/IxjN/yEc0/8hG9b/IRzS/yEc0f8hHNH/IRzR/yEc - 0f8hHNH/IRzR/yEc0f8hHdD/IR3Q/yEd0P8hHdD/IRzP/x8bzv8fG87/HxvO/yAbzv8iHdD/Ix3Q/yMd - 0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yIcz/8hG87/IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvN/yEb - zP8hHMv/IRzL/yEcy/8hHMv/IRzL/yEcy/8hHMv/IRvM/yMaz/8lHsf/Ix3I/x8bzf8fHc3/IxzK/zks - uv+fm9T/yM3Ol8LE1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMXIzADLzcuYpqe+/zUx - gP8cFYT/HRmE/x0Zg/8dGYP/HRmD/x0Zg/8dGYP/HRmD/x0Zg/8cGIL/Hxig/yUezf8fG9f/Hh3T/yMc - 1P8kGdn/IhvX/yAe0v8iHdT/IhzV/yIc1f8iHNX/Ix3W/yMd1v8jHdb/Ix3W/yMc2P8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iHNn/IhzZ/yIc2f8iHNn/IhzZ/yIc2f8iHNn/IhzZ/yIc2f8iHNn/IhzZ/yIc - 2f8iHNn/IhzZ/yIc2f8iHNn/IhzZ/yIc2f8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jHNn/IxzZ/yIb - 1/8kHdj/IhzV/yId1v8kG8j/LCCd/4OCu//p7/f/+fz6//77/f//+v7//fv8//v8+v/7+f3//fn///r9 - +//4/vf/9/74//j9+//7+/7//vz8///8+v/9/Pv//Pz8//z8/P/8/Pz/+/v7//r6+v/6+vr/+vr6//r6 - +v/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//n4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//X29//49/P/+/fz//b0+//c3/j/VE7F/yMYzf8hHNP/IRvX/yEc0v8hHNH/IRzR/yEc - 0f8hHNH/IRzR/yEc0f8hHNH/IR3Q/yEd0P8hHdD/IR3Q/yAcz/8fG87/HxvO/x8bzv8fG87/Ix3Q/yMd - 0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8iHM//IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG8z/IRzL/yEcy/8hHMv/IRzL/yEcy/8hHMv/IRzL/yEbzf8jGs//JR7H/yMdyP8fG83/Hx3O/yMc - yv85Lbr/n5vU/8jNzZfCxNYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFyMwAy83Ll6an - vv81MX//HBWE/x0ZhP8dGYP/HRmD/x0Zg/8dGYP/HRmD/x0Zg/8dGYP/HBeC/x8Yof8lHs7/HxrX/x4c - 0/8jHNX/JBna/yIb2P8gHtL/IhzV/yIb1v8iG9b/IhvW/yMc1/8jHNf/IxzX/yMc1/8jHNj/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/IxzZ/yMc - 2f8jHNj/IxzX/yIb1v8jHNf/JRvV/yobx/8nH53/amuv/9rd9f/4+f//+/j+//75/f/++/7///n////3 - ///++v///Pv9//r8/f/6+v///Pv+//79+v/+//X//P35//z8/P/8/Pz//Pz8//v7+//6+vr/+vr6//r6 - +v/6+vr/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/5+Pj/+Pj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/19vf/+Pfz//v38//29Pv/3N/4/1ROxf8jGM3/IRzT/yEb1/8hHNL/IRzR/yEc - 0f8hHNH/IRzR/yEc0f8hHNH/IRzR/yEc0f8hHdD/IR3Q/yEd0P8gHM//HxvO/x8bzv8fG87/HxvO/yId - 0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/IhzP/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvN/yEbzP8hG8z/IRvM/yEbzP8hG8z/IRvM/yEbzP8hG87/IxrQ/yUex/8jHcj/HxvN/x8d - zv8jHMr/OS26/5+b1P/Izc2XwsTWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxcjMAMvN - y5emp77/NTF//xwVhP8dGYT/HRmD/x0Zg/8dGYP/HRmD/x0Zg/8dGYP/HRmD/xwXgv8fF6H/JR3P/x8a - 2P8eHNT/IxzV/yQZ2/8iGtn/IB3T/yIc1f8iG9b/IhvW/yIb1v8jHNf/IxzX/yMc1/8jHNf/IxzZ/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMc - 2f8jHNn/JR7a/yUe2v8kHdn/JB3a/yQd2P8kG9b/KBrS/yIWrf9QTaX/w8nk//b7///6+P7//ff+///5 - ////+f7///v8//78+//8+/3//Pr///z7/v/8/fn//f/0//z9+f/8/Pz//Pz8//z8/P/7+/v/+vr6//r6 - +v/6+vr/+vr6//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+fj4//j4+P/4+Pj/+Pj4//j4 - +P/4+Pj/+Pj4//j4+P/4+Pj/9fb3//j38//79/P/9vT7/9zf+P9UTsT/IxjN/yEc0/8hGtf/IRzT/yEc - 0v8hHNL/IRzS/yEc0v8hHNL/IRzS/yEc0v8hHNH/IRzR/yEc0f8hHNH/IBzQ/x8az/8fGs//HxrP/x8a - z/8iHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yIcz/8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yEbzf8hG8z/IRvM/yEbzP8hG8z/IRvM/yEbzP8hG8z/IRvO/yMa0P8lHsf/Ix3I/x8b - zf8fHc7/IxzK/zktuv+fm9T/yM3Nl8LE1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMXI - zADLzcuXpqe+/zUxf/8cFYX/HhmE/x4ahP8eGoT/HhqE/x4ahP8eGoT/HhqE/x4ahP8cF4P/Hxeh/yYe - 0P8gG9v/HxzW/yMc1/8lGdz/Ixva/yEe1P8iHNf/IxzY/yMc2P8jHNj/IxzY/yMc2P8jHNj/IxzY/yMc - 2f8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ixzb/yMc - 2/8jHNv/Ixzb/yMc2/8jHNv/Ixzb/yMc2/8jHNz/Ixzd/yMc3f8jHN3/Ixzd/yMc3f8jHN3/Ixzd/yMc - 3f8jHN3/Ixzd/yMc3f8jHN3/Ixzd/yMc3f8jHN3/Ixzd/yMc3P8jHNv/Ixzb/yMc2/8jHNv/Ixzb/yMc - 2/8jHNv/Ixzb/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMc - 2f8jG9r/Ixva/yQc2v8kHdv/Ixva/yIb2f8jHNr/IBvc/yQb3/8mGdb/Ihew/zw7l/+kqsv/7vP6//r5 - ///8+P7//fz4//399P/9/fT//Pz3//37/f/8+////P37//v++P/7/Pn/+/v7//v7+//7+/v/+/v7//v7 - +//6+vr/+fn5//r5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//n4+P/4+Pj/+Pj4//j4 - +P/4+Pj/9/f3//f39//39/f/9vf3//X29//49/P/+/fz//b0+//b3/j/VlDH/yQYzv8iHdT/IhvY/yIc - 1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3T/yId0v8iHdL/Ih3S/yEc0f8gG9D/IBvQ/yAb - 0P8hG9D/Ix3Q/yMd0P8jHdD/Ix3Q/yIcz/8iHM//IhzP/yIcz/8hG87/IRvO/yEbzv8hG87/IRvO/yIc - z/8iHM//IhzP/yIcz/8iHM//IhzP/yIcz/8iHM//IhzO/yEbzf8hG83/IRvN/yEaz/8jGtD/JR7H/yMd - yP8fG83/HxzN/yMbyf84K7n/nprT/8fMzJfBw9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADFyMwAy83Ll6anvv81MX//HRWF/x4ahf8eGoT/HhqE/x4ahP8eGoT/HhqE/x4ahP8eGoT/HBiD/x8X - ov8nHtH/IRzc/yAd1/8jHNj/JRnd/yMa2/8hHtX/IxzY/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ixzb/yQd - 3P8kHdz/JB3c/yQd3P8kHdz/JB3c/yQd3P8kHdz/JBzd/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN3/JB3c/yQd3P8kHdz/JB3c/yQd - 3P8kHdz/JB3c/yQd3P8jHNv/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMc - 2f8jHNn/Ixva/yMb2v8jG9r/Ixrb/yMa2/8jGtv/Ihrc/yAa3f8gG9n/IRvX/yYd0v8lHLX/KCaO/3l9 - tP/X2/P/9Pj+//j7+f/3+/P/+v3x//3+9P/+/fr//fv+//z7/v/6/Pz/+vv6//r6+v/6+vr/+vr6//v7 - +//8/Pz/+/v7//n5+f/5+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/5+Pj/+Pj4//j4 - +P/4+Pj/9/f3//b29v/29vb/9vb2//b29v/19vb/+Pfz//v38//29Pv/29/4/1dRyP8kGc//Ih3U/yIb - 2f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yId1P8iHdP/Ih3T/yId0/8iHdP/IRzS/yEc - 0v8hHNL/IRzS/yMd0P8jHdD/Ix3Q/yMd0P8iHM//IRvO/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8jHdD/Ix3Q/yIcz/8hG87/IRvO/yEbzv8hGs//IxnQ/yUe - x/8jHcj/HxvN/x4czf8iG8n/Nyu5/52a0//HzMyXwMPUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAxcjMAMvNy5emp77/NTF//x0Vhf8eGoX/HhqE/x4ahP8eGoT/HhqE/x4ahP8eGoT/HhqE/xwX - hP8fF6P/Jx7S/yEc3f8gHdf/IxzY/yUZ3f8jGtv/IR3W/yMc2f8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yMc - 2/8kHdz/JB3c/yQd3P8kHdz/JB3c/yQd3P8kHdz/JB3c/yQc3f8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBze/yQd3P8kHdz/JB3c/yQd - 3P8kHdz/JB3c/yQd3P8kHdz/Ixzb/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jHNn/IxzZ/yMb2v8jG9r/Ixvb/yMa3P8jGd3/Ixnd/yMZ3f8jGdz/IBnZ/yAd1v8jIdf/JiDX/ykd - zf8eF6H/Sk+f/7C32v/t7/7/9/v+//f8+P/6/vX//f74//77/f/8+///+vv///r6+//6+vr/+vr6//r6 - +v/7+/v//Pz8//v7+//5+fn/+fn5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+fj4//j4 - +P/4+Pj/+Pj4//j4+P/29vb/9vb2//b29v/29vb/9fb2//j38//79/P/9vT7/9vf+P9WUcf/JBnO/yId - 1P8iG9n/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHdT/Ih3U/yId1P8iHdT/Ih3U/yEc - 0/8hHNP/IRzT/yEc0v8jHNH/Ix3Q/yMd0P8jHdD/IhzP/yEbzv8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/Ix3Q/yMd0P8jHdD/Ix3Q/yMd0P8jHNH/IxzR/yMd0f8iHND/IRrP/yEaz/8hGs7/IRrQ/yMZ - 0P8lHsf/Ix3I/x8bzf8eHM3/IhvJ/zcruf+dmtP/x8zMl8DD1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMXIzADLzcuapqe+/zUxgP8dFYX/HhqF/x4ahP8eGoT/HhqE/x4ahP8eGoT/HhqE/x4a - hP8cF4T/Hxej/ycd0v8hG93/IB3Y/yMb2f8lGN7/Ixrb/yEd1v8jHNn/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iHNr/JB3c/yQd3P8kHdz/JB3c/yQd3P8kHdz/JB3c/yQd3P8kHN7/JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3v8kHd3/JB3c/yQd - 3P8kHdz/JB3c/yQd3P8kHdz/JB3c/yMc2/8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/IxzZ/yMc2f8jG9r/Ixva/yMb2/8jGtz/Ixnd/yMZ3v8lGd7/KBje/yYb2/8jH9j/Hx/c/x8a - 5P8hFub/Jh3W/x4brf8rKZH/fnq4/9bW8f/z9/7/9fv3//v++P/9/Pv//Pv9//v7///6+vz/+vr6//r6 - +v/6+vr/+/v7//z8/P/7+/v/+fn5//n5+f/7+fn/+/n5//v5+f/7+fn/+/n5//v5+f/7+fn/+/n5//n4 - +P/4+Pj/+Pj4//j4+P/4+Pj/9vb2//b29v/29vb/9vb2//X29v/49/P/+/fz//b0+//b3/j/VlHH/yQZ - z/8iHdT/IhvZ/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yId1P8iHdT/Ih3U/yIc - 1P8hHNP/IRzT/yEc0/8hHNP/IxzR/yMd0P8jHdD/Ix3Q/yIcz/8hG87/IRvO/yEbzv8hG87/IRvO/yEb - zv8hG87/IRvO/yMd0P8jHdD/Ix3Q/yMd0P8jHNH/IxzR/yMc0f8jHNH/IhvQ/yEaz/8hGs//IRrP/yEZ - 0P8jGdD/JR7H/yMdyP8fG83/HhzN/yIbyf83K7n/nZrT/8fMzJfAw9QAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADExs0Ay83Ma6Okvfs1MYD/HRWF/x0ZhP8dGYP/HRmD/x0Zg/8dGYP/HRmD/x0Z - g/8dGYP/HReE/yAXpP8nHtP/IRze/yAd2f8jG9n/JRje/yMa3P8hHdb/IhzZ/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMc2/8jHNv/Ixzb/yMc2/8jG9z/Ixvc/yMb3P8jG9z/Ixvc/yMb3P8jG9z/Ixvc/yMb - 3P8jG9z/Ixvc/yMb3P8jG9z/Ixvc/yMb3P8jG9z/Ixvc/yMb3P8jG9z/Ixvc/yMb3P8jG9z/Ixvc/yMb - 3P8jG9z/Ixzc/yMd3f8jHd3/Ix3d/yMd3f8jHd3/Ix3d/yMd3f8jHN7/Ixzf/yMc3/8jHN//Ixzf/yMc - 3/8jHN//Ixzf/yMc3/8jHN//Ixzf/yMc3/8jHN//Ixzf/yMc3/8jHN//Ixzf/yMc3/8jHN//Ixze/yMc - 3v8jHN7/Ixze/yMc3v8jHN7/Ixze/yMc3v8jHNz/Ixvc/yMb3P8jG9z/Ixvc/yMb3P8jG9z/Ixvc/yMb - 3P8jG9z/Ixvc/yMb3P8jG9z/Ixvc/yMb3P8jG9z/Ixvc/yMb3P8jG9z/Ixvc/yMb3P8jG9z/Ixvc/yMb - 3P8jG9z/Ixvb/yMc2/8jHNr/Ixzb/yMc2/8jG9v/Ixrb/yMa3P8jGd3/JBnd/ycZ3v8mHtr/JB/Z/x8b - 3v8cFuP/Hxnj/yEb2/8nH9n/KRzF/yQYof9HQKH/oaLQ/+fr9//7//3//f33//78+f/9+vr/+vn6//n8 - +//5+/n/+/z5//z8+v/9+/z//fj9//z2/f/89vz//Pn3//z59//8+ff//Pn3//z59//8+ff//Pn3//z5 - 9//5+fj/+Pj4//j4+P/4+Pj/+Pj4//b29v/29vb/9vb2//b29v/19/X/+Pb1//v19//29Pz/2+D4/1ZR - yP8lF9L/Ix3V/yIc1/8iG9b/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IRvU/yEb1P8hG9T/IRzU/yIc0v8jHdL/Ix3S/yMd0v8iG9H/IRvQ/yEb0P8hG9D/IRvQ/yEb - z/8hG8//IRvP/yEbz/8hHND/IRzQ/yEc0P8hHND/IhzQ/yIc0P8iHND/IhzQ/yIb0P8iG8//IhvP/yIb - z/8iGtH/IxrR/yQeyf8jHsr/HxvP/x4cz/8iGsv/OCu7/52a1f/GzM6XwMPWAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAwcPNAMvN0yOfoLzrNTCB/x0Vhf8dGYP/HRmC/x0Zgv8dGYL/HRmC/x0Z - gv8dGYL/HRmC/x0XhP8hGKX/KB7U/yIc3/8hHtn/IxvZ/yUY3v8jGt3/IR3X/yIc2f8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yMc2/8kHdz/JB3c/yQd3P8kHdz/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yMc3v8iHN//Ihzf/yIc3/8iHN//Ihzf/yIc3/8iHN//Ihzf/yIc4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ixzf/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHdz/JB3c/yQd3P8kHdz/Ixzb/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihvb/yIb2/8iG9r/Ihva/ycc3/8pHNj/Ixq5/yYhl/9eXKX/t7be//Hw+//++vv//fj4//r7 - +v/6/fv/+/z8//v7+//7+vr//fv9//35/P/89/r//Pj6//34+f/9+Pn//fj6//z4+f/8+fn/+/n5//v5 - 9//7+vf/+fn3//j4+P/4+Pj/+Pj4//j4+P/29vb/9vb2//b29v/29/X/9ffz//j0+P/78vz/9vT8/9vi - 9/9WUcn/JRbX/yMc1/8hHNb/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IRzU/yEb1P8hG9T/IRvU/yEc - 0/8hHNH/IRzR/yEc0f8hHNH/HxrP/x8az/8fGs//HxrP/yAbzv8hG87/IRvO/yEbzv8iHM//Ix3Q/yMd - 0P8jHdD/IxzS/yMb1P8lH8z/Ix7N/yAc0v8eHNH/IhvN/zgrvf+emtf/x8zQl8DE2AAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHDzQDLzdIkn6C86zUwgf8dFob/HhqE/x4ag/8eGoP/HhqD/x4a - g/8eGoP/HhqD/x4ag/8dF4X/IRil/yge1P8iHN//IR7Z/yMb2f8lGN7/Ixrd/yEd1/8iHNn/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8jHNv/JB3c/yQd3P8kHdz/JB3c/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8jHN7/Ihzf/yIc3/8iHN//Ihzf/yIc3/8iHN//Ihzf/yIc3/8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yMc3/8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JB3d/yQd3P8kHdz/JB3c/yMc2/8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8gHtf/ICHS/yQh0v8nH8n/Ihaw/ysgnP9nYLL/urnh/+vu - +//+//7//v38//z5/v/79///+/j///r7/f/5/ff/9//v//f98f/69/3/+/b///r2/v/59/3/+Pj7//f5 - +v/2+vn/9vr4//f5+P/4+Pj/+Pj4//j4+P/4+Pj/9vb2//b29v/29vb/9vf1//X38//49Pj/+/L8//b0 - /P/b4vf/VlHJ/yUW2P8jHNf/IRzV/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yEb1P8hG9T/IRvU/yEb - 1P8hHNP/IRzR/yEc0f8hHNH/IRzR/x8az/8fGs//HxrP/x8az/8gG87/IRvO/yEbzv8hG87/IhzP/yMd - 0P8jHdD/Ix3Q/yMc0f8jG9T/JR/M/yMezf8gHNL/HhzR/yIazf84K73/nprX/8fM0JfAw9kAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBw80Ay83SJJ+gvOs1MIH/HRaG/x8ahf8fG4X/HxuF/x8b - hf8fG4X/HxuF/x8bhf8fG4X/HRiF/yEYpf8oHtT/Ihzf/yEe2f8jG9n/JRje/yMa3f8hHdf/IhzZ/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ixzb/yQd3P8kHdz/JB3c/yQd3f8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/Ixze/yIc3/8iHN//Ihzf/yIc3/8iHN//Ihzf/yIc3/8iHN//Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8jHN//JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3f8kHdz/JB3c/yQd3P8jHNz/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/HB7V/xkg0/8eH93/Hxjh/yca4/8nGc//HRar/yQk - lf9bYK3/trjW/+vr8//4+f7/+fr+//j6/v/4/P3/9/v7//X6+P/2+vj/+vj6//r4+v/5+fn/+Pr3//f7 - 9v/1/PX/9Pz0//T89f/1+vb/+Pj4//j4+P/4+Pj/9/f3//b29v/29vb/9vb2//b29f/19/P/+PT4//vy - /P/29Pz/2+L3/1ZRyf8lFtj/IxzX/yEc1f8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8hG9T/IRvU/yEb - 1P8hG9T/IRvT/yEc0v8hHNH/IRzR/yEc0f8fGtD/HxrP/x8az/8fGs//IBvO/yEbzv8hG87/IRvO/yIc - z/8jHdD/Ix3Q/yMd0P8jHNH/IxvU/yUfzP8jHs3/IBzS/x4c0f8iGs3/OCu9/56a1//HzNCXwMPZAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwcPNAMvO0ySfoLzrNjCB/x4Wh/8fGob/HxuF/x8b - hf8fG4X/HxuF/x8bhf8fG4X/HxuF/x0Yhf8hGKX/KB7U/yIc3/8hHtr/JBvZ/yUY3/8jGt3/IR7X/yIc - 2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihvb/yIa3P8iGtz/Ihrc/yIa3P8iGtz/Ihrc/yIa - 3P8iGtz/Ihrc/yIa3P8iGtz/Ihrc/yMb3f8kHN7/JBze/yQc3v8kHN7/JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yMc3/8iHN//Ihzf/yIc3/8iHN//Ihzf/yIc3/8iHN//Ihzf/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ixzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN7/JBze/yQc3v8kHN7/Ixvd/yIa3P8iGtz/Ihrc/yIa - 3P8iGtz/Ihrc/yIa3P8iGtz/Ihrc/yIa3P8iGtz/Ihrc/x4b3P8bHN//HBzh/x4a4f8gGt//JR7c/yUf - 0/8hHcX/GBWv/yghkf9XUaD/nZzP/9Xa8P/v+P3/+P/+//j6/v/59v//+vX+//z3+v/8+fn/+/r4//r6 - 9v/6+vf/+Pr4//f5+f/3+fr/9/j5//j4+P/39/f/+Pj4//j4+P/39/f/9/f3//b29v/29/b/9ffz//j0 - +P/78vz/9vT8/9vi9/9WUcn/JRbY/yMc1/8hHNX/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb - 1v8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IRvU/yEb - 1P8hG9T/IRvU/yEb1P8hHNP/IRzT/yEc0/8hHNP/HxrR/x8a0f8fGtH/HxrR/yEbz/8hG87/IRvO/yEb - zv8iHM//Ix3Q/yMd0P8jHdD/IxzR/yMb1P8lH8z/Ix7N/yAc0v8eHNH/IhvN/zgsvv+emtf/xszQl8DD - 2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPFzwDNz9QkoaG96zcygv8fF4j/HxqH/x8a - h/8fGof/HxqH/x8ah/8fGof/HxqH/x8ah/8dGIb/IRil/yge1P8iHN//Ih7a/yUd2/8nGuD/JRzf/yMf - 2f8kHdv/JB3c/yQd3P8kHdz/JB3c/yQd3P8kHdz/JB3c/yQc3f8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8jHN//Ihzf/yIc3/8iHN//Ihzf/yIc3/8iHN//Ihzf/yIc - 3/8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yMc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8iG+D/IRzh/yEd3v8iH9v/Ix/Y/yQf - 2f8kHdv/JRze/ycb4P8mGdP/HhK4/x0Wnf85OZb/en21/7q92v/n5/T/+vf///75///89/7/+/f9//v4 - +//8+fr/+/f5//v2+//89v7/+/T+//j0+//39/j/9vb2//b29v/5+fn/+fn5//j4+P/39/j/9/f2//X4 - 8//49Pj/+/L8//b0/P/b4vf/VlHJ/yUW2P8jHNf/IRzV/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb - 1v8iG9b/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/Ih3U/yId1P8iHdT/Ih3U/yEc0/8hHNP/IRzT/yEc0/8iHNH/Ix3Q/yMd - 0P8jHdD/IhzP/yEbzv8hG87/IRvO/yEa0P8jGtT/JR/M/yMezf8gHNL/HRzQ/yIbzf85LL7/nprX/8bL - z5e/w9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDxc8Azc/UJKGhves3MoL/HxeI/x8a - h/8fGof/HxqH/x8ah/8fGof/HxqH/x8ah/8fGof/HRiG/yEYpf8oHtT/Ihzf/yIe2v8lHdv/Jxrg/yUc - 3/8jH9n/JB7b/yQd3P8kHdz/JB3c/yQd3P8kHdz/JB3c/yQd3P8kHd3/JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kG+D/JBvg/yQb - 4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb - 4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/Ixvg/yIc3/8iHN//Ihzf/yIc3/8iHN//Ihzf/yIc - 3/8iHN//Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8jG+D/JBvg/yQb - 4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb - 4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JB3c/yUe2f8lHtn/JR7b/yUd - 3P8lHN3/JRze/yUc3v8lHN//IBre/yAa2v8nINT/Ixu8/yEYn/8tJY7/VE2Z/4uFuv/DwN//5eb2//P2 - /f/4+/7/9/v4//f69f/4+vT/+vr1//n39f/6+fj/9/f3//b29v/39/f/9vb2//j4+P/39/f/9vb2//b2 - 9f/19/P/+PT4//vy/P/29Pz/2+L3/1ZRyf8lFtj/IxzX/yEc1f8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb - 1v8iG9b/IhvW/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8hG9T/IRvU/yEb1P8hG9T/IhzR/yMd - 0P8jHdD/Ix3Q/yIcz/8hG87/IRvO/yEbzv8hGtD/IxrU/yUfzP8jHs3/IBzS/x0b0P8iG83/OSy+/56a - 1//Fy8+Xv8LYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw8XPAM3P1CShob3rNzKC/x8X - if8fGYj/HxmI/x8ZiP8fGYj/HxmI/x8ZiP8fGYj/HxqH/x0Yhv8hGKX/KB7U/yIc3/8iHtr/JR3b/yca - 4P8lHN//Ix/Z/yQe2/8kHdz/JB3c/yQd3P8kHdz/JB3c/yQd3P8kHdz/JBze/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBvg/yQb - 4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb - 4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yMb4P8iHN//Ihzf/yIc3/8iHN//Ihzf/yIc - 3/8iHN//Ihzf/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ixvg/yQb - 4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb - 4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQe2/8lH9n/JR3b/yUb - 3/8lGuH/JBrh/yQc3/8kHdz/JB/Z/yEh1P8hINX/Ih3Z/yYb2/8oGtX/KRvI/yIXsP8eFpz/KCSS/0pK - l/90drP/o6jS/8vS6P/k7Pf/8vr6//X89//4/ff/+Pr3//j5+P/5+fn/+fn4//j4+P/4+Pj/9/f3//b2 - 9v/19vX/9ffz//j0+P/78vz/9vT8/9vi9/9WUcn/JRbY/yMc1/8hHNX/IhvW/yIb1v8iG9b/IhvW/yIb - 1v8iG9b/IhvW/yIb1v8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IRvU/yEb1P8hG9T/IRvU/yIc - 0f8jHdD/Ix3Q/yMd0P8iHM//IRvO/yEbzv8hG87/IRrQ/yMa1P8lH8z/Ix7N/yAc0v8dG9D/IhvN/zks - vv+emtf/xcvPl7/C2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPFzwDNz9QkoaG96zcy - gv8fF4n/HxmJ/x8ZiP8fGYj/HxmI/x8ZiP8fGYj/HxmI/x8ZiP8dF4f/IRil/yge1P8iHN//IR7a/yUd - 2/8nGuD/JRzf/yMf2f8kHdz/JB3d/yQd3f8kHd3/JB3d/yQd3f8kHd3/JB3d/yQc3v8kG+D/JBvg/yQb - 4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQa - 4f8kGuL/JBri/yQa4v8kGuL/JBri/yQa4v8kGuL/JBri/yQa4v8kGuL/JBri/yQa4v8kGuL/JBri/yQa - 4v8kGuL/JBri/yQa4v8kGuL/JBri/yQa4v8kGuL/JBri/yQa4v8jG+D/Ihzf/yIc3/8iHN//Ihzf/yIc - 3/8iHN//Ihzf/yIc3/8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yMb - 4f8kGuL/JBri/yQa4v8kGuL/JBri/yQa4v8kGuL/JBri/yQa4v8kGuL/JBri/yQa4v8kGuL/JBri/yQa - 4v8kGuL/JBri/yQa4v8kGuL/JBri/yQa4v8kGuL/JBri/yQa4v8kGuH/JBvg/yQb4P8kG+D/JBvg/yQb - 4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+H/Ixri/yMb - 4v8jG+H/Ixvg/yEc4P8hHN//IR3e/yId3f8kHtv/Jh3b/yQa3f8hF93/IRff/yIb3/8gHNv/HhzW/yAb - zf8jF73/HBKn/yAZmf8xLZX/UE+e/3V1sf+cncz/v8Dh/9nZ7f/u7vf/9/f8//f4+v/7+/3/+vv9//r6 - /P/5+vv/+Pn5//b59v/59vr/+/T8//b1/f/c4vf/V1HJ/yUW1v8jHNf/IRzW/yIb1v8iG9b/IhvW/yIb - 1v8iG9b/IhvW/yIb1v8iG9b/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yEb1P8hG9T/IRvU/yEb - 1P8iHNL/Ix3Q/yMd0P8jHdD/IhzQ/yEbzv8hG87/IRvO/yEa0P8jGtT/JR/M/yMezf8gHNL/HRvQ/yIb - zf85LL7/nprX/8XLz5e/wtgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCxM4AzM7TJKGh - ves3MoP/HhaJ/x8Zif8fGYj/HxmI/x8ZiP8fGYj/HxmI/x8ZiP8fGYj/HReH/yAYpv8nH9T/IRzf/yEe - 2/8lHdz/Jxrh/yQc3/8hH9r/Ihze/yMc3/8jHN//Ixzf/yMc3/8jHN//Ixzf/yMc3/8jHN//Ixvg/yMb - 4P8jG+D/Ixvg/yMb4P8jG+D/Ixvg/yMb4P8jG+D/Ixvg/yMb4P8jG+D/Ixvg/yMb4P8jG+D/Ixvg/yMb - 4P8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb - 4f8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb4f8jG+H/Ixzh/yMc4f8jHOD/Ixzg/yMc - 4P8jHOD/Ixzg/yMc4P8jHOD/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixvh/yMb4f8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb - 4f8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb4f8jG+H/Ixvh/yMb4P8jG+D/Ixvg/yMb - 4P8jG+D/Ixvg/yMb4P8jG+D/Ixvg/yMb4P8jG+D/Ixvg/yMb4P8jG+D/Ixvg/yMb4P8jG+D/Ihvh/yIa - 4/8iG+L/Ihvg/yIb4P8hHN//IRvg/yEb4P8iG+D/JRzg/yYc3/8lHN//Ixve/yQc3/8iHN//IRzf/yAb - 3v8iHN7/Jh3c/yge2f8mHdL/IhrG/x0Wt/8WEqb/ExOa/x4em/8zM5n/TEye/2Zlrv+AgL//lpjM/6ms - 1v+9wN//ys7j/9PY5//c3u3/4eLu/+Po7//j6fb/ztH4/1VOx/8oHMv/JR3W/yIc2P8jG9n/IxvZ/yMb - 2f8jG9n/IxvZ/yMb2f8jG9n/IxvZ/yIc1/8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIb - 1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzU/yIc0/8iHNP/Ih3T/yIc0/8hG9L/IRvS/yEb0v8hGtP/IhjU/yMdy/8hHM3/HhrS/x0b - 0f8iGs7/OSy//56a2P/FytCXv8LYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwsTOAMzO - 0yShob3rODOD/x4Wif8fGYn/HxmI/x8ZiP8fGYj/HxmI/x8ZiP8fGYj/HxmI/x0Xh/8fGKb/Jh7V/yAc - 3/8hHtv/JR3c/yca4f8kHN//IR/a/yIc3/8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iHOD/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yMc3/8kHN7/JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JB3c/yQf2v8kHtv/JBze/yQc3/8kHdz/Ix7X/yEfz/8fH8j/IB3B/x4Wt/8aEaz/GBGi/xoU - mv8fGZP/Jh+O/y0njv82MJP/QDSa/0Q9lP9JSJD/S0ua/0hEsv80KsH/KB7P/yUf2f8hHdj/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8iHNf/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IRvU/yEb1P8hG9T/IRrV/yEY1P8jHMv/IRvM/x4Z - 0f8dGtH/IhrP/zkswP+emtj/xcrQl7/C2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLE - zgDMztMkoaG96zgzg/8eFon/HxmJ/x8ZiP8fGYj/HxmI/x8ZiP8fGYj/HxmI/x8ZiP8dF4f/Hxin/yYe - 1f8gHOD/IR7c/yUd3f8nGuL/JBvf/yEe2v8iHN//Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ixzg/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8kHN//JBze/yQc3v8kHN7/JBze/yQc - 3v8kHN7/JBze/yQd3P8kHtr/JB3c/yQc3v8kHN//JBze/yMd2v8jH9X/Ih/R/yMe1f8jGtn/Jh3Z/yof - 2f8pHtX/KBzP/ycayv8oG8n/JhjH/yQRyv8kFML/JBq1/yIatP8gFb//JRnV/yIZ3P8gHtz/Hx7Y/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/IhvX/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb - 1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yEb1P8hG9T/IRvU/yEa1f8hGNT/IxzL/yEb - zP8eGdH/HRrR/yIaz/85LMD/nprY/8XK0Je/wtkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADCxM4AzM7TJKGhves4M4P/HhaJ/x8Zif8fGYj/HxmI/x8ZiP8fGYj/HxmI/x8ZiP8fGYj/HReI/x8X - p/8mHtb/IBzg/yEd3P8lHN3/Jxni/yQb4P8hHtv/Ihzf/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yMc4f8jHOL/Ixzi/yMc - 4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc - 4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc - 4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc - 4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc - 4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4f8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHd3/JB7b/yQd3P8kHN//JBvg/yQa4P8jG97/Ihvb/yEc1/8iHdj/Ih7Z/yIf - 2v8jH9r/Ix7b/yId2/8gGdn/IRva/yEa3P8iGeL/Ixze/yQf2P8kH9j/JBvf/yIW4/8gGOL/HBrZ/yAe - 1/8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yIb2P8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb - 1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8hG9T/IRvU/yEb1P8hGtX/IRjU/yMc - y/8hG8z/HhnR/x0a0f8iGs//OSzA/56a2P/FytCXv8LYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAwsTOAMzO0yShob7rODOE/x8Wif8fGYj/HxmI/x8ZiP8fGYj/HxmI/x8ZiP8fGYj/HxmI/x0X - iP8fF6j/Jh3X/yAb4f8hHd3/JRzd/ycZ4/8kG+H/IR7c/yIc3/8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8jHOL/Ixzj/yMc - 4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd - 5P8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd - 5P8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd - 5P8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd5P8kHeT/JB3k/yQd5P8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc - 4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOL/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBze/yQd3P8kHN3/JBzf/yQa4f8kGuL/JBrh/yMa3v8iG93/Ixzc/yUe - 3P8jHdv/Ihzb/yId3P8gG9v/Hhra/x4a2/8eG9r/HR/V/x0h0v8fIdL/IB/X/yAa3f8hF+D/Ihje/yMc - 2P8kHtb/IxvZ/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9n/IhvX/yIb1/8iG9f/IhvX/yIb - 1/8iG9f/IhvX/yIb1/8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IRvU/yEb1P8hG9T/IRrV/yIZ - 1f8kHcz/IhzN/x4a0v8dG9L/IhrP/zkrv/+emtj/xsvQl8DD2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMLEzgDMztMkoaG+6zk0hP8fF4n/HhiI/x4Yh/8eGIf/HhiH/x8ZiP8fGYj/HxmI/x8Z - iP8dF4j/Hxep/yYd1/8gG+L/IRze/yUc3/8nGeT/JBri/yEe3P8iHN//Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzi/yMc - 4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOP/JR3l/yUe5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe - 5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe - 5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe - 5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe5f8kHeX/Ixzj/yMc4/8jHOP/Ixzj/yMc - 4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOP/Ixzi/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8kG+D/JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN3/JBze/yQc3/8kG+H/JBrh/yQa4f8kG+D/JBvg/yYZ - 4/8nGOX/Jhnk/yYZ4/8kGeL/Ixnf/yIZ3v8hGt3/IRvb/yAe1f8gH9P/IB7W/yEc2f8iGtz/JBrc/yYb - 2P8oHtL/Jx7T/yQb2f8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIb - 1v8jGtb/JR7N/yMdzv8gG9P/HhzT/yIaz/84Kr7/nprY/8fL0ZfAw9oAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADCxM4AzM7TJKGhvus5NIT/HxeJ/x8Zif8fGYj/HxmI/x8ZiP8fGYj/HxmI/x8Z - iP8fGYj/HRaJ/x8Wqf8mHdf/IBri/yEc3/8lG+D/Jxnl/yQa4v8hHtz/Ihzf/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4v8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JBzl/yMb5P8jG+T/Ixvk/yMb - 5P8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMc4/8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/JBvg/yQb - 4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBzf/yQc3/8kHN//JBvg/yQb4P8kG+D/JBvg/yQb - 4P8mGuH/Jhrh/yYb4f8mG+D/JRve/yQa2/8jG9r/IxzZ/yMb2f8lGd7/JBfh/yIX4v8iGOH/IRne/yIb - 2v8lHdb/Jx7S/ycd1P8jG9n/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iG9b/IxrW/yUezf8jHc7/IBvT/x4c0/8iGs//OCq+/56a2P/Hy9GXwMPaAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAwsTOAMzO0yShob7rOTSE/yAXiv8gGor/IBqJ/yAaif8gGon/HxmI/x8Z - iP8fGYj/HxmI/x0Wif8fFqn/Jh3Y/yAa4v8hHN//JRvg/ycY5f8kGuL/IR3d/yIc3/8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jG+L/Ixvk/yMb5P8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMb5P8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yQc5f8jG+T/Ixvk/yMb - 5P8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMb5P8jHOP/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yQb - 4P8kG+H/JBvh/yQb4f8kG+H/JBvh/yQb4f8kG+H/JBvh/yQb4P8kG+D/JBzf/yQc3/8kHN7/JBze/yQc - 3v8kHN7/Ix7b/yIf2f8iH9r/Ih/a/yIe2v8hG9r/Ihva/yIb2v8jG9v/Jxnc/yYY3v8iGOD/Hxnf/x0b - 3P8dHdn/Hx3Z/yEb2/8iGtz/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2f8iG9f/IhvW/yIb1v8iG9b/IhvW/yIb1v8iG9b/IhvW/yIb - 1v8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhvW/yMa1v8lHs3/Ix3O/yAb0/8eHNP/IhrP/zgqvv+emtj/x8vRl8DD2gAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLEzgDLztMkoaK+6zg0hP8fGIr/IBuL/yAbiv8gG4r/IBqK/x8Z - if8fGYj/HxmI/x8Zif8dF4r/Hxeq/yYd2P8gG+P/IBzf/yQb4P8mGeX/JBrj/yEd3f8iHN//Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc - 4v8jHOL/Ixzj/yMb5f8jG+X/Ixvl/yMb5f8jG+X/Ixvl/yMb5f8jG+X/JBzm/yQd5v8kHeb/JB3m/yQd - 5v8kHeb/JB3m/yQd5v8kHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8kHeb/JBzn/yQc5/8kHOf/JB3n/yUd5/8lHef/JR3n/yUd - 5/8lHeb/JR3m/yUd5v8lHeb/JB3m/yQd5v8kHeb/JB3m/yQd5v8kHeb/JB3m/yQd5v8kHOX/Ixvk/yMb - 5P8jG+T/Ixvk/yMb5f8jG+X/Ixvl/yMb5f8jG+X/Ixvl/yMb5f8jG+X/Ixzk/yMc4/8jHOP/Ixzj/yMc - 4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzh/yMc - 4f8jHOH/Ixzh/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8jGuH/JBri/yQa4v8kGuL/JBri/yQa4v8kGuL/JBri/yQa4v8kGuH/JBvg/yQc3/8kHN//JBze/yQc - 3v8kHN7/Ixze/yEe3P8fH9v/Hx7c/yAd3f8gHN7/IBrf/yEZ4P8hGOL/Ihjh/yYd1/8lHdX/Ih3Y/x8d - 2f8cHtj/HB3Y/xwc2/8dGeH/IBjh/yMb2/8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/IhvY/yIb1/8iG9f/IhvX/yIb1/8iG9f/IhvX/yIb - 1/8iG9b/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIb1v8iGtb/JR7O/yQd0P8gG9X/HhzU/yAa0P83K7//nprY/8fM0JfAw9gAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAxc4Ays/TJKCivus3NIT/HheK/x0Ziv8dGYr/HRmK/x0Z - iv8dGYr/HRmK/x0Ziv8dGYr/HRmM/x8Zq/8mH9n/Hxvj/x8c3/8jG+D/JRnl/yIb4v8gHtz/Ix3g/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/JB3i/yUe4/8lHuP/JR7j/yUe5P8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe - 5f8lHuX/JR7l/yQd5v8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yIb5v8hG+b/IRvm/yEb - 5v8hG+b/IRvm/yEb5v8hG+b/Ihzm/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/IRvn/yEa5/8hGuf/IRrn/yIb6P8jHOn/Ixzp/yMc - 6f8jHej/Ix3o/yMd6P8jHej/Ix3o/yEb5v8hG+b/IRvm/yEb5v8hG+b/IRvm/yEb5v8hG+b/IRvm/yEb - 5v8hG+b/IRvm/yEb5v8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yQd6P8lHOf/JRzn/yUc - 5/8lHOf/JRzn/yUc5/8lHOf/JRzn/yUd5v8lHeb/JR3m/yUd5v8kHOX/Ixvk/yMb5P8jG+T/Ixvj/yMc - 4v8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8jHN//Ixze/yMc3/8jHN//Ixzf/yQc3/8kG+D/JBvg/yQb4P8kHdz/JB3b/yQd - 2/8jHdv/Ihza/yEb2v8hG9r/IRvb/yEb2/8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/IxzY/yId1P8iHdT/Ih3U/yId1P8iHdT/Ih3U/yId1P8iHdT/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8hHNb/IBvY/yQe0P8oHNP/IxrZ/x4c2P8eHNP/Ni7C/52a1v/HzM+XwcPWAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMXOAMnP0ySgor7rNzSE/x0Xiv8dGYr/HRmK/x0Z - iv8dGYr/HRmK/x0Ziv8dGYr/HRmK/x0ZjP8gGaz/Jh/Z/x8c4/8eHN//Ixzg/yUZ5f8iG+L/IB7c/yMd - 4P8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzi/yMc4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc - 4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yQd5P8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe5f8lHuX/JR7l/yUe - 5f8lHuX/JR7l/yUe5f8kHef/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8hG+b/IRvm/yEb - 5v8hG+b/IRvm/yEb5v8hG+b/IRvm/yIc5/8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yEa5/8hGuf/IRrn/yEa5/8iG+j/Ixzp/yMc - 6f8jHOn/Ixzp/yMd6P8jHej/Ix3o/yMd6P8hG+b/IRvm/yEb5v8hG+b/IRvm/yEb5v8hG+b/IRvm/yEb - 5v8hG+b/IRvm/yEb5v8hG+b/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8kHej/JRzo/yUc - 6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHef/JR3m/yUd5v8lHeb/JBzl/yMb5P8jG+T/Ixvk/yMb - 5P8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4v8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ixzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzd/yQd - 3P8kHdz/JB3c/yMc2/8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMc2P8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IRzW/yAb2f8kHtH/KBvU/yQZ2v8dHNn/HRzT/zYvwv+dmtb/x8zOl8HD - 1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDFzgDJz9MkoKK+6zc0hP8dF4r/HRmK/x0Z - iv8dGYr/HRmK/x0Ziv8dGYr/HRmK/x0Ziv8dGYz/IBms/yYf2f8fHOP/Hhzf/yMc4P8lGeX/Ihvi/yAe - 3P8jHeD/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4v8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc - 4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8kHeT/JR7l/yUe5f8lHuX/JR7l/yUd5v8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JB3n/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/IRvm/yEb - 5v8hG+b/IRvm/yEb5v8hG+b/IRvm/yEb5v8iHOf/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8hGuf/IRrn/yEa5/8hGuf/Ihvo/yMc - 6f8jHOn/Ixzp/yMc6f8jHej/Ix3o/yMd6P8jHej/IRvm/yEb5v8hG+b/IRvm/yEb5v8hG+b/IRvm/yEb - 5v8hG+b/IRvm/yEb5v8hG+b/IRvm/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/JB3o/yUc - 6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JR3n/yUd5v8lHeb/JR3m/yQc5f8jG+T/Ixvk/yMb - 5P8jG+T/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOL/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yMc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3f8kHdz/JB3c/yQd3P8jHNv/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9j/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yEc1v8gG9n/JB7R/ygb1P8kGdr/HRzZ/x0c0/82L8L/nZrW/8fM - zpfBw9YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAxc4Ayc/TJKCivus3NIT/HheK/x0Z - iv8dGYr/HRmK/x0Ziv8dGYr/HRmK/x0Ziv8dGYr/HRmM/yAZq/8mH9n/Hxzj/x8d3/8jHOD/JRnl/yIb - 4v8gHtz/Ixzh/yMc4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc - 4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOP/JB3k/yUe5f8lHuX/JR7l/yUe5f8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yQd5/8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yEb - 5v8hG+b/IRvm/yEb5v8hG+b/IRvm/yEb5v8hG+b/Ihzn/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/IRrn/yEa5/8hGuf/IRrn/yIb - 6P8jHOn/Ixzp/yMc6f8jHOn/Ix3o/yMd6P8jHej/Ix3o/yEb5v8hG+b/IRvm/yEb5v8hG+b/IRvm/yEb - 5v8hG+b/IRvm/yEb5v8hG+b/IRvm/yEb5v8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yQd - 6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUd5/8lHeb/JR3m/yUd5v8kHOX/Ixvk/yMb - 5P8jG+T/Ixvk/yMc4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc - 4/8jHOP/Ixzj/yMc4/8jHOP/Ihvh/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8jHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN7/JBze/yQc3v8kHN7/Ixvd/yIa3P8iGtz/Ihrc/yIa2/8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/IxzY/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc - 1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8hHNb/IBvZ/yQe0f8oG9T/JBna/x0c2f8dHNP/Ni/C/52a - 1v/HzM6XwcPWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMXOAMnP0ySgor7rNzSE/x4X - iv8fGoz/HxuM/x8bjP8fG4z/HxuM/x8bjP8fG4z/HxuL/x0ZjP8fGKv/Jh/Z/yAd5P8fHeD/Ixzg/yYa - 5f8jHOL/IB/d/yMc4v8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOP/JBzk/yUd5f8lHeX/JR3l/yUd - 5f8lHeX/JR3l/yUd5f8lHeX/JR3l/yUd5f8lHeX/JR3l/yUd5v8lHeb/JR3m/yUd5v8lHeb/JRzn/yUc - 6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8kHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMc6P8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8kHej/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHef/JR3m/yUd5v8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeX/JR3l/yUd5f8lHeX/JR3l/yUd5f8lHeX/JR3l/yQc5P8jHOP/Ixzj/yMc - 4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8iG+D/Ihvg/yIb4P8iG+D/Ixzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN7/JBze/yQc3v8kHN3/JBzc/yQd3P8kHdz/JB3c/yQd - 3P8kHdz/JB3c/yQd3P8jHNv/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMc2f8jHNf/IxzX/yMc1/8jHNf/IxzX/yMc1/8jHNf/IxzX/yIc - 1v8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IRzW/yAb2f8kHtH/KBvU/yQZ2v8dHNn/HRzT/zYv - wv+dmtb/x8zOl8HD1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDFzgDJz9MkoKK+6zc0 - hP8eF4r/HxuM/x8bjP8fG4z/HxuM/x8bjP8fG4z/HxuM/x8bjP8dGYz/Hxir/ycf2f8gHeT/IB7g/yQd - 4f8mGub/Ixzj/yAf3v8jHOL/Ixvk/yMb5P8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yQc5f8lHOj/JRzn/yUc - 5/8lHOf/JRzn/yUc5/8lHOf/JRzn/yUc5/8lHOf/JRzn/yUc5/8lHOf/JRzn/yUc5/8lHOf/JRzo/yUc - 6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JB3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/JB3o/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JR3n/yUd5v8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JRzn/yUc5/8lHOf/JRzn/yUc5/8lHOf/JRzn/yUc5/8kHOX/Ixvk/yMb - 5P8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMc4/8jHOL/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ihvg/yIb4P8iG+D/Ihvg/yMc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBze/yQd3f8kHdz/JB3c/yQd - 3P8kHdz/JB3c/yQd3P8kHdz/Ixzb/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/IxzZ/yMc2P8jHNj/IxzY/yMc2P8jHNj/IxzY/yMc - 2P8iHNb/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yEc1v8gG9n/JB7R/ygb1P8kGdr/HRzZ/x0c - 0/82L8L/nZrW/8fMzpfBw9YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAxc4Ayc/TJKCi - vus3NIT/HheK/x8bjP8fG4z/HxuM/x8bjP8fG4z/HxuM/x8bjP8fG4z/HRmM/x8Yq/8nH9n/IB3k/yAe - 4P8kHeH/Jhrm/yMc4/8gHt7/Ixzi/yMb5P8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMb5P8kG+b/JRzo/yUc - 6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc - 6P8lG+n/JRvp/yUb6f8lG+n/JRvp/yUb6f8lG+n/JRvp/yQc6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yQd6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUd5/8lHeb/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JBzm/yMb - 5P8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMb5P8jG+T/Ixzi/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yIb4P8iG+D/Ihvg/yIb4P8jHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3v8kHd3/JB3c/yQd - 3P8kHdz/JB3c/yQd3P8kHdz/JB3c/yMc2/8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IhzW/yIc1f8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8hHNb/IBvZ/yQe0f8oG9T/JBna/x0c - 2f8dHNP/Ni/C/52a1v/HzM6XwcPWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMXOAMnP - 0ySgor7rNzSE/x4Xiv8fG4z/HxuM/x8bjP8fG4z/HxuM/x8bjP8fG4z/HxuM/x0ZjP8fGKv/Jx/Z/yAd - 5P8gHuD/JB3h/yYa5v8jHOP/IB7e/yMc4v8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMb5P8jG+T/JBvm/yUc - 6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc - 6P8lHOj/JRvp/yUb6f8lG+n/JRvp/yUb6f8lG+n/JRvp/yUb6f8kHOj/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8kHej/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHef/JR3m/yUd - 5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5/8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yQc - 5v8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMb5P8jG+T/Ixvk/yMc4v8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8iG+D/Ihvg/yIb4P8iG+D/Ixzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBzf/yQc3/8kHN//JBzf/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kHN//JB3d/yQd - 3P8kHdz/JB3c/yQd3P8kHdz/JB3c/yQd3P8jHNv/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yIc1v8iHNX/IhzV/yIc1f8iHNX/IhzV/yIc1f8iHNX/IRzW/yAb2f8kHtH/KBvU/yQZ - 2v8dHNn/HRzT/zYvwv+dmtb/x8zOl8HD1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHE - 0ADLztUkoKG/6zYzhv8dF4z/HxqN/x8bjP8fGo3/HxqN/x8ajf8fGo3/HxqN/x8bjP8dGI7/Hxit/ycf - 3P8hHOf/IR7i/yUd4/8nGuj/JBzm/yEf4f8kHOX/JBvm/yQc5v8kHOb/JBzm/yQc5v8kHOb/JBvm/yQc - 5/8kHej/JB3o/yQd6P8kHej/JB3o/yQd6P8kHej/JBzo/yQc6P8kHOn/JBzp/yQc6f8kHOn/JBzp/yQc - 6f8kHOj/JBzp/yQc6f8kHOn/JBzp/yQc6f8kHOn/JBzp/yQc6f8kG+n/Ixzp/yMd6P8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8kHun/JB7p/yQe6f8kHun/JB7p/yQe - 6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQd - 6f8kHen/JB3p/yQd6f8kHen/JB3p/yQd6f8kHen/JB3p/yQd6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe - 6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHen/Ixzp/yQc6f8kHOn/JBzp/yQc6f8kHOn/JBzp/yQc6f8kHOn/JBzo/yQd - 6P8kHOj/JBzo/yQc6P8kHOj/JBzo/yQc6P8kHOj/JB3o/yQd6P8kHej/JB3o/yQd6P8kHej/JB3o/yQd - 6P8jHOf/Ihvl/yIb5f8iG+X/Ihvl/yMc5v8jHOb/Ixzm/yMc5v8kHeT/JB3k/yQd5P8kHeT/JBzj/yMc - 4/8jHOP/Ixzj/yMc4v8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yIb4P8jHOH/Ihvh/yMc4P8kHOD/Ixzg/yQc - 4P8jHOD/Ixzg/yMb4P8jG+D/Ixvg/yMb4P8jG+D/Ixvg/yMb4P8jG+D/Ixvg/yMb4P8jG+D/Ixzf/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBzd/yMb3P8kHNz/JBzc/yMb3P8iGtv/Ihrb/yIa - 2/8iG9v/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMc2f8jHNj/IhzX/yMc1/8jHNf/IhzX/yIb1v8iG9b/IhvW/yEb2P8gG9n/JB7R/ygb - 1P8kGdr/HRzZ/x0c0/82L8L/nZrW/8fMzpfBw9YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADCw9EAzM3WJJ+hwOs1Mon/HBaO/x8ajv8fGo3/HxqN/x8ajf8fGo3/HxqN/x8ajf8fGo3/HReQ/yAX - sP8oHt7/IRzp/yIe5f8mHeX/KBrq/yUc6f8iH+P/JR3n/yUc6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc - 6P8kHOj/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMd6P8jHej/Ix3o/yMd6P8kHun/JB7p/yQe6f8kHun/JB7p/yQe - 6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe - 6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe - 6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yMd6P8jHej/Ix3o/yMd6P8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ihzn/yEb5v8hG+b/IRvm/yEb5v8jHej/Ix3o/yMd6P8jHej/JR3m/yUd5v8lHeb/JR3m/yQc - 5f8jG+T/Ixvk/yMb5P8jHOP/Ixzi/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yMb - 4P8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3v8kHN7/JBze/yQc3v8jG93/Ihrc/yIa - 3P8iGtz/Ihrc/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yMb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8iG9j/IhvY/yIb2P8hGtn/IBvZ/yQe - 0f8oG9T/JBna/x0c2f8dHNP/Ni/C/52a1v/HzM6XwcPWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAwsPRAMzN1iSfocDrNTKJ/xwWj/8fGY7/HxqN/x8ajf8fGo3/HxqN/x8ajf8fGo3/HxqN/x0X - kP8gF7D/KB7e/yEc6f8iHuX/Jh3l/yga6v8lHOn/Ih/j/yUd5/8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc - 6P8lHOj/JBzo/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHej/Ix3o/yMd6P8jHej/JB3p/yQe6f8kHun/JB7p/yQe - 6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe - 6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe - 6f8kHun/JB7p/yQe6f8kHun/JB7p/yQe6f8kHun/JB7p/yQd6f8jHej/Ix3o/yMd6P8jHej/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yIc5/8hG+b/IRvm/yEb5v8hG+b/Ix3o/yMd6P8jHej/Ix3o/yUd5v8lHeb/JR3m/yUd - 5v8kHOX/Ixvk/yMb5P8jG+T/Ixzj/yMc4v8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc - 4f8jHOH/Ixzh/yMc4f8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8jG+D/JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN7/JBze/yQc3v8kHN7/Ixvd/yIa - 3P8iGtz/Ihrc/yIa3P8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IhvY/yIb2P8iG9j/IRrZ/yAb - 2f8kHtH/KBvU/yQZ2v8dHNn/HRzT/zYvwv+dmtb/x8zOl8HD1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMLD0QDMzdYkn6HA6zUyif8cFo//HxmP/x8Zjv8fGY7/HxmO/x8Zjv8fGY7/HxmO/x8Z - jv8dF5D/IBew/yge3v8hHOn/Ih7l/yYd5f8oGur/JRzp/yIf4/8lHef/JRzo/yUc6P8lHOj/JRzo/yUc - 6P8lHOj/JRzo/yQc6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yQd6v8kHer/JB3q/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8iHOf/IRvm/yEb5v8hG+b/IRvm/yMd6P8jHej/Ix3o/yMd6P8lHeb/JR3m/yUd - 5v8lHeb/JBzl/yMb5P8jG+T/Ixvk/yMb5P8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ixvg/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBze/yQc3v8kHN7/JBze/yMb - 3f8iGtz/Ihrc/yIa3P8iGtz/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yIb2P8iG9j/IhvY/yEa - 2f8gG9n/JB7R/ygb1P8kGdr/HRzZ/x0c0/82L8L/nZrW/8fMzpfBw9YAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADCw9EAzM3WJJ+hwOs1Mon/HBaP/x8Zj/8fGY7/HxmO/x8Zjv8fGY7/HxmO/x8Z - jv8fGY7/HReQ/yAXsP8oHt7/IRzp/yIe5f8mHeX/KBrq/yUc6f8iH+P/JR3n/yUc6P8lHOj/JRzo/yUc - 6P8lHOj/JRzo/yUc6P8kHOj/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8kHOr/JB3q/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JBzq/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ihzn/yEb5v8hG+b/IRvm/yIc5/8iHOf/Ix3o/yMd6P8jHef/JB3m/yUd - 5v8lHeb/JR3m/yQc5f8jG+T/Ixvk/yMb5P8jHOT/Ixzj/yMc4/8jHOP/Ixzj/yMc4/8jHOP/Ixzj/yMc - 4/8jHOL/Ixzh/yMc4f8jHOH/Ixzh/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yMb4P8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3v8kHN7/JBze/yQc - 3v8kHN7/Ihrc/yIa3P8iGtz/Ihvc/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/IxzZ/yMc2f8jHNn/IxzZ/yMc2f8iG9j/IhvY/yIb - 2P8hG9n/IBvZ/yQe0f8oG9T/JBna/x0c2f8dHNP/Ni7C/52a1v/HzM6XwcPWAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAwsPRAMzN1iSfocDrNTKJ/xwWj/8fGZD/HxmQ/x8ZkP8fGZD/HxmQ/x8Z - kP8fGZD/HxmQ/x0Xkf8gF7D/KB7e/yEc6f8iHuX/Jh3l/yga6v8lHOn/Ih/j/yUd5/8lHOj/JRzo/yUc - 6P8lHOj/JRzo/yUc6P8lHOj/JBzo/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yQd6v8kHer/JB3q/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc - 6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc - 6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc - 6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc - 6/8kHOv/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHej/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/IRvm/yEb5v8hG+b/IRvm/yMb - 5f8jG+T/Ixvk/yMb5P8kHOX/JR3m/yUd5v8lHeb/JR3m/yUe5f8lHuX/JR7l/yUe5f8jHOT/Ixzj/yMc - 4/8jHOP/Ixzi/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8jG+D/JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN7/JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8iG9v/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMc2f8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/Ihva/yAb2f8kHtH/KBvU/yQZ2v8dHNn/Hh3U/zUuwf+em9f/x8vOl8HD1wAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLD0QDMzdYkn6HA6zUyif8cFo//HxmR/x8ZkP8fGZD/HxmQ/x8Z - kP8fGZD/HxmQ/x8ZkP8dF5H/IBew/yge3v8hHOn/Ih7l/yYd5f8oGur/JRzp/yIf4/8lHef/JRzo/yUc - 6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yQc6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8kHer/JB3q/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JBzr/yQc6/8kHOv/JBzr/yQc - 6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc - 6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc - 6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc - 6/8kHOv/JBzr/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ix3o/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yEb5v8hG+b/IRvm/yEb - 5v8jG+T/Ixvk/yMb5P8jG+T/JBzl/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/Ixvk/yMb - 5P8jG+T/Ixvk/yMc4v8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ixvg/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBze/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/Ihvb/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jHNn/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yIb2v8gG9n/JB7R/ygb1P8kGdr/HRzZ/x4d1P81LsH/npvX/8fLzpfBw9cAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCw9EAzM3WJJ+hwOs1Mon/HBWQ/x8Ykf8fGJH/HxiR/x8Y - kf8fGJH/HxiR/x8Ykf8fGJH/HReR/yAXsP8oHt7/IRzp/yIe5f8mHeX/KBrq/yUc6f8iH+P/JR3n/yUc - 6P8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8kHOj/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/JB3q/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQc7P8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQc7P8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8kHer/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMd - 6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8hG+b/IRvm/yEb - 5v8hG+b/Ixvk/yMb5P8jG+T/Ixvk/yQc5f8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yMb - 5P8jG+T/Ixvk/yMb5P8jHOP/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yMb4P8kHN//JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/IxzZ/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8iG9r/IBvZ/yQe0f8oG9T/JBna/x0c2f8eHdT/NS7B/56b1//Hy86XwcPXAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwsPRAMzN1iSfocDrNTKJ/xwVkP8fGJL/HxiR/x8Y - kf8fGJH/HxiR/x8Ykf8fGJH/HxiR/x0Xkf8gF7D/Jx7f/yEc6f8hHuX/Jh3l/yga6v8lG+n/Ih/j/yQd - 5/8lHOj/JRzo/yUc6P8lHOj/JRzo/yUc6P8lHOj/JBzo/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd - 6P8jHej/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6/8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+z/JBzr/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8kHer/JB3q/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/Ix3o/yMd6P8jHej/IRvm/yEb - 5v8hG+b/IRvm/yMb5f8jG+X/Ixvl/yMb5f8kHOX/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd - 5v8jG+X/Ixvk/yMb5P8jG+T/Ixzj/yMc4v8jHOL/Ixzi/yMc4v8jHOH/Ixzh/yMc4f8jHOH/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8jG+D/JBzf/yQc3/8kHN//JBzf/yQc3/8kHN//JBzf/yQc - 3/8kHN//JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8iG9v/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8iG9r/Ihva/yIb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMc2f8jHNn/IxzZ/yMc - 2f8jHNn/IxzZ/yMc2f8jHNn/Ihva/yAb2f8kHtH/KBvU/yQZ2v8dHNn/Hh3U/zUuwf+em9f/x8vOl8HD - 1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLD0QDMzdYkn6HA6zUyif8cFpD/HhmS/x4Z - kv8eGZL/HhmS/x4Zkv8eGZL/HhmS/x4Zkv8cF5L/Hhew/yYe3/8hHOr/IR7m/yUd5v8nGuv/JBvq/yEe - 5P8jHej/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQc6/8kHOv/JBzr/yQc - 6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc7P8kG+z/JBzs/yQc7P8kHOz/JBzs/yQc7P8kG+z/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7P8kHOz/JBzs/yQb7P8kHOz/JBzs/yQb7P8kHOz/JBzr/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8kHer/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6P8jHOj/Ixzo/yMc6P8jHOj/Ixzo/yMc6P8jHOj/Ihvn/yIb5/8iG+f/Ihvn/yIb5/8iG+b/Ihvm/yIb - 5v8iG+b/Ixzn/yMd5/8jHef/Ix3n/yQd5v8lHeX/JR3l/yUd5f8kHeX/Ixvj/yMb4/8jG+P/Ixzj/yMc - 4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ixvg/yQb3/8kG9//JBvf/yQb3/8kG9//JBvf/yQb4P8kHN//JBze/yQc3f8kHN3/JBzd/yMb - 3P8iGtz/Ihrc/yIa3P8iGtv/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8jG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yIb2/8gG9v/JR7S/ykc1f8lGdz/Hhzb/x4c1P80LMH/nZrX/8fL - z5rBw9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCw9EAzM3WJJ+hwOs1Mon/GxaQ/x4Z - k/8eGZL/HhmS/x4Zkv8eGZL/HhmS/x4Zkv8eGZL/HBeS/x4Xsf8mHuD/IBzq/yAe5v8kHef/Jxrs/yMb - 6v8hHuX/Ix3o/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHOv/JBzr/yQc - 6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQb7P8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQc - 6/8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8kHer/JB3q/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yIb6P8hGuf/IRrn/yEa5/8hGuf/IRvm/yEb - 5v8hG+b/IRvm/yMd6P8jHej/Ix3o/yMd6P8kHef/JR3m/yUd5v8lHeb/JR3m/yMb5P8jG+T/Ixvk/yMb - 5P8jHOL/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yMb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBzg/yQc3/8kHN7/JBze/yQc - 3v8jG93/Ihrc/yIa3P8iGtz/Ihrb/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ixva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8iGtv/IRvb/yUe0/8pHNb/JRnc/x4c2/8eHNX/NS3B/52a - 2f3JzdJ3w8TbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwsPRAMzN1iSfocDrNTKJ/xsW - kP8eGZP/HhmS/x4Zkv8eGZL/HhmS/x4Zkv8eGZL/HhmS/xwXkv8eF7H/Jh7g/yAc6v8gHub/JB3n/yca - 7P8jG+r/IR7l/yMd6P8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JBzr/yQc - 6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kG+z/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kHOv/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8kHer/JB3q/yQd6v8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8iG+j/IRrn/yEa5/8hGuf/IRrn/yEb - 5v8hG+b/IRvm/yEb5v8jHej/Ix3o/yMd6P8jHej/JB3n/yUd5v8lHeb/JR3m/yUd5v8jG+T/Ixvk/yMb - 5P8jG+T/Ixzi/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ixzh/yMc4f8jHOH/Ihvg/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8jG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQc4P8kHN//JBze/yQc - 3v8kHN7/Ixvd/yIa3P8iGtz/Ihrc/yIa2/8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yMb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ihrb/yEb2/8lHtP/KRzW/yUZ3P8eHNv/HhzV/zYu - w/+cmNzszs/iJcPD4QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLD0QDMzdYkn6HA6zUy - if8bFpD/HhmT/x4Zkv8eGZL/HhmS/x4Zkv8eGZL/HhmS/x4Zkv8cF5L/Hhex/yYe4P8gHOr/IB7m/yQd - 5/8nGuz/Ixvq/yEe5f8jHej/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yQc6v8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc - 6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBvs/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvs/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc - 6/8kHOv/JBzr/yQc6/8kHOr/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ihvo/yEa5/8hGuf/IRrn/yEa - 5/8hG+b/IRvm/yEb5v8hG+b/Ix3o/yMd6P8jHej/Ix3o/yQd5/8lHeb/JR3m/yUd5v8lHeb/Ixvk/yMb - 5P8jG+T/Ixvk/yMc4/8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yMc4v8jHOL/Ixzi/yIb4P8iG+D/Ihvg/yIb - 4P8iG+D/Ihvg/yIb4P8iG+D/Ixvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kHOD/JBzf/yQc - 3v8kHN7/JBze/yMb3f8iGtz/Ihrc/yIa3P8iGtv/Ihva/yIb2v8iG9r/Ihva/yIb2v8iG9r/Ihva/yIb - 2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yIa2/8hG9v/JR7T/ykc1v8lGdz/HRvb/x4c - 1f83L8T/npre7c/Q5SXFxeMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDxNIAzM3XJKCi - wes2NIr/HReR/x4Zk/8eGZL/HhmS/x4Zkv8eGZL/HhmS/x4Zkv8eGZL/HBeS/x4Xsf8mHuD/IBzq/yAe - 5v8kHef/Jxrs/yMb6v8hHuX/Ix3o/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/JB3q/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHOv/JBvs/yQb7P8kG+z/JBvs/yQb7P8kG+z/JBvs/yQc - 7P8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQb7P8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+z/JBvs/yQb7P8kG+z/JBvs/yQb7P8kG+z/JBvs/yQb7P8kG+z/JBvs/yQb - 7P8kG+z/JBvs/yQb7P8kG+z/JBzr/yQc6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8iG+j/Ihvo/yIb - 6P8iG+j/Ihzn/yIc5/8iHOf/Ihzn/yIc5/8iHOf/Ihzn/yIc5/8jHOb/JBzl/yQc5f8kHOX/JBzl/yQc - 5f8kHOX/JBzl/yQc5f8kHeT/JB3k/yQd5P8kHeT/Ix3k/yMc4/8jHOP/Ixzj/yMc4v8jHOH/Ixzh/yMc - 4f8jHOH/Ihvg/yIb4P8iG+D/Ihvg/yMb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBzg/yQc - 3/8kHN7/JBze/yQc3v8jG93/Ixvd/yMb3f8jG93/Ixvc/yMc2/8jHNv/Ixzb/yMc2/8iG9r/Ihva/yIb - 2v8iG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8iGtv/IRvb/yUe0/8pHNb/JRnc/x0b - 2/8dHNX/ODDD/5KN3bHk5+kNxsbkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw8TSAM3O - 1yShosLrNzWL/x0Ykv8eGZP/HhmS/x4Zkv8eGZL/HhmS/x4Zkv8eGZL/HhmS/xwXkv8eF7H/Jh7g/yAc - 6v8gHub/JB3n/yca7P8jG+r/IR7l/yMd6P8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yQd - 6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JBzs/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kG+z/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQc7P8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMd6P8jHej/Ix3o/yMd6P8hG+b/IRvm/yEb5v8hG+b/Ihvl/yMb5P8jG+T/Ixvk/yMb - 5P8lHeb/JR3m/yUd5v8lHeb/JR3m/yUe5v8lHub/JR7m/yQc5P8jG+P/Ixzj/yMc5P8jHOP/Ixzh/yMc - 4f8jHOH/Ixzh/yIb4P8iG+D/Ihvg/yIb4P8jG+D/JBvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQc - 4P8kHN//JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3f8kHdz/JB3c/yQd3P8kHdz/Ihva/yIb - 2v8iG9r/Ihva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ihrb/yEb2/8lHtP/KRzW/yUZ - 3P8dG9v/HRvV/zkxw/+Cet2CgnzZAMjI5gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPE - 0gDNztckoaLC6zc1i/8dGJL/HhmT/x4Zkv8eGZL/HhmS/x4Zkv8eGZL/HhmS/x4Zkv8cF5L/Hhex/yYe - 4P8gHOr/IB7m/yQd5/8nGuz/Ixvq/yEe5f8jHej/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQb7P8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBvs/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kHOz/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8kHer/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHej/Ix3o/yMd6P8jHej/IRvm/yEb5v8hG+b/IRvm/yIb5f8jG+T/Ixvk/yMb - 5P8jG+T/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8kHOX/Ixvk/yMb5P8jG+T/Ixzj/yMc - 4v8jHOH/Ixzh/yMc4f8iG+D/Ihvg/yIb4P8iG+D/Ixvg/yQb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb - 4P8kHOD/JBzf/yQc3v8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN3/JB3c/yQd3P8kHdz/JB3c/yIb - 2v8iG9r/Ihva/yIb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yIa2/8hG9v/JR7T/ykc - 1v8lGdz/Hhzb/x4c1f86MsX/ioPjiTgrxADh4f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADDxNIAzc7XJKGiwus3NYv/HRiS/x4Zk/8eGZL/HhmS/x4Zkv8eGZL/HhmS/x4Zkv8eGZL/HBeS/x4X - sf8mHuD/IBzq/yAe5v8kHef/Jxrs/yMb6v8hHuX/Ix3o/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/JB3q/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd6v8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kHOv/JBzr/yQc6/8kHOv/JBzr/yQc6/8kHOv/JBzr/yQb7P8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb - 7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQb7f8kG+3/JBvt/yQd6v8kHer/JB3q/yQd6v8kHer/JB3q/yQd - 6v8kHer/JB3q/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc6f8jHOn/Ixzp/yMc - 6f8jHOn/Ixzp/yMc6f8jHOn/Ix3o/yMd6P8jHej/Ix3o/yEb5v8hG+b/IRvm/yEb5v8iG+X/Ixvk/yMb - 5P8jG+T/JBvk/yUd5v8lHeb/JR3m/yUd5v8lHeb/JR3m/yUd5v8lHeb/JBzl/yMb5P8jG+T/Ixvk/yMc - 4/8jHOL/Ixzh/yMc4f8jHOH/Ihvg/yIb4P8iG+D/Ihvg/yMb4P8kG+D/JBvg/yQb4P8kG+D/JBvg/yQb - 4P8kG+D/JBvf/yQc3/8kHN7/JBze/yQc3v8kHN7/JBze/yQc3v8kHN7/JBzd/yQd3P8kHdz/JB3c/yQd - 3P8iG9r/Ihva/yIb2v8iG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8jG9r/Ixva/yMb2v8iGtv/IBvb/yUe - 0/8pHNb/JRnc/x0b2/8fHdb/OTHF/66p8Nj29/8c5eX/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAw8TSAM3O1yShosLrNzSL/x4Ykf8gGpH/HxmT/x4Ylf8eGJX/HhmT/x4bkf8dG47/HhuP/xkV - mf8bFbb/Jh7d/yIb5/8iHOb/Jhvp/ycZ7v8lGe3/JBzq/yMc6v8jHOr/Ixzq/yMc6v8jHOr/Ixzq/yMc - 6v8jHOr/Ixzq/yQd6/8kHev/JB3r/yQc6/8jHOr/Ixzq/yMc6v8jG+r/JBvt/yQb7/8kG+//JBvv/yQb - 7v8jGu7/Ixru/yMa7v8jGu7/Ixrt/yMa7f8jGu3/Ixrt/yQb7f8kG+3/JBvt/yQb7f8jG+3/Ixru/yMa - 7v8jGu7/Ixru/yMa7v8jGu7/Ixru/yMa7v8jGu7/Ixru/yMa7v8jGu7/Ixru/yMa7v8jGu7/Ixru/yMa - 7v8jGu7/Ixru/yMa7v8jGu7/Ixru/yMa7v8jGu7/Ixru/yMa7f8jGu3/Ixrt/yMa7f8jGu3/JBvu/yQb - 7v8kG+7/JBvu/yQb7v8kG+7/JBvu/yQb7v8jGu7/Ixru/yMa7v8jGu7/Ixru/yQa7v8kGu7/JBru/yQa - 7v8kGu7/JBru/yQa7v8kGu7/JBvu/yQb7/8kG+//JBvv/yQb7v8jGu7/Ixru/yMa7v8jGu7/JBvu/yQb - 7v8kG+7/JBvu/yQb7v8kG+7/JBvu/yQb7v8kGu//Ixrv/yMa7/8jGu//Ixrv/yQa7/8kG+//JBvv/yQb - 7/8jGu7/Ixru/yMa7v8jGu7/JBru/yQb7/8kG+//JBvv/yQb7v8kHOv/JB3r/yQd6/8kHev/JBzr/yQc - 6/8kHOv/JBzr/yMc6v8jG+r/Ixvq/yMb6v8jG+r/Ixvq/yMb6v8jG+r/Ixvq/yMb6v8jHOr/Ixzq/yMc - 6v8jHOr/Ixzq/yMc6v8jHOr/Ixzq/yMc6f8jHOn/Ixzp/yMc6f8hG+j/IRrn/yEa6P8hGuj/Ihvn/yMa - 5/8jGuf/Ixrn/yMb5/8kHOj/JBzo/yQc6P8kHOj/Jhzo/yYc6P8mHOj/Jhzo/yYb5/8lGub/JRrm/yUa - 5v8kG+X/Ihvj/yIb4/8iG+P/Ihvi/yEb4v8hG+L/IRvi/yEb4v8iGuH/Ixrh/yMa4f8jGuH/Ixrh/yQb - 4v8kG+L/JBvi/yQb4v8lGt//JRrf/yUa3/8lGt//JRrf/yUa3/8lGt//JRrf/yUb3/8lG97/JRve/yUb - 3v8lG97/JBrd/yQa3P8kGtz/JBrc/yUa3P8lGtz/JRrc/yUa3P8lGtz/JBnc/yQZ3P8lGtz/JRnf/yMY - 4f8mHNj/Jx3V/yUb2v8gGNz/JBrY/zwwxP+3s/Pv9Pb/J+jo/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAMPE0gDNztckoKLB6zYziv8fGI//IhuO/yAZkv8dGJb/HBiX/xoYkv8bGo//HhyN/x8c - jv8XFZr/Ghiu/ygjw/8tJs//LSPT/y0h2P8tINr/LR/a/y0g2f8pItf/KSPW/ykj1v8pI9b/KSPW/ykj - 1v8pI9b/KSPW/ykj1v8qJNf/KiTX/yok1/8qJNf/KCLV/ygi1f8oItX/KCLW/yoj2f8qI9r/KiPa/yoj - 2v8qI9n/KSLZ/yki2f8pItn/KSLZ/yki2v8qItr/KiLa/yoi2v8pItr/KSLa/yki2v8pItr/KSLa/yoi - 2v8qItr/KiLa/ykh2v8pIdr/KSHa/ykh2v8pIdr/KSLa/yoi2v8qItr/KiLa/yoi2v8qItr/KiLa/yoi - 2v8qItr/KiLa/yoi2v8qItr/KiLa/yoi2v8qItr/KiLa/yoi2v8qItr/KiPZ/yoj2f8pI9n/KiPa/yoj - 2v8qI9r/KiPa/yoj2v8qI9v/KiLb/yoi2/8qItv/KSHa/ykh2f8pIdr/KSHa/ykh2v8pIdr/KSHa/ykh - 2v8pIdr/KSHa/ykh2v8pIdr/KSHa/ykh2v8qItr/KiLa/yoi2v8pItr/KSHa/ykh2v8pIdr/KSHa/yki - 2v8qItr/KiLa/yoi2v8qItr/KiLa/yoi2v8qItr/KSHa/ygg2f8oINn/KCDZ/ygg2f8pIdv/KiLb/yoi - 2/8qItv/KCHY/ygg2P8oINj/KCDY/ygh2P8pItn/KSLZ/yki2f8pItj/KiPX/yok1/8qJNf/KiTX/ykj - 1v8oItX/KCLV/ygi1f8pItX/KSPW/ykj1v8pI9b/KSPW/ykj1v8pI9b/KSPW/ykj1v8pI9b/KSPW/ykj - 1v8pI9b/KSPW/ykj1v8pI9b/KSPW/ykj1v8pI9b/KSPW/ykj1v8pI9b/KCLV/ygi1f8oItX/KCLV/ygi - 1P8oItT/KCLU/ygi1P8oItT/KCLU/ygi1P8oItT/KSLU/ysh0/8rIdP/KyHT/ysh0/8rIdP/KyHT/ysh - 0/8rIdP/KiHR/yYhzv8lIc7/JSHO/yUhzv8lIc7/JSHO/yUhzv8mIc7/JiDO/yYgzf8mIM3/JiDN/ych - zv8oIc//KCHP/ychz/8oIc//KyDN/ywgzP8sIMz/LCDM/y0hzf8tIc7/LSHO/y0hzv8tIc3/LSLM/y0i - zP8tIsz/LSLM/ywgyv8rIMr/KyDK/ysgyv8rIMr/KyDK/ywhy/8rH8r/KyDK/ywgyv8sIMr/Kx/J/ywf - z/8tHNb/LCHK/yonwP8pJMT/Kh3N/zMgyv9KO7b/urfu4uvw/1Lo6/8AAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADDxNIAzc7XJKCiwes2M4r/HheR/yAZkf8fG43/HB2M/xscjv8aGZH/GhaT/x8X - lP8gGI//ICB9/1xfrv+TleL/lJXl/5WU5/+UlOj/lJTo/5SV6P+Vlej/lpXo/5eV6P+Xlej/l5Xo/5eV - 6P+Xlej/l5Xo/5eV6P+Xlej/mJbo/5iW6P+Yluj/mJbo/5iW6P+Yluj/mJbo/5iW6P+Zlun/mZbp/5mW - 6f+Zlun/mZbp/5iW6f+Ylun/mJbp/5mW6f+al+r/mpfq/5qX6v+al+r/mpbp/5qW6P+aluj/mpbo/5qW - 6f+al+r/mpfq/5qX6v+al+r/mpfq/5qX6v+al+r/mpfq/5qX6v+al+r/mpfq/5qX6v+al+r/mpfq/5qX - 6v+al+r/mpfq/5qX6v+al+r/mpfq/5qX6v+al+r/mpfq/5qX6v+al+r/mpfp/5qX6f+al+n/mpfp/5qX - 6f+Zlun/mZbp/5mW6f+Zlun/mZXq/5mV6v+Zler/mZXq/5iU6f+XlOn/l5Tp/5eU6f+XlOn/l5Pp/5eT - 6f+Xk+n/l5Pp/5eT6f+Xk+n/l5Pp/5eT6f+Wk+n/lpPq/5aT6v+Wk+r/lpPp/5WS6f+Vkun/lZLp/5WS - 6f+UkOn/k5Dp/5OQ6f+TkOn/k5Dp/5OQ6f+TkOn/k5Dp/5OP6f+Sj+n/ko/p/5KP6f+Sj+n/k4/p/5OP - 6f+Tj+n/k4/p/5GO6f+Rjen/kY3p/5GN6f+Rjun/ko7p/5KO6f+Sjun/kY7p/5CO6P+Qj+j/kI/o/5CP - 6P+Pjuj/j43o/4+N6P+Pjej/j43o/4+N6P+Pjej/j43o/4+N6P+OjOj/jozo/46M6P+OjOj/jozn/42L - 5/+NjOf/jYzn/42L5/+Miuf/jIrn/4yK5/+Miuf/jIrn/4yK5/+Miuf/jIrn/4uJ5v+Lieb/i4nm/4uJ - 5v+KiOX/iojl/4qI5f+KiOX/iojl/4qI5f+KiOX/iojl/4qI5P+HhuL/hobh/4aG4f+GhuH/hobh/4WF - 4P+FheD/hYXg/4WF3/+FhN7/hYTe/4WE3v+FhN7/hYTe/4WE3v+FhN7/hYTe/4WD3f+Fgtz/hYLc/4WC - 3P+Fg93/hoPd/4aD3f+Gg93/hoPd/4SD2/+Eg9r/hIPa/4SD2v+GhNz/hoXc/4aF3P+Ghdz/hoXc/4aF - 2/+Ghdv/hoXb/4aF2/+FhNr/hYTa/4WE2v+FhNr/hYTa/4WE2v+Eg9n/eXjO/3h4zf+Cgdf/iIfd/4uK - 4P+QjuT/lZHo/5SV5P+TmeD/kpfj/5WT5v+akuP8m5TW3MjG7HL///8D5+n+AAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAw8TSAM3O1ySgosHrNjOK/xwVlP8dGJX/HB6L/xshhP8bHoj/HRmT/yAX - mv8hFpb/IxqJ/29uo//X2uv/5ej5/+To+f/n6/n/5+z1/+ft9P/n7vL/6O/z/+7t9//v7Pj/7+z4/+/s - +P/v7Pj/7+z4/+/s+P/v7Pj/7+z4//Dt+P/w7fj/8O34//Dt+f/x7vn/8e75//Hu+f/x7vn/8u76//Lu - +v/y7vr/8u76//Lv+v/z7/r/8+/6//Pv+v/z8Pr/9PH6//Tx+v/08fr/9PH7//Xy/P/28/z/9vP8//bz - /P/18vv/9PH6//Tx+v/08fr/9fL7//Xy+//18vv/9fL7//Xy+//18vv/9PH6//Tx+v/08fr/9PH6//Tx - +v/08fr/9PH6//Tx+v/08fr/9PH6//Tx+v/08fr/9PH6//Tx+v/08fr/9PH6//Tx+//08fv/9PH7//Tx - +//08Pv/8u76//Lu+v/y7vr/8u/6//Lv+f/y7/n/8u/5//Lv+f/x7vn/8O74//Hu+P/x7vj/8O34/+/s - 9//v7Pf/7+z3/+/s9//v7Pf/7+z3/+/s9//v7Pf/7uv3/+7r9//u6/f/7uv3/+7r9//t6vf/7er3/+3q - 9//t6vf/6uj2/+rn9v/q5/b/6uf2/+rn9v/q5/b/6uf2/+rn9v/q5/X/6eb1/+nm9f/p5vX/6OX1/+jl - 9P/o5fT/6OX0/+jl9P/n5PT/5+P1/+fj9f/n4/X/5uP1/+bi9P/m4vT/5uL0/+Xi9P/j4PL/4t/x/+Lf - 8f/i3/H/4d/x/+He8f/h3vH/4d7x/+He8f/h3vH/4d7x/+He8f/h3vH/39zv/9/c7//f3O//39zv/9/c - 7v/e3O7/3tzu/97c7v/d2+3/3Nns/9zZ7P/c2ez/3Nns/9zZ7P/c2ez/3Nns/9zZ7P/b2Ov/29jr/9vY - 6//b2Ov/2tfq/9nW6f/Z1un/2dbp/9nW6f/Z1un/2dbp/9nW6f/Y1uj/0tXm/9HV5f/R1eX/0dXl/9DU - 5P/P1OP/z9Tj/8/U4//Q0+P/0NHj/9HR4//R0eP/0dHj/9HR4//R0eP/0dHj/9HR4//R0OL/0c/h/9HP - 4f/Rz+L/0c/h/9DO4f/QzuH/0M7h/9DP4P/Lzt7/ys7d/8rO3f/Kzt3/y8/e/8zQ3//M0N//zNDf/8zQ - 3//M0N7/zNDe/8zQ3v/M0N7/ys7c/8rO3P/Kztz/ys7c/8rO3P/Kztz/ys7c/7u+zP+8wM7/y8/d/9fb - 6f/g5PH/5un28ebp/37k6/9x5O3/cuPs/3Lj5/9z6en/YfDu/xX4+P8I8vP/AOjq/gAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPE0gDNztckoKLC6zYziv8cFZX/HBiX/xsdjf8bH4j/HByO/x8X - mP8jFpX/JBuE/2xorv/a2Oz/7+3u/+/s7v/v7u3/7e3q/+7v6P/u8Ob/7vHl//Dx5f/28Ov/9/Ds//fw - 7P/38Oz/9/Ds//fw7P/38Oz/9/Ds//jx7f/58u7/+fHu//nx7v/58u7/+fLu//ny7v/58u7/+fLu//rz - 8P/79PD/+/Tw//v08P/89fH//fby//328v/99vL//fby//338P/99/D//ffw//338P/99/D//ffw//33 - 8P/99/D//ffw//338P/99/D//ffw//338P/++fH//vny//758v/++fH//vjw//338P/99/D//ffw//33 - 8P/99/D//ffw//338P/99/D//ffw//338P/99/D//ffw//338P/99/D//ffw//338P/99/H//fby//32 - 8//99vP//fXy//v08f/79PH/+/Tx//v08P/79e7/+/Xu//v17v/79e7/+vTt//r07f/69O3/+vTt//nz - 7P/38er/9/Hq//fx6v/38er/9/Hq//fx6v/38er/9/Hq//bw6f/17+j/9vDo//bw6P/17+j/9e/n//Xv - 5//17+f/9e/n//Pt5f/z7eX/8+3l//Pt5f/z7eX/8uzl//Ls5f/z7eX/8uzk//Hr4//x6+P/8evj//Dq - 4//w6uL/8Ori//Dq4v/w6eL/7+fk/+7m5P/u5uT/7ubk/+3m5P/t5eP/7eXj/+3l4//s5eL/6+Tg/+vk - 4P/r5OD/6+Tg/+rj3//p4t7/6eLe/+ni3v/p4t7/6eLe/+ni3v/q4t7/6eLe/+fg3P/n4Nz/5+Dc/+fg - 3P/n4Nz/5+Dc/+fg3P/n4Nz/5t/b/+Xd2f/l3dn/5d3Z/+Xd2f/k3dn/5N3Z/+Td2f/k3dn/5NzY/+Pc - 2P/j3Nj/49zY/+Lb1//g2dX/4NnV/+DZ1f/g2dX/4NnV/+DZ1f/h2dX/4NnV/9va1P/a2tP/2trT/9ra - 0//Y2dL/19jR/9fY0f/X2NH/19fR/9fV0f/X1dL/19XS/9fV0v/X1dH/19XR/9fV0f/X1dH/2NTR/9jT - 0P/Y09D/2NPR/9fT0P/W0c//1tHP/9bRz//W0s//09LN/9PSzf/T0s3/09LN/9PTzv/U087/1NPO/9TT - zv/U087/1NPO/9TTzv/U087/1NPO/9LSzf/S0sz/0tLM/9LSzP/S0cz/0dDL/9PSzf/Fxb//ycnD/9jX - 0v/l5N//6urlse3v53D6+9cH4Ob8AN7o/wDd5/8A3eH/AOLi/wDU0foA4+L8AN/d+gAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFxtQAz9DZJaKjw+42NIv/HBaS/xsZlP8bGpL/HBmS/yAY - mP8kFpf/KByG/21pqP/S1+n/7e7w//Ht7P/w7Oz/8e3t//Ht7f/y7e7/8uzv//Hs8P/y7PD/8+7v//Pv - 7//z7+//8+/v//Pv7//z7+//8+/v//Pv7v/18PD/9vHx//bx8f/28fH/9vHx//bx8f/28fH/9vHx//bx - 8f/48/P/+PTz//j08//49PP/+fT0//n19f/59fX/+fX1//r19P/69/P/+vfz//r38//69/P/+/j0//z4 - 9P/8+PT//Pj0//v39P/69/P/+vfz//r38//79/T//fn2//359v/9+fb//fn2//359f/9+fX//fn1//35 - 9f/9+fX//fn1//359f/9+fX//Pn1//r38//69/P/+vfz//r38//69/P/+vfz//r38//69/P/+vb0//r2 - 9f/69vX/+vb1//r19f/59PT/+fT0//n09P/59fT/+PXx//j18f/49fH/+PXx//f08P/28+//9vPv//bz - 7//28+//9vLv//Xy7v/08e3/8/Ds//Pw7P/z8Oz/8/Ds//Pw7P/z8Oz/8/Ds//Pw7P/z8Oz/8u/r//Ht - 6v/x7er/8e3q//Ht6v/x7er/8e3q//Ht6v/x7er/8Ozo/+/s6P/v7Oj/7+zo/+/r5//u6+f/7uvn/+7r - 5//u6uf/7erm/+3q5v/t6ub/7enm/+3o6P/s5uj/6+bn/+rl5v/q5eb/6uXm/+rl5v/q5eb/6uTm/+jk - 5P/o5OP/6OTj/+jk4//n4+P/5+Pi/+fj4v/n4+L/5+Li/+bi4f/m4uH/5uLh/+bh4f/k39//5N/f/+Tf - 3//k39//5ODf/+Tf3//j397/4t7e/+Ld3f/i3d3/4t3d/+Ld3f/i3d3/4Nzc/+Dc3P/g3Nz/4Nzb/+Db - 2//f29r/39vb/9/b2//e2tn/3djY/93Z2P/d2dj/3dnY/93Z2P/d2dj/3dnY/93Z2P/c2Nf/3NjX/9zY - 1//c2Nf/29fW/9rX1v/a19b/2tfW/9jW1v/U1Nb/1NTW/9TU1v/U1Nb/09PW/9PT1v/T09b/09PW/9PS - 1f/U0tT/1NLU/9TS1P/U0tT/09HU/9PR1P/T0dT/1NLU/9TQ0v/U0NH/1NDR/9TQ0f/V0NH/1dDS/9XQ - 0v/V0NL/1dDS/9XQ0v/V0NL/1dDS/9XQ0v/V0NL/1dDS/9XQ0v/V0NL/1dDS/9XQ0v/V0NL/ycTG/83I - yv/d2Nr/6uXm/vDq7FLu7OoA7vDpAO3v6QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxsfVANbX3RadnsHJNjSK/xsXj/8ZGI//GhaT/x8W - mP8iFpX/JhqE/25nqv/X2Oz/6vHo/+vw5f/u7+n/7u7q/+7u6//u7u3/7+3w/+/r9P/v6ff/7ur2/+zv - 8P/s8O//7PDv/+zw7//s8O//7PDv/+zw7//s8O//7fHw/+/z8v/v8/L/7/Py/+/z8v/v8/L/7/Py/+/z - 8v/v8/L/8PTz//H19P/x9fT/8fX0//H19P/y9vX/8vb1//L29f/y9vX/8/f1//P39f/z9/X/8/f1//T5 - 9//1+ff/9fn3//X59//0+Pb/9Pj2//T49v/0+Pb/9Pj2//b6+P/2+vj/9vr4//b6+P/2+vj/9vr4//b6 - +P/2+vj/9vr4//b6+P/2+vj/9vr4//X59//0+Pb/9Pj2//T49v/0+Pb/8/f1//P39f/z9/X/8/f1//P3 - 9f/z9/b/8/f2//P39v/z9vb/8vb1//L29f/y9vX/8vb1//H18//x9fP/8fXz//H18//w9PL/7/Px/+/z - 8f/v8/H/7/Px/+/z8f/u8vD/7fHv/+zw7v/s8O7/7PDu/+zw7v/s8O7/7PDu/+zw7v/s8O7/7PDu/+vv - 7f/q7uz/6u7s/+ru7P/q7uz/6u7s/+ru7P/q7uz/6u7s/+nt6//o7Or/6Ozq/+js6v/o7Or/5+vp/+fr - 6f/n6+n/5+vp/+bq6P/m6uj/5uro/+bq6P/m6uj/5ejo/+Tn5//j5+f/4+bm/+Pm5//j5uf/4+bn/+Pm - 5v/h5eT/4eXk/+Hl5P/h5eT/4OTj/+Dk4//g5OP/4OTj/9/j4//f4+L/3+Pi/9/j4v/f4uL/3eHg/93h - 4P/d4eD/3eHg/93h4P/d4eD/3ODf/9vf3v/a3t7/29/e/9vf3v/b397/2t7e/9nd3P/Z3dz/2d3c/9nd - 3P/Y3Nv/2Nzb/9jc2//Y3Nv/19va/9ba2f/W2tn/1trZ/9ba2f/W2tn/1trZ/9ba2f/W2dn/2NjZ/9nX - 2f/Z19n/2dfZ/9jX2P/Y1tj/2NbY/9jW2P/W1tj/0NXY/9DV2P/Q1dj/0NXY/8/U1//P1Nf/z9TX/8/U - 1//P09b/z9LW/8/S1v/P0tb/z9LW/8/S1v/P0tb/z9LW/9DS1f/R0NP/0tDS/9LQ0v/S0NL/0tDS/9LQ - 0v/S0NL/0tDS/9LQ0//S0NP/0tDT/9LQ0//S0NP/0tDT/9LQ0//S0NP/0tDT/9LP0//S0NT/0tDT/8nG - yv/Ny8//3dre/+fl6c7v6u8V8OrvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPE0gB+gLEAioy6hDg2i/8bF4z/Hx2P/yAY - lv8hF5X/JRuE/21pqP/X2Oz/6+zq/+/u4//u7ub/7e/p/+3v6P/t8Oj/7vDp/+7v7P/u7u7/7uzx/+7t - 8f/s8O7/7PDt/+zw7f/s8O3/7PDt/+zw7f/s8O3/7PDt/+7y7//v8/D/7/Pw/+/z8P/v8/D/7/Pw/+/z - 8P/v8/D/7/Pw//H18f/x9vH/8fbx//H28f/y9vL/8vfy//L38v/y9/L/8/fz//P49P/z+PT/8/j0//P4 - 9P/1+fb/9fr2//X69v/1+vb/9fr2//X69v/1+vb/9fr2//b69v/2+/f/9vv3//b79//2+/f/9vv3//b7 - 9//2+/f/9vv3//b79//2+/f/9vv3//b79//2+vf/9fr2//X69v/1+vb/9fr2//T49P/z+PT/8/j0//P4 - 9P/z+PP/8/jz//P48//z+PP/8/fz//L38v/y9/L/8vfy//L38v/x9vL/8fby//H28v/x9vL/8PTx/+/0 - 8P/v9PD/7/Tw/+/08P/v9PD/7vPv/+3y7v/s8e3/7PHt/+zx7f/s8e3/7PHt/+zx7f/s8e3/7PHt/+zx - 7f/s8Oz/6u/r/+rv6//q7+v/6u/r/+rv6//q7+v/6u/r/+rv6//p7er/6O3p/+jt6f/o7en/6Ozp/+fs - 6P/n7Oj/5+zo/+fr6P/m6+f/5uvn/+br5//m6+f/5urn/+Xp5v/k6OX/4+fk/+Pn5P/j5+T/4+fk/+Pn - 5P/j5+T/4ebi/+Hl4v/h5eL/4eXi/+Hl4v/g5OH/4OTh/+Dk4f/g5OH/3+Pg/9/j4P/f4+D/3+Pg/93h - 3v/d4d7/3eHe/93h3v/d4d7/3eHe/9zg3f/b39z/29/c/9vf3P/b39z/29/c/9vf3P/Z3dr/2d3a/9nd - 2v/Z3dr/2d3a/9jc2f/Y3Nn/2NzZ/9fb2P/W2tf/1trX/9ba1//W2tf/1trX/9ba1//W2tf/19rY/9jZ - 2P/Y2Nj/2NjY/9jY2P/Y2Nf/19fX/9fX1//X19f/1tfW/9LW1P/S1tT/0tbU/9LW1P/R1dP/0dXT/9HV - 0//R1dP/0dTT/9LU0v/S1NL/0tTS/9LU0v/S1NL/0tTS/9LU0v/R09L/0NLQ/8/S0P/P0tD/z9LQ/8/S - 0P/P0tD/z9LQ/8/S0P/P0tD/z9HR/8/R0f/P0dH/z9HR/8/R0f/P0dH/z9HR/8/R0f/P0ND/z9DQ/8/R - 0f/Jy8v/z9HR/93f3//n6OjB7PDuBPfq9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgIC1AI+Qv4Q6N43/HRiN/yEc - j/8hF5H/IxqK/21qrv/T2On/6/Hp/+/u5P/06e7/8uny//Dr8P/w7ez/8O7p//Dw6P/x8Oj/8fDp//Hv - 6//x7+3/8u/u//Lv7v/y7+7/8u/u//Lv7v/y7+7/8u/u//Lv7v/z8O//9fLx//Xy8f/18vH/9fLx//Xy - 8f/18vH/9fLx//Xy8f/29PL/9/Xy//f18v/39fL/9/Xy//j28//49vP/+Pbz//j19P/59vX/+fb2//n2 - 9v/59vb/+vf3//v4+P/7+Pj/+/j4//v4+P/8+fn//Pn5//z5+f/8+fn//Pn5//z5+f/8+fn//Pn5//z5 - +f/8+fn//Pn5//z5+f/8+fn//Pn5//z5+f/8+fn//Pn5//z5+f/8+fn//Pn5//z4+f/59vb/+fb2//n2 - 9v/59vb/+fb0//n39P/59/T/+ff0//n28//49vP/+Pbz//j28//49fP/9/Tz//f09P/39PT/9/T0//by - 8//18vL/9fLy//Xy8v/18vL/9fLy//Tx8f/z7/D/8u/v//Lv7//y7+//8u/v//Lv7//y7+//8u/v//Lv - 7//y7+//8e7u//Ds7f/w7e3/8O3t//Dt7f/w7e3/8O3t//Dt7f/w7e3/7+vr/+7q6//u6+v/7uvr/+3q - 6v/t6ur/7erq/+3q6v/t6er/7Onp/+zp6f/s6en/7Onp/+zp6P/r6Of/6ufm/+nm5f/p5uX/6ebl/+nm - 5f/p5uX/6ebl/+fk4//n5OP/5+Tj/+fk4//m4+L/5uPi/+bj4v/m4+L/5eLi/+Xi4f/l4uH/5eLh/+Th - 4f/j4N//4+Df/+Pg3//j4N//4+Df/+Pg3//i397/4d7d/+Dd3f/h3t3/4d7d/+He3f/g3d3/39zb/9/c - 2//f3Nv/39zb/97b2v/e29r/3tva/97b2v/d2tn/3NnY/9zZ2P/c2dj/3NnY/9zZ2P/c2dj/3NnY/9zZ - 2P/b2Nn/2tfZ/9rX2f/a19n/2tfY/9nW2P/Z1tj/2tbY/9nW1//Y1dT/2NXU/9jV1P/Y1dT/2NTT/9fU - 0//X1NP/19TT/9jT0//Z0tL/2dLS/9nS0v/Z0tL/2dLS/9nS0v/Z0tL/19PS/9LS0P/Q0s//0NLP/9DS - z//Q0s//0NLP/9DSz//Q0s//0NLQ/9DR0f/Q0dH/0NHR/9DR0f/Q0dH/0NHR/9DR0f/Q0dH/z9DQ/87P - z//Q0dH/zc7N/9TV1P/h4uH/6uvqw+/w7wXr7OwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIGCvQCSk8mEOTaP/x8W - lP8iGJf/JB2D/29srf/V1e3/6uvx/+zr6P/x7en/8err//Dq7v/w7O//8Ozt//Dt7P/w7ur/8e/r//Hv - 6v/x7+v/8e/s//Lv7v/y7+7/8u/u//Lv7v/y7+7/8+/v//Tw7//08PD/9PHx//Xy8f/18vH/9fLx//Xy - 8v/28/P/9vPz//bz8//28/P/9/Tz//j19P/49fT/+PX0//n19P/59vX/+fb1//n29f/59vX/+vf3//r3 - 9//69/f/+vf3//v4+P/7+Pj/+/j4//v4+P/7+fn//Pn5//z5+f/8+fn//Pn5//z5+f/8+fn//Pn5//z5 - +f/8+fn//Pn5//z5+f/8+fn//Pn5//z5+f/8+fn//Pn5//z5+f/8+fn//Pn5//z5+f/7+fn/+/j4//r3 - 9//59/f/+fb2//n29f/59vX/+fb1//n29f/59vX/+fb1//n29f/59vX/+fb1//f19P/39PT/9/T0//f0 - 9P/29PT/9vPz//bz8//28/P/9fPz//Xx8v/18fH/9fDx//Tw8f/z7u//8u7v//Lu7//y7u//8u7v//Lu - 7//y7u//8u7v//Lu7//y7u7/8e3u//Hs7f/w7O3/8Ozt//Ds7f/w7O3/8Ozt/+/r6//u6uv/7urr/+7q - 6//u6uv/7enq/+3p6v/t6er/7enq/+3o6f/s6On/7Ojp/+zo6f/s5+j/6+fn/+rm5//q5uf/6ubn/+rm - 5//p5eb/6eXl/+jk5f/o4+T/5+Pk/+fj5P/n4+T/5+Pj/+bi4//m4uP/5uLj/+bi4v/l4uH/5eLh/+Xi - 4f/l4eH/5ODf/+Pg3//j4N//4+Df/+Pg4P/i3+D/4d7f/+De3v/g3d7/4d7e/+He3v/h3t7/4N3e/9/c - 3P/f3Nz/39zc/97c3P/e29v/3tvb/97b2//e29v/3Nra/9vZ2f/c2dn/3NnZ/9zZ2f/c2dn/3NnZ/9zZ - 2f/c2dn/2tjZ/9rX2f/a19n/2tfZ/9nX2f/Z19n/2NbY/9jV1//Y1db/2NXV/9jV1f/Y1dX/2NXV/9fU - 1P/X1NT/19TU/9fU1P/X09P/19PT/9fT0//X09P/19PT/9fT0//X09P/19PT/9bS0//S0dH/0dHR/9HR - 0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR - 0f/R0dH/0tLS/9HR0f/b29v/5eXl/+zs7Hji4uIA7e3tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODj/gCUlc8AmJjUgjw4 - kf8gFo//IxqK/21rrv/V2e//6+zu/+7p7f/w6O//7+rs/+3t5v/u7un/7+3s/+/t7P/v7ez/7+3s//Du - 7f/w7u3/8O7t//Du7f/x7+7/8e/u//Hv7v/x7+7/8e/u//Lw7//z8fD/9PLx//Py8f/y8/H/8vPx//Lz - 8f/y8/H/9PXz//T18//09fP/9PXz//b19P/39fT/9/X0//f19P/49fT/+Pb1//j29f/49vX/+Pf1//j5 - 9//4+ff/+Pn3//j59//5+vj/+fr4//n6+P/5+vj/+fr4//n6+P/5+vj/+fr4//n6+P/6+vn/+vr5//r6 - +f/6+vn/+vr5//r6+f/6+vn/+vr5//r6+f/6+vn/+vr5//r6+f/5+vj/+fr4//n6+P/5+vj/+fr4//n6 - +P/5+vj/9/j2//b39f/39vX/+Pb1//j29f/49vX/+Pb1//j29f/49vX/+Pb1//j29f/29vT/9fb0//X2 - 9P/19vT/9fXz//T18//09fP/9PXz//T08v/08vH/9PLx//Ty8f/08vH/8e/u//Hv7v/x7+7/8e/u//Hv - 7v/x7+7/8e/u//Hv7v/x7+7/8e/u//Du7f/v7ez/7+3s/+/t7P/v7ez/7+3s/+/t7P/u7Ov/7evq/+3r - 6v/t6+r/7evq/+zq6v/s6ur/7Orq/+zq6v/r6en/6+np/+vp6f/r6en/6ujo/+nn5//p5+f/6efn/+nn - 5//p5+f/6Obm/+fl5f/m5OT/5uTk/+bk5P/m5OT/5uTk/+Xj4//l4+P/5ePj/+Xj4//l4+L/5OLh/+Ti - 4f/k4uH/5OLh/+Lg3//i4N//4uDf/+Lg3//h4OD/4ODg/9/f3//e3t7/3t7e/97e3v/e3t7/3t7e/97e - 3v/c3Nz/3Nzc/9zc3P/c3Nz/29vb/9vb2//b29v/29vb/9ra2v/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ - 2f/Z2dn/2dnZ/9jY2P/Y2Nj/2NjY/9jY2P/Y2Nj/2NjY/9fX1//W1tb/1dXV/9XV1f/V1dX/1dXV/9XV - 1f/U1NT/1NTU/9TU1P/U1NT/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/0dHR/9HR - 0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR - 0f/R0dH/0tLS/9LS0v/W1tb/4eHh/+jo6Nfs7Owe7OzsAO3t7QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg4v4A+v7/D7Oz - 5LU+OYv/Ix15/2trqP/R1u//5+3t/+zt5v/v6ur/8Ojv/+7p7f/t7ej/7u7p/+/t7P/v7ez/7+3s/+/t - 7P/w7u3/8O7t//Du7f/w7u3/8e/u//Hv7v/x7+7/8e/u//Hv7v/y8O//8/Hw//Ty8f/z8vH/8vPx//Lz - 8f/y8/H/8vPx//T18//09fP/9PXz//T18//29fT/9/X0//f19P/39fT/9/X0//j29f/49vX/+Pb1//j3 - 9f/4+ff/+Pn3//j59//4+ff/+fr4//n6+P/5+vj/+fr4//n6+P/5+vj/+fr4//n6+P/5+vj/+vv5//r7 - +f/6+/n/+vv5//r7+f/6+/n/+vv5//r7+f/6+/n/+vv5//r7+f/6+/n/+vv5//n6+P/5+vj/+fr4//n6 - +P/5+vj/+fr4//f49v/29/X/9/b1//j29f/49vX/+Pb1//j29f/49vX/+Pb1//j29f/49vX/9fb0//X2 - 9P/19vT/9fb0//T18//09fP/9PXz//T18//09PL/9PLx//Ty8f/08vH/9PLx//Hv7v/x7+7/8e/u//Hv - 7v/x7+7/8e/u//Hv7v/x7+7/8e/u//Hv7v/w7u3/7+3s/+/t7P/v7ez/7+3s/+/t7P/v7ez/7uzr/+3r - 6v/t6+r/7evq/+3r6v/s6ur/7Orq/+zq6v/s6ur/6+np/+vp6f/r6en/6+np/+ro6P/p5+f/6efn/+nn - 5//p5+f/6efn/+jm5v/n5eX/5uTk/+bk5P/m5OT/5uTk/+bk5P/l4+P/5ePj/+Xj4//l4+P/5ePi/+Ti - 4f/k4uH/5OLh/+Ti4f/i4N//4uDf/+Lg3//i4N//4ODg/+Dg4P/f39//3t7e/97e3v/e3t7/3t7e/97e - 3v/e3t7/3Nzc/9zc3P/c3Nz/3Nzc/9vb2//b29v/29vb/9vb2//a2tr/2dnZ/9nZ2f/Z2dn/2dnZ/9nZ - 2f/Z2dn/2dnZ/9nZ2f/Y2Nj/2NjY/9jY2P/Y2Nj/2NjY/9jY2P/X19f/1tbW/9XV1f/V1dX/1dXV/9XV - 1f/V1dX/1NTU/9TU1P/U1NT/1NTU/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9HR - 0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR - 0f/R0dH/0dHR/9HR0f/R0dH/29vb/+fn5/vr6+tz6urqAOzs7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5+j/APLz - /yPDwubpQj5//2xpof/V2ur/6O/s/+rw4v/v7+P/8Orq/+/o7//t6u3/7Ozo/+7u6f/v7ez/7+3s/+/t - 7P/v7ez/8O7t//Du7f/w7u3/8O7t//Hv7v/x7+7/8e/u//Hv7v/x7+7/8vDv//Px8P/08vH/8/Lx//Lz - 8f/y8/H/8vPx//Lz8f/09fP/9PXz//T18//09fP/9vX0//f19P/39fT/9/X0//j29f/49vX/+Pb1//j2 - 9f/49/X/+Pn3//j59//4+ff/+Pn3//n6+P/5+vj/+fr4//n6+P/5+vj/+fr4//n6+P/5+vj/+vv5//v8 - +v/8/fv//P37//z9+//8/fv//P37//z9+//8/fv//P37//z9+//8/fv//P37//v8+v/5+vj/+fr4//n6 - +P/5+vj/+fr4//n6+P/3+Pb/9vf1//f29f/49vX/+Pb1//j29f/49vX/+Pb1//j29f/49vX/+Pb1//X2 - 9P/19vT/9fb0//X29P/09fP/9PXz//T18//09fP/9PTy//Ty8f/08vH/9PLx//Ty8f/x7+7/8e/u//Hv - 7v/x7+7/8e/u//Hv7v/x7+7/8e/u//Hv7v/x7+7/8O7t/+/t7P/v7ez/7+3s/+/t7P/v7ez/7+3s/+7s - 6//t6+r/7evq/+3r6v/t6+r/7Orq/+zq6v/s6ur/7Orq/+vp6f/r6en/6+np/+vp6f/q6Oj/6efn/+nn - 5//p5+f/6efn/+nn5//o5ub/5+Xl/+bk5P/m5OT/5uTk/+bk5P/m5OT/5ePj/+Xj4//l4+P/5ePj/+Xj - 4v/k4uH/5OLh/+Ti4f/k4uH/4uDf/+Lg3//i4N//4uDf/+Dg4P/g4OD/39/f/97e3v/e3t7/3t7e/97e - 3v/e3t7/3t7e/9zc3P/c3Nz/3Nzc/9zc3P/b29v/29vb/9vb2//b29v/2tra/9nZ2f/Z2dn/2dnZ/9nZ - 2f/Z2dn/2dnZ/9nZ2f/Z2dn/2NjY/9jY2P/Y2Nj/2NjY/9jY2P/Y2Nj/19fX/9bW1v/V1dX/1dXV/9XV - 1f/V1dX/1dXV/9TU1P/U1NT/1NTU/9TU1P/T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT - 0//R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR0f/R0dH/0dHR/9HR - 0f/R0dH/0dHR/9HR0f/R0dH/0NDQ/97e3tTs7Oxs7+/vBezs7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO3u - /wD///8DvLzWmI2Lsv/T0+r86+7u/Ovu5fzv7+T87+zm/e/p7P/u6O7/7Ovq/+nt5f/t7ej/7uzr/+7s - 6//u7Ov/7+3s//Du7f/w7u3/8O7t//Du7f/w7u3/8e/u//Hv7v/x7+7/8e/u//Hv7v/y8O//8/Hw//Lx - 8P/x8vD/8fLw//Hy8P/y8/H/8/Ty//P08v/z9PL/8/Ty//X08//29PP/9vTz//b08//29PP/9vTz//b0 - 8//29PP/9vX0//b39f/29/X/9vf1//b39f/3+Pb/9/j2//f49v/3+Pb/9/j2//f49v/3+Pb/9/j2//j5 - 9//5+vj/+fr4//n6+P/5+vj/+fr4//n6+P/5+vj/+fr4//n6+P/5+vj/+fr4//n6+P/5+vj/9/j2//f4 - 9v/3+Pb/9/j2//f49v/3+Pb/9vf1//X29P/29fT/9vTz//b08//29PP/9vTz//b08//29PP/9vTz//b0 - 8//09fP/9PXz//T18//09fP/8/Ty//Lz8f/z9PL/8/Ty//Pz8f/z8fD/8/Hw//Px8P/z8fD/8e/u//Hv - 7v/x7+7/8e/u//Hv7v/x7+7/8e/u//Hv7v/x7+7/8O7t//Du7f/v7ez/7+3s/+7s6//u7Ov/7uzr/+7s - 6//t6+r/7evq/+3r6v/t6+r/7Orq/+zq6v/s6ur/7Orq/+zq6v/r6en/6+np/+vp6f/r6en/6ujo/+nn - 5//p5+f/6efn/+nn5//p5+f/6efn/+jm5v/n5eX/5uTk/+bk5P/m5OT/5uTk/+bk5P/m5OT/5uTk/+bk - 5P/l4+L/5OLh/+Ti4f/k4uH/5OLh/+Ph4P/j4eD/4+Hg/+Ph4P/h4eD/4ODg/+Dg4P/f39//39/f/9/f - 3//f39//39/f/9/f3//d3d3/3d3d/93d3f/d3d3/3Nzc/9zc3P/c3Nz/3Nzc/9vb2//a2tr/29vb/9vb - 2//b29v/29vb/9vb2//b29v/2tra/9ra2v/a2tr/2tra/9ra2v/a2tr/2dnZ/9nZ2f/Y2Nj/19fX/9bW - 1v/W1tb/1tbW/9bW1v/V1dX/1dXV/9XV1f/V1dX/1dXV/9XV1f/V1dX/1dXV/9XV1f/V1dX/1dXV/9XV - 1f/V1dX/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT0//T09P/09PT/9PT - 0//T09P/09PT/9PT0//U1NT+0tLS+9LS0v/b29uK39/fAOzs7ADs7OwAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADs7f8A29vrANPT4i/b3O556ur8Qevs60Ls7OdC7uvmQe7o6lHv6e+x7urtu+zt6NPr8OX/7e7o0O3r - 6rrt6+q87evqvO3r6rzt6+q87evqvO3r6rzt6+q87evqvO3r6rzt6+q87evqvO7s67zu7Ou87uzrvO7s - 67zu7ey87e7svO3u7Lzt7uy87e7svO3u7Lzt7uy87e7svO3u7Lzv7uy87+3svO/t7Lzv7ey87+3svO/t - 7Lzv7ey87+3svO/u7bzv8O687/DuvO/w7rzv8O687/DuvO/w7rzv8O687/DuvO/w7rzv8O687/DuvO/w - 7rzv8O687u/tvO7v7bzu7+287u/tvO7v7bzu7+287u/tvO7v7bzu7+287u/tvO7v7bzu7+287/DuvO/w - 7rzv8O687/DuvO/w7rzv8O687/DuvO/w7rzv8O687+/tvO/t7Lzv7ey87+3svO/t7Lzv7ey87+3svO/t - 7Lzv7uy87u7svO3u7Lzt7uy87e7svO3u7Lzt7uy87e7svO3u7Lzu7uy87uzrvO7s67zu7Ou87uzrvO7s - 67zt6+q87evqvO3r6rzt6+q87evqvO3r6rzt6+q87evqvO7s67zu7Ou87uzrvO7s67zt6+q87evqvO3r - 6rzt6+q87evqvO3r6rzt6+q87evqvO3r67zt6+u87evrvO3r67zt6+u87OrqvOzq6rzs6uq87OrqvOzq - 6rzs6uq87OrqvOzq6rzs6uq87OrqvOzq6rzs6uq87OrqvOvp6bzr6em86+npvOvp6bzr6em86+npvOvp - 6bzr6em86ujnvOnn5bzp5+a86efmvOnn5rzp5+a86efmvOnn5rzp5+a85+fnvOfn57zn5+e85+fnvOfn - 57zo6Oi86OjovOjo6Lzo6Oi85+fnvOfn57zn5+e85+fnvObm5rzm5ua85ubmvObm5rzm5ua85ubmvObm - 5rzm5ua85ubmvObm5rzm5ua85ubmvObm5rzm5ua85ubmvObm5rzm5ua85ubmvOXl5bzl5eW85eXlvOXl - 5bzj4+O84+PjvOPj47zj4+O84+PjvOPj47zj4+O84+PjvOPj47zj4+O84+PjvOPj47zj4+O84+PjvOPj - 47zj4+O84+PjvOPj47zj4+O84+PjvOPj47zj4+O84+PjvOPj47zj4+O84+PjvOPj47zj4+O84+PjvOPj - 47zk5OS85OTkvOTk5Lzk5OS84ODgatTU1D/X19dD4ODgJN7e3gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAK6sxwC9vNAAm5TTAOfn+gDr7OsA7O3nAO3r5gDt6OcA8e32Au/s9wHv8uke7/PoUu/y - 6Rvz7PQB8e/uA/Hv7gPt6+oD5uTjA+bk4wPm5OMD5uTjA+bk4wPm5OMD5uTjA+bk4wPn5eQD5+XkA+fl - 5APn5eQD5ubkA+bn5QPm5+UD5uflA+Xm5APg4d8D4OHfA+Dh3wPg4d8D4uDfA+Lg3wPi4N8D4uDfA+Lg - 3wPi4N8D4uDfA+Lg3wPi4eAD5OXjA+Tl4wPk5eMD5OXjA+Lj4QPi4+ED4uPhA+Lj4QPi4+ED4uPhA+Lj - 4QPi4+ED4eLgA9zd2wPc3dsD3N3bA9zd2wPc3dsD3N3bA9zd2wPc3dsD3N3bA9zd2wPc3dsD29zaA93e - 3APi4+ED4uPhA+Lj4QPi4+ED4+TiA+Tl4wPk5eMD5OXjA+Pi4QPi4N8D4uDfA+Lg3wPi4N8D4uDfA+Lg - 3wPi4N8D4uDfA+Dh3wPg4d8D4OHfA+Dh3wPk5eMD5uflA+bn5QPm5+UD5ubkA+fl5APn5eQD5+XkA+fl - 5APm5OMD5uTjA+bk4wPm5OMD5uTjA+bk4wPm5OMD5uTjA+fl5APq6OcD6ujnA+ro5wPr6egD8O7tA/Hv - 7gPx7+4D8e/uA/Hv7gPx7+4D8e/uA/Hv7gPx7+4D8e/vA/Hv7wPx7+8D8e/vA/Du7gPw7u4D8O7uA/Du - 7gPx7+8D8vDwA/Lw8APy8PAD8vDwA/Lw8APy8PAD8vDwA/Px8QP39fUD+Pb2A/j29gP49vYD+Pb2A/j2 - 9gP49vYD+Pb2A/f19AP29PMD9vTzA/b08wP29PMD9vTzA/b08wP29PMD9vTzA/f39wP4+PgD+Pj4A/j4 - +AP7+/sD////A////wP///8D/v7+A/7+/gP+/v4D/v7+A/7+/gP///8D////A////wP///8D////A/// - /wP///8D////A////wP///8D////A////wP///8D////A////wP///8D////A////wP///8D////A/// - /wP///8D////A////wP///8D////A////wP///8D////A////wP///8D////A////wP///8D////A/// - /wP///8D////A////wP///8D////A////wP///8D////A////wP///8D////A////wP///8D////A/// - /wP///8D////A////wP///8D////A8PDwwDV1dUA19fXAODg4ADd3d0AAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADv8ukA7/LpAO/y - 6QDv8ukA7/LpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAD///////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////gB/AD/////////////+A - D8AAB//4Af///////////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///+AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/+AAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4A - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAA///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//+AAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAP//4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///AAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAD//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//wAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAD///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//8AAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////8 - H/////////////////////////////////////////////////////////////////////////////// - //8= - - - \ No newline at end of file diff --git a/FlashPatcher/SilicaAndPina.pfx b/FlashPatcher/SilicaAndPina.pfx deleted file mode 100644 index 2ddd31f..0000000 Binary files a/FlashPatcher/SilicaAndPina.pfx and /dev/null differ diff --git a/FlashPatcher/TaskService/Action.cs b/FlashPatcher/TaskService/Action.cs new file mode 100644 index 0000000..194cd31 --- /dev/null +++ b/FlashPatcher/TaskService/Action.cs @@ -0,0 +1,1017 @@ +using JetBrains.Annotations; +using Microsoft.Win32.TaskScheduler.V2Interop; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Xml.Serialization; + +namespace Microsoft.Win32.TaskScheduler +{ + /// Defines the type of actions a task can perform. + /// The action type is defined when the action is created and cannot be changed later. See . + public enum TaskActionType + { + /// + /// This action performs a command-line operation. For example, the action can run a script, launch an executable, or, if the name + /// of a document is provided, find its associated application and launch the application with the document. + /// + Execute = 0, + + /// This action fires a handler. + ComHandler = 5, + + /// This action sends and e-mail. + SendEmail = 6, + + /// This action shows a message box. + ShowMessage = 7 + } + + /// An interface that exposes the ability to convert an actions functionality to a PowerShell script. + internal interface IBindAsExecAction + { + } + + /// + /// Abstract base class that provides the common properties that are inherited by all action objects. An action object is created by the + /// method. + /// + [PublicAPI] + public abstract class Action : IDisposable, ICloneable, IEquatable, INotifyPropertyChanged, IComparable, IComparable + { + internal IAction iAction; + internal V1Interop.ITask v1Task; + + /// List of unbound values when working with Actions not associated with a registered task. + protected readonly Dictionary unboundValues = new Dictionary(); + + internal Action() + { + } + + internal Action([NotNull] IAction action) => iAction = action; + + internal Action([NotNull] V1Interop.ITask iTask) => v1Task = iTask; + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// Gets the type of the action. + /// The type of the action. + [XmlIgnore] + public TaskActionType ActionType => iAction?.Type ?? InternalActionType; + + /// Gets or sets the identifier of the action. + [DefaultValue(null)] + [XmlAttribute(AttributeName = "id")] + public virtual string Id + { + get => GetProperty(nameof(Id)); + set => SetProperty(nameof(Id), value); + } + + internal abstract TaskActionType InternalActionType { get; } + + /// Creates the specified action. + /// Type of the action to instantiate. + /// of specified type. + public static Action CreateAction(TaskActionType actionType) => Activator.CreateInstance(GetObjectType(actionType)) as Action; + + /// Creates a new object that is a copy of the current instance. + /// A new object that is a copy of this instance. + public object Clone() + { + var ret = CreateAction(ActionType); + ret.CopyProperties(this); + return ret; + } + + /// + /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current + /// instance precedes, follows, or occurs in the same position in the sort order as the other object. + /// + /// An object to compare with this instance. + /// A value that indicates the relative order of the objects being compared. + public int CompareTo(Action obj) => string.Compare(Id, obj?.Id, StringComparison.InvariantCulture); + + /// Releases all resources used by this class. + public virtual void Dispose() + { + if (iAction != null) + Marshal.ReleaseComObject(iAction); + } + + /// Determines whether the specified , is equal to this instance. + /// The to compare with this instance. + /// true if the specified is equal to this instance; otherwise, false. + public override bool Equals([CanBeNull] object obj) + { + if (obj is Action) + return Equals((Action)obj); + return base.Equals(obj); + } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public virtual bool Equals([NotNull] Action other) => ActionType == other.ActionType && Id == other.Id; + + /// Returns a hash code for this instance. + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + public override int GetHashCode() => new { A = ActionType, B = Id }.GetHashCode(); + + /// Returns the action Id. + /// String representation of action. + public override string ToString() => Id; + + /// Returns a that represents this action. + /// The culture. + /// String representation of action. + public virtual string ToString([NotNull] System.Globalization.CultureInfo culture) + { + using (new CultureSwitcher(culture)) + return ToString(); + } + + int IComparable.CompareTo(object obj) => CompareTo(obj as Action); + + internal static Action ActionFromScript(string actionType, string script) + { + var tat = TryParse(actionType, TaskActionType.Execute); + var t = GetObjectType(tat); + return (Action)t.InvokeMember("FromPowerShellCommand", BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { script }); + } + + internal static Action ConvertFromPowerShellAction(ExecAction execAction) + { + var psi = execAction.ParsePowerShellItems(); + if (psi != null && psi.Length == 2) + { + var a = ActionFromScript(psi[0], psi[1]); + if (a != null) + { + a.v1Task = execAction.v1Task; + a.iAction = execAction.iAction; + return a; + } + } + return null; + } + + /// Creates a specialized class from a defined interface. + /// Version 1.0 interface. + /// Specialized action class + internal static Action CreateAction(V1Interop.ITask iTask) + { + var tempAction = new ExecAction(iTask); + return ConvertFromPowerShellAction(tempAction) ?? tempAction; + } + + /// Creates a specialized class from a defined interface. + /// Version 2.0 Action interface. + /// Specialized action class + internal static Action CreateAction(IAction iAction) + { + var t = GetObjectType(iAction.Type); + return Activator.CreateInstance(t, BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { iAction }, null) as Action; + } + + internal static T TryParse(string val, T defaultVal) + { + var ret = defaultVal; + if (val != null) + try { ret = (T)Enum.Parse(typeof(T), val); } catch { } + return ret; + } + + internal virtual void Bind(V1Interop.ITask iTask) + { + if (Id != null) + iTask.SetDataItem("ActionId", Id); + var bindable = this as IBindAsExecAction; + if (bindable != null) + iTask.SetDataItem("ActionType", InternalActionType.ToString()); + unboundValues.TryGetValue("Path", out var o); + iTask.SetApplicationName(bindable != null ? ExecAction.PowerShellPath : o?.ToString() ?? string.Empty); + unboundValues.TryGetValue("Arguments", out o); + iTask.SetParameters(bindable != null ? ExecAction.BuildPowerShellCmd(ActionType.ToString(), GetPowerShellCommand()) : o?.ToString() ?? string.Empty); + unboundValues.TryGetValue("WorkingDirectory", out o); + iTask.SetWorkingDirectory(o?.ToString() ?? string.Empty); + } + + internal virtual void Bind(ITaskDefinition iTaskDef) + { + var iActions = iTaskDef.Actions; + if (iActions.Count >= ActionCollection.MaxActions) + throw new ArgumentOutOfRangeException(nameof(iTaskDef), @"A maximum of 32 actions is allowed within a single task."); + CreateV2Action(iActions); + Marshal.ReleaseComObject(iActions); + foreach (var key in unboundValues.Keys) + { + try { ReflectionHelper.SetProperty(iAction, key, unboundValues[key]); } + catch (TargetInvocationException tie) { throw tie.InnerException; } + catch { } + } + unboundValues.Clear(); + } + + /// Copies the properties from another the current instance. + /// The source . + internal virtual void CopyProperties([NotNull] Action sourceAction) => Id = sourceAction.Id; + + internal abstract void CreateV2Action(IActionCollection iActions); + + internal abstract string GetPowerShellCommand(); + + internal T GetProperty(string propName, T defaultValue = default) + { + if (iAction == null) + return unboundValues.TryGetValue(propName, out var value) ? (T)value : defaultValue; + return ReflectionHelper.GetProperty((TB)iAction, propName, defaultValue); + } + + internal void OnPropertyChanged(string propName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); + + internal void SetProperty(string propName, T value) + { + if (iAction == null) + { + if (Equals(value, default(T))) + unboundValues.Remove(propName); + else + unboundValues[propName] = value; + } + else + ReflectionHelper.SetProperty((TB)iAction, propName, value); + OnPropertyChanged(propName); + } + + [NotNull] + private static Type GetObjectType(TaskActionType actionType) => actionType switch + { + TaskActionType.ComHandler => typeof(ComHandlerAction), + TaskActionType.SendEmail => typeof(EmailAction), + TaskActionType.ShowMessage => typeof(ShowMessageAction), + _ => typeof(ExecAction), + }; + } + + /// + /// Represents an action that fires a handler. Only available on Task Scheduler 2.0. Only available for Task Scheduler 2.0 on + /// Windows Vista or Windows Server 2003 and later. + /// + /// + /// This action is the most complex. It allows the task to execute and In-Proc COM server object that implements the ITaskHandler + /// interface. There is a sample project that shows how to do this in the Downloads section. + /// + /// + /// + /// + /// + /// + [XmlType(IncludeInSchema = true)] + [XmlRoot("ComHandler", Namespace = TaskDefinition.tns, IsNullable = false)] + public class ComHandlerAction : Action, IBindAsExecAction + { + /// Creates an unbound instance of . + public ComHandlerAction() { } + + /// Creates an unbound instance of . + /// Identifier of the handler class. + /// Addition data associated with the handler. + public ComHandlerAction(Guid classId, [CanBeNull] string data) + { + ClassId = classId; + Data = data; + } + + internal ComHandlerAction([NotNull] V1Interop.ITask task) : base(task) + { + } + + internal ComHandlerAction([NotNull] IAction action) : base(action) + { + } + + /// Gets or sets the identifier of the handler class. + public Guid ClassId + { + get => new Guid(GetProperty(nameof(ClassId), Guid.Empty.ToString())); + set => SetProperty(nameof(ClassId), value.ToString()); + } + + /// Gets the name of the object referred to by . + public string ClassName => GetNameForCLSID(ClassId); + + /// Gets or sets additional data that is associated with the handler. + [DefaultValue(null)] + [CanBeNull] + public string Data + { + get => GetProperty(nameof(Data)); + set => SetProperty(nameof(Data), value); + } + + internal override TaskActionType InternalActionType => TaskActionType.ComHandler; + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Action other) => base.Equals(other) && ClassId == ((ComHandlerAction)other).ClassId && Data == ((ComHandlerAction)other).Data; + + /// Gets a string representation of the . + /// String representation of this action. + public override string ToString() => string.Format(Properties.Resources.ComHandlerAction, ClassId, Data, Id, ClassName); + + internal static Action FromPowerShellCommand(string p) + { + var match = System.Text.RegularExpressions.Regex.Match(p, @"^\[Reflection.Assembly\]::LoadFile\('(?:[^']*)'\); \[Microsoft.Win32.TaskScheduler.TaskService\]::RunComHandlerAction\(\[GUID\]\('(?[^']*)'\), '(?[^']*)'\);?\s*$"); + return match.Success ? new ComHandlerAction(new Guid(match.Groups["g"].Value), match.Groups["d"].Value.Replace("''", "'")) : null; + } + + /// Copies the properties from another the current instance. + /// The source . + internal override void CopyProperties(Action sourceAction) + { + if (sourceAction.GetType() == GetType()) + { + base.CopyProperties(sourceAction); + ClassId = ((ComHandlerAction)sourceAction).ClassId; + Data = ((ComHandlerAction)sourceAction).Data; + } + } + + internal override void CreateV2Action([NotNull] IActionCollection iActions) => iAction = iActions.Create(TaskActionType.ComHandler); + + internal override string GetPowerShellCommand() + { + var sb = new System.Text.StringBuilder(); + sb.Append($"[Reflection.Assembly]::LoadFile('{Assembly.GetExecutingAssembly().Location}'); "); + sb.Append($"[Microsoft.Win32.TaskScheduler.TaskService]::RunComHandlerAction([GUID]('{ClassId:D}'), '{Data?.Replace("'", "''") ?? string.Empty}'); "); + return sb.ToString(); + } + + /// Gets the name for CLSID. + /// The unique identifier. + /// + [CanBeNull] + private static string GetNameForCLSID(Guid guid) + { + using (var k = Registry.ClassesRoot.OpenSubKey("CLSID", false)) + { + if (k != null) + { + using var k2 = k.OpenSubKey(guid.ToString("B"), false); + return k2?.GetValue(null) as string; + } + } + return null; + } + } + + /// + /// Represents an action that sends an e-mail. Only available for Task Scheduler 2.0 on Windows Vista or Windows Server 2003 and + /// later.This action has been deprecated in Windows 8 and later. However, this library is able to mimic its + /// functionality using PowerShell if the property is set to . To disable this conversion, set the value to . + /// + /// The EmailAction allows for an email to be sent when the task is triggered. + /// + /// + /// + /// + /// + [XmlType(IncludeInSchema = true)] + [XmlRoot("SendEmail", Namespace = TaskDefinition.tns, IsNullable = false)] + public sealed class EmailAction : Action, IBindAsExecAction + { + private const string ImportanceHeader = "Importance"; + + private NamedValueCollection nvc; + private bool validateAttachments = true; + + /// Creates an unbound instance of . + public EmailAction() { } + + /// Creates an unbound instance of . + /// Subject of the e-mail. + /// E-mail address that you want to send the e-mail from. + /// E-mail address or addresses that you want to send the e-mail to. + /// Body of the e-mail that contains the e-mail message. + /// Name of the server that you use to send e-mail from. + public EmailAction([CanBeNull] string subject, [NotNull] string from, [NotNull] string to, [CanBeNull] string body, [NotNull] string mailServer) + { + Subject = subject; + From = from; + To = to; + Body = body; + Server = mailServer; + } + + internal EmailAction([NotNull] V1Interop.ITask task) : base(task) + { + } + + internal EmailAction([NotNull] IAction action) : base(action) + { + } + + /// + /// Gets or sets an array of file paths to be sent as attachments with the e-mail. Each item must be a value + /// containing a path to file. + /// + [XmlArray("Attachments", IsNullable = true)] + [XmlArrayItem("File", typeof(string))] + [DefaultValue(null)] + public object[] Attachments + { + get => GetProperty(nameof(Attachments)); + set + { + if (value != null) + { + if (value.Length > 8) + throw new ArgumentOutOfRangeException(nameof(Attachments), @"Attachments array cannot contain more than 8 items."); + if (validateAttachments) + { + foreach (var o in value) + if (!(o is string) || !System.IO.File.Exists((string)o)) + throw new ArgumentException(@"Each value of the array must contain a valid file reference.", nameof(Attachments)); + } + } + if (iAction == null && (value == null || value.Length == 0)) + { + unboundValues.Remove(nameof(Attachments)); + OnPropertyChanged(nameof(Attachments)); + } + else + SetProperty(nameof(Attachments), value); + } + } + + /// Gets or sets the e-mail address or addresses that you want to Bcc in the e-mail. + [DefaultValue(null)] + public string Bcc + { + get => GetProperty(nameof(Bcc)); + set => SetProperty(nameof(Bcc), value); + } + + /// Gets or sets the body of the e-mail that contains the e-mail message. + [DefaultValue(null)] + public string Body + { + get => GetProperty(nameof(Body)); + set => SetProperty(nameof(Body), value); + } + + /// Gets or sets the e-mail address or addresses that you want to Cc in the e-mail. + [DefaultValue(null)] + public string Cc + { + get => GetProperty(nameof(Cc)); + set => SetProperty(nameof(Cc), value); + } + + /// Gets or sets the e-mail address that you want to send the e-mail from. + [DefaultValue(null)] + public string From + { + get => GetProperty(nameof(From)); + set => SetProperty(nameof(From), value); + } + + /// Gets or sets the header information in the e-mail message to send. + [XmlArray] + [XmlArrayItem("HeaderField", typeof(NameValuePair))] + [NotNull] + public NamedValueCollection HeaderFields + { + get + { + if (nvc == null) + { + nvc = iAction == null ? new NamedValueCollection() : new NamedValueCollection(((IEmailAction)iAction).HeaderFields); + nvc.AttributedXmlFormat = false; + nvc.CollectionChanged += (o, e) => OnPropertyChanged(nameof(HeaderFields)); + } + return nvc; + } + } + + /// Gets or sets the priority of the e-mail message. + /// A that contains the priority of this message. + [XmlIgnore] + [DefaultValue(typeof(System.Net.Mail.MailPriority), "Normal")] + public System.Net.Mail.MailPriority Priority + { + get + { + if (nvc != null && HeaderFields.TryGetValue(ImportanceHeader, out var s)) + return TryParse(s, System.Net.Mail.MailPriority.Normal); + return System.Net.Mail.MailPriority.Normal; + } + set => HeaderFields[ImportanceHeader] = value.ToString(); + } + + /// Gets or sets the e-mail address that you want to reply to. + [DefaultValue(null)] + public string ReplyTo + { + get => GetProperty(nameof(ReplyTo)); + set => SetProperty(nameof(ReplyTo), value); + } + + /// Gets or sets the name of the server that you use to send e-mail from. + [DefaultValue(null)] + public string Server + { + get => GetProperty(nameof(Server)); + set => SetProperty(nameof(Server), value); + } + + /// Gets or sets the subject of the e-mail. + [DefaultValue(null)] + public string Subject + { + get => GetProperty(nameof(Subject)); + set => SetProperty(nameof(Subject), value); + } + + /// Gets or sets the e-mail address or addresses that you want to send the e-mail to. + [DefaultValue(null)] + public string To + { + get => GetProperty(nameof(To)); + set => SetProperty(nameof(To), value); + } + + internal override TaskActionType InternalActionType => TaskActionType.SendEmail; + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Action other) => base.Equals(other) && GetPowerShellCommand() == other.GetPowerShellCommand(); + + /// Gets a string representation of the . + /// String representation of this action. + public override string ToString() => string.Format(Properties.Resources.EmailAction, Subject, To, Cc, Bcc, From, ReplyTo, Body, Server, Id); + + internal static Action FromPowerShellCommand(string p) + { + var match = System.Text.RegularExpressions.Regex.Match(p, @"^Send-MailMessage -From '(?(?:[^']|'')*)' -Subject '(?(?:[^']|'')*)' -SmtpServer '(?(?:[^']|'')*)'(?: -Encoding UTF8)?(?: -To (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?: -Cc (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?: -Bcc (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?:(?: -BodyAsHtml)? -Body '(?(?:[^']|'')*)')?(?: -Attachments (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?: -Priority (?High|Normal|Low))?;?\s*$"); + if (match.Success) + { + var action = new EmailAction(UnPrep(FromUTF8(match.Groups["subject"].Value)), UnPrep(match.Groups["from"].Value), FromPS(match.Groups["to"]), UnPrep(FromUTF8(match.Groups["body"].Value)), UnPrep(match.Groups["server"].Value)) + { Cc = FromPS(match.Groups["cc"]), Bcc = FromPS(match.Groups["bcc"]) }; + action.validateAttachments = false; + if (match.Groups["att"].Success) + action.Attachments = Array.ConvertAll(FromPS(match.Groups["att"].Value), s => s); + action.validateAttachments = true; + if (match.Groups["imp"].Success) + action.HeaderFields[ImportanceHeader] = match.Groups["imp"].Value; + return action; + } + return null; + } + + internal override void Bind(ITaskDefinition iTaskDef) + { + base.Bind(iTaskDef); + nvc?.Bind(((IEmailAction)iAction).HeaderFields); + } + + /// Copies the properties from another the current instance. + /// The source . + internal override void CopyProperties(Action sourceAction) + { + if (sourceAction.GetType() == GetType()) + { + base.CopyProperties(sourceAction); + if (((EmailAction)sourceAction).Attachments != null) + Attachments = (object[])((EmailAction)sourceAction).Attachments.Clone(); + Bcc = ((EmailAction)sourceAction).Bcc; + Body = ((EmailAction)sourceAction).Body; + Cc = ((EmailAction)sourceAction).Cc; + From = ((EmailAction)sourceAction).From; + if (((EmailAction)sourceAction).nvc != null) + ((EmailAction)sourceAction).HeaderFields.CopyTo(HeaderFields); + ReplyTo = ((EmailAction)sourceAction).ReplyTo; + Server = ((EmailAction)sourceAction).Server; + Subject = ((EmailAction)sourceAction).Subject; + To = ((EmailAction)sourceAction).To; + } + } + + internal override void CreateV2Action(IActionCollection iActions) => iAction = iActions.Create(TaskActionType.SendEmail); + + internal override string GetPowerShellCommand() + { + // Send-MailMessage [-To] [-Subject] [[-Body] ] [[-SmtpServer] ] -From + // [-Attachments ] [-Bcc ] [-BodyAsHtml] [-Cc ] [-Credential ] + // [-DeliveryNotificationOption ] [-Encoding ] [-Port ] [-Priority + // ] [-UseSsl] [ ] + var bodyIsHtml = Body != null && Body.Trim().StartsWith("<") && Body.Trim().EndsWith(">"); + var sb = new System.Text.StringBuilder(); + sb.AppendFormat("Send-MailMessage -From '{0}' -Subject '{1}' -SmtpServer '{2}' -Encoding UTF8", Prep(From), ToUTF8(Prep(Subject)), Prep(Server)); + if (!string.IsNullOrEmpty(To)) + sb.AppendFormat(" -To {0}", ToPS(To)); + if (!string.IsNullOrEmpty(Cc)) + sb.AppendFormat(" -Cc {0}", ToPS(Cc)); + if (!string.IsNullOrEmpty(Bcc)) + sb.AppendFormat(" -Bcc {0}", ToPS(Bcc)); + if (bodyIsHtml) + sb.Append(" -BodyAsHtml"); + if (!string.IsNullOrEmpty(Body)) + sb.AppendFormat(" -Body '{0}'", ToUTF8(Prep(Body))); + if (Attachments != null && Attachments.Length > 0) + sb.AppendFormat(" -Attachments {0}", ToPS(Array.ConvertAll(Attachments, o => Prep(o.ToString())))); + var hdr = new List(HeaderFields.Names); + if (hdr.Contains(ImportanceHeader)) + { + var p = Priority; + if (p != System.Net.Mail.MailPriority.Normal) + sb.Append($" -Priority {p}"); + hdr.Remove(ImportanceHeader); + } + if (hdr.Count > 0) + throw new InvalidOperationException("Under Windows 8 and later, EmailAction objects are converted to PowerShell. This action contains headers that are not supported."); + sb.Append("; "); + return sb.ToString(); + + /*var msg = new System.Net.Mail.MailMessage(this.From, this.To, this.Subject, this.Body); + if (!string.IsNullOrEmpty(this.Bcc)) + msg.Bcc.Add(this.Bcc); + if (!string.IsNullOrEmpty(this.Cc)) + msg.CC.Add(this.Cc); + if (!string.IsNullOrEmpty(this.ReplyTo)) + msg.ReplyTo = new System.Net.Mail.MailAddress(this.ReplyTo); + if (this.Attachments != null && this.Attachments.Length > 0) + foreach (string s in this.Attachments) + msg.Attachments.Add(new System.Net.Mail.Attachment(s)); + if (this.nvc != null) + foreach (var ha in this.HeaderFields) + msg.Headers.Add(ha.Name, ha.Value); + var client = new System.Net.Mail.SmtpClient(this.Server); + client.Send(msg);*/ + } + + private static string[] FromPS(string p) + { + var list = p.Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries); + return Array.ConvertAll(list, i => UnPrep(i).Trim('\'')); + } + + private static string FromPS(System.Text.RegularExpressions.Group g, string delimeter = ";") => g.Success ? string.Join(delimeter, FromPS(g.Value)) : null; + + private static string FromUTF8(string s) + { + var bytes = System.Text.Encoding.UTF8.GetBytes(s); + return System.Text.Encoding.Default.GetString(bytes); + } + + private static string Prep(string s) => s?.Replace("'", "''"); + + private static string ToPS(string input, char[] delimeters = null) + { + if (delimeters == null) + delimeters = new[] { ';', ',' }; + return ToPS(Array.ConvertAll(input.Split(delimeters), i => Prep(i.Trim()))); + } + + private static string ToPS(string[] input) => string.Join(", ", Array.ConvertAll(input, i => string.Concat("'", i.Trim(), "'"))); + + private static string ToUTF8(string s) + { + if (s == null) return null; + var bytes = System.Text.Encoding.Default.GetBytes(s); + return System.Text.Encoding.UTF8.GetString(bytes); + } + + private static string UnPrep(string s) => s?.Replace("''", "'"); + } + + /// Represents an action that executes a command-line operation. + /// + /// All versions of the base library support the ExecAction. It only has three properties that allow it to run an executable with parameters. + /// + /// + /// + /// + /// + /// + [XmlRoot("Exec", Namespace = TaskDefinition.tns, IsNullable = false)] + public class ExecAction : Action + { +#if DEBUG + internal const string PowerShellArgFormat = "-NoExit -Command \"& {{<# {0}:{1} #> {2}}}\""; +#else + internal const string PowerShellArgFormat = "-NoLogo -NonInteractive -WindowStyle Hidden -Command \"& {{<# {0}:{1} #> {2}}}\""; +#endif + internal const string PowerShellPath = "powershell"; + internal const string ScriptIdentifer = "TSML_20140424"; + + /// Creates a new instance of an that can be added to . + public ExecAction() { } + + /// Creates a new instance of an that can be added to . + /// Path to an executable file. + /// Arguments associated with the command-line operation. This value can be null. + /// + /// Directory that contains either the executable file or the files that are used by the executable file. This value can be null. + /// + public ExecAction([NotNull] string path, string arguments = null, string workingDirectory = null) + { + Path = path; + Arguments = arguments; + WorkingDirectory = workingDirectory; + } + + internal ExecAction([NotNull] V1Interop.ITask task) : base(task) + { + } + + internal ExecAction([NotNull] IAction action) : base(action) + { + } + + /// Gets or sets the arguments associated with the command-line operation. + [DefaultValue("")] + public string Arguments + { + get + { + if (v1Task != null) + return v1Task.GetParameters(); + return GetProperty(nameof(Arguments), ""); + } + set + { + if (v1Task != null) + v1Task.SetParameters(value); + else + SetProperty(nameof(Arguments), value); + } + } + + /// Gets or sets the path to an executable file. + [XmlElement("Command")] + [DefaultValue("")] + public string Path + { + get + { + if (v1Task != null) + return v1Task.GetApplicationName(); + return GetProperty(nameof(Path), ""); + } + set + { + if (v1Task != null) + v1Task.SetApplicationName(value); + else + SetProperty(nameof(Path), value); + } + } + + /// + /// Gets or sets the directory that contains either the executable file or the files that are used by the executable file. + /// + [DefaultValue("")] + public string WorkingDirectory + { + get + { + if (v1Task != null) + return v1Task.GetWorkingDirectory(); + return GetProperty(nameof(WorkingDirectory), ""); + } + set + { + if (v1Task != null) + v1Task.SetWorkingDirectory(value); + else + SetProperty(nameof(WorkingDirectory), value); + } + } + + internal override TaskActionType InternalActionType => TaskActionType.Execute; + + /// Determines whether the specified path is a valid filename and, optionally, if it exists. + /// The path. + /// if set to true check if file exists. + /// if set to true throw exception on error. + /// true if the specified path is a valid filename; otherwise, false. + public static bool IsValidPath(string path, bool checkIfExists = true, bool throwOnException = false) + { + try + { + if (path == null) throw new ArgumentNullException(nameof(path)); + /*if (path.StartsWith("\"") && path.EndsWith("\"") && path.Length > 1) + path = path.Substring(1, path.Length - 2);*/ + var fn = System.IO.Path.GetFileName(path); + System.Diagnostics.Debug.WriteLine($"IsValidPath fn={fn}"); + if (fn == string.Empty) + return false; + var dn = System.IO.Path.GetDirectoryName(path); + System.Diagnostics.Debug.WriteLine($"IsValidPath dir={dn ?? "null"}"); + System.IO.Path.GetFullPath(path); + return true; + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"IsValidPath exc={ex}"); + if (throwOnException) throw; + } + return false; + } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Action other) => base.Equals(other) && Path == ((ExecAction)other).Path && Arguments == ((ExecAction)other).Arguments && WorkingDirectory == ((ExecAction)other).WorkingDirectory; + + /// + /// Validates the input as a valid filename and optionally checks for its existence. If valid, the property is + /// set to the validated absolute file path. + /// + /// The file path to validate. + /// if set to true check if the file exists. + public void SetValidatedPath([NotNull] string path, bool checkIfExists = true) + { + if (IsValidPath(path, checkIfExists, true)) + Path = path; + } + + /// Gets a string representation of the . + /// String representation of this action. + public override string ToString() => string.Format(Properties.Resources.ExecAction, Path, Arguments, WorkingDirectory, Id); + + internal static string BuildPowerShellCmd(string actionType, string cmd) => string.Format(PowerShellArgFormat, ScriptIdentifer, actionType, cmd); + + internal static ExecAction ConvertToPowerShellAction(Action action) => CreatePowerShellAction(action.ActionType.ToString(), action.GetPowerShellCommand()); + + internal static ExecAction CreatePowerShellAction(string actionType, string cmd) => new ExecAction(PowerShellPath, BuildPowerShellCmd(actionType, cmd)); + + internal static Action FromPowerShellCommand(string p) + { + var match = System.Text.RegularExpressions.Regex.Match(p, "^Start-Process -FilePath '(?

[^']*)'(?: -ArgumentList '(?[^']*)')?(?: -WorkingDirectory '(?[^']*)')?;?\\s*$"); + return match.Success ? new ExecAction(match.Groups["p"].Value, match.Groups["a"].Success ? match.Groups["a"].Value.Replace("''", "'") : null, match.Groups["d"].Success ? match.Groups["d"].Value : null) : null; + } + + ///

Copies the properties from another the current instance. + /// The source . + internal override void CopyProperties(Action sourceAction) + { + if (sourceAction.GetType() == GetType()) + { + base.CopyProperties(sourceAction); + Path = ((ExecAction)sourceAction).Path; + Arguments = ((ExecAction)sourceAction).Arguments; + WorkingDirectory = ((ExecAction)sourceAction).WorkingDirectory; + } + } + + internal override void CreateV2Action(IActionCollection iActions) => iAction = iActions.Create(TaskActionType.Execute); + + internal override string GetPowerShellCommand() + { + var sb = new System.Text.StringBuilder($"Start-Process -FilePath '{Path}'"); + if (!string.IsNullOrEmpty(Arguments)) + sb.Append($" -ArgumentList '{Arguments.Replace("'", "''")}'"); + if (!string.IsNullOrEmpty(WorkingDirectory)) + sb.Append($" -WorkingDirectory '{WorkingDirectory}'"); + return sb.Append("; ").ToString(); + } + + internal string[] ParsePowerShellItems() + { + if (((Path?.EndsWith(PowerShellPath, StringComparison.InvariantCultureIgnoreCase) ?? false) || + (Path?.EndsWith(PowerShellPath + ".exe", StringComparison.InvariantCultureIgnoreCase) ?? false)) && (Arguments?.Contains(ScriptIdentifer) ?? false)) + { + var match = System.Text.RegularExpressions.Regex.Match(Arguments, @"<# " + ScriptIdentifer + ":(?\\w+) #> (?.+)}\"$"); + if (match.Success) + return new[] { match.Groups["type"].Value, match.Groups["cmd"].Value }; + } + return null; + } + } + + /// + /// Represents an action that shows a message box when a task is activated. Only available for Task Scheduler 2.0 on Windows Vista + /// or Windows Server 2003 and later.This action has been deprecated in Windows 8 and later. However, this + /// library is able to mimic its functionality using PowerShell if the property is + /// set to . To disable this conversion, set the value to . + /// + /// Display a message when the trigger fires using the ShowMessageAction. + /// + /// + /// + /// + /// + [XmlType(IncludeInSchema = true)] + [XmlRoot("ShowMessage", Namespace = TaskDefinition.tns, IsNullable = false)] + public sealed class ShowMessageAction : Action, IBindAsExecAction + { + /// Creates a new unbound instance of . + public ShowMessageAction() { } + + /// Creates a new unbound instance of . + /// Message text that is displayed in the body of the message box. + /// Title of the message box. + public ShowMessageAction([CanBeNull] string messageBody, [CanBeNull] string title) + { + MessageBody = messageBody; + Title = title; + } + + internal ShowMessageAction([NotNull] V1Interop.ITask task) : base(task) + { + } + + internal ShowMessageAction([NotNull] IAction action) : base(action) + { + } + + /// Gets or sets the message text that is displayed in the body of the message box. + [XmlElement("Body")] + [DefaultValue(null)] + public string MessageBody + { + get => GetProperty(nameof(MessageBody)); + set => SetProperty(nameof(MessageBody), value); + } + + /// Gets or sets the title of the message box. + [DefaultValue(null)] + public string Title + { + get => GetProperty(nameof(Title)); + set => SetProperty(nameof(Title), value); + } + + internal override TaskActionType InternalActionType => TaskActionType.ShowMessage; + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Action other) => base.Equals(other) && string.Equals(Title, (other as ShowMessageAction)?.Title) && string.Equals(MessageBody, (other as ShowMessageAction)?.MessageBody); + + /// Gets a string representation of the . + /// String representation of this action. + public override string ToString() => string.Format(Properties.Resources.ShowMessageAction, Title, MessageBody, Id); + + internal static Action FromPowerShellCommand(string p) + { + var match = System.Text.RegularExpressions.Regex.Match(p, @"^\[System.Reflection.Assembly\]::LoadWithPartialName\('System.Windows.Forms'\); \[System.Windows.Forms.MessageBox\]::Show\('(?(?:[^']|'')*)'(?:,'(?(?:[^']|'')*)')?\);?\s*$"); + return match.Success ? new ShowMessageAction(match.Groups["msg"].Value.Replace("''", "'"), match.Groups["t"].Success ? match.Groups["t"].Value.Replace("''", "'") : null) : null; + } + + /// Copies the properties from another the current instance. + /// The source . + internal override void CopyProperties(Action sourceAction) + { + if (sourceAction.GetType() == GetType()) + { + base.CopyProperties(sourceAction); + Title = ((ShowMessageAction)sourceAction).Title; + MessageBody = ((ShowMessageAction)sourceAction).MessageBody; + } + } + + internal override void CreateV2Action(IActionCollection iActions) => iAction = iActions.Create(TaskActionType.ShowMessage); + + internal override string GetPowerShellCommand() + { + // [System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Your_Desired_Message','Your_Desired_Title'); + var sb = new System.Text.StringBuilder("[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('"); + sb.Append(MessageBody.Replace("'", "''")); + if (Title != null) + { + sb.Append("','"); + sb.Append(Title.Replace("'", "''")); + } + sb.Append("'); "); + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/ActionCollection.cs b/FlashPatcher/TaskService/ActionCollection.cs new file mode 100644 index 0000000..7546db0 --- /dev/null +++ b/FlashPatcher/TaskService/ActionCollection.cs @@ -0,0 +1,771 @@ +using JetBrains.Annotations; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Xml.Serialization; + +namespace Microsoft.Win32.TaskScheduler +{ + /// Options for when to convert actions to PowerShell equivalents. + [Flags] + public enum PowerShellActionPlatformOption + { + /// + /// Never convert any actions to PowerShell. This will force exceptions to be thrown when unsupported actions our action quantities + /// are found. + /// + Never = 0, + + /// + /// Convert actions under Version 1 of the library (Windows XP or Windows Server 2003 and earlier). This option supports multiple + /// actions of all types. If not specified, only a single is supported. Developer must ensure that + /// PowerShell v2 or higher is installed on the target computer. + /// + Version1 = 1, + + /// + /// Convert all and references to their PowerShell equivalents on systems + /// on or after Windows 8 / Server 2012. + /// + Version2 = 2, + + /// Convert all actions regardless of version or operating system. + All = 3 + } + + /// Collection that contains the actions that are performed by the task. + [XmlRoot("Actions", Namespace = TaskDefinition.tns, IsNullable = false)] + [PublicAPI] + public sealed class ActionCollection : IList, IDisposable, IXmlSerializable, IList, INotifyCollectionChanged, INotifyPropertyChanged + { + internal const int MaxActions = 32; + private const string IndexerName = "Item[]"; + private static readonly string psV2IdRegex = $"(?:; )?{nameof(PowerShellConversion)}=(?0|1)"; + private bool inV2set; + private PowerShellActionPlatformOption psConvert = PowerShellActionPlatformOption.Version2; + private readonly List v1Actions; + private V1Interop.ITask v1Task; + private readonly V2Interop.IActionCollection v2Coll; + private V2Interop.ITaskDefinition v2Def; + + internal ActionCollection([NotNull] V1Interop.ITask task) + { + v1Task = task; + v1Actions = GetV1Actions(); + PowerShellConversion = Action.TryParse(v1Task.GetDataItem(nameof(PowerShellConversion)), psConvert | PowerShellActionPlatformOption.Version2); + } + + internal ActionCollection([NotNull] V2Interop.ITaskDefinition iTaskDef) + { + v2Def = iTaskDef; + v2Coll = iTaskDef.Actions; + System.Text.RegularExpressions.Match match; + if (iTaskDef.Data != null && (match = System.Text.RegularExpressions.Regex.Match(iTaskDef.Data, psV2IdRegex)).Success) + { + var on = false; + try { on = bool.Parse(match.Groups["v"].Value); } catch { try { on = int.Parse(match.Groups["v"].Value) == 1; } catch { } } + if (on) + psConvert |= PowerShellActionPlatformOption.Version2; + else + psConvert &= ~PowerShellActionPlatformOption.Version2; + } + UnconvertUnsupportedActions(); + } + + /// Occurs when a collection changes. + public event NotifyCollectionChangedEventHandler CollectionChanged; + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// Gets or sets the identifier of the principal for the task. + [XmlAttribute] + [DefaultValue(null)] + [CanBeNull] + public string Context + { + get + { + if (v2Coll != null) + return v2Coll.Context; + return v1Task.GetDataItem("ActionCollectionContext"); + } + set + { + if (v2Coll != null) + v2Coll.Context = value; + else + v1Task.SetDataItem("ActionCollectionContext", value); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets the systems under which unsupported actions will be converted to PowerShell instances. + /// + /// The PowerShell platform options. + /// + /// This property will affect how many actions are physically stored in the system and is tied to the version of Task Scheduler. + /// + /// If set to , then no actions will ever be converted to PowerShell. This will + /// force exceptions to be thrown when unsupported actions our action quantities are found. + /// + /// + /// If set to , then actions will be converted only under Version 1 of the + /// library (Windows XP or Windows Server 2003 and earlier). This option supports multiple actions of all types. If not specified, + /// only a single is supported. Developer must ensure that PowerShell v2 or higher is installed on the + /// target computer. + /// + /// + /// If set to (which is the default value), then and references will be converted to their PowerShell equivalents on systems + /// on or after Windows 8 / Server 2012. + /// + /// + /// If set to , then any actions not supported by the Task Scheduler version will be + /// converted to PowerShell. + /// + /// + [DefaultValue(typeof(PowerShellActionPlatformOption), "Version2")] + public PowerShellActionPlatformOption PowerShellConversion + { + get => psConvert; + set + { + if (psConvert != value) + { + psConvert = value; + if (v1Task != null) + v1Task.SetDataItem(nameof(PowerShellConversion), value.ToString()); + if (v2Def != null) + { + if (!string.IsNullOrEmpty(v2Def.Data)) + v2Def.Data = System.Text.RegularExpressions.Regex.Replace(v2Def.Data, psV2IdRegex, ""); + if (!SupportV2Conversion) + v2Def.Data = string.Format("{0}; {1}=0", v2Def.Data, nameof(PowerShellConversion)); + } + OnNotifyPropertyChanged(); + } + } + } + + /// Gets or sets an XML-formatted version of the collection. + public string XmlText + { + get + { + if (v2Coll != null) + return v2Coll.XmlText; + return XmlSerializationHelper.WriteObjectToXmlText(this); + } + set + { + if (v2Coll != null) + v2Coll.XmlText = value; + else + XmlSerializationHelper.ReadObjectFromXmlText(value, this); + OnNotifyPropertyChanged(); + } + } + + /// Gets the number of actions in the collection. + public int Count => (v2Coll != null) ? v2Coll.Count : v1Actions.Count; + + bool IList.IsFixedSize => false; + bool ICollection.IsReadOnly => false; + bool IList.IsReadOnly => false; + bool ICollection.IsSynchronized => false; + + object ICollection.SyncRoot => this; + private bool SupportV1Conversion => (PowerShellConversion & PowerShellActionPlatformOption.Version1) != 0; + + private bool SupportV2Conversion => (PowerShellConversion & PowerShellActionPlatformOption.Version2) != 0; + + /// Gets or sets a specified action from the collection. + /// The . + /// The id ( ) of the action to be retrieved. + /// Specialized instance. + /// + /// + /// + /// Mismatching Id for action and lookup. + [NotNull] + public Action this[string actionId] + { + get + { + if (string.IsNullOrEmpty(actionId)) + throw new ArgumentNullException(nameof(actionId)); + var t = Find(a => string.Equals(a.Id, actionId)); + if (t != null) + return t; + throw new ArgumentOutOfRangeException(nameof(actionId)); + } + set + { + if (value == null) + throw new NullReferenceException(); + if (string.IsNullOrEmpty(actionId)) + throw new ArgumentNullException(nameof(actionId)); + var index = IndexOf(actionId); + value.Id = actionId; + if (index >= 0) + this[index] = value; + else + Add(value); + } + } + + /// Gets or sets a an action at the specified index. + /// The zero-based index of the action to get or set. + [NotNull] + public Action this[int index] + { + get + { + if (v2Coll != null) + return Action.CreateAction(v2Coll[++index]); + if (v1Task != null) + { + if (SupportV1Conversion) + return v1Actions[index]; + else + { + if (index == 0) + return v1Actions[0]; + } + } + throw new ArgumentOutOfRangeException(); + } + set + { + if (index < 0 || Count <= index) + throw new ArgumentOutOfRangeException(nameof(index), index, "Index is not a valid index in the ActionCollection"); + var orig = this[index].Clone(); + if (v2Coll != null) + { + inV2set = true; + try + { + Insert(index, value); + RemoveAt(index + 1); + } + finally + { + inV2set = false; + } + } + else + { + v1Actions[index] = value; + SaveV1Actions(); + } + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, orig, index)); + } + } + + object IList.this[int index] + { + get => this[index]; + set => this[index] = (Action)value; + } + + /// Adds an action to the task. + /// A type derived from . + /// A derived class. + /// The bound that was added to the collection. + [NotNull] + public TAction Add([NotNull] TAction action) where TAction : Action + { + if (action == null) + throw new ArgumentNullException(nameof(action)); + if (v2Def != null) + action.Bind(v2Def); + else + { + if (!SupportV1Conversion && (v1Actions.Count >= 1 || !(action is ExecAction))) + throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + v1Actions.Add(action); + SaveV1Actions(); + } + OnNotifyPropertyChanged(nameof(Count)); + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, action)); + return action; + } + + /// Adds an to the task. + /// Path to an executable file. + /// Arguments associated with the command-line operation. This value can be null. + /// + /// Directory that contains either the executable file or the files that are used by the executable file. This value can be null. + /// + /// The bound that was added to the collection. + [NotNull] + public ExecAction Add([NotNull] string path, [CanBeNull] string arguments = null, [CanBeNull] string workingDirectory = null) => + Add(new ExecAction(path, arguments, workingDirectory)); + + /// Adds a new instance to the task. + /// Type of task to be created + /// Specialized instance. + [NotNull] + public Action AddNew(TaskActionType actionType) + { + if (Count >= MaxActions) + throw new ArgumentOutOfRangeException(nameof(actionType), "A maximum of 32 actions is allowed within a single task."); + if (v1Task != null) + { + if (!SupportV1Conversion && (v1Actions.Count >= 1 || actionType != TaskActionType.Execute)) + throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + return Action.CreateAction(v1Task); + } + return Action.CreateAction(v2Coll.Create(actionType)); + } + + /// Adds a collection of actions to the end of the . + /// + /// The actions to be added to the end of the . The collection itself cannot be null and cannot + /// contain null elements. + /// + /// is null. + public void AddRange([ItemNotNull, NotNull] IEnumerable actions) + { + if (actions == null) + throw new ArgumentNullException(nameof(actions)); + if (v1Task != null) + { + var list = new List(actions); + var at = list.Count == 1 && list[0].ActionType == TaskActionType.Execute; + if (!SupportV1Conversion && ((v1Actions.Count + list.Count) > 1 || !at)) + throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + v1Actions.AddRange(actions); + SaveV1Actions(); + } + else + { + foreach (var item in actions) + Add(item); + } + } + + /// Clears all actions from the task. + public void Clear() + { + if (v2Coll != null) + v2Coll.Clear(); + else + { + v1Actions.Clear(); + SaveV1Actions(); + } + OnNotifyPropertyChanged(nameof(Count)); + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + + /// Determines whether the contains a specific value. + /// The object to locate in the . + /// true if is found in the ; otherwise, false. + public bool Contains([NotNull] Action item) => Find(a => a.Equals(item)) != null; + + /// Determines whether the specified action type is contained in this collection. + /// Type of the action. + /// true if the specified action type is contained in this collection; otherwise, false. + public bool ContainsType(Type actionType) => Find(a => a.GetType() == actionType) != null; + + /// + /// Copies the elements of the to an array of , starting at a particular index. + /// + /// + /// The array that is the destination of the elements copied from . The array must have zero-based indexing. + /// + /// The zero-based index in array at which copying begins. + public void CopyTo(Action[] array, int arrayIndex) => CopyTo(0, array, arrayIndex, Count); + + /// + /// Copies the elements of the to an array, starting at a particular array index. + /// + /// The zero-based index in the source at which copying begins. + /// + /// The array that is the destination of the elements copied from . The array must have zero-based indexing. + /// + /// The zero-based index in array at which copying begins. + /// The number of elements to copy. + /// is null. + /// is less than 0. + /// + /// The number of elements in the source is greater than the available space from to the end of the destination . + /// + public void CopyTo(int index, [NotNull] Action[] array, int arrayIndex, int count) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException(nameof(index)); + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + if (count < 0 || count > (Count - index)) + throw new ArgumentOutOfRangeException(nameof(count)); + if ((Count - index) > (array.Length - arrayIndex)) + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + for (var i = 0; i < count; i++) + array[arrayIndex + i] = (Action)this[index + i].Clone(); + } + + /// Releases all resources used by this class. + public void Dispose() + { + v1Task = null; + v2Def = null; + if (v2Coll != null) Marshal.ReleaseComObject(v2Coll); + } + + /// + /// Searches for an that matches the conditions defined by the specified predicate, and returns the first + /// occurrence within the entire collection. + /// + /// + /// The delegate that defines the conditions of the to search for. + /// + /// + /// The first that matches the conditions defined by the specified predicate, if found; otherwise, null. + /// + public Action Find(Predicate match) + { + if (match == null) + throw new ArgumentNullException(nameof(match)); + foreach (var item in this) + if (match(item)) return item; + return null; + } + + /// + /// Searches for an that matches the conditions defined by the specified predicate, and returns the zero-based + /// index of the first occurrence within the collection that starts at the specified index and contains the specified number of elements. + /// + /// The zero-based starting index of the search. + /// The number of elements in the collection to search. + /// The delegate that defines the conditions of the element to search for. + /// + /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1. + /// + public int FindIndexOf(int startIndex, int count, [NotNull] Predicate match) + { + if (startIndex < 0 || startIndex >= Count) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + if (startIndex + count > Count) + throw new ArgumentOutOfRangeException(nameof(count)); + if (match == null) + throw new ArgumentNullException(nameof(match)); + for (var i = startIndex; i < startIndex + count; i++) + if (match(this[i])) return i; + return -1; + } + + /// + /// Searches for an that matches the conditions defined by the specified predicate, and returns the zero-based + /// index of the first occurrence within the collection. + /// + /// The delegate that defines the conditions of the element to search for. + /// + /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1. + /// + public int FindIndexOf([NotNull] Predicate match) => FindIndexOf(0, Count, match); + + /// Retrieves an enumeration of each of the actions. + /// + /// Returns an object that implements the interface and that can iterate through the + /// objects within the . + /// + public IEnumerator GetEnumerator() + { + if (v2Coll != null) + return new ComEnumerator(() => v2Coll.Count, i => v2Coll[i], Action.CreateAction); + return v1Actions.GetEnumerator(); + } + + /// Determines the index of a specific item in the . + /// The object to locate in the . + /// The index of if found in the list; otherwise, -1. + public int IndexOf(Action item) => FindIndexOf(a => a.Equals(item)); + + /// Determines the index of a specific item in the . + /// The id ( ) of the action to be retrieved. + /// The index of if found in the list; otherwise, -1. + public int IndexOf(string actionId) + { + if (string.IsNullOrEmpty(actionId)) + throw new ArgumentNullException(nameof(actionId)); + return FindIndexOf(a => string.Equals(a.Id, actionId)); + } + + /// Inserts an action at the specified index. + /// The zero-based index at which action should be inserted. + /// The action to insert into the list. + public void Insert(int index, [NotNull] Action action) + { + if (action == null) + throw new ArgumentNullException(nameof(action)); + if (index < 0 || index > Count) + throw new ArgumentOutOfRangeException(nameof(index)); + + if (v2Coll != null) + { + var pushItems = new Action[Count - index]; + if (Count != index) + { + CopyTo(index, pushItems, 0, Count - index); + for (var j = Count - 1; j >= index; j--) + RemoveAt(j); + } + Add(action); + if (Count != index) + for (var k = 0; k < pushItems.Length; k++) + Add(pushItems[k]); + } + else + { + if (!SupportV1Conversion && (index > 0 || !(action is ExecAction))) + throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + v1Actions.Insert(index, action); + SaveV1Actions(); + } + + if (!inV2set) + { + OnNotifyPropertyChanged(nameof(Count)); + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, action, index)); + } + } + + /// Removes the first occurrence of a specific object from the . + /// The object to remove from the . + /// + /// true if was successfully removed from the ; otherwise, false. This method + /// also returns false if is not found in the original . + /// + public bool Remove([NotNull] Action item) + { + var idx = IndexOf(item); + if (idx != -1) + { + try + { + RemoveAt(idx); + return true; + } + catch { } + } + return false; + } + + /// Removes the action at a specified index. + /// Index of action to remove. + /// Index out of range. + public void RemoveAt(int index) + { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException(nameof(index), index, "Failed to remove action. Index out of range."); + var item = this[index].Clone(); + if (v2Coll != null) + v2Coll.Remove(++index); + else + { + v1Actions.RemoveAt(index); + SaveV1Actions(); + } + if (!inV2set) + { + OnNotifyPropertyChanged(nameof(Count)); + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); + } + } + + /// Copies the elements of the to a new array. + /// An array containing copies of the elements of the . + [NotNull, ItemNotNull] + public Action[] ToArray() + { + var ret = new Action[Count]; + CopyTo(ret, 0); + return ret; + } + + /// Returns a that represents the actions in this collection. + /// A that represents the actions in this collection. + public override string ToString() + { + if (Count == 1) + return this[0].ToString(); + if (Count > 1) + return Properties.Resources.MultipleActions; + return string.Empty; + } + + void ICollection.Add(Action item) => Add(item); + + int IList.Add(object value) + { + Add((Action)value); + return Count - 1; + } + + bool IList.Contains(object value) => Contains((Action)value); + + void ICollection.CopyTo(Array array, int index) + { + if (array != null && array.Rank != 1) + throw new RankException("Multi-dimensional arrays are not supported."); + var src = new Action[Count]; + CopyTo(src, 0); + Array.Copy(src, 0, array, index, Count); + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() => null; + + int IList.IndexOf(object value) => IndexOf((Action)value); + + void IList.Insert(int index, object value) => Insert(index, (Action)value); + + void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) + { + reader.ReadStartElement(XmlSerializationHelper.GetElementName(this), TaskDefinition.tns); + Context = reader.GetAttribute("Context"); + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + var a = Action.CreateAction(Action.TryParse(reader.LocalName == "Exec" ? "Execute" : reader.LocalName, TaskActionType.Execute)); + XmlSerializationHelper.ReadObject(reader, a); + Add(a); + } + reader.ReadEndElement(); + } + + void IList.Remove(object value) => Remove((Action)value); + + void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) + { + // TODO:FIX if (!string.IsNullOrEmpty(Context)) writer.WriteAttributeString("Context", Context); + foreach (var item in this) + XmlSerializationHelper.WriteObject(writer, item); + } + + internal void ConvertUnsupportedActions() + { + if (TaskService.LibraryVersion.Minor > 3 && SupportV2Conversion) + { + for (var i = 0; i < Count; i++) + { + var action = this[i]; + var bindable = action as IBindAsExecAction; + if (bindable != null && !(action is ComHandlerAction)) + this[i] = ExecAction.ConvertToPowerShellAction(action); + } + } + } + + private List GetV1Actions() + { + var ret = new List(); + if (v1Task != null && v1Task.GetDataItem("ActionType") != "EMPTY") + { + var exec = new ExecAction(v1Task); + var items = exec.ParsePowerShellItems(); + if (items != null) + { + if (items.Length == 2 && items[0] == "MULTIPLE") + { + PowerShellConversion |= PowerShellActionPlatformOption.Version1; + var mc = System.Text.RegularExpressions.Regex.Matches(items[1], @"<# (?\w+):(?\w+) #>\s*(?[^<#]*)\s*"); + foreach (System.Text.RegularExpressions.Match ms in mc) + { + var a = Action.ActionFromScript(ms.Groups["t"].Value, ms.Groups["c"].Value); + if (a != null) + { + if (ms.Groups["id"].Value != "NO_ID") + a.Id = ms.Groups["id"].Value; + ret.Add(a); + } + } + } + else + ret.Add(ExecAction.ConvertFromPowerShellAction(exec)); + } + else if (!string.IsNullOrEmpty(exec.Path)) + { + ret.Add(exec); + } + } + return ret; + } + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + + private void SaveV1Actions() + { + if (v1Task == null) + throw new ArgumentNullException(nameof(v1Task)); + if (v1Actions.Count == 0) + { + v1Task.SetApplicationName(string.Empty); + v1Task.SetParameters(string.Empty); + v1Task.SetWorkingDirectory(string.Empty); + v1Task.SetDataItem("ActionId", null); + v1Task.SetDataItem("ActionType", "EMPTY"); + } + else if (v1Actions.Count == 1) + { + if (!SupportV1Conversion && v1Actions[0].ActionType != TaskActionType.Execute) + throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + v1Task.SetDataItem("ActionType", null); + v1Actions[0].Bind(v1Task); + } + else + { + if (!SupportV1Conversion) + throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + // Build list of internal PowerShell scripts + var sb = new System.Text.StringBuilder(); + foreach (var item in v1Actions) + sb.Append($"<# {item.Id ?? "NO_ID"}:{item.ActionType} #> {item.GetPowerShellCommand()} "); + + // Build and save PS ExecAction + var ea = ExecAction.CreatePowerShellAction("MULTIPLE", sb.ToString()); + ea.Bind(v1Task); + v1Task.SetDataItem("ActionId", null); + v1Task.SetDataItem("ActionType", "MULTIPLE"); + } + } + + private void UnconvertUnsupportedActions() + { + if (TaskService.LibraryVersion.Minor > 3) + { + for (var i = 0; i < Count; i++) + { + var action = this[i] as ExecAction; + if (action != null) + { + var newAction = Action.ConvertFromPowerShellAction(action); + if (newAction != null) + this[i] = newAction; + } + } + } + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/CultureSwitcher.cs b/FlashPatcher/TaskService/CultureSwitcher.cs new file mode 100644 index 0000000..f4d1b7f --- /dev/null +++ b/FlashPatcher/TaskService/CultureSwitcher.cs @@ -0,0 +1,23 @@ +using System; +using System.Threading; + +namespace Microsoft.Win32.TaskScheduler +{ + internal class CultureSwitcher : IDisposable + { + private readonly System.Globalization.CultureInfo cur, curUI; + + public CultureSwitcher([JetBrains.Annotations.NotNull] System.Globalization.CultureInfo culture) + { + cur = Thread.CurrentThread.CurrentCulture; + curUI = Thread.CurrentThread.CurrentUICulture; + Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = culture; + } + + public void Dispose() + { + Thread.CurrentThread.CurrentCulture = cur; + Thread.CurrentThread.CurrentUICulture = curUI; + } + } +} diff --git a/FlashPatcher/TaskService/EnumGlobalizer.cs b/FlashPatcher/TaskService/EnumGlobalizer.cs new file mode 100644 index 0000000..b636406 --- /dev/null +++ b/FlashPatcher/TaskService/EnumGlobalizer.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Functions to provide localized strings for enumerated types and values. + /// + public static class TaskEnumGlobalizer + { + /// + /// Gets a string representing the localized value of the provided enum. + /// + /// The enum value. + /// A localized string, if available. + public static string GetString(object enumValue) + { + switch (enumValue.GetType().Name) + { + case "DaysOfTheWeek": + return GetCultureEquivalentString((DaysOfTheWeek)enumValue); + case "MonthsOfTheYear": + return GetCultureEquivalentString((MonthsOfTheYear)enumValue); + case "TaskTriggerType": + return BuildEnumString("TriggerType", enumValue); + case "WhichWeek": + return BuildEnumString("WW", enumValue); + case "TaskActionType": + return BuildEnumString("ActionType", enumValue); + case "TaskState": + return BuildEnumString("TaskState", enumValue); + } + return enumValue.ToString(); + } + + private static string GetCultureEquivalentString(DaysOfTheWeek val) + { + if (val == DaysOfTheWeek.AllDays) + return Properties.Resources.DOWAllDays; + + var s = new List(7); + var vals = Enum.GetValues(val.GetType()); + for (var i = 0; i < vals.Length - 1; i++) + { + if ((val & (DaysOfTheWeek)vals.GetValue(i)) > 0) + s.Add(DateTimeFormatInfo.CurrentInfo.GetDayName((DayOfWeek)i)); + } + + return string.Join(Properties.Resources.ListSeparator, s.ToArray()); + } + + private static string GetCultureEquivalentString(MonthsOfTheYear val) + { + if (val == MonthsOfTheYear.AllMonths) + return Properties.Resources.MOYAllMonths; + + var s = new List(12); + var vals = Enum.GetValues(val.GetType()); + for (var i = 0; i < vals.Length - 1; i++) + { + if ((val & (MonthsOfTheYear)vals.GetValue(i)) > 0) + s.Add(DateTimeFormatInfo.CurrentInfo.GetMonthName(i+1)); + } + + return string.Join(Properties.Resources.ListSeparator, s.ToArray()); + } + + private static string BuildEnumString(string preface, object enumValue) + { + var vals = enumValue.ToString().Split(new[] { ", " }, StringSplitOptions.None); + if (vals.Length == 0) + return string.Empty; + for (var i = 0; i < vals.Length; i++) + vals[i] = Properties.Resources.ResourceManager.GetString(preface + vals[i]); + return string.Join(Properties.Resources.ListSeparator, vals); + } + } +} diff --git a/FlashPatcher/TaskService/JetBrains.Annotations.cs b/FlashPatcher/TaskService/JetBrains.Annotations.cs new file mode 100644 index 0000000..0c68ef1 --- /dev/null +++ b/FlashPatcher/TaskService/JetBrains.Annotations.cs @@ -0,0 +1,1065 @@ +/* MIT License + +Copyright (c) 2016 JetBrains http://www.jetbrains.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. */ + +using System; + +#pragma warning disable 1591 +// ReSharper disable UnusedMember.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable IntroduceOptionalParameters.Global +// ReSharper disable MemberCanBeProtected.Global +// ReSharper disable InconsistentNaming + +namespace JetBrains.Annotations +{ + /// + /// Indicates that the value of the marked element could be null sometimes, + /// so the check for null is necessary before its usage. + /// + /// + /// [CanBeNull] object Test() => null; + /// + /// void UseTest() { + /// var p = Test(); + /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] + internal sealed class CanBeNullAttribute : Attribute { } + + /// + /// Indicates that the value of the marked element could never be null. + /// + /// + /// [NotNull] object Foo() { + /// return null; // Warning: Possible 'null' assignment + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] + internal sealed class NotNullAttribute : Attribute { } + + /// + /// Can be appplied to symbols of types derived from IEnumerable as well as to symbols of Task + /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property + /// or of the Lazy.Value property can never be null. + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field)] + internal sealed class ItemNotNullAttribute : Attribute { } + + /// + /// Can be appplied to symbols of types derived from IEnumerable as well as to symbols of Task + /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property + /// or of the Lazy.Value property can be null. + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field)] + internal sealed class ItemCanBeNullAttribute : Attribute { } + + /// + /// Indicates that the marked method builds string by format pattern and (optional) arguments. + /// Parameter, which contains format string, should be given in constructor. The format string + /// should be in -like form. + /// + /// + /// [StringFormatMethod("message")] + /// void ShowError(string message, params object[] args) { /* do something */ } + /// + /// void Foo() { + /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string + /// } + /// + [AttributeUsage( + AttributeTargets.Constructor | AttributeTargets.Method | + AttributeTargets.Property | AttributeTargets.Delegate)] + internal sealed class StringFormatMethodAttribute : Attribute + { + /// + /// Specifies which parameter of an annotated method should be treated as format-string + /// + public StringFormatMethodAttribute([NotNull] string formatParameterName) + { + FormatParameterName = formatParameterName; + } + + [NotNull] public string FormatParameterName { get; private set; } + } + + /// + /// For a parameter that is expected to be one of the limited set of values. + /// Specify fields of which type should be used as values for this parameter. + /// + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field, + AllowMultiple = true)] + internal sealed class ValueProviderAttribute : Attribute + { + public ValueProviderAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; private set; } + } + + /// + /// Indicates that the function argument should be string literal and match one + /// of the parameters of the caller function. For example, ReSharper annotates + /// the parameter of . + /// + /// + /// void Foo(string param) { + /// if (param == null) + /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol + /// } + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class InvokerParameterNameAttribute : Attribute { } + + /// + /// Indicates that the method is contained in a type that implements + /// System.ComponentModel.INotifyPropertyChanged interface and this method + /// is used to notify that some property value changed. + /// + /// + /// The method should be non-static and conform to one of the supported signatures: + /// + /// NotifyChanged(string) + /// NotifyChanged(params string[]) + /// NotifyChanged{T}(Expression{Func{T}}) + /// NotifyChanged{T,U}(Expression{Func{T,U}}) + /// SetProperty{T}(ref T, T, string) + /// + /// + /// + /// public class Foo : INotifyPropertyChanged { + /// public event PropertyChangedEventHandler PropertyChanged; + /// + /// [NotifyPropertyChangedInvocator] + /// protected virtual void NotifyChanged(string propertyName) { ... } + /// + /// string _name; + /// + /// public string Name { + /// get { return _name; } + /// set { _name = value; NotifyChanged("LastName"); /* Warning */ } + /// } + /// } + /// + /// Examples of generated notifications: + /// + /// NotifyChanged("Property") + /// NotifyChanged(() => Property) + /// NotifyChanged((VM x) => x.Property) + /// SetProperty(ref myField, value, "Property") + /// + /// + [AttributeUsage(AttributeTargets.Method)] + internal sealed class NotifyPropertyChangedInvocatorAttribute : Attribute + { + public NotifyPropertyChangedInvocatorAttribute() { } + public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName) + { + ParameterName = parameterName; + } + + [CanBeNull] public string ParameterName { get; private set; } + } + + /// + /// Describes dependency between method input and output. + /// + /// + ///

Function Definition Table syntax:

+ /// + /// FDT ::= FDTRow [;FDTRow]* + /// FDTRow ::= Input => Output | Output <= Input + /// Input ::= ParameterName: Value [, Input]* + /// Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value} + /// Value ::= true | false | null | notnull | canbenull + /// + /// If method has single input parameter, it's name could be omitted.
+ /// Using halt (or void/nothing, which is the same) for method output + /// means that the methos doesn't return normally (throws or terminates the process).
+ /// Value canbenull is only applicable for output parameters.
+ /// You can use multiple [ContractAnnotation] for each FDT row, or use single attribute + /// with rows separated by semicolon. There is no notion of order rows, all rows are checked + /// for applicability and applied per each program state tracked by R# analysis.
+ ///
+ /// + /// + /// [ContractAnnotation("=> halt")] + /// public void TerminationMethod() + /// + /// + /// [ContractAnnotation("halt <= condition: false")] + /// public void Assert(bool condition, string text) // regular assertion method + /// + /// + /// [ContractAnnotation("s:null => true")] + /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() + /// + /// + /// // A method that returns null if the parameter is null, + /// // and not null if the parameter is not null + /// [ContractAnnotation("null => null; notnull => notnull")] + /// public object Transform(object data) + /// + /// + /// [ContractAnnotation("=> true, result: notnull; => false, result: null")] + /// public bool TryParse(string s, out Person result) + /// + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + internal sealed class ContractAnnotationAttribute : Attribute + { + public ContractAnnotationAttribute([NotNull] string contract) + : this(contract, false) { } + + public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) + { + Contract = contract; + ForceFullStates = forceFullStates; + } + + [NotNull] public string Contract { get; private set; } + + public bool ForceFullStates { get; private set; } + } + + /// + /// Indicates that marked element should be localized or not. + /// + /// + /// [LocalizationRequiredAttribute(true)] + /// class Foo { + /// string str = "my string"; // Warning: Localizable string + /// } + /// + [AttributeUsage(AttributeTargets.All)] + internal sealed class LocalizationRequiredAttribute : Attribute + { + public LocalizationRequiredAttribute() : this(true) { } + + public LocalizationRequiredAttribute(bool required) + { + Required = required; + } + + public bool Required { get; private set; } + } + + /// + /// Indicates that the value of the marked type (or its derivatives) + /// cannot be compared using '==' or '!=' operators and Equals() + /// should be used instead. However, using '==' or '!=' for comparison + /// with null is always permitted. + /// + /// + /// [CannotApplyEqualityOperator] + /// class NoEquality { } + /// + /// class UsesNoEquality { + /// void Test() { + /// var ca1 = new NoEquality(); + /// var ca2 = new NoEquality(); + /// if (ca1 != null) { // OK + /// bool condition = ca1 == ca2; // Warning + /// } + /// } + /// } + /// + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct)] + internal sealed class CannotApplyEqualityOperatorAttribute : Attribute { } + + /// + /// When applied to a target attribute, specifies a requirement for any type marked + /// with the target attribute to implement or inherit specific type or types. + /// + /// + /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement + /// class ComponentAttribute : Attribute { } + /// + /// [Component] // ComponentAttribute requires implementing IComponent interface + /// class MyComponent : IComponent { } + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + [BaseTypeRequired(typeof(Attribute))] + internal sealed class BaseTypeRequiredAttribute : Attribute + { + public BaseTypeRequiredAttribute([NotNull] Type baseType) + { + BaseType = baseType; + } + + [NotNull] public Type BaseType { get; private set; } + } + + /// + /// Indicates that the marked symbol is used implicitly (e.g. via reflection, in external library), + /// so this symbol will not be marked as unused (as well as by other usage inspections). + /// + [AttributeUsage(AttributeTargets.All)] + internal sealed class UsedImplicitlyAttribute : Attribute + { + public UsedImplicitlyAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) { } + + public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) { } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + public ImplicitUseKindFlags UseKindFlags { get; private set; } + + public ImplicitUseTargetFlags TargetFlags { get; private set; } + } + + /// + /// Should be used on attributes and causes ReSharper to not mark symbols marked with such attributes + /// as unused (as well as by other usage inspections) + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.GenericParameter)] + internal sealed class MeansImplicitUseAttribute : Attribute + { + public MeansImplicitUseAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } + + public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) { } + + public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) { } + + public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; private set; } + + [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; private set; } + } + + [Flags] + internal enum ImplicitUseKindFlags + { + Default = Access | Assign | InstantiatedWithFixedConstructorSignature, + /// Only entity marked with attribute considered used. + Access = 1, + /// Indicates implicit assignment to a member. + Assign = 2, + /// + /// Indicates implicit instantiation of a type with fixed constructor signature. + /// That means any unused constructor parameters won't be reported as such. + /// + InstantiatedWithFixedConstructorSignature = 4, + /// Indicates implicit instantiation of a type. + InstantiatedNoFixedConstructorSignature = 8, + } + + /// + /// Specify what is considered used implicitly when marked + /// with or . + /// + [Flags] + internal enum ImplicitUseTargetFlags + { + Default = Itself, + Itself = 1, + /// Members of entity marked with attribute are considered used. + Members = 2, + /// Entity marked with attribute and all its members considered used. + WithMembers = Itself | Members + } + + /// + /// This attribute is intended to mark publicly available API + /// which should not be removed and so is treated as used. + /// + [MeansImplicitUse(ImplicitUseTargetFlags.WithMembers)] + internal sealed class PublicAPIAttribute : Attribute + { + public PublicAPIAttribute() { } + + public PublicAPIAttribute([NotNull] string comment) + { + Comment = comment; + } + + [CanBeNull] public string Comment { get; private set; } + } + + /// + /// Tells code analysis engine if the parameter is completely handled when the invoked method is on stack. + /// If the parameter is a delegate, indicates that delegate is executed while the method is executed. + /// If the parameter is an enumerable, indicates that it is enumerated while the method is executed. + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class InstantHandleAttribute : Attribute { } + + /// + /// Indicates that a method does not make any observable state changes. + /// The same as System.Diagnostics.Contracts.PureAttribute. + /// + /// + /// [Pure] int Multiply(int x, int y) => x * y; + /// + /// void M() { + /// Multiply(123, 42); // Waring: Return value of pure method is not used + /// } + /// + [AttributeUsage(AttributeTargets.Method)] + internal sealed class PureAttribute : Attribute { } + + /// + /// Indicates that the return value of method invocation must be used. + /// + [AttributeUsage(AttributeTargets.Method)] + internal sealed class MustUseReturnValueAttribute : Attribute + { + public MustUseReturnValueAttribute() { } + + public MustUseReturnValueAttribute([NotNull] string justification) + { + Justification = justification; + } + + [CanBeNull] public string Justification { get; private set; } + } + + /// + /// Indicates the type member or parameter of some type, that should be used instead of all other ways + /// to get the value that type. This annotation is useful when you have some "context" value evaluated + /// and stored somewhere, meaning that all other ways to get this value must be consolidated with existing one. + /// + /// + /// class Foo { + /// [ProvidesContext] IBarService _barService = ...; + /// + /// void ProcessNode(INode node) { + /// DoSomething(node, node.GetGlobalServices().Bar); + /// // ^ Warning: use value of '_barService' field + /// } + /// } + /// + [AttributeUsage( + AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Method | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.GenericParameter)] + internal sealed class ProvidesContextAttribute : Attribute { } + + /// + /// Indicates that a parameter is a path to a file or a folder within a web project. + /// Path can be relative or absolute, starting from web root (~). + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class PathReferenceAttribute : Attribute + { + public PathReferenceAttribute() { } + + public PathReferenceAttribute([NotNull, PathReference] string basePath) + { + BasePath = basePath; + } + + [CanBeNull] public string BasePath { get; private set; } + } + + /// + /// An extension method marked with this attribute is processed by ReSharper code completion + /// as a 'Source Template'. When extension method is completed over some expression, it's source code + /// is automatically expanded like a template at call site. + /// + /// + /// Template method body can contain valid source code and/or special comments starting with '$'. + /// Text inside these comments is added as source code when the template is applied. Template parameters + /// can be used either as additional method parameters or as identifiers wrapped in two '$' signs. + /// Use the attribute to specify macros for parameters. + /// + /// + /// In this example, the 'forEach' method is a source template available over all values + /// of enumerable types, producing ordinary C# 'foreach' statement and placing caret inside block: + /// + /// [SourceTemplate] + /// public static void forEach<T>(this IEnumerable<T> xs) { + /// foreach (var x in xs) { + /// //$ $END$ + /// } + /// } + /// + /// + [AttributeUsage(AttributeTargets.Method)] + internal sealed class SourceTemplateAttribute : Attribute { } + + /// + /// Allows specifying a macro for a parameter of a source template. + /// + /// + /// You can apply the attribute on the whole method or on any of its additional parameters. The macro expression + /// is defined in the property. When applied on a method, the target + /// template parameter is defined in the property. To apply the macro silently + /// for the parameter, set the property value = -1. + /// + /// + /// Applying the attribute on a source template method: + /// + /// [SourceTemplate, Macro(Target = "item", Expression = "suggestVariableName()")] + /// public static void forEach<T>(this IEnumerable<T> collection) { + /// foreach (var item in collection) { + /// //$ $END$ + /// } + /// } + /// + /// Applying the attribute on a template method parameter: + /// + /// [SourceTemplate] + /// public static void something(this Entity x, [Macro(Expression = "guid()", Editable = -1)] string newguid) { + /// /*$ var $x$Id = "$newguid$" + x.ToString(); + /// x.DoSomething($x$Id); */ + /// } + /// + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple = true)] + internal sealed class MacroAttribute : Attribute + { + /// + /// Allows specifying a macro that will be executed for a source template + /// parameter when the template is expanded. + /// + [CanBeNull] public string Expression { get; set; } + + /// + /// Allows specifying which occurrence of the target parameter becomes editable when the template is deployed. + /// + /// + /// If the target parameter is used several times in the template, only one occurrence becomes editable; + /// other occurrences are changed synchronously. To specify the zero-based index of the editable occurrence, + /// use values >= 0. To make the parameter non-editable when the template is expanded, use -1. + /// > + public int Editable { get; set; } + + /// + /// Identifies the target parameter of a source template if the + /// is applied on a template method. + /// + [CanBeNull] public string Target { get; set; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + internal sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute + { + public AspMvcAreaMasterLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; private set; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + internal sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute + { + public AspMvcAreaPartialViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; private set; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + internal sealed class AspMvcAreaViewLocationFormatAttribute : Attribute + { + public AspMvcAreaViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; private set; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + internal sealed class AspMvcMasterLocationFormatAttribute : Attribute + { + public AspMvcMasterLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; private set; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + internal sealed class AspMvcPartialViewLocationFormatAttribute : Attribute + { + public AspMvcPartialViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; private set; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + internal sealed class AspMvcViewLocationFormatAttribute : Attribute + { + public AspMvcViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; private set; } + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC action. If applied to a method, the MVC action name is calculated + /// implicitly from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + internal sealed class AspMvcActionAttribute : Attribute + { + public AspMvcActionAttribute() { } + + public AspMvcActionAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC area. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class AspMvcAreaAttribute : Attribute + { + public AspMvcAreaAttribute() { } + + public AspMvcAreaAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is + /// an MVC controller. If applied to a method, the MVC controller name is calculated + /// implicitly from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + internal sealed class AspMvcControllerAttribute : Attribute + { + public AspMvcControllerAttribute() { } + + public AspMvcControllerAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC Master. Use this attribute + /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, String). + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class AspMvcMasterAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC model type. Use this attribute + /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, Object). + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class AspMvcModelTypeAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is an MVC + /// partial view. If applied to a method, the MVC partial view name is calculated implicitly + /// from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + internal sealed class AspMvcPartialViewAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Allows disabling inspections for MVC views within a class or a method. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + internal sealed class AspMvcSuppressViewErrorAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class AspMvcDisplayTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC editor template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class AspMvcEditorTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC template. + /// Use this attribute for custom wrappers similar to + /// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String). + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class AspMvcTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view component. If applied to a method, the MVC view name is calculated implicitly + /// from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(Object). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + internal sealed class AspMvcViewAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view component name. + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class AspMvcViewComponentAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view component view. If applied to a method, the MVC view component view name is default. + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + internal sealed class AspMvcViewComponentViewAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. When applied to a parameter of an attribute, + /// indicates that this parameter is an MVC action name. + /// + /// + /// [ActionName("Foo")] + /// public ActionResult Login(string returnUrl) { + /// ViewBag.ReturnUrl = Url.Action("Foo"); // OK + /// return RedirectToAction("Bar"); // Error: Cannot resolve action + /// } + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] + internal sealed class AspMvcActionSelectorAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field)] + internal sealed class HtmlElementAttributesAttribute : Attribute + { + public HtmlElementAttributesAttribute() { } + + public HtmlElementAttributesAttribute([NotNull] string name) + { + Name = name; + } + + [CanBeNull] public string Name { get; private set; } + } + + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] + internal sealed class HtmlAttributeValueAttribute : Attribute + { + public HtmlAttributeValueAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; private set; } + } + + /// + /// Razor attribute. Indicates that a parameter or a method is a Razor section. + /// Use this attribute for custom wrappers similar to + /// System.Web.WebPages.WebPageBase.RenderSection(String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + internal sealed class RazorSectionAttribute : Attribute { } + + /// + /// Indicates how method, constructor invocation or property access + /// over collection type affects content of the collection. + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)] + internal sealed class CollectionAccessAttribute : Attribute + { + public CollectionAccessAttribute(CollectionAccessType collectionAccessType) + { + CollectionAccessType = collectionAccessType; + } + + public CollectionAccessType CollectionAccessType { get; private set; } + } + + [Flags] + internal enum CollectionAccessType + { + /// Method does not use or modify content of the collection. + None = 0, + /// Method only reads content of the collection but does not modify it. + Read = 1, + /// Method can change content of the collection but does not add new elements. + ModifyExistingContent = 2, + /// Method can add new elements to the collection. + UpdatedContent = ModifyExistingContent | 4 + } + + /// + /// Indicates that the marked method is assertion method, i.e. it halts control flow if + /// one of the conditions is satisfied. To set the condition, mark one of the parameters with + /// attribute. + /// + [AttributeUsage(AttributeTargets.Method)] + internal sealed class AssertionMethodAttribute : Attribute { } + + /// + /// Indicates the condition parameter of the assertion method. The method itself should be + /// marked by attribute. The mandatory argument of + /// the attribute is the assertion type. + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class AssertionConditionAttribute : Attribute + { + public AssertionConditionAttribute(AssertionConditionType conditionType) + { + ConditionType = conditionType; + } + + public AssertionConditionType ConditionType { get; private set; } + } + + /// + /// Specifies assertion type. If the assertion method argument satisfies the condition, + /// then the execution continues. Otherwise, execution is assumed to be halted. + /// + internal enum AssertionConditionType + { + /// Marked parameter should be evaluated to true. + IS_TRUE = 0, + /// Marked parameter should be evaluated to false. + IS_FALSE = 1, + /// Marked parameter should be evaluated to null value. + IS_NULL = 2, + /// Marked parameter should be evaluated to not null value. + IS_NOT_NULL = 3, + } + + /// + /// Indicates that the marked method unconditionally terminates control flow execution. + /// For example, it could unconditionally throw exception. + /// + [Obsolete("Use [ContractAnnotation('=> halt')] instead")] + [AttributeUsage(AttributeTargets.Method)] + internal sealed class TerminatesProgramAttribute : Attribute { } + + /// + /// Indicates that method is pure LINQ method, with postponed enumeration (like Enumerable.Select, + /// .Where). This annotation allows inference of [InstantHandle] annotation for parameters + /// of delegate type by analyzing LINQ method chains. + /// + [AttributeUsage(AttributeTargets.Method)] + internal sealed class LinqTunnelAttribute : Attribute { } + + /// + /// Indicates that IEnumerable, passed as parameter, is not enumerated. + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class NoEnumerationAttribute : Attribute { } + + /// + /// Indicates that parameter is regular expression pattern. + /// + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class RegexPatternAttribute : Attribute { } + + /// + /// Prevents the Member Reordering feature from tossing members of the marked class. + /// + /// + /// The attribute must be mentioned in your member reordering patterns + /// + [AttributeUsage( + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Enum)] + internal sealed class NoReorderAttribute : Attribute { } + + /// + /// XAML attribute. Indicates the type that has ItemsSource property and should be treated + /// as ItemsControl-derived type, to enable inner items DataContext type resolve. + /// + [AttributeUsage(AttributeTargets.Class)] + internal sealed class XamlItemsControlAttribute : Attribute { } + + /// + /// XAML attribute. Indicates the property of some BindingBase-derived type, that + /// is used to bind some item of ItemsControl-derived type. This annotation will + /// enable the DataContext type resolve for XAML bindings for such properties. + /// + /// + /// Property should have the tree ancestor of the ItemsControl type or + /// marked with the attribute. + /// + [AttributeUsage(AttributeTargets.Property)] + internal sealed class XamlItemBindingOfItemsControlAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + internal sealed class AspChildControlTypeAttribute : Attribute + { + public AspChildControlTypeAttribute([NotNull] string tagName, [NotNull] Type controlType) + { + TagName = tagName; + ControlType = controlType; + } + + [NotNull] public string TagName { get; private set; } + + [NotNull] public Type ControlType { get; private set; } + } + + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] + internal sealed class AspDataFieldAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] + internal sealed class AspDataFieldsAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Property)] + internal sealed class AspMethodPropertyAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + internal sealed class AspRequiredAttributeAttribute : Attribute + { + public AspRequiredAttributeAttribute([NotNull] string attribute) + { + Attribute = attribute; + } + + [NotNull] public string Attribute { get; private set; } + } + + [AttributeUsage(AttributeTargets.Property)] + internal sealed class AspTypePropertyAttribute : Attribute + { + public bool CreateConstructorReferences { get; private set; } + + public AspTypePropertyAttribute(bool createConstructorReferences) + { + CreateConstructorReferences = createConstructorReferences; + } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + internal sealed class RazorImportNamespaceAttribute : Attribute + { + public RazorImportNamespaceAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; private set; } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + internal sealed class RazorInjectionAttribute : Attribute + { + public RazorInjectionAttribute([NotNull] string type, [NotNull] string fieldName) + { + Type = type; + FieldName = fieldName; + } + + [NotNull] public string Type { get; private set; } + + [NotNull] public string FieldName { get; private set; } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + internal sealed class RazorDirectiveAttribute : Attribute + { + public RazorDirectiveAttribute([NotNull] string directive) + { + Directive = directive; + } + + [NotNull] public string Directive { get; private set; } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + internal sealed class RazorPageBaseTypeAttribute : Attribute + { + public RazorPageBaseTypeAttribute([NotNull] string baseType) + { + BaseType = baseType; + } + public RazorPageBaseTypeAttribute([NotNull] string baseType, string pageName) + { + BaseType = baseType; + PageName = pageName; + } + + [NotNull] public string BaseType { get; private set; } + [CanBeNull] public string PageName { get; private set; } + } + + [AttributeUsage(AttributeTargets.Method)] + internal sealed class RazorHelperCommonAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Property)] + internal sealed class RazorLayoutAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Method)] + internal sealed class RazorWriteLiteralMethodAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Method)] + internal sealed class RazorWriteMethodAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class RazorWriteMethodParameterAttribute : Attribute { } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/NamedValueCollection.cs b/FlashPatcher/TaskService/NamedValueCollection.cs new file mode 100644 index 0000000..50e195e --- /dev/null +++ b/FlashPatcher/TaskService/NamedValueCollection.cs @@ -0,0 +1,616 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Xml.Serialization; +using Microsoft.Win32.TaskScheduler.V2Interop; +using JetBrains.Annotations; + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Pair of name and value. + /// + [PublicAPI] + public class NameValuePair : IXmlSerializable, INotifyPropertyChanged, ICloneable, IEquatable, IEquatable + { + private readonly ITaskNamedValuePair v2Pair; + private string name, value; + + /// + /// Occurs when a property has changed. + /// + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Initializes a new instance of the class. + /// + public NameValuePair() { } + + internal NameValuePair([NotNull] ITaskNamedValuePair iPair) + { + v2Pair = iPair; + } + + internal NameValuePair([NotNull] string name, [NotNull] string value) + { + if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value)) + throw new ArgumentException("Both name and value must be non-empty strings."); + this.name = name; this.value = value; + } + + [XmlIgnore] + internal bool AttributedXmlFormat { get; set; } = true; + + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// + [NotNull] + public string Name + { + get { return v2Pair == null ? name : v2Pair.Name; } + set { if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(Name)); if (v2Pair == null) name = value; else v2Pair.Name = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name))); } + } + + /// + /// Gets or sets the value. + /// + /// + /// The value. + /// + [NotNull] + public string Value + { + get { return v2Pair == null ? value : v2Pair.Value; } + set { if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(Value)); if (v2Pair == null) this.value = value; else v2Pair.Value = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value))); } + } + + /// + /// Clones this instance. + /// + /// A copy of an unbound . + [NotNull] + public NameValuePair Clone() => new NameValuePair(Name, Value); + + object ICloneable.Clone() => Clone(); + + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + public override bool Equals(object obj) + { + var valuePair = obj as ITaskNamedValuePair; + if (valuePair != null) + return (this as IEquatable).Equals(valuePair); + var pair = obj as NameValuePair; + if (pair != null) + return Equals(pair); + return base.Equals(obj); + } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public bool Equals([NotNull] NameValuePair other) => other.Name == Name && other.Value == Value; + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + bool IEquatable.Equals(ITaskNamedValuePair other) => other.Name == Name && other.Value == Value; + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + public override int GetHashCode() => new { A = Name, B = Value }.GetHashCode(); + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() => $"{Name}={Value}"; + + /// + /// Implements the operator implicit NameValuePair. + /// + /// The KeyValuePair. + /// + /// The result of the operator. + /// + public static implicit operator NameValuePair(KeyValuePair kvp) => new NameValuePair(kvp.Key, kvp.Value); + + System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() => null; + + void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) + { + if (reader.MoveToContent() == System.Xml.XmlNodeType.Element && reader.LocalName == "Value") + { + Name = reader.GetAttribute("name"); + Value = reader.ReadString(); + reader.Read(); + } + else + { + reader.ReadStartElement(); + XmlSerializationHelper.ReadObjectProperties(reader, this); + reader.ReadEndElement(); + } + } + + void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) + { + if (AttributedXmlFormat) + { + writer.WriteAttributeString("name", Name); + writer.WriteString(Value); + } + else + { + XmlSerializationHelper.WriteObjectProperties(writer, this); + } + } + } + + /// + /// Contains a collection of name-value pairs. + /// + [PublicAPI] + public sealed class NamedValueCollection : IDisposable, ICollection, IDictionary, INotifyCollectionChanged, INotifyPropertyChanged + { + private ITaskNamedValueCollection v2Coll; + private readonly List unboundDict; + + /// + /// Occurs when the collection has changed. + /// + public event NotifyCollectionChangedEventHandler CollectionChanged; + + /// + /// Occurs when a property has changed. + /// + public event PropertyChangedEventHandler PropertyChanged; + + internal NamedValueCollection([NotNull] ITaskNamedValueCollection iColl) { v2Coll = iColl; } + + internal NamedValueCollection() + { + unboundDict = new List(5); + } + + [XmlIgnore] + internal bool AttributedXmlFormat { get; set; } = true; + + internal void Bind([NotNull] ITaskNamedValueCollection iTaskNamedValueCollection) + { + v2Coll = iTaskNamedValueCollection; + v2Coll.Clear(); + foreach (var item in unboundDict) + v2Coll.Create(item.Name, item.Value); + } + + /// + /// Copies current to another. + /// + /// The destination collection. + public void CopyTo([NotNull] NamedValueCollection destCollection) + { + if (v2Coll != null) + { + for (var i = 1; i <= Count; i++) + destCollection.Add(v2Coll[i].Name, v2Coll[i].Value); + } + else + { + foreach (var item in unboundDict) + destCollection.Add(item.Name, item.Value); + } + } + + /// + /// Releases all resources used by this class. + /// + public void Dispose() + { + if (v2Coll != null) Marshal.ReleaseComObject(v2Coll); + } + + /// + /// Gets the number of items in the collection. + /// + public int Count => v2Coll?.Count ?? unboundDict.Count; + + /// + /// Gets a collection of the names. + /// + /// + /// The names. + /// + [ItemNotNull, NotNull] + public ICollection Names + { + get + { + if (v2Coll == null) + return unboundDict.ConvertAll(p => p.Name); + + var ret = new List(v2Coll.Count); + foreach (var item in this) + ret.Add(item.Name); + return ret; + } + } + + /// + /// Gets a collection of the values. + /// + /// + /// The values. + /// + [ItemNotNull, NotNull] + public ICollection Values + { + get + { + if (v2Coll == null) + return unboundDict.ConvertAll(p => p.Value); + + var ret = new List(v2Coll.Count); + foreach (var item in this) + ret.Add(item.Value); + return ret; + } + } + + /// + /// Gets the value of the item at the specified index. + /// + /// The index of the item being requested. + /// The value of the name-value pair at the specified index. + [NotNull] + public string this[int index] + { + get + { + if (v2Coll != null) + return v2Coll[++index].Value; + return unboundDict[index].Value; + } + } + + /// + /// Gets the value of the item with the specified name. + /// + /// Name to get the value for. + /// Value for the name, or null if not found. + public string this[string name] + { + [CanBeNull] + get + { + string ret; + TryGetValue(name, out ret); + return ret; + } + [NotNull] + set + { + int idx; + NameValuePair old = null; + var nvp = new NameValuePair(name, value); + if (v2Coll == null) + { + idx = unboundDict.FindIndex(p => p.Name == name); + if (idx == -1) + unboundDict.Add(nvp); + else + { + old = unboundDict[idx]; + unboundDict[idx] = nvp; + } + } + else + { + var array = new KeyValuePair[Count]; + ((ICollection>)this).CopyTo(array, 0); + idx = Array.FindIndex(array, p => p.Key == name); + if (idx == -1) + v2Coll.Create(name, value); + else + { + old = array[idx]; + array[idx] = new KeyValuePair(name, value); + v2Coll.Clear(); + foreach (KeyValuePair t in array) + v2Coll.Create(t.Key, t.Value); + } + } + if (idx == -1) + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, nvp)); + else + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, nvp, old, idx)); + } + } + + /// + /// Adds an item to the . + /// + /// The object to add to the . + public void Add([NotNull] NameValuePair item) + { + if (v2Coll != null) + v2Coll.Create(item.Name, item.Value); + else + unboundDict.Add(item); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); + } + + /// + /// Adds a name-value pair to the collection. + /// + /// The name associated with a value in a name-value pair. + /// The value associated with a name in a name-value pair. + public void Add([NotNull] string name, [NotNull] string value) + { + Add(new NameValuePair(name, value)); + } + + /// + /// Adds the elements of the specified collection to the end of . + /// + /// The collection of whose elements should be added to the end of . + public void AddRange([ItemNotNull, NotNull] IEnumerable items) + { + if (v2Coll != null) + { + foreach (var item in items) + v2Coll.Create(item.Name, item.Value); + } + else + unboundDict.AddRange(items); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, items)); + } + + /// + /// Clears the entire collection of name-value pairs. + /// + public void Clear() + { + if (v2Coll != null) + v2Coll.Clear(); + else + unboundDict.Clear(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]")); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// A that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() + { + if (v2Coll == null) + return unboundDict.GetEnumerator(); + + return new ComEnumerator(() => v2Coll.Count, i => v2Coll[i], o => new NameValuePair(o)); + } + + private void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + { + if (e.NewItems != null) + foreach (NameValuePair item in e.NewItems) + item.AttributedXmlFormat = AttributedXmlFormat; + CollectionChanged?.Invoke(this, e); + } + + /// + /// Removes the name-value pair with the specified key from the collection. + /// + /// The name associated with a value in a name-value pair. + /// true if item successfully removed; false otherwise. + public bool Remove([NotNull] string name) + { + var i = -1; + NameValuePair nvp = null; + try + { + if (v2Coll == null) + { + i = unboundDict.FindIndex(p => p.Name == name); + if (i != -1) + { + nvp = unboundDict[i]; + unboundDict.RemoveAt(i); + } + return (i != -1); + } + + for (i = 0; i < v2Coll.Count; i++) + { + if (name == v2Coll[i].Name) + { + nvp = new NameValuePair(v2Coll[i]).Clone(); + v2Coll.Remove(i); + return true; + } + } + i = -1; + } + finally + { + if (i != -1) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]")); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, nvp, i)); + } + } + return false; + } + + /// + /// Removes a selected name-value pair from the collection. + /// + /// Index of the pair to remove. + public void RemoveAt(int index) + { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException(nameof(index)); + NameValuePair nvp; + if (v2Coll != null) + { + nvp = new NameValuePair(v2Coll[index]).Clone(); + v2Coll.Remove(index); + } + else + { + nvp = unboundDict[index]; + unboundDict.RemoveAt(index); + } + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]")); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, nvp, index)); + } + + /// + /// Gets the value associated with the specified name. + /// + /// The name whose value to get. + /// When this method returns, the value associated with the specified name, if the name is found; otherwise, null. This parameter is passed uninitialized. + /// true if the collection contains an element with the specified name; otherwise, false. + public bool TryGetValue(string name, out string value) + { + if (v2Coll != null) + { + foreach (var item in this) + { + if (string.CompareOrdinal(item.Name, name) == 0) + { + value = item.Value; + return true; + } + } + value = null; + return false; + } + + var nvp = unboundDict.Find(p => p.Name == name); + value = nvp?.Value; + return nvp != null; + } + + /// + /// Gets the collection enumerator for the name-value collection. + /// + /// An for the collection. + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); + + bool ICollection.Contains(NameValuePair item) + { + if (v2Coll == null) + return unboundDict.Contains(item); + + foreach (var invp in this) + if (Equals(item, invp)) return true; + return false; + } + + void ICollection.CopyTo(NameValuePair[] array, int arrayIndex) + { + if (v2Coll == null) + unboundDict.CopyTo(array, arrayIndex); + else + { + if (array.Length - arrayIndex < v2Coll.Count) + throw new ArgumentException("Items in collection exceed available items in destination array."); + if (arrayIndex < 0) + throw new ArgumentException(@"Array index must be 0 or greater.", nameof(arrayIndex)); + for (var i = 0; i < v2Coll.Count; i++) + array[i + arrayIndex] = new NameValuePair(v2Coll[i]); + } + } + + bool ICollection.IsReadOnly => false; + + ICollection IDictionary.Keys => Names; + + bool ICollection>.IsReadOnly => false; + + bool ICollection.Remove(NameValuePair item) + { + var i = -1; + try + { + if (v2Coll == null) + { + if ((i = unboundDict.IndexOf(item)) != -1) + return unboundDict.Remove(item); + } + else + { + for (i = 0; i < v2Coll.Count; i++) + { + if (item.Equals(v2Coll[i])) + { + v2Coll.Remove(i); + return true; + } + } + } + i = -1; + } + finally + { + if (i != -1) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count))); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]")); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, i)); + } + } + return false; + } + + bool IDictionary.ContainsKey(string key) => Names.Contains(key); + + void ICollection>.Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + bool ICollection>.Contains(KeyValuePair item) => + ((ICollection)this).Contains(new NameValuePair(item.Key, item.Value)); + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + if (array.Length < Count + arrayIndex) + throw new ArgumentOutOfRangeException(nameof(array), @"Array has insufficient capacity to support copy."); + foreach (var item in ((IEnumerable>)this)) + array[arrayIndex++] = item; + } + + bool ICollection>.Remove(KeyValuePair item) => + ((ICollection)this).Remove(new NameValuePair(item.Key, item.Value)); + + IEnumerator> IEnumerable>.GetEnumerator() + { + foreach (var nvp in this) + yield return new KeyValuePair(nvp.Name, nvp.Value); + } + } +} diff --git a/FlashPatcher/TaskService/Native/ADVAPI32.cs b/FlashPatcher/TaskService/Native/ADVAPI32.cs new file mode 100644 index 0000000..e1be994 --- /dev/null +++ b/FlashPatcher/TaskService/Native/ADVAPI32.cs @@ -0,0 +1,363 @@ +using System; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; +using System.Text; + +namespace Microsoft.Win32 +{ + internal static partial class NativeMethods + { + const string ADVAPI32 = "advapi32.dll"; + + [Flags] + public enum AccessTypes : uint + { + TokenAssignPrimary = 0x0001, + TokenDuplicate = 0x0002, + TokenImpersonate = 0x0004, + TokenQuery = 0x0008, + TokenQuerySource = 0x0010, + TokenAdjustPrivileges = 0x0020, + TokenAdjustGroups = 0x0040, + TokenAdjustDefault = 0x0080, + TokenAdjustSessionID = 0x0100, + TokenAllAccessP = 0x000F00FF, + TokenAllAccess = 0x000F01FF, + TokenRead = 0x00020008, + TokenWrite = 0x000200E0, + TokenExecute = 0x00020000, + + Delete = 0x00010000, + ReadControl = 0x00020000, + WriteDac = 0x00040000, + WriteOwner = 0x00080000, + Synchronize = 0x00100000, + StandardRightsRequired = 0x000F0000, + StandardRightsRead = 0x00020000, + StandardRightsWrite = 0x00020000, + StandardRightsExecute = 0x00020000, + StandardRightsAll = 0x001F0000, + SpecificRightsAll = 0x0000FFFF, + AccessSystemSecurity = 0x01000000, + MaximumAllowed = 0x02000000, + GenericRead = 0x80000000, + GenericWrite = 0x40000000, + GenericExecute = 0x20000000, + GenericAll = 0x10000000, + } + + [Flags] + public enum PrivilegeAttributes : uint + { + Disabled = 0x00000000, + EnabledByDefault = 0x00000001, + Enabled = 0x00000002, + UsedForAccess = 0x80000000, + } + + public enum SECURITY_IMPERSONATION_LEVEL + { + Anonymous, + Identification, + Impersonation, + Delegation + } + + public enum TOKEN_ELEVATION_TYPE + { + Default = 1, + Full, + Limited + } + + public enum TOKEN_INFORMATION_CLASS + { + TokenUser = 1, + TokenGroups, + TokenPrivileges, + TokenOwner, + TokenPrimaryGroup, + TokenDefaultDacl, + TokenSource, + TokenType, + TokenImpersonationLevel, + TokenStatistics, + TokenRestrictedSids, + TokenSessionId, + TokenGroupsAndPrivileges, + TokenSessionReference, + TokenSandBoxInert, + TokenAuditPolicy, + TokenOrigin, + TokenElevationType, + TokenLinkedToken, + TokenElevation, + TokenHasRestrictions, + TokenAccessInformation, + TokenVirtualizationAllowed, + TokenVirtualizationEnabled, + TokenIntegrityLevel, + TokenUIAccess, + TokenMandatoryPolicy, + TokenLogonSid, + MaxTokenInfoClass + } + + [Serializable] + public enum TokenType + { + TokenImpersonation = 2, + TokenPrimary = 1 + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), DllImport(ADVAPI32, CharSet = CharSet.Unicode, SetLastError = true)] + public static extern bool AdjustTokenPrivileges([In] SafeTokenHandle TokenHandle, [In] bool DisableAllPrivileges, [In] ref TOKEN_PRIVILEGES NewState, [In] uint BufferLength, [In, Out] ref TOKEN_PRIVILEGES PreviousState, [In, Out] ref uint ReturnLength); + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), DllImport(ADVAPI32, CharSet = CharSet.Unicode, SetLastError = true)] + public static extern bool AdjustTokenPrivileges([In] SafeTokenHandle TokenHandle, [In] bool DisableAllPrivileges, [In] ref TOKEN_PRIVILEGES NewState, [In] uint BufferLength, [In] IntPtr PreviousState, [In] IntPtr ReturnLength); + + [DllImport(ADVAPI32, CharSet = CharSet.Auto, SetLastError = true)] + public static extern bool ConvertStringSidToSid([In, MarshalAs(UnmanagedType.LPTStr)] string pStringSid, ref IntPtr sid); + + [DllImport(ADVAPI32, CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public extern static bool DuplicateToken(SafeTokenHandle ExistingTokenHandle, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, out SafeTokenHandle DuplicateTokenHandle); + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), DllImport(ADVAPI32, CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DuplicateTokenEx([In] SafeTokenHandle ExistingTokenHandle, [In] AccessTypes DesiredAccess, [In] IntPtr TokenAttributes, [In] SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, [In] TokenType TokenType, [In, Out] ref SafeTokenHandle DuplicateTokenHandle); + + [DllImport(ADVAPI32, CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr GetSidSubAuthority(IntPtr pSid, UInt32 nSubAuthority); + + [DllImport(ADVAPI32, CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetTokenInformation(SafeTokenHandle hToken, TOKEN_INFORMATION_CLASS tokenInfoClass, IntPtr pTokenInfo, Int32 tokenInfoLength, out Int32 returnLength); + + [DllImport(ADVAPI32, ExactSpelling = true, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ImpersonateLoggedOnUser(IntPtr hToken); + + [DllImport(ADVAPI32, SetLastError = true, CharSet = CharSet.Unicode)] + public static extern int LogonUser(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken); + + [DllImport(ADVAPI32, CharSet = CharSet.Unicode, SetLastError = true)] + public static extern bool LookupAccountSid(string systemName, byte[] accountSid, StringBuilder accountName, ref int nameLength, StringBuilder domainName, ref int domainLength, out int accountType); + + [DllImport(ADVAPI32, CharSet = CharSet.Unicode, SetLastError = true)] + public static extern bool LookupAccountSid([In, MarshalAs(UnmanagedType.LPTStr)] string systemName, IntPtr sid, StringBuilder name, ref int cchName, StringBuilder referencedDomainName, ref int cchReferencedDomainName, out int use); + + [DllImport(ADVAPI32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool LookupPrivilegeValue(string systemName, string name, out LUID luid); + + [DllImport(ADVAPI32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool OpenProcessToken(IntPtr ProcessHandle, AccessTypes DesiredAccess, out SafeTokenHandle TokenHandle); + + [DllImport(ADVAPI32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool OpenThreadToken(IntPtr ThreadHandle, AccessTypes DesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool OpenAsSelf, out SafeTokenHandle TokenHandle); + + [DllImport(ADVAPI32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool PrivilegeCheck(IntPtr ClientToken, ref PRIVILEGE_SET RequiredPrivileges, out int result); + + [DllImport(ADVAPI32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool RevertToSelf(); + + [DllImport(ADVAPI32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetThreadToken(IntPtr ThreadHandle, SafeTokenHandle TokenHandle); + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LUID + { + public uint LowPart; + public int HighPart; + + public static LUID FromName(string name, string systemName = null) + { + LUID val; + if (!NativeMethods.LookupPrivilegeValue(systemName, name, out val)) + throw new System.ComponentModel.Win32Exception(); + return val; + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LUID_AND_ATTRIBUTES + { + public LUID Luid; + public PrivilegeAttributes Attributes; + + public LUID_AND_ATTRIBUTES(LUID luid, PrivilegeAttributes attr) + { + Luid = luid; + Attributes = attr; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct PRIVILEGE_SET : IDisposable + { + public uint PrivilegeCount; + public uint Control; + public IntPtr Privilege; + + public PRIVILEGE_SET(uint control, params LUID_AND_ATTRIBUTES[] privileges) + { + PrivilegeCount = (uint)privileges.Length; + Control = control; + Privilege = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES)) * (int)PrivilegeCount); + for (int i = 0; i < PrivilegeCount; i++) + Marshal.StructureToPtr(privileges[i], (IntPtr)((int)Privilege + (Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES)) * i)), false); + } + + public void Dispose() + { + Marshal.FreeHGlobal(Privilege); + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct SID_AND_ATTRIBUTES + { + public IntPtr Sid; + public UInt32 Attributes; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TOKEN_ELEVATION + { + public Int32 TokenIsElevated; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TOKEN_MANDATORY_LABEL + { + public SID_AND_ATTRIBUTES Label; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct TOKEN_PRIVILEGES + { + public uint PrivilegeCount; + public LUID_AND_ATTRIBUTES Privileges; + + public TOKEN_PRIVILEGES(LUID luid, PrivilegeAttributes attribute) + { + PrivilegeCount = 1; + Privileges.Luid = luid; + Privileges.Attributes = attribute; + } + + public static uint SizeInBytes => (uint)Marshal.SizeOf(typeof(TOKEN_PRIVILEGES)); + } + + public partial class SafeTokenHandle + { + private const Int32 ERROR_NO_TOKEN = 0x000003F0; + private const Int32 ERROR_INSUFFICIENT_BUFFER = 122; + private static SafeTokenHandle currentProcessToken = null; + + public T GetInfo(TOKEN_INFORMATION_CLASS type) + { + int cbSize = Marshal.SizeOf(typeof(T)); + IntPtr pType = Marshal.AllocHGlobal(cbSize); + + try + { + // Retrieve token information. + if (!NativeMethods.GetTokenInformation(this, type, pType, cbSize, out cbSize)) + throw new System.ComponentModel.Win32Exception(); + + // Marshal from native to .NET. + switch (type) + { + case TOKEN_INFORMATION_CLASS.TokenType: + case TOKEN_INFORMATION_CLASS.TokenImpersonationLevel: + case TOKEN_INFORMATION_CLASS.TokenSessionId: + case TOKEN_INFORMATION_CLASS.TokenSandBoxInert: + case TOKEN_INFORMATION_CLASS.TokenOrigin: + case TOKEN_INFORMATION_CLASS.TokenElevationType: + case TOKEN_INFORMATION_CLASS.TokenHasRestrictions: + case TOKEN_INFORMATION_CLASS.TokenUIAccess: + case TOKEN_INFORMATION_CLASS.TokenVirtualizationAllowed: + case TOKEN_INFORMATION_CLASS.TokenVirtualizationEnabled: + return (T)Convert.ChangeType(Marshal.ReadInt32(pType), typeof(T)); + + case TOKEN_INFORMATION_CLASS.TokenLinkedToken: + return (T)Convert.ChangeType(Marshal.ReadIntPtr(pType), typeof(T)); + + case TOKEN_INFORMATION_CLASS.TokenUser: + case TOKEN_INFORMATION_CLASS.TokenGroups: + case TOKEN_INFORMATION_CLASS.TokenPrivileges: + case TOKEN_INFORMATION_CLASS.TokenOwner: + case TOKEN_INFORMATION_CLASS.TokenPrimaryGroup: + case TOKEN_INFORMATION_CLASS.TokenDefaultDacl: + case TOKEN_INFORMATION_CLASS.TokenSource: + case TOKEN_INFORMATION_CLASS.TokenStatistics: + case TOKEN_INFORMATION_CLASS.TokenRestrictedSids: + case TOKEN_INFORMATION_CLASS.TokenGroupsAndPrivileges: + case TOKEN_INFORMATION_CLASS.TokenElevation: + case TOKEN_INFORMATION_CLASS.TokenAccessInformation: + case TOKEN_INFORMATION_CLASS.TokenIntegrityLevel: + case TOKEN_INFORMATION_CLASS.TokenMandatoryPolicy: + case TOKEN_INFORMATION_CLASS.TokenLogonSid: + return (T)Marshal.PtrToStructure(pType, typeof(T)); + + case TOKEN_INFORMATION_CLASS.TokenSessionReference: + case TOKEN_INFORMATION_CLASS.TokenAuditPolicy: + default: + return default(T); + } + } + finally + { + Marshal.FreeHGlobal(pType); + } + } + + public static SafeTokenHandle FromCurrentProcess(AccessTypes desiredAccess = AccessTypes.TokenDuplicate) + { + lock (currentProcessToken) + { + if (currentProcessToken == null) + currentProcessToken = FromProcess(NativeMethods.GetCurrentProcess(), desiredAccess); + return currentProcessToken; + } + } + + public static SafeTokenHandle FromCurrentThread(AccessTypes desiredAccess = AccessTypes.TokenDuplicate, bool openAsSelf = true) => FromThread(NativeMethods.GetCurrentThread(), desiredAccess, openAsSelf); + + public static SafeTokenHandle FromProcess(IntPtr hProcess, AccessTypes desiredAccess = AccessTypes.TokenDuplicate) + { + SafeTokenHandle val; + if (!NativeMethods.OpenProcessToken(hProcess, desiredAccess, out val)) + throw new System.ComponentModel.Win32Exception(); + return val; + } + + public static SafeTokenHandle FromThread(IntPtr hThread, AccessTypes desiredAccess = AccessTypes.TokenDuplicate, bool openAsSelf = true) + { + SafeTokenHandle val; + if (!NativeMethods.OpenThreadToken(hThread, desiredAccess, openAsSelf, out val)) + { + if (Marshal.GetLastWin32Error() == ERROR_NO_TOKEN) + { + SafeTokenHandle pval = FromCurrentProcess(); + if (!NativeMethods.DuplicateTokenEx(pval, AccessTypes.TokenImpersonate | desiredAccess, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.Impersonation, TokenType.TokenImpersonation, ref val)) + throw new System.ComponentModel.Win32Exception(); + if (!NativeMethods.SetThreadToken(IntPtr.Zero, val)) + throw new System.ComponentModel.Win32Exception(); + } + else + throw new System.ComponentModel.Win32Exception(); + } + return val; + } + } + } +} diff --git a/FlashPatcher/TaskService/Native/AccessControlExtension.cs b/FlashPatcher/TaskService/Native/AccessControlExtension.cs new file mode 100644 index 0000000..e68c356 --- /dev/null +++ b/FlashPatcher/TaskService/Native/AccessControlExtension.cs @@ -0,0 +1,89 @@ +using System.Linq; + +namespace System.Security.AccessControl +{ + /// Extensions for classes in the System.Security.AccessControl namespace. + public static class AccessControlExtension + { + /// Canonicalizes the specified Access Control List. + /// The Access Control List. + public static void Canonicalize(this RawAcl acl) + { + if (acl == null) throw new ArgumentNullException(nameof(acl)); + + // Extract aces to list + var aces = new Collections.Generic.List(acl.Cast()); + + // Sort aces based on canonical order + aces.Sort((a, b) => Collections.Generic.Comparer.Default.Compare(GetComparisonValue(a), GetComparisonValue(b))); + + // Add sorted aces back to ACL + while (acl.Count > 0) acl.RemoveAce(0); + var aceIndex = 0; + aces.ForEach(ace => acl.InsertAce(aceIndex++, ace)); + } + + /// Sort ACEs according to canonical form for this . + /// The object security whose DiscretionaryAcl will be made canonical. + public static void CanonicalizeAccessRules(this ObjectSecurity objectSecurity) + { + if (objectSecurity == null) throw new ArgumentNullException(nameof(objectSecurity)); + if (objectSecurity.AreAccessRulesCanonical) return; + + // Get raw SD from objectSecurity and canonicalize DACL + var sd = new RawSecurityDescriptor(objectSecurity.GetSecurityDescriptorBinaryForm(), 0); + sd.DiscretionaryAcl.Canonicalize(); + + // Convert SD back into objectSecurity + objectSecurity.SetSecurityDescriptorBinaryForm(sd.GetBinaryForm()); + } + + /// Returns an array of byte values that represents the information contained in this object. + /// The object. + /// The byte array into which the contents of the is marshaled. + public static byte[] GetBinaryForm(this GenericSecurityDescriptor sd) + { + if (sd == null) throw new ArgumentNullException(nameof(sd)); + var bin = new byte[sd.BinaryLength]; + sd.GetBinaryForm(bin, 0); + return bin; + } + + // A canonical ACL must have ACES sorted according to the following order: + // 1. Access-denied on the object + // 2. Access-denied on a child or property + // 3. Access-allowed on the object + // 4. Access-allowed on a child or property + // 5. All inherited ACEs + private static byte GetComparisonValue(GenericAce ace) + { + if ((ace.AceFlags & AceFlags.Inherited) != 0) + return 5; + switch (ace.AceType) + { + case AceType.AccessDenied: + case AceType.AccessDeniedCallback: + case AceType.SystemAudit: + case AceType.SystemAlarm: + case AceType.SystemAuditCallback: + case AceType.SystemAlarmCallback: + return 0; + case AceType.AccessDeniedObject: + case AceType.AccessDeniedCallbackObject: + case AceType.SystemAuditObject: + case AceType.SystemAlarmObject: + case AceType.SystemAuditCallbackObject: + case AceType.SystemAlarmCallbackObject: + return 1; + case AceType.AccessAllowed: + case AceType.AccessAllowedCallback: + return 2; + case AceType.AccessAllowedObject: + case AceType.AccessAllowedCallbackObject: + return 3; + default: + return 4; + } + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/EnumUtil.cs b/FlashPatcher/TaskService/Native/EnumUtil.cs new file mode 100644 index 0000000..814660c --- /dev/null +++ b/FlashPatcher/TaskService/Native/EnumUtil.cs @@ -0,0 +1,147 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; + +namespace System +{ + internal static class EnumUtil + { + public static void CheckIsEnum(bool checkHasFlags = false) + { + if (!typeof(T).IsEnum) + throw new ArgumentException($"Type '{typeof(T).FullName}' is not an enum"); + if (checkHasFlags && !IsFlags()) + throw new ArgumentException($"Type '{typeof(T).FullName}' doesn't have the 'Flags' attribute"); + } + + public static bool IsFlags() => Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)); + + public static void CheckHasValue(T value, string argName = null) + { + CheckIsEnum(); + if (IsFlags()) + { + var allFlags = 0L; + foreach (T flag in Enum.GetValues(typeof(T))) + allFlags |= Convert.ToInt64(flag); + if ((allFlags & Convert.ToInt64(value)) != 0L) + return; + } + else if (Enum.IsDefined(typeof(T), value)) + return; + throw new InvalidEnumArgumentException(argName ?? "value", Convert.ToInt32(value), typeof(T)); + } + + public static byte BitPosition(this T flags) where T : struct, IConvertible + { + CheckIsEnum(true); + var flagValue = Convert.ToInt64(flags); + if (flagValue == 0) throw new ArgumentException("The flag value is zero and has no bit position."); + var r = Math.Log(flagValue, 2); + if (r % 1 > 0) throw new ArithmeticException("The flag value has more than a single bit set."); + return Convert.ToByte(r); + } + + public static bool IsFlagSet(this T flags, T flag) where T : struct, IConvertible + { + CheckIsEnum(true); + var flagValue = Convert.ToInt64(flag); + return (Convert.ToInt64(flags) & flagValue) == flagValue; + } + + public static bool IsValidFlagValue(this T flags) where T : struct, IConvertible + { + CheckIsEnum(true); + var found = 0L; + foreach (T flag in Enum.GetValues(typeof(T))) + { + if (flags.IsFlagSet(flag)) + found |= Convert.ToInt64(flag); + } + return found == Convert.ToInt64(flags); + } + + public static void SetFlags(ref T flags, T flag, bool set = true) where T : struct, IConvertible + { + CheckIsEnum(true); + var flagsValue = Convert.ToInt64(flags); + var flagValue = Convert.ToInt64(flag); + if (set) + flagsValue |= flagValue; + else + flagsValue &= (~flagValue); + flags = (T)Enum.ToObject(typeof(T), flagsValue); + } + + public static T SetFlags(this T flags, T flag, bool set = true) where T : struct, IConvertible + { + var ret = flags; + SetFlags(ref ret, flag, set); + return ret; + } + + public static T ClearFlags(this T flags, T flag) where T : struct, IConvertible => flags.SetFlags(flag, false); + + public static IEnumerable GetFlags(this T value) where T : struct, IConvertible + { + CheckIsEnum(true); + foreach (T flag in Enum.GetValues(typeof(T))) + { + if (value.IsFlagSet(flag)) + yield return flag; + } + } + + public static T CombineFlags(this IEnumerable flags) where T : struct, IConvertible + { + CheckIsEnum(true); + long lValue = 0; + foreach (var flag in flags) + { + var lFlag = Convert.ToInt64(flag); + lValue |= lFlag; + } + return (T)Enum.ToObject(typeof(T), lValue); + } + + public static string GetDescription(this T value) where T : struct, IConvertible + { + CheckIsEnum(); + var name = Enum.GetName(typeof(T), value); + if (name != null) + { + var field = typeof(T).GetField(name); + if (field != null) + { + var attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute; + if (attr != null) + { + return attr.Description; + } + } + } + return null; + } + + /// + /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object or returns the value of . If is undefined, it returns the first declared item in the enumerated type. + /// + /// The enumeration type to which to convert . + /// The string representation of the enumeration name or underlying value to convert. + /// true to ignore case; false to consider case. + /// The default value. + /// An object of type whose value is represented by value. + public static TEnum TryParse(string value, bool ignoreCase = false, TEnum defaultVal = default(TEnum)) where TEnum : struct, IConvertible + { + CheckIsEnum(); + try { return (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase); } catch { } + if (!Enum.IsDefined(typeof(TEnum), defaultVal)) + { + var v = Enum.GetValues(typeof(TEnum)); + if (v != null && v.Length > 0) + return (TEnum)v.GetValue(0); + } + return defaultVal; + } + } +} diff --git a/FlashPatcher/TaskService/Native/EventLog.cs b/FlashPatcher/TaskService/Native/EventLog.cs new file mode 100644 index 0000000..ccc2ba9 --- /dev/null +++ b/FlashPatcher/TaskService/Native/EventLog.cs @@ -0,0 +1,5882 @@ +#if NET20 +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * Event methods and classes literally pulled from the .NET 4.0 implementation. + * None of this is original work. It comes straight from decompiled Microsoft + * assemblies. + * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +using Microsoft.Win32.SafeHandles; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.IO; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Security; +using System.Security.Permissions; +using System.Security.Principal; +using System.Text; +using System.Threading; + +namespace System.Diagnostics.Eventing.Reader +{ + /// + public enum EventLogIsolation + { + /// The application + Application, + + /// The system + System, + + /// The custom + Custom + } + + /// + public enum EventLogMode + { + /// The circular + Circular, + + /// The automatic backup + AutoBackup, + + /// The retain + Retain + } + + /// + public enum EventLogType + { + /// The administrative + Administrative, + + /// The operational + Operational, + + /// The analytical + Analytical, + + /// The debug + Debug + } + + /// PathType + public enum PathType + { + /// The file path + FilePath = 2, + + /// The log name + LogName = 1 + } + + /// SessionAuthentication + public enum SessionAuthentication + { + /// The default + Default, + + /// The negotiate + Negotiate, + + /// The kerberos + Kerberos, + + /// The NTLM + Ntlm + } + + /// Defines the standard keywords that are attached to events by the event provider. For more information about keywords, see . + [Flags] + public enum StandardEventKeywords : long + { + /// The audit failure + AuditFailure = 0x10000000000000L, + + /// The audit success + AuditSuccess = 0x20000000000000L, + + /// The correlation hint + [Obsolete("Incorrect value: use CorrelationHint2 instead", false)] + CorrelationHint = 0x10000000000000L, + + /// The correlation hint2 + CorrelationHint2 = 0x40000000000000L, + + /// The event log classic + EventLogClassic = 0x80000000000000L, + + /// The none + None = 0L, + + /// The response time + ResponseTime = 0x01000000000000L, + + /// The SQM + Sqm = 0x08000000000000L, + + /// The wdi context + WdiContext = 0x02000000000000L, + + /// The wdi diagnostic + WdiDiagnostic = 0x04000000000000L + } + + /// + /// Represents a placeholder (bookmark) within an event stream. You can use the placeholder to mark a position and return to this position in a stream of + /// events. An instance of this object can be obtained from an EventRecord object, in which case it corresponds to the position of that event record. + /// + [Serializable] + public class EventBookmark : ISerializable + { + // Fields + private string bookmark; + + // Methods + internal EventBookmark(string bookmarkText) + { + if (bookmarkText == null) + { + throw new ArgumentNullException(nameof(bookmarkText)); + } + bookmark = bookmarkText; + } + + /// Initializes a new instance of the class. + /// The information. + /// The context. + protected EventBookmark(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + bookmark = info.GetString("BookmarkText"); + } + + // Properties + internal string BookmarkText => bookmark; + + [SecurityCritical, SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)] + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + GetObjectData(info, context); + } + + /// Gets the object data. + /// The information. + /// The context. + [SecurityCritical, SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)] + protected virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + info.AddValue("BookmarkText", bookmark); + } + } + + /// + /// Represents a keyword for an event. Keywords are defined in an event provider and are used to group the event with other similar events (based on the + /// usage of the events). + /// + public sealed class EventKeyword + { + // Fields + private bool dataReady; + + private string displayName; + private string name; + private ProviderMetadata pmReference; + private object syncObject; + private long value; + + // Methods + internal EventKeyword(long value, ProviderMetadata pmReference) + { + this.value = value; + this.pmReference = pmReference; + syncObject = new object(); + } + + internal EventKeyword(string name, long value, string displayName) + { + this.value = value; + this.name = name; + this.displayName = displayName; + dataReady = true; + syncObject = new object(); + } + + // Properties + /// Gets the display name. + /// The display name. + public string DisplayName + { + get + { + PrepareData(); + return displayName; + } + } + + /// Gets the name. + /// The name. + public string Name + { + get + { + PrepareData(); + return name; + } + } + + /// Gets the value. + /// The value. + public long Value => value; + + internal void PrepareData() + { + if (!dataReady) + { + lock (syncObject) + { + if (!dataReady) + { + IEnumerable keywords = pmReference.Keywords; + name = null; + displayName = null; + dataReady = true; + foreach (EventKeyword keyword in keywords) + { + if (keyword.Value == value) + { + name = keyword.Name; + displayName = keyword.DisplayName; + break; + } + } + } + } + } + } + } + + /// Contains an event level that is defined in an event provider. The level signifies the severity of the event. + public sealed class EventLevel + { + // Fields + private bool dataReady; + + private string displayName; + private string name; + private ProviderMetadata pmReference; + private object syncObject; + private int value; + + // Methods + internal EventLevel(int value, ProviderMetadata pmReference) + { + this.value = value; + this.pmReference = pmReference; + syncObject = new object(); + } + + internal EventLevel(string name, int value, string displayName) + { + this.value = value; + this.name = name; + this.displayName = displayName; + dataReady = true; + syncObject = new object(); + } + + // Properties + /// Gets the display name. + /// The display name. + public string DisplayName + { + get + { + PrepareData(); + return displayName; + } + } + + /// Gets the name. + /// The name. + public string Name + { + get + { + PrepareData(); + return name; + } + } + + /// Gets the value. + /// The value. + public int Value => value; + + internal void PrepareData() + { + if (!dataReady) + { + lock (syncObject) + { + if (!dataReady) + { + IEnumerable levels = pmReference.Levels; + name = null; + displayName = null; + dataReady = true; + foreach (EventLevel level in levels) + { + if (level.Value == value) + { + name = level.Name; + displayName = level.DisplayName; + break; + } + } + } + } + } + } + } + + /// EventLogConfiguration + public class EventLogConfiguration : IDisposable + { + private string channelName; + private EventLogHandle handle; + private EventLogSession session; + + /// Initializes a new instance of the class. + /// Name of the log. + public EventLogConfiguration(string logName) : this(logName, null) { } + + /// Initializes a new instance of the class. + /// Name of the log. + /// The session. + [SecurityCritical] + public EventLogConfiguration(string logName, EventLogSession session) + { + handle = EventLogHandle.Zero; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + if (session == null) + { + session = EventLogSession.GlobalSession; + } + this.session = session; + channelName = logName; + handle = NativeWrapper.EvtOpenChannelConfig(this.session.Handle, channelName, 0); + } + + // Properties + /// Gets a value indicating whether this instance is classic log. + /// true if this instance is classic log; otherwise, false. + public bool IsClassicLog => (bool)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigClassicEventlog); + + /// Gets or sets a value indicating whether this instance is enabled. + /// true if this instance is enabled; otherwise, false. + public bool IsEnabled + { + get + { + return (bool)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigEnabled); + } + set + { + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigEnabled, value); + } + } + + /// Gets or sets the log file path. + /// The log file path. + public string LogFilePath + { + get + { + return (string)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigLogFilePath); + } + set + { + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigLogFilePath, value); + } + } + + /// Gets the log isolation. + /// The log isolation. + public EventLogIsolation LogIsolation => (EventLogIsolation)((uint)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigIsolation)); + + /// Gets or sets the log mode. + /// The log mode. + public EventLogMode LogMode + { + get + { + object obj2 = NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention); + object obj3 = NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup); + bool flag = (obj2 != null) && ((bool)obj2); + if ((obj3 != null) && ((bool)obj3)) + { + return EventLogMode.AutoBackup; + } + if (flag) + { + return EventLogMode.Retain; + } + return EventLogMode.Circular; + } + set + { + switch (value) + { + case EventLogMode.Circular: + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup, false); + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention, false); + return; + + case EventLogMode.AutoBackup: + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup, true); + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention, true); + return; + + case EventLogMode.Retain: + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup, false); + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention, true); + return; + } + } + } + + /// Gets the name of the log. + /// The name of the log. + public string LogName => channelName; + + /// Gets the type of the log. + /// The type of the log. + public EventLogType LogType => (EventLogType)((uint)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigType)); + + /// Gets or sets the maximum size in bytes. + /// The maximum size in bytes. + public long MaximumSizeInBytes + { + get + { + return (long)((ulong)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigMaxSize)); + } + set + { + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigMaxSize, value); + } + } + + /// Gets the name of the owning provider. + /// The name of the owning provider. + public string OwningProviderName => (string)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigOwningPublisher); + + /// Gets the size of the provider buffer. + /// The size of the provider buffer. + public int? ProviderBufferSize + { + get + { + uint? nullable = (uint?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigBufferSize); + if (!nullable.HasValue) + { + return null; + } + return new int?((int)nullable.GetValueOrDefault()); + } + } + + /// Gets the provider control unique identifier. + /// The provider control unique identifier. + public Guid? ProviderControlGuid => (Guid?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigControlGuid); + + /// Gets or sets the provider keywords. + /// The provider keywords. + public long? ProviderKeywords + { + get + { + ulong? nullable = (ulong?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigKeywords); + if (!nullable.HasValue) + { + return null; + } + return new long?((long)nullable.GetValueOrDefault()); + } + set + { + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigKeywords, value); + } + } + + /// Gets the provider latency. + /// The provider latency. + public int? ProviderLatency + { + get + { + uint? nullable = (uint?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigLatency); + if (!nullable.HasValue) + { + return null; + } + return new int?((int)nullable.GetValueOrDefault()); + } + } + + /// Gets or sets the provider level. + /// The provider level. + public int? ProviderLevel + { + get + { + uint? nullable = (uint?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigLevel); + if (!nullable.HasValue) + { + return null; + } + return new int?((int)nullable.GetValueOrDefault()); + } + set + { + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigLevel, value); + } + } + + /// Gets the provider maximum number of buffers. + /// The provider maximum number of buffers. + public int? ProviderMaximumNumberOfBuffers + { + get + { + uint? nullable = (uint?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigMaxBuffers); + if (!nullable.HasValue) + { + return null; + } + return new int?((int)nullable.GetValueOrDefault()); + } + } + + /// Gets the provider minimum number of buffers. + /// The provider minimum number of buffers. + public int? ProviderMinimumNumberOfBuffers + { + get + { + uint? nullable = (uint?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigMinBuffers); + if (!nullable.HasValue) + { + return null; + } + return new int?((int)nullable.GetValueOrDefault()); + } + } + + /// Gets the provider names. + /// The provider names. + public IEnumerable ProviderNames => (string[])NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublisherList); + + /// Gets or sets the security descriptor. + /// The security descriptor. + public string SecurityDescriptor + { + get + { + return (string)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigAccess); + } + set + { + NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigAccess, value); + } + } + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// Saves the changes. + public void SaveChanges() + { + NativeWrapper.EvtSaveChannelConfig(handle, 0); + } + + /// Releases unmanaged and - optionally - managed resources. + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + [SecuritySafeCritical] + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + } + if ((handle != null) && !handle.IsInvalid) + { + handle.Dispose(); + } + } + } + + /// + /// Allows you to access the run-time properties of active event logs and event log files. These properties include the number of events in the log, the size of the log, a value that determines whether the log is full, and the last time the log was written to or accessed. + /// + public sealed class EventLogInformation + { + // Fields + private DateTime? creationTime; + + private int? fileAttributes; + private long? fileSize; + private bool? isLogFull; + private DateTime? lastAccessTime; + private DateTime? lastWriteTime; + private long? oldestRecordNumber; + private long? recordCount; + + // Methods + [SecurityCritical] + internal EventLogInformation(EventLogSession session, string channelName, PathType pathType) + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + EventLogHandle handle = NativeWrapper.EvtOpenLog(session.Handle, channelName, pathType); + using (handle) + { + creationTime = (DateTime?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogCreationTime); + lastAccessTime = (DateTime?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogLastAccessTime); + lastWriteTime = (DateTime?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogLastWriteTime); + ulong? nullable = (ulong?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogFileSize); + fileSize = nullable.HasValue ? (long?)(nullable.GetValueOrDefault()) : null; + uint? nullable3 = (uint?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogAttributes); + fileAttributes = nullable3.HasValue ? (int?)(nullable3.GetValueOrDefault()) : null; + ulong? nullable5 = (ulong?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogNumberOfLogRecords); + recordCount = nullable5.HasValue ? (long?)(nullable5.GetValueOrDefault()) : null; + ulong? nullable7 = (ulong?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogOldestRecordNumber); + oldestRecordNumber = nullable7.HasValue ? (long?)(nullable7.GetValueOrDefault()) : null; + isLogFull = (bool?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogFull); + } + } + + // Properties + /// Gets the attributes. + /// The attributes. + public int? Attributes => fileAttributes; + + /// Gets the creation time. + /// The creation time. + public DateTime? CreationTime => creationTime; + + /// Gets the size of the file. + /// The size of the file. + public long? FileSize => fileSize; + + /// Gets the is log full. + /// The is log full. + public bool? IsLogFull => isLogFull; + + /// Gets the last access time. + /// The last access time. + public DateTime? LastAccessTime => lastAccessTime; + + /// Gets the last write time. + /// The last write time. + public DateTime? LastWriteTime => lastWriteTime; + + /// Gets the oldest record number. + /// The oldest record number. + public long? OldestRecordNumber => oldestRecordNumber; + + /// Gets the record count. + /// The record count. + public long? RecordCount => recordCount; + } + + /// + /// Represents a link between an event provider and an event log that the provider publishes events into. This object cannot be instantiated. + /// + public sealed class EventLogLink + { + // Fields + private uint channelId; + + private string channelName; + private bool dataReady; + private string displayName; + private bool isImported; + private ProviderMetadata pmReference; + private object syncObject; + + // Methods + internal EventLogLink(uint channelId, ProviderMetadata pmReference) + { + this.channelId = channelId; + this.pmReference = pmReference; + syncObject = new object(); + } + + internal EventLogLink(string channelName, bool isImported, string displayName, uint channelId) + { + this.channelName = channelName; + this.isImported = isImported; + this.displayName = displayName; + this.channelId = channelId; + dataReady = true; + syncObject = new object(); + } + + /// Gets the display name. + /// The display name. + public string DisplayName + { + get + { + PrepareData(); + return displayName; + } + } + + /// Gets a value indicating whether this instance is imported. + /// true if this instance is imported; otherwise, false. + public bool IsImported + { + get + { + PrepareData(); + return isImported; + } + } + + /// Gets the name of the log. + /// The name of the log. + public string LogName + { + get + { + PrepareData(); + return channelName; + } + } + + // Properties + internal uint ChannelId => channelId; + + private void PrepareData() + { + if (!dataReady) + { + lock (syncObject) + { + if (!dataReady) + { + IEnumerable logLinks = pmReference.LogLinks; + channelName = null; + isImported = false; + displayName = null; + dataReady = true; + foreach (EventLogLink link in logLinks) + { + if (link.ChannelId == channelId) + { + channelName = link.LogName; + isImported = link.IsImported; + displayName = link.DisplayName; + dataReady = true; + break; + } + } + } + } + } + } + } + + /// + /// Contains an array of strings that represent XPath queries for elements in the XML representation of an event, which is based on the Event Schema. The queries in this object are used to extract values from the event. + /// + /// + public class EventLogPropertySelector : IDisposable + { + // Fields + private EventLogHandle renderContextHandleValues; + + // Methods + /// Initializes a new instance of the class. + /// The property queries. + [SecurityCritical] + public EventLogPropertySelector(IEnumerable propertyQueries) + { + string[] strArray; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + if (propertyQueries == null) + { + throw new ArgumentNullException(nameof(propertyQueries)); + } + ICollection is2 = propertyQueries as ICollection; + if (is2 != null) + { + strArray = new string[is2.Count]; + is2.CopyTo(strArray, 0); + } + else + { + strArray = new List(propertyQueries).ToArray(); + } + renderContextHandleValues = NativeWrapper.EvtCreateRenderContext(strArray.Length, strArray, UnsafeNativeMethods.EvtRenderContextFlags.EvtRenderContextValues); + } + + // Properties + internal EventLogHandle Handle => renderContextHandleValues; + + /// Releases unmanaged and - optionally - managed resources. + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// Releases unmanaged and - optionally - managed resources. + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + [SecurityCritical] + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + } + if ((renderContextHandleValues != null) && !renderContextHandleValues.IsInvalid) + { + renderContextHandleValues.Dispose(); + } + } + } + + /// + /// Contains the properties of an event instance for an event that is received from an EventLogReader object. The event properties provide information about the event such as the name of the computer where the event was logged and the time that the event was created. + /// + /// + public class EventLogRecord : EventRecord + { + private const int SYSTEM_PROPERTY_COUNT = 0x12; + + private ProviderMetadataCachedInformation cachedMetadataInformation; + private string containerChannel; + + private EventLogHandle handle; + private IEnumerable keywordsNames; + private string levelName; + private bool levelNameReady; + private int[] matchedQueryIds; + private string opcodeName; + private bool opcodeNameReady; + private EventLogSession session; + private object syncObject; + private NativeWrapper.SystemProperties systemProperties; + private string taskName; + private bool taskNameReady; + + internal EventLogRecord(EventLogHandle handle, EventLogSession session, ProviderMetadataCachedInformation cachedMetadataInfo) + { + cachedMetadataInformation = cachedMetadataInfo; + this.handle = handle; + this.session = session; + systemProperties = new NativeWrapper.SystemProperties(); + syncObject = new object(); + } + + /// Gets the activity identifier. + /// The activity identifier. + public override Guid? ActivityId + { + get + { + PrepareSystemData(); + return systemProperties.ActivityId; + } + } + + /// Gets the bookmark. + /// The bookmark. + public override EventBookmark Bookmark + { + [SecurityCritical] + get + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + EventLogHandle bookmark = NativeWrapper.EvtCreateBookmark(null); + NativeWrapper.EvtUpdateBookmark(bookmark, handle); + return new EventBookmark(NativeWrapper.EvtRenderBookmark(bookmark)); + } + } + + /// Gets the container log. + /// The container log. + public string ContainerLog + { + get + { + if (containerChannel != null) + { + return containerChannel; + } + lock (syncObject) + { + if (containerChannel == null) + { + containerChannel = (string)NativeWrapper.EvtGetEventInfo(Handle, UnsafeNativeMethods.EvtEventPropertyId.EvtEventPath); + } + return containerChannel; + } + } + } + + /// Gets the identifier. + /// The identifier. + public override int Id + { + get + { + PrepareSystemData(); + ushort? id = systemProperties.Id; + int? nullable3 = id.HasValue ? new int?(id.GetValueOrDefault()) : null; + if (!nullable3.HasValue) + { + return 0; + } + return systemProperties.Id.Value; + } + } + + /// Gets the keywords. + /// The keywords. + public override long? Keywords + { + get + { + PrepareSystemData(); + ulong? keywords = systemProperties.Keywords; + if (!keywords.HasValue) + { + return null; + } + return (long)(keywords.GetValueOrDefault()); + } + } + + /// Gets the keywords display names. + /// The keywords display names. + public override IEnumerable KeywordsDisplayNames + { + get + { + if (keywordsNames != null) + { + return keywordsNames; + } + lock (syncObject) + { + if (keywordsNames == null) + { + keywordsNames = cachedMetadataInformation.GetKeywordDisplayNames(ProviderName, handle); + } + return keywordsNames; + } + } + } + + /// Gets the level. + /// The level. + public override byte? Level + { + get + { + PrepareSystemData(); + return systemProperties.Level; + } + } + + /// Gets the display name of the level. + /// The display name of the level. + public override string LevelDisplayName + { + get + { + if (levelNameReady) + { + return levelName; + } + lock (syncObject) + { + if (!levelNameReady) + { + levelNameReady = true; + levelName = cachedMetadataInformation.GetLevelDisplayName(ProviderName, handle); + } + return levelName; + } + } + } + + /// Gets the name of the log. + /// The name of the log. + public override string LogName + { + get + { + PrepareSystemData(); + return systemProperties.ChannelName; + } + } + + /// Gets the name of the machine. + /// The name of the machine. + public override string MachineName + { + get + { + PrepareSystemData(); + return systemProperties.ComputerName; + } + } + + /// Gets the matched query ids. + /// The matched query ids. + public IEnumerable MatchedQueryIds + { + get + { + if (matchedQueryIds != null) + { + return matchedQueryIds; + } + lock (syncObject) + { + if (matchedQueryIds == null) + { + matchedQueryIds = (int[])NativeWrapper.EvtGetEventInfo(Handle, UnsafeNativeMethods.EvtEventPropertyId.EvtEventQueryIDs); + } + return matchedQueryIds; + } + } + } + + /// Gets the opcode. + /// The opcode. + public override short? Opcode + { + get + { + PrepareSystemData(); + byte? opcode = systemProperties.Opcode; + ushort? nullable3 = opcode.HasValue ? new ushort?(opcode.GetValueOrDefault()) : null; + if (!nullable3.HasValue) + { + return null; + } + return new short?((short)nullable3.GetValueOrDefault()); + } + } + + /// Gets the display name of the opcode. + /// The display name of the opcode. + public override string OpcodeDisplayName + { + get + { + lock (syncObject) + { + if (!opcodeNameReady) + { + opcodeNameReady = true; + opcodeName = cachedMetadataInformation.GetOpcodeDisplayName(ProviderName, handle); + } + return opcodeName; + } + } + } + + /// Gets the process identifier. + /// The process identifier. + public override int? ProcessId + { + get + { + PrepareSystemData(); + uint? processId = systemProperties.ProcessId; + if (!processId.HasValue) + { + return null; + } + return (int)processId.GetValueOrDefault(); + } + } + + /// Gets the properties. + /// The properties. + public override IList Properties + { + get + { + session.SetupUserContext(); + IList list = NativeWrapper.EvtRenderBufferWithContextUserOrValues(session.renderContextHandleUser, handle); + List list2 = new List(); + foreach (object obj2 in list) + { + list2.Add(new EventProperty(obj2)); + } + return list2; + } + } + + /// Gets the provider identifier. + /// The provider identifier. + public override Guid? ProviderId + { + get + { + PrepareSystemData(); + return systemProperties.ProviderId; + } + } + + /// Gets the name of the provider. + /// The name of the provider. + public override string ProviderName + { + get + { + PrepareSystemData(); + return systemProperties.ProviderName; + } + } + + /// Gets the qualifiers. + /// The qualifiers. + public override int? Qualifiers + { + get + { + PrepareSystemData(); + ushort? qualifiers = systemProperties.Qualifiers; + uint? nullable3 = qualifiers.HasValue ? new uint?(qualifiers.GetValueOrDefault()) : null; + if (!nullable3.HasValue) + { + return null; + } + return (int)(nullable3.GetValueOrDefault()); + } + } + + /// Gets the record identifier. + /// The record identifier. + public override long? RecordId + { + get + { + PrepareSystemData(); + ulong? recordId = systemProperties.RecordId; + if (!recordId.HasValue) + { + return null; + } + return (long)(recordId.GetValueOrDefault()); + } + } + + /// Gets the related activity identifier. + /// The related activity identifier. + public override Guid? RelatedActivityId + { + get + { + PrepareSystemData(); + return systemProperties.RelatedActivityId; + } + } + + /// Gets the task. + /// The task. + public override int? Task + { + get + { + PrepareSystemData(); + ushort? task = systemProperties.Task; + uint? nullable3 = task.HasValue ? new uint?(task.GetValueOrDefault()) : null; + if (!nullable3.HasValue) + { + return null; + } + return (int)(nullable3.GetValueOrDefault()); + } + } + + /// Gets the display name of the task. + /// The display name of the task. + public override string TaskDisplayName + { + get + { + if (taskNameReady) + { + return taskName; + } + lock (syncObject) + { + if (!taskNameReady) + { + taskNameReady = true; + taskName = cachedMetadataInformation.GetTaskDisplayName(ProviderName, handle); + } + return taskName; + } + } + } + + /// Gets the thread identifier. + /// The thread identifier. + public override int? ThreadId + { + get + { + PrepareSystemData(); + uint? threadId = systemProperties.ThreadId; + if (!threadId.HasValue) + { + return null; + } + return (int)(threadId.GetValueOrDefault()); + } + } + + /// Gets the time created. + /// The time created. + public override DateTime? TimeCreated + { + get + { + PrepareSystemData(); + return systemProperties.TimeCreated; + } + } + + /// Gets the user identifier. + /// The user identifier. + public override SecurityIdentifier UserId + { + get + { + PrepareSystemData(); + return systemProperties.UserId; + } + } + + /// Gets the version. + /// The version. + public override byte? Version + { + get + { + PrepareSystemData(); + return systemProperties.Version; + } + } + + internal EventLogHandle Handle + { + get + { + return handle; + } + } + + /// Formats the description. + /// + public override string FormatDescription() => cachedMetadataInformation.GetFormatDescription(ProviderName, handle); + + /// Formats the description. + /// The values. + /// + public override string FormatDescription(IEnumerable values) + { + if (values == null) + { + return FormatDescription(); + } + string[] array = new string[0]; + int index = 0; + foreach (object obj2 in values) + { + if (array.Length == index) + { + Array.Resize(ref array, index + 1); + } + array[index] = obj2.ToString(); + index++; + } + return cachedMetadataInformation.GetFormatDescription(ProviderName, handle, array); + } + + /// Gets the property values. + /// The property selector. + /// + public IList GetPropertyValues(EventLogPropertySelector propertySelector) + { + if (propertySelector == null) + { + throw new ArgumentNullException(nameof(propertySelector)); + } + return NativeWrapper.EvtRenderBufferWithContextUserOrValues(propertySelector.Handle, handle); + } + + /// To the XML. + /// + [SecurityCritical] + public override string ToXml() + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + StringBuilder buffer = new StringBuilder(0x7d0); + NativeWrapper.EvtRender(EventLogHandle.Zero, handle, UnsafeNativeMethods.EvtRenderFlags.EvtRenderEventXml, buffer); + return buffer.ToString(); + } + + [SecurityCritical] + internal static EventLogHandle GetBookmarkHandleFromBookmark(EventBookmark bookmark) + { + if (bookmark == null) + { + return EventLogHandle.Zero; + } + return NativeWrapper.EvtCreateBookmark(bookmark.BookmarkText); + } + + internal void PrepareSystemData() + { + if (!systemProperties.filled) + { + session.SetupSystemContext(); + lock (syncObject) + { + if (!systemProperties.filled) + { + NativeWrapper.EvtRenderBufferWithContextSystem(session.renderContextHandleSystem, handle, UnsafeNativeMethods.EvtRenderFlags.EvtRenderEventValues, systemProperties, 0x12); + systemProperties.filled = true; + } + } + } + } + + /// Releases unmanaged and - optionally - managed resources. + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + [SecurityCritical] + protected override void Dispose(bool disposing) + { + try + { + if (disposing) + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + } + if ((handle != null) && !handle.IsInvalid) + { + handle.Dispose(); + } + } + finally + { + } + } + } + + /// + /// Enables you to read events from an event log based on an event query. The events that are read by this object are returned as EventRecord objects. + /// + /// + public class EventLogSession : IDisposable + { + internal EventLogHandle renderContextHandleSystem; + + internal EventLogHandle renderContextHandleUser; + + private static EventLogSession globalSession = new EventLogSession(); + + // Fields + private string domain; + + private EventLogHandle handle; + private SessionAuthentication logOnType; + private string server; + private object syncObject; + private string user; + + // Methods + /// Initializes a new instance of the class. + [SecurityCritical] + public EventLogSession() + { + renderContextHandleSystem = EventLogHandle.Zero; + renderContextHandleUser = EventLogHandle.Zero; + handle = EventLogHandle.Zero; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + syncObject = new object(); + } + + /// Initializes a new instance of the class. + /// The server. + public EventLogSession(string server) + : this(server, null, null, null, SessionAuthentication.Default) + { + } + + /// Initializes a new instance of the class. + /// The server. + /// The domain. + /// The user. + /// The password. + /// Type of the log on. + [SecurityCritical] + public EventLogSession(string server, string domain, string user, SecureString password, SessionAuthentication logOnType) + { + renderContextHandleSystem = EventLogHandle.Zero; + renderContextHandleUser = EventLogHandle.Zero; + handle = EventLogHandle.Zero; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + if (server == null) + { + server = "localhost"; + } + syncObject = new object(); + this.server = server; + this.domain = domain; + this.user = user; + this.logOnType = logOnType; + UnsafeNativeMethods.EvtRpcLogin login = new UnsafeNativeMethods.EvtRpcLogin(); + login.Server = this.server; + login.User = this.user; + login.Domain = this.domain; + login.Flags = (int)this.logOnType; + login.Password = CoTaskMemUnicodeSafeHandle.Zero; + try + { + if (password != null) + { + login.Password.SetMemory(Marshal.SecureStringToCoTaskMemUnicode(password)); + } + handle = NativeWrapper.EvtOpenSession(UnsafeNativeMethods.EvtLoginClass.EvtRpcLogin, ref login, 0, 0); + } + finally + { + login.Password.Close(); + } + } + + // Properties + /// Gets the global session. + /// The global session. + public static EventLogSession GlobalSession => globalSession; + + internal EventLogHandle Handle => handle; + + /// Cancels the current operations. + public void CancelCurrentOperations() + { + NativeWrapper.EvtCancel(handle); + } + + /// Clears the log. + /// Name of the log. + public void ClearLog(string logName) + { + ClearLog(logName, null); + } + + /// Clears the log. + /// Name of the log. + /// The backup path. + /// logName + public void ClearLog(string logName, string backupPath) + { + if (logName == null) + { + throw new ArgumentNullException(nameof(logName)); + } + NativeWrapper.EvtClearLog(Handle, logName, backupPath, 0); + } + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// Exports the log. + /// The path. + /// Type of the path. + /// The query. + /// The target file path. + public void ExportLog(string path, PathType pathType, string query, string targetFilePath) + { + ExportLog(path, pathType, query, targetFilePath, false); + } + + /// Exports the log. + /// The path. + /// Type of the path. + /// The query. + /// The target file path. + /// if set to true [tolerate query errors]. + /// path or targetFilePath + /// pathType + public void ExportLog(string path, PathType pathType, string query, string targetFilePath, bool tolerateQueryErrors) + { + UnsafeNativeMethods.EvtExportLogFlags evtExportLogChannelPath; + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + if (targetFilePath == null) + { + throw new ArgumentNullException(nameof(targetFilePath)); + } + switch (pathType) + { + case PathType.LogName: + evtExportLogChannelPath = UnsafeNativeMethods.EvtExportLogFlags.EvtExportLogChannelPath; + break; + + case PathType.FilePath: + evtExportLogChannelPath = UnsafeNativeMethods.EvtExportLogFlags.EvtExportLogFilePath; + break; + + default: + throw new ArgumentOutOfRangeException(nameof(pathType)); + } + if (!tolerateQueryErrors) + { + NativeWrapper.EvtExportLog(Handle, path, query, targetFilePath, (int)evtExportLogChannelPath); + } + else + { + NativeWrapper.EvtExportLog(Handle, path, query, targetFilePath, ((int)evtExportLogChannelPath) | 0x1000); + } + } + + /// Exports the log and messages. + /// The path. + /// Type of the path. + /// The query. + /// The target file path. + public void ExportLogAndMessages(string path, PathType pathType, string query, string targetFilePath) + { + ExportLogAndMessages(path, pathType, query, targetFilePath, false, CultureInfo.CurrentCulture); + } + + /// Exports the log and messages. + /// The path. + /// Type of the path. + /// The query. + /// The target file path. + /// if set to true [tolerate query errors]. + /// The target culture information. + public void ExportLogAndMessages(string path, PathType pathType, string query, string targetFilePath, bool tolerateQueryErrors, CultureInfo targetCultureInfo) + { + if (targetCultureInfo == null) + { + targetCultureInfo = CultureInfo.CurrentCulture; + } + ExportLog(path, pathType, query, targetFilePath, tolerateQueryErrors); + NativeWrapper.EvtArchiveExportedLog(Handle, targetFilePath, targetCultureInfo.LCID, 0); + } + + /// Gets the log information. + /// Name of the log. + /// Type of the path. + /// + /// logName + public EventLogInformation GetLogInformation(string logName, PathType pathType) + { + if (logName == null) + { + throw new ArgumentNullException(nameof(logName)); + } + return new EventLogInformation(this, logName, pathType); + } + + /// Gets the log names. + /// + [SecurityCritical] + public IEnumerable GetLogNames() + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + List list = new List(100); + using (EventLogHandle handle = NativeWrapper.EvtOpenChannelEnum(Handle, 0)) + { + bool finish = false; + do + { + string item = NativeWrapper.EvtNextChannelPath(handle, ref finish); + if (!finish) + { + list.Add(item); + } + } + while (!finish); + return list; + } + } + + /// Gets the provider names. + /// + [SecurityCritical] + public IEnumerable GetProviderNames() + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + List list = new List(100); + using (EventLogHandle handle = NativeWrapper.EvtOpenProviderEnum(Handle, 0)) + { + bool finish = false; + do + { + string item = NativeWrapper.EvtNextPublisherId(handle, ref finish); + if (!finish) + { + list.Add(item); + } + } + while (!finish); + return list; + } + } + + [SecurityCritical] + internal void SetupSystemContext() + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + if (renderContextHandleSystem.IsInvalid) + { + lock (syncObject) + { + if (renderContextHandleSystem.IsInvalid) + { + renderContextHandleSystem = NativeWrapper.EvtCreateRenderContext(0, null, UnsafeNativeMethods.EvtRenderContextFlags.EvtRenderContextSystem); + } + } + } + } + + [SecurityCritical] + internal void SetupUserContext() + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + lock (syncObject) + { + if (renderContextHandleUser.IsInvalid) + { + renderContextHandleUser = NativeWrapper.EvtCreateRenderContext(0, null, UnsafeNativeMethods.EvtRenderContextFlags.EvtRenderContextUser); + } + } + } + + /// Releases unmanaged and - optionally - managed resources. + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + /// + [SecurityCritical] + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (this == globalSession) + { + throw new InvalidOperationException(); + } + EventLogPermissionHolder.GetEventLogPermission().Demand(); + } + if ((renderContextHandleSystem != null) && !renderContextHandleSystem.IsInvalid) + { + renderContextHandleSystem.Dispose(); + } + if ((renderContextHandleUser != null) && !renderContextHandleUser.IsInvalid) + { + renderContextHandleUser.Dispose(); + } + if ((handle != null) && !handle.IsInvalid) + { + handle.Dispose(); + } + } + } + + /// Contains the metadata (properties and settings) for an event that is defined in an event provider. + public sealed class EventMetadata + { + // Fields + private byte channelId; + + private string description; + private long id; + private long keywords; + private byte level; + private short opcode; + private ProviderMetadata pmReference; + private int task; + private string template; + private byte version; + + // Methods + internal EventMetadata(uint id, byte version, byte channelId, byte level, byte opcode, short task, long keywords, string template, string description, ProviderMetadata pmReference) + { + this.id = id; + this.version = version; + this.channelId = channelId; + this.level = level; + this.opcode = opcode; + this.task = task; + this.keywords = keywords; + this.template = template; + this.description = description; + this.pmReference = pmReference; + } + + // Properties + /// Gets the description. + /// The description. + public string Description => description; + + /// Gets the identifier. + /// The identifier. + public long Id => id; + + /// Gets the keywords. + /// The keywords. + public IEnumerable Keywords + { + get + { + List list = new List(); + ulong keywords = (ulong)this.keywords; + ulong num2 = 9223372036854775808L; + for (int i = 0; i < 0x40; i++) + { + if ((keywords & num2) > 0L) + { + list.Add(new EventKeyword((long)num2, pmReference)); + } + num2 = num2 >> 1; + } + return list; + } + } + + /// Gets the level. + /// The level. + public EventLevel Level => new EventLevel(level, pmReference); + + /// Gets the log link. + /// The log link. + public EventLogLink LogLink => new EventLogLink(channelId, pmReference); + + /// Gets the opcode. + /// The opcode. + public EventOpcode Opcode => new EventOpcode(opcode, pmReference); + + /// Gets the task. + /// The task. + public EventTask Task => new EventTask(task, pmReference); + + /// Gets the template. + /// The template. + public string Template => template; + + /// Gets the version. + /// The version. + public byte Version => version; + } + + /// + /// Contains an event opcode that is defined in an event provider. An opcode defines a numeric value that identifies the activity or a point within an activity that the application was performing when it raised the event. + /// + public sealed class EventOpcode + { + // Fields + private bool dataReady; + + private string displayName; + private string name; + private ProviderMetadata pmReference; + private object syncObject; + private int value; + + // Methods + internal EventOpcode(int value, ProviderMetadata pmReference) + { + this.value = value; + this.pmReference = pmReference; + syncObject = new object(); + } + + internal EventOpcode(string name, int value, string displayName) + { + this.value = value; + this.name = name; + this.displayName = displayName; + dataReady = true; + syncObject = new object(); + } + + // Properties + /// Gets the display name. + /// The display name. + public string DisplayName + { + get + { + PrepareData(); + return displayName; + } + } + + /// Gets the name. + /// The name. + public string Name + { + get + { + PrepareData(); + return name; + } + } + + /// Gets the value. + /// The value. + public int Value => value; + + internal void PrepareData() + { + lock (syncObject) + { + if (!dataReady) + { + IEnumerable opcodes = pmReference.Opcodes; + name = null; + displayName = null; + dataReady = true; + foreach (EventOpcode opcode in opcodes) + { + if (opcode.Value == value) + { + name = opcode.Name; + displayName = opcode.DisplayName; + dataReady = true; + break; + } + } + } + } + } + } + + /// + /// Contains the value of an event property that is specified by the event provider when the event is published. + /// + public sealed class EventProperty + { + // Fields + private object value; + + // Methods + internal EventProperty(object value) + { + this.value = value; + } + + // Properties + /// Gets the value. + /// The value. + public object Value => value; + } + + /// + /// Contains the value of an event property that is specified by the event provider when the event is published. + /// + /// Contains the properties of an event instance for an event that is received from an EventLogReader object. The event properties provide information about + /// the event such as the name of the computer where the event was logged and the time that the event was created. + /// + public abstract class EventRecord : IDisposable + { + /// Initializes a new instance of the class. + protected EventRecord() + { + } + + /// Gets the activity identifier. + /// The activity identifier. + public abstract Guid? ActivityId { get; } + + /// Gets the bookmark. + /// The bookmark. + public abstract EventBookmark Bookmark { get; } + + /// Gets the identifier. + /// The identifier. + public abstract int Id { get; } + + /// Gets the keywords. + /// The keywords. + public abstract long? Keywords { get; } + + /// Gets the keywords display names. + /// The keywords display names. + public abstract IEnumerable KeywordsDisplayNames { get; } + + /// Gets the level. + /// The level. + public abstract byte? Level { get; } + + /// Gets the display name of the level. + /// The display name of the level. + public abstract string LevelDisplayName { get; } + + /// Gets the name of the log. + /// The name of the log. + public abstract string LogName { get; } + + /// Gets the name of the machine. + /// The name of the machine. + public abstract string MachineName { get; } + + /// Gets the opcode. + /// The opcode. + public abstract short? Opcode { get; } + + /// Gets the display name of the opcode. + /// The display name of the opcode. + public abstract string OpcodeDisplayName { get; } + + /// Gets the process identifier. + /// The process identifier. + public abstract int? ProcessId { get; } + + /// Gets the properties. + /// The properties. + public abstract IList Properties { get; } + + /// Gets the provider identifier. + /// The provider identifier. + public abstract Guid? ProviderId { get; } + + /// Gets the name of the provider. + /// The name of the provider. + public abstract string ProviderName { get; } + + /// Gets the qualifiers. + /// The qualifiers. + public abstract int? Qualifiers { get; } + + /// Gets the record identifier. + /// The record identifier. + public abstract long? RecordId { get; } + + /// Gets the related activity identifier. + /// The related activity identifier. + public abstract Guid? RelatedActivityId { get; } + + /// Gets the task. + /// The task. + public abstract int? Task { get; } + + /// Gets the display name of the task. + /// The display name of the task. + public abstract string TaskDisplayName { get; } + + /// Gets the thread identifier. + /// The thread identifier. + public abstract int? ThreadId { get; } + + /// Gets the time created. + /// The time created. + public abstract DateTime? TimeCreated { get; } + + /// Gets the user identifier. + /// The user identifier. + public abstract SecurityIdentifier UserId { get; } + + /// Gets the version. + /// The version. + public abstract byte? Version { get; } + + /// Releases unmanaged and - optionally - managed resources. + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// Formats the description. + /// + public abstract string FormatDescription(); + + /// Formats the description. + /// The values. + /// + public abstract string FormatDescription(IEnumerable values); + + /// To the XML. + /// + public abstract string ToXml(); + + /// Releases unmanaged and - optionally - managed resources. + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + } + } + + /// the custom event handler args. + public sealed class EventRecordWrittenEventArgs : EventArgs + { + private Exception exception; + private EventRecord record; + + internal EventRecordWrittenEventArgs(EventLogRecord record) + { + this.record = record; + } + + internal EventRecordWrittenEventArgs(EventLogException exception) + { + this.exception = exception; + } + + /// + /// If any error occurred during subscription, this will be non-null. After a notification containing an exception, no more notifications will be made + /// for this subscription. + /// + public Exception EventException => exception; + + /// + /// The EventRecord being notified. + /// NOTE: If non null, then caller is required to call Dispose(). + /// + public EventRecord EventRecord => record; + } + + /// + /// Contains an event task that is defined in an event provider. The task identifies a portion of an application or a component that publishes an event. A task is a 16-bit value with 16 top values reserved. + /// + public sealed class EventTask + { + // Fields + private bool dataReady; + + private string displayName; + private Guid guid; + private string name; + private ProviderMetadata pmReference; + private object syncObject; + private int value; + + // Methods + internal EventTask(int value, ProviderMetadata pmReference) + { + this.value = value; + this.pmReference = pmReference; + syncObject = new object(); + } + + internal EventTask(string name, int value, string displayName, Guid guid) + { + this.value = value; + this.name = name; + this.displayName = displayName; + this.guid = guid; + dataReady = true; + syncObject = new object(); + } + + // Properties + /// Gets the display name. + /// The display name. + public string DisplayName + { + get + { + PrepareData(); + return displayName; + } + } + + /// Gets the event unique identifier. + /// The event unique identifier. + public Guid EventGuid + { + get + { + PrepareData(); + return guid; + } + } + + /// Gets the name. + /// The name. + public string Name + { + get + { + PrepareData(); + return name; + } + } + + /// Gets the value. + /// The value. + public int Value => value; + + internal void PrepareData() + { + lock (syncObject) + { + if (!dataReady) + { + IEnumerable tasks = pmReference.Tasks; + name = null; + displayName = null; + guid = Guid.Empty; + dataReady = true; + foreach (EventTask task in tasks) + { + if (task.Value == value) + { + name = task.Name; + displayName = task.DisplayName; + guid = task.EventGuid; + dataReady = true; + break; + } + } + } + } + } + } + + /// + /// Contains static information about an event provider, such as the name and id of the provider, and the collection of events defined in the provider. + /// + /// + public class ProviderMetadata : IDisposable + { + // Fields + private IList channelReferences; + + private CultureInfo cultureInfo; + private EventLogHandle defaultProviderHandle; + private EventLogHandle handle; + private IList keywords; + private IList levels; + private string logFilePath; + private IList opcodes; + private string providerName; + private EventLogSession session; + private IList standardKeywords; + private IList standardLevels; + private IList standardOpcodes; + private IList standardTasks; + private object syncObject; + private IList tasks; + + // Methods + /// Initializes a new instance of the class. + /// Name of the provider. + public ProviderMetadata(string providerName) + : this(providerName, null, null, null) + { + } + + /// Initializes a new instance of the class. + /// Name of the provider. + /// The session. + /// The target culture information. + public ProviderMetadata(string providerName, EventLogSession session, CultureInfo targetCultureInfo) + : this(providerName, session, targetCultureInfo, null) + { + } + + [SecurityCritical] + internal ProviderMetadata(string providerName, EventLogSession session, CultureInfo targetCultureInfo, string logFilePath) + { + handle = EventLogHandle.Zero; + defaultProviderHandle = EventLogHandle.Zero; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + if (targetCultureInfo == null) + { + targetCultureInfo = CultureInfo.CurrentCulture; + } + if (session == null) + { + session = EventLogSession.GlobalSession; + } + this.session = session; + this.providerName = providerName; + cultureInfo = targetCultureInfo; + this.logFilePath = logFilePath; + handle = NativeWrapper.EvtOpenProviderMetadata(this.session.Handle, this.providerName, this.logFilePath, cultureInfo.LCID, 0); + syncObject = new object(); + } + + // Nested Types + internal enum ObjectTypeName + { + Level, + Opcode, + Task, + Keyword + } + + // Properties + /// Gets the display name. + /// The display name. + public string DisplayName + { + [SecurityCritical] + get + { + uint providerMessageID = ProviderMessageID; + if (providerMessageID == uint.MaxValue) + { + return null; + } + EventLogPermissionHolder.GetEventLogPermission().Demand(); + return NativeWrapper.EvtFormatMessage(handle, providerMessageID); + } + } + + /// Gets the events. + /// The events. + public IEnumerable Events + { + [SecurityCritical] + get + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + List list = new List(); + EventLogHandle eventMetadataEnum = NativeWrapper.EvtOpenEventMetadataEnum(handle, 0); + using (eventMetadataEnum) + { + Label_0020: + EventLogHandle handle2 = NativeWrapper.EvtNextEventMetadata(eventMetadataEnum, 0); + if (handle2 != null) + { + using (handle2) + { + string str2; + uint id = (uint)NativeWrapper.EvtGetEventMetadataProperty(handle2, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventID); + byte version = (byte)((uint)NativeWrapper.EvtGetEventMetadataProperty(handle2, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventVersion)); + byte channelId = (byte)((uint)NativeWrapper.EvtGetEventMetadataProperty(handle2, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventChannel)); + byte level = (byte)((uint)NativeWrapper.EvtGetEventMetadataProperty(handle2, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventLevel)); + byte opcode = (byte)((uint)NativeWrapper.EvtGetEventMetadataProperty(handle2, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventOpcode)); + short task = (short)((uint)NativeWrapper.EvtGetEventMetadataProperty(handle2, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventTask)); + long keywords = (long)((ulong)NativeWrapper.EvtGetEventMetadataProperty(handle2, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventKeyword)); + string template = (string)NativeWrapper.EvtGetEventMetadataProperty(handle2, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventTemplate); + int num8 = (int)((uint)NativeWrapper.EvtGetEventMetadataProperty(handle2, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventMessageID)); + if (num8 == -1) + { + str2 = null; + } + else + { + str2 = NativeWrapper.EvtFormatMessage(handle, (uint)num8); + } + EventMetadata item = new EventMetadata(id, version, channelId, level, opcode, task, keywords, template, str2, this); + list.Add(item); + goto Label_0020; + } + } + return list.AsReadOnly(); + } + } + } + + /// Gets the help link. + /// The help link. + public Uri HelpLink + { + get + { + string uriString = (string)NativeWrapper.EvtGetPublisherMetadataProperty(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataHelpLink); + if ((uriString != null) && (uriString.Length != 0)) + { + return new Uri(uriString); + } + return null; + } + } + + /// Gets the identifier. + /// The identifier. + public Guid Id => (Guid)NativeWrapper.EvtGetPublisherMetadataProperty(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataPublisherGuid); + + /// Gets the keywords. + /// The keywords. + public IList Keywords + { + get + { + lock (syncObject) + { + if (keywords != null) + { + return keywords; + } + keywords = ((List)GetProviderListProperty(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywords)).AsReadOnly(); + } + return keywords; + } + } + + /// Gets the levels. + /// The levels. + public IList Levels + { + get + { + lock (syncObject) + { + if (levels != null) + { + return levels; + } + levels = ((List)GetProviderListProperty(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevels)).AsReadOnly(); + } + return levels; + } + } + + /// Gets the log links. + /// The log links. + public IList LogLinks + { + [SecurityCritical] + get + { + IList channelReferences; + EventLogHandle zero = EventLogHandle.Zero; + try + { + lock (syncObject) + { + if (this.channelReferences != null) + { + return this.channelReferences; + } + EventLogPermissionHolder.GetEventLogPermission().Demand(); + zero = NativeWrapper.EvtGetPublisherMetadataPropertyHandle(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataChannelReferences); + int capacity = NativeWrapper.EvtGetObjectArraySize(zero); + List list = new List(capacity); + for (int i = 0; i < capacity; i++) + { + bool flag; + string str2; + string strA = (string)NativeWrapper.EvtGetObjectArrayProperty(zero, i, 7); + uint channelId = (uint)NativeWrapper.EvtGetObjectArrayProperty(zero, i, 9); + uint num4 = (uint)NativeWrapper.EvtGetObjectArrayProperty(zero, i, 10); + if (num4 == 1) + { + flag = true; + } + else + { + flag = false; + } + int num5 = (int)((uint)NativeWrapper.EvtGetObjectArrayProperty(zero, i, 11)); + if (num5 == -1) + { + str2 = null; + } + else + { + str2 = NativeWrapper.EvtFormatMessage(handle, (uint)num5); + } + if ((str2 == null) && flag) + { + if (string.Compare(strA, "Application", StringComparison.OrdinalIgnoreCase) == 0) + { + num5 = 0x100; + } + else if (string.Compare(strA, "System", StringComparison.OrdinalIgnoreCase) == 0) + { + num5 = 0x102; + } + else if (string.Compare(strA, "Security", StringComparison.OrdinalIgnoreCase) == 0) + { + num5 = 0x101; + } + else + { + num5 = -1; + } + if (num5 != -1) + { + if (defaultProviderHandle.IsInvalid) + { + defaultProviderHandle = NativeWrapper.EvtOpenProviderMetadata(session.Handle, null, null, cultureInfo.LCID, 0); + } + str2 = NativeWrapper.EvtFormatMessage(defaultProviderHandle, (uint)num5); + } + } + list.Add(new EventLogLink(strA, flag, str2, channelId)); + } + this.channelReferences = list.AsReadOnly(); + } + channelReferences = this.channelReferences; + } + finally + { + zero.Close(); + } + return channelReferences; + } + } + + /// Gets the message file path. + /// The message file path. + public string MessageFilePath => (string)NativeWrapper.EvtGetPublisherMetadataProperty(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataMessageFilePath); + + /// Gets the name. + /// The name. + public string Name => providerName; + + /// Gets the opcodes. + /// The opcodes. + public IList Opcodes + { + get + { + lock (syncObject) + { + if (opcodes != null) + { + return opcodes; + } + opcodes = ((List)GetProviderListProperty(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodes)).AsReadOnly(); + } + return opcodes; + } + } + + /// Gets the parameter file path. + /// The parameter file path. + public string ParameterFilePath => (string)NativeWrapper.EvtGetPublisherMetadataProperty(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataParameterFilePath); + + /// Gets the resource file path. + /// The resource file path. + public string ResourceFilePath => (string)NativeWrapper.EvtGetPublisherMetadataProperty(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataResourceFilePath); + + /// Gets the tasks. + /// The tasks. + public IList Tasks + { + get + { + lock (syncObject) + { + if (tasks != null) + { + return tasks; + } + tasks = ((List)GetProviderListProperty(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTasks)).AsReadOnly(); + } + return tasks; + } + } + + internal EventLogHandle Handle => handle; + + private uint ProviderMessageID => (uint)NativeWrapper.EvtGetPublisherMetadataProperty(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataPublisherMessageID); + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + internal void CheckReleased() + { + lock (syncObject) + { + GetProviderListProperty(handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTasks); + } + } + + internal string FindStandardKeywordDisplayName(string name, long value) + { + if (standardKeywords == null) + { + standardKeywords = (List)GetProviderListProperty(defaultProviderHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywords); + } + foreach (EventKeyword keyword in standardKeywords) + { + if ((keyword.Name == name) && (keyword.Value == value)) + { + return keyword.DisplayName; + } + } + return null; + } + + internal string FindStandardLevelDisplayName(string name, uint value) + { + if (standardLevels == null) + { + standardLevels = (List)GetProviderListProperty(defaultProviderHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevels); + } + foreach (EventLevel level in standardLevels) + { + if ((level.Name == name) && (level.Value == value)) + { + return level.DisplayName; + } + } + return null; + } + + internal string FindStandardOpcodeDisplayName(string name, uint value) + { + if (standardOpcodes == null) + { + standardOpcodes = (List)GetProviderListProperty(defaultProviderHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodes); + } + foreach (EventOpcode opcode in standardOpcodes) + { + if ((opcode.Name == name) && (opcode.Value == value)) + { + return opcode.DisplayName; + } + } + return null; + } + + internal string FindStandardTaskDisplayName(string name, uint value) + { + if (standardTasks == null) + { + standardTasks = (List)GetProviderListProperty(defaultProviderHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTasks); + } + foreach (EventTask task in standardTasks) + { + if ((task.Name == name) && (task.Value == value)) + { + return task.DisplayName; + } + } + return null; + } + + [SecurityCritical] + internal object GetProviderListProperty(EventLogHandle providerHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId metadataProperty) + { + object obj2; + EventLogHandle zero = EventLogHandle.Zero; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + try + { + UnsafeNativeMethods.EvtPublisherMetadataPropertyId evtPublisherMetadataOpcodeName; + UnsafeNativeMethods.EvtPublisherMetadataPropertyId evtPublisherMetadataOpcodeValue; + UnsafeNativeMethods.EvtPublisherMetadataPropertyId evtPublisherMetadataOpcodeMessageID; + ObjectTypeName opcode; + List list = null; + List list2 = null; + List list3 = null; + List list4 = null; + zero = NativeWrapper.EvtGetPublisherMetadataPropertyHandle(providerHandle, metadataProperty); + int capacity = NativeWrapper.EvtGetObjectArraySize(zero); + switch (metadataProperty) + { + case UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodes: + evtPublisherMetadataOpcodeName = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodeName; + evtPublisherMetadataOpcodeValue = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodeValue; + evtPublisherMetadataOpcodeMessageID = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodeMessageID; + opcode = ObjectTypeName.Opcode; + list2 = new List(capacity); + break; + + case UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywords: + evtPublisherMetadataOpcodeName = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywordName; + evtPublisherMetadataOpcodeValue = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywordValue; + evtPublisherMetadataOpcodeMessageID = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywordMessageID; + opcode = ObjectTypeName.Keyword; + list3 = new List(capacity); + break; + + case UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevels: + evtPublisherMetadataOpcodeName = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevelName; + evtPublisherMetadataOpcodeValue = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevelValue; + evtPublisherMetadataOpcodeMessageID = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevelMessageID; + opcode = ObjectTypeName.Level; + list = new List(capacity); + break; + + case UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTasks: + evtPublisherMetadataOpcodeName = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTaskName; + evtPublisherMetadataOpcodeValue = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTaskValue; + evtPublisherMetadataOpcodeMessageID = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTaskMessageID; + opcode = ObjectTypeName.Task; + list4 = new List(capacity); + break; + + default: + return null; + } + for (int i = 0; i < capacity; i++) + { + string name = (string)NativeWrapper.EvtGetObjectArrayProperty(zero, i, (int)evtPublisherMetadataOpcodeName); + uint num3 = 0; + long num4 = 0L; + if (opcode != ObjectTypeName.Keyword) + { + num3 = (uint)NativeWrapper.EvtGetObjectArrayProperty(zero, i, (int)evtPublisherMetadataOpcodeValue); + } + else + { + num4 = (long)((ulong)NativeWrapper.EvtGetObjectArrayProperty(zero, i, (int)evtPublisherMetadataOpcodeValue)); + } + int num5 = (int)((uint)NativeWrapper.EvtGetObjectArrayProperty(zero, i, (int)evtPublisherMetadataOpcodeMessageID)); + string displayName = null; + if (num5 == -1) + { + if (providerHandle != defaultProviderHandle) + { + if (defaultProviderHandle.IsInvalid) + { + defaultProviderHandle = NativeWrapper.EvtOpenProviderMetadata(session.Handle, null, null, cultureInfo.LCID, 0); + } + switch (opcode) + { + case ObjectTypeName.Level: + displayName = FindStandardLevelDisplayName(name, num3); + goto Label_01BA; + + case ObjectTypeName.Opcode: + displayName = FindStandardOpcodeDisplayName(name, num3 >> 0x10); + goto Label_01BA; + + case ObjectTypeName.Task: + displayName = FindStandardTaskDisplayName(name, num3); + goto Label_01BA; + + case ObjectTypeName.Keyword: + displayName = FindStandardKeywordDisplayName(name, num4); + goto Label_01BA; + } + displayName = null; + } + } + else + { + displayName = NativeWrapper.EvtFormatMessage(providerHandle, (uint)num5); + } + Label_01BA: + switch (opcode) + { + case ObjectTypeName.Level: + list.Add(new EventLevel(name, (int)num3, displayName)); + break; + + case ObjectTypeName.Opcode: + list2.Add(new EventOpcode(name, (int)(num3 >> 0x10), displayName)); + break; + + case ObjectTypeName.Task: + { + Guid guid = (Guid)NativeWrapper.EvtGetObjectArrayProperty(zero, i, 0x12); + list4.Add(new EventTask(name, (int)num3, displayName, guid)); + break; + } + case ObjectTypeName.Keyword: + list3.Add(new EventKeyword(name, num4, displayName)); + break; + + default: + return null; + } + } + switch (opcode) + { + case ObjectTypeName.Level: + return list; + + case ObjectTypeName.Opcode: + return list2; + + case ObjectTypeName.Task: + return list4; + + case ObjectTypeName.Keyword: + return list3; + } + obj2 = null; + } + finally + { + zero.Close(); + } + return obj2; + } + + /// Releases unmanaged and - optionally - managed resources. + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + [SecurityCritical] + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + } + if ((handle != null) && !handle.IsInvalid) + { + handle.Dispose(); + } + } + } + + internal static class UnsafeNativeMethods + { + internal enum EvtChannelConfigPropertyId + { + EvtChannelConfigEnabled, + EvtChannelConfigIsolation, + EvtChannelConfigType, + EvtChannelConfigOwningPublisher, + EvtChannelConfigClassicEventlog, + EvtChannelConfigAccess, + EvtChannelLoggingConfigRetention, + EvtChannelLoggingConfigAutoBackup, + EvtChannelLoggingConfigMaxSize, + EvtChannelLoggingConfigLogFilePath, + EvtChannelPublishingConfigLevel, + EvtChannelPublishingConfigKeywords, + EvtChannelPublishingConfigControlGuid, + EvtChannelPublishingConfigBufferSize, + EvtChannelPublishingConfigMinBuffers, + EvtChannelPublishingConfigMaxBuffers, + EvtChannelPublishingConfigLatency, + EvtChannelPublishingConfigClockType, + EvtChannelPublishingConfigSidType, + EvtChannelPublisherList, + EvtChannelConfigPropertyIdEND + } + + internal enum EvtEventMetadataPropertyId + { + EventMetadataEventID, + EventMetadataEventVersion, + EventMetadataEventChannel, + EventMetadataEventLevel, + EventMetadataEventOpcode, + EventMetadataEventTask, + EventMetadataEventKeyword, + EventMetadataEventMessageID, + EventMetadataEventTemplate + } + + internal enum EvtEventPropertyId + { + EvtEventQueryIDs, + EvtEventPath + } + + internal enum EvtExportLogFlags + { + EvtExportLogChannelPath = 1, + EvtExportLogFilePath = 2, + EvtExportLogTolerateQueryErrors = 0x1000 + } + + internal enum EvtFormatMessageFlags + { + EvtFormatMessageChannel = 6, + EvtFormatMessageEvent = 1, + EvtFormatMessageId = 8, + EvtFormatMessageKeyword = 5, + EvtFormatMessageLevel = 2, + EvtFormatMessageOpcode = 4, + EvtFormatMessageProvider = 7, + EvtFormatMessageTask = 3, + EvtFormatMessageXml = 9 + } + + internal enum EvtLoginClass + { + EvtRpcLogin = 1 + } + + internal enum EvtLogPropertyId + { + EvtLogCreationTime, + EvtLogLastAccessTime, + EvtLogLastWriteTime, + EvtLogFileSize, + EvtLogAttributes, + EvtLogNumberOfLogRecords, + EvtLogOldestRecordNumber, + EvtLogFull + } + + internal enum EvtPublisherMetadataPropertyId + { + EvtPublisherMetadataPublisherGuid, + EvtPublisherMetadataResourceFilePath, + EvtPublisherMetadataParameterFilePath, + EvtPublisherMetadataMessageFilePath, + EvtPublisherMetadataHelpLink, + EvtPublisherMetadataPublisherMessageID, + EvtPublisherMetadataChannelReferences, + EvtPublisherMetadataChannelReferencePath, + EvtPublisherMetadataChannelReferenceIndex, + EvtPublisherMetadataChannelReferenceID, + EvtPublisherMetadataChannelReferenceFlags, + EvtPublisherMetadataChannelReferenceMessageID, + EvtPublisherMetadataLevels, + EvtPublisherMetadataLevelName, + EvtPublisherMetadataLevelValue, + EvtPublisherMetadataLevelMessageID, + EvtPublisherMetadataTasks, + EvtPublisherMetadataTaskName, + EvtPublisherMetadataTaskEventGuid, + EvtPublisherMetadataTaskValue, + EvtPublisherMetadataTaskMessageID, + EvtPublisherMetadataOpcodes, + EvtPublisherMetadataOpcodeName, + EvtPublisherMetadataOpcodeValue, + EvtPublisherMetadataOpcodeMessageID, + EvtPublisherMetadataKeywords, + EvtPublisherMetadataKeywordName, + EvtPublisherMetadataKeywordValue, + EvtPublisherMetadataKeywordMessageID + } + + internal enum EvtQueryPropertyId + { + EvtQueryNames, + EvtQueryStatuses + } + + internal enum EvtRenderContextFlags + { + EvtRenderContextValues, + EvtRenderContextSystem, + EvtRenderContextUser + } + + internal enum EvtRenderFlags + { + EvtRenderEventValues, + EvtRenderEventXml, + EvtRenderBookmark + } + + [Flags] + internal enum EvtSeekFlags + { + EvtSeekOriginMask = 7, + EvtSeekRelativeToBookmark = 4, + EvtSeekRelativeToCurrent = 3, + EvtSeekRelativeToFirst = 1, + EvtSeekRelativeToLast = 2, + EvtSeekStrict = 0x10000 + } + + [Flags] + internal enum EvtSubscribeFlags + { + EvtSubscribeToFutureEvents = 1, + EvtSubscribeStartAtOldestRecord = 2, + EvtSubscribeStartAfterBookmark = 3, + EvtSubscribeTolerateQueryErrors = 0x1000, + EvtSubscribeStrict = 0x10000 + } + + internal enum EvtVariantType + { + EvtVarTypeAnsiString = 2, + EvtVarTypeBinary = 14, + EvtVarTypeBoolean = 13, + EvtVarTypeByte = 4, + EvtVarTypeDouble = 12, + EvtVarTypeEvtHandle = 0x20, + EvtVarTypeEvtXml = 0x23, + EvtVarTypeFileTime = 0x11, + EvtVarTypeGuid = 15, + EvtVarTypeHexInt32 = 20, + EvtVarTypeHexInt64 = 0x15, + EvtVarTypeInt16 = 5, + EvtVarTypeInt32 = 7, + EvtVarTypeInt64 = 9, + EvtVarTypeNull = 0, + EvtVarTypeSByte = 3, + EvtVarTypeSid = 0x13, + EvtVarTypeSingle = 11, + EvtVarTypeSizeT = 0x10, + EvtVarTypeString = 1, + EvtVarTypeStringArray = 0x81, + EvtVarTypeSysTime = 0x12, + EvtVarTypeUInt16 = 6, + EvtVarTypeUInt32 = 8, + EvtVarTypeUInt32Array = 0x88, + EvtVarTypeUInt64 = 10 + } + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtArchiveExportedLog(EventLogHandle session, [MarshalAs(UnmanagedType.LPWStr)] string logFilePath, int locale, int flags); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", SetLastError = true)] + internal static extern bool EvtCancel(EventLogHandle handle); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtClearLog(EventLogHandle session, [MarshalAs(UnmanagedType.LPWStr)] string channelPath, [MarshalAs(UnmanagedType.LPWStr)] string targetFilePath, int flags); + + [return: MarshalAs(UnmanagedType.Bool)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("wevtapi.dll")] + internal static extern bool EvtClose(IntPtr handle); + + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern EventLogHandle EvtCreateBookmark([MarshalAs(UnmanagedType.LPWStr)] string bookmarkXml); + + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern EventLogHandle EvtCreateRenderContext(int valuePathsCount, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] valuePaths, [MarshalAs(UnmanagedType.I4)] EvtRenderContextFlags flags); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtExportLog(EventLogHandle session, [MarshalAs(UnmanagedType.LPWStr)] string channelPath, [MarshalAs(UnmanagedType.LPWStr)] string query, [MarshalAs(UnmanagedType.LPWStr)] string targetFilePath, int flags); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtFormatMessage(EventLogHandle publisherMetadataHandle, EventLogHandle eventHandle, uint messageId, int valueCount, EvtStringVariant[] values, [MarshalAs(UnmanagedType.I4)] EvtFormatMessageFlags flags, int bufferSize, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder buffer, out int bufferUsed); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", EntryPoint = "EvtFormatMessage", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtFormatMessageBuffer(EventLogHandle publisherMetadataHandle, EventLogHandle eventHandle, uint messageId, int valueCount, IntPtr values, [MarshalAs(UnmanagedType.I4)] EvtFormatMessageFlags flags, int bufferSize, IntPtr buffer, out int bufferUsed); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtGetChannelConfigProperty(EventLogHandle channelConfig, [MarshalAs(UnmanagedType.I4)] EvtChannelConfigPropertyId propertyId, int flags, int propertyValueBufferSize, IntPtr propertyValueBuffer, out int propertyValueBufferUsed); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtGetEventInfo(EventLogHandle eventHandle, [MarshalAs(UnmanagedType.I4)] EvtEventPropertyId propertyId, int bufferSize, IntPtr bufferPtr, out int bufferUsed); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtGetEventMetadataProperty(EventLogHandle eventMetadata, [MarshalAs(UnmanagedType.I4)] EvtEventMetadataPropertyId propertyId, int flags, int eventMetadataPropertyBufferSize, IntPtr eventMetadataPropertyBuffer, out int eventMetadataPropertyBufferUsed); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtGetLogInfo(EventLogHandle log, [MarshalAs(UnmanagedType.I4)] EvtLogPropertyId propertyId, int propertyValueBufferSize, IntPtr propertyValueBuffer, out int propertyValueBufferUsed); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtGetObjectArrayProperty(EventLogHandle objectArray, int propertyId, int arrayIndex, int flags, int propertyValueBufferSize, IntPtr propertyValueBuffer, out int propertyValueBufferUsed); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtGetObjectArraySize(EventLogHandle objectArray, out int objectArraySize); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtGetPublisherMetadataProperty(EventLogHandle publisherMetadataHandle, [MarshalAs(UnmanagedType.I4)] EvtPublisherMetadataPropertyId propertyId, int flags, int publisherMetadataPropertyBufferSize, IntPtr publisherMetadataPropertyBuffer, out int publisherMetadataPropertyBufferUsed); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtGetQueryInfo(EventLogHandle queryHandle, [MarshalAs(UnmanagedType.I4)] EvtQueryPropertyId propertyId, int bufferSize, IntPtr buffer, ref int bufferRequired); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", SetLastError = true)] + internal static extern bool EvtNext(EventLogHandle queryHandle, int eventSize, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] events, int timeout, int flags, ref int returned); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtNextChannelPath(EventLogHandle channelEnum, int channelPathBufferSize, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder channelPathBuffer, out int channelPathBufferUsed); + + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern EventLogHandle EvtNextEventMetadata(EventLogHandle eventMetadataEnum, int flags); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtNextPublisherId(EventLogHandle publisherEnum, int publisherIdBufferSize, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder publisherIdBuffer, out int publisherIdBufferUsed); + + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern EventLogHandle EvtOpenChannelConfig(EventLogHandle session, [MarshalAs(UnmanagedType.LPWStr)] string channelPath, int flags); + + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern EventLogHandle EvtOpenChannelEnum(EventLogHandle session, int flags); + + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern EventLogHandle EvtOpenEventMetadataEnum(EventLogHandle publisherMetadata, int flags); + + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern EventLogHandle EvtOpenLog(EventLogHandle session, [MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.I4)] PathType flags); + + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern EventLogHandle EvtOpenPublisherEnum(EventLogHandle session, int flags); + + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern EventLogHandle EvtOpenPublisherMetadata(EventLogHandle session, [MarshalAs(UnmanagedType.LPWStr)] string publisherId, [MarshalAs(UnmanagedType.LPWStr)] string logFilePath, int locale, int flags); + + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern EventLogHandle EvtOpenSession([MarshalAs(UnmanagedType.I4)] EvtLoginClass loginClass, ref EvtRpcLogin login, int timeout, int flags); + + [DllImport("wevtapi.dll", SetLastError = true)] + internal static extern EventLogHandle EvtQuery(EventLogHandle session, [MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPWStr)] string query, int flags); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", SetLastError = true)] + internal static extern bool EvtRender(EventLogHandle context, EventLogHandle eventHandle, EvtRenderFlags flags, int buffSize, IntPtr buffer, out int buffUsed, out int propCount); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", SetLastError = true)] + internal static extern bool EvtRender(EventLogHandle context, EventLogHandle eventHandle, EvtRenderFlags flags, int buffSize, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder buffer, out int buffUsed, out int propCount); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtSaveChannelConfig(EventLogHandle channelConfig, int flags); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtSeek(EventLogHandle resultSet, long position, EventLogHandle bookmark, int timeout, [MarshalAs(UnmanagedType.I4)] EvtSeekFlags flags); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtSetChannelConfigProperty(EventLogHandle channelConfig, [MarshalAs(UnmanagedType.I4)] EvtChannelConfigPropertyId propertyId, int flags, ref EvtVariant propertyValue); + + [DllImport("wevtapi.dll", SetLastError = true)] + internal static extern EventLogHandle EvtSubscribe(EventLogHandle session, SafeWaitHandle signalEvent, [MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPWStr)] string query, EventLogHandle bookmark, IntPtr context, IntPtr callback, int flags); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("wevtapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EvtUpdateBookmark(EventLogHandle bookmark, EventLogHandle eventHandle); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal struct EvtRpcLogin + { + [MarshalAs(UnmanagedType.LPWStr)] + public string Server; + + [MarshalAs(UnmanagedType.LPWStr)] + public string User; + + [MarshalAs(UnmanagedType.LPWStr)] + public string Domain; + + public CoTaskMemUnicodeSafeHandle Password; + public int Flags; + } + + [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto)] + internal struct EvtStringVariant + { + // Fields + [FieldOffset(8)] + public uint Count; + + [MarshalAs(UnmanagedType.LPWStr), FieldOffset(0)] + public string StringVal; + + [FieldOffset(12)] + public uint Type; + } + + [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto)] + internal struct EvtVariant + { + // Fields + [FieldOffset(0)] + public IntPtr AnsiString; + + [FieldOffset(0)] + public IntPtr Binary; + + [FieldOffset(0)] + public uint Bool; + + [FieldOffset(0)] + public byte ByteVal; + + [FieldOffset(8)] + public uint Count; + + [FieldOffset(0)] + public double Double; + + [FieldOffset(0)] + public ulong FileTime; + + [FieldOffset(0)] + public IntPtr GuidReference; + + [FieldOffset(0)] + public IntPtr Handle; + + [FieldOffset(0)] + public int Integer; + + [FieldOffset(0)] + public long Long; + + [FieldOffset(0)] + public IntPtr Reference; + + [FieldOffset(0)] + public byte SByte; + + [FieldOffset(0)] + public short Short; + + [FieldOffset(0)] + public IntPtr SidVal; + + [FieldOffset(0)] + public IntPtr StringVal; + + [FieldOffset(0)] + public IntPtr SystemTime; + + [FieldOffset(12)] + public uint Type; + + [FieldOffset(0)] + public byte UInt8; + + [FieldOffset(0)] + public uint UInteger; + + [FieldOffset(0)] + public ulong ULong; + + [FieldOffset(0)] + public ushort UShort; + } + } + + /// + /// + [SecurityCritical] + internal sealed class CoTaskMemSafeHandle : SafeHandle + { + // Methods + internal CoTaskMemSafeHandle() + : base(IntPtr.Zero, true) + { + } + + public static CoTaskMemSafeHandle Zero => new CoTaskMemSafeHandle(); + + // Properties + public override bool IsInvalid + { + get + { + if (!base.IsClosed) + { + return (base.handle == IntPtr.Zero); + } + return true; + } + } + + internal IntPtr GetMemory() => base.handle; + + internal void SetMemory(IntPtr handle) + { + base.SetHandle(handle); + } + + protected override bool ReleaseHandle() + { + Marshal.FreeCoTaskMem(base.handle); + base.handle = IntPtr.Zero; + return true; + } + } + + [SecurityCritical] + internal sealed class CoTaskMemUnicodeSafeHandle : SafeHandle + { + // Methods + internal CoTaskMemUnicodeSafeHandle() + : base(IntPtr.Zero, true) + { + } + + internal CoTaskMemUnicodeSafeHandle(IntPtr handle, bool ownsHandle) + : base(IntPtr.Zero, ownsHandle) + { + base.SetHandle(handle); + } + + public static CoTaskMemUnicodeSafeHandle Zero => new CoTaskMemUnicodeSafeHandle(); + + // Properties + public override bool IsInvalid + { + get + { + if (!base.IsClosed) + { + return (base.handle == IntPtr.Zero); + } + return true; + } + } + + internal IntPtr GetMemory() => base.handle; + + internal void SetMemory(IntPtr handle) + { + base.SetHandle(handle); + } + + protected override bool ReleaseHandle() + { + Marshal.ZeroFreeCoTaskMemUnicode(base.handle); + base.handle = IntPtr.Zero; + return true; + } + } + + [Serializable] + internal class EventLogException : Exception, ISerializable + { + // Fields + private int errorCode; + + // Methods + public EventLogException() + { + } + + public EventLogException(string message) + : base(message) + { + } + + public EventLogException(string message, Exception innerException) + : base(message, innerException) + { + } + + protected EventLogException(int errorCode) + { + this.errorCode = errorCode; + } + + protected EventLogException(SerializationInfo serializationInfo, StreamingContext streamingContext) + : base(serializationInfo, streamingContext) + { + } + + // Properties + public override string Message + { + [SecurityCritical] + get + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + Win32Exception exception = new Win32Exception(errorCode); + return exception.Message; + } + } + + [SecurityCritical, SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + info.AddValue("errorCode", errorCode); + base.GetObjectData(info, context); + } + + internal static void Throw(int errorCode) + { + switch (errorCode) + { + case 0x4c7: + case 0x71a: + throw new OperationCanceledException(); + + case 2: + case 3: + case 0x3a9f: + case 0x3a9a: + case 0x3ab3: + case 0x3ab4: + throw new EventLogNotFoundException(errorCode); + + case 5: + throw new UnauthorizedAccessException(); + + case 13: + case 0x3a9d: + throw new EventLogInvalidDataException(errorCode); + + case 0x3aa3: + case 0x3aa4: + throw new EventLogReadingException(errorCode); + + case 0x3abd: + throw new EventLogProviderDisabledException(errorCode); + } + throw new EventLogException(errorCode); + } + } + + [SecurityCritical] + internal sealed class EventLogHandle : SafeHandle + { + internal EventLogHandle(IntPtr handle, bool ownsHandle) + : base(IntPtr.Zero, ownsHandle) + { + base.SetHandle(handle); + } + + // Methods + private EventLogHandle() + : base(IntPtr.Zero, true) + { + } + + public static EventLogHandle Zero => new EventLogHandle(); + + // Properties + public override bool IsInvalid + { + get + { + if (!base.IsClosed) + { + return (base.handle == IntPtr.Zero); + } + return true; + } + } + + protected override bool ReleaseHandle() + { + NativeWrapper.EvtClose(base.handle); + base.handle = IntPtr.Zero; + return true; + } + } + + /// + /// Allows you to access the run-time properties of active event logs and event log files. These properties include the number of events in the log, the size + /// of the log, a value that determines whether the log is full, and the last time the log was written to or accessed. + /// + [Serializable] + internal class EventLogInvalidDataException : EventLogException + { + // Methods + public EventLogInvalidDataException() + { + } + + public EventLogInvalidDataException(string message) + : base(message) + { + } + + public EventLogInvalidDataException(string message, Exception innerException) + : base(message, innerException) + { + } + + internal EventLogInvalidDataException(int errorCode) + : base(errorCode) + { + } + + protected EventLogInvalidDataException(SerializationInfo serializationInfo, StreamingContext streamingContext) + : base(serializationInfo, streamingContext) + { + } + } + + /// Represents a link between an event provider and an event log that the provider publishes events into. This object cannot be instantiated. + [Serializable] + internal class EventLogNotFoundException : EventLogException + { + // Methods + public EventLogNotFoundException() + { + } + + public EventLogNotFoundException(string message) + : base(message) + { + } + + public EventLogNotFoundException(string message, Exception innerException) + : base(message, innerException) + { + } + + internal EventLogNotFoundException(int errorCode) + : base(errorCode) + { + } + + protected EventLogNotFoundException(SerializationInfo serializationInfo, StreamingContext streamingContext) + : base(serializationInfo, streamingContext) + { + } + } + + internal class EventLogPermissionHolder + { + // Methods + public static EventLogPermission GetEventLogPermission() + { + EventLogPermission permission = new EventLogPermission(); + EventLogPermissionEntry entry = new EventLogPermissionEntry(EventLogPermissionAccess.Administer, "."); + permission.PermissionEntries.Add(entry); + return permission; + } + } + + /// + /// Contains an array of strings that represent XPath queries for elements in the XML representation of an event, which is based on the Event Schema. The + /// queries in this object are used to extract values from the event. + /// + [Serializable] + internal class EventLogProviderDisabledException : EventLogException + { + // Methods + public EventLogProviderDisabledException() + { + } + + public EventLogProviderDisabledException(string message) + : base(message) + { + } + + public EventLogProviderDisabledException(string message, Exception innerException) + : base(message, innerException) + { + } + + internal EventLogProviderDisabledException(int errorCode) + : base(errorCode) + { + } + + protected EventLogProviderDisabledException(SerializationInfo serializationInfo, StreamingContext streamingContext) + : base(serializationInfo, streamingContext) + { + } + } + + internal class EventLogQuery + { + // Fields + private string path; + + private PathType pathType; + private string query; + private bool reverseDirection; + private EventLogSession session; + private bool tolerateErrors; + + // Methods + public EventLogQuery(string path, PathType pathType) + : this(path, pathType, null) + { + } + + public EventLogQuery(string path, PathType pathType, string query) + { + session = EventLogSession.GlobalSession; + this.path = path; + this.pathType = pathType; + if (query == null) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + } + else + { + this.query = query; + } + } + + public bool ReverseDirection + { + get + { + return reverseDirection; + } + set + { + reverseDirection = value; + } + } + + public EventLogSession Session + { + get + { + return session; + } + set + { + session = value; + } + } + + public bool TolerateQueryErrors + { + get + { + return tolerateErrors; + } + set + { + tolerateErrors = value; + } + } + + // Properties + internal string Path => path; + + internal string Query => query; + + internal PathType ThePathType => pathType; + } + + internal class EventLogReader : IDisposable + { + // Fields + private int batchSize; + + private ProviderMetadataCachedInformation cachedMetadataInformation; + private int currentIndex; + private int eventCount; + private EventLogQuery eventQuery; + private IntPtr[] eventsBuffer; + private EventLogHandle handle; + private bool isEof; + + // Methods + public EventLogReader(EventLogQuery eventQuery) + : this(eventQuery, null) + { + } + + public EventLogReader(string path) + : this(new EventLogQuery(path, PathType.LogName), null) + { + } + + [SecurityCritical] + public EventLogReader(EventLogQuery eventQuery, EventBookmark bookmark) + { + if (eventQuery == null) + { + throw new ArgumentNullException(nameof(eventQuery)); + } + string logfile = null; + if (eventQuery.ThePathType == PathType.FilePath) + { + logfile = eventQuery.Path; + } + cachedMetadataInformation = new ProviderMetadataCachedInformation(eventQuery.Session, logfile, 50); + this.eventQuery = eventQuery; + batchSize = 0x40; + eventsBuffer = new IntPtr[batchSize]; + int flags = 0; + if (this.eventQuery.ThePathType == PathType.LogName) + { + flags |= 1; + } + else + { + flags |= 2; + } + if (this.eventQuery.ReverseDirection) + { + flags |= 0x200; + } + if (this.eventQuery.TolerateQueryErrors) + { + flags |= 0x1000; + } + EventLogPermissionHolder.GetEventLogPermission().Demand(); + handle = NativeWrapper.EvtQuery(this.eventQuery.Session.Handle, this.eventQuery.Path, this.eventQuery.Query, flags); + EventLogHandle bookmarkHandleFromBookmark = EventLogRecord.GetBookmarkHandleFromBookmark(bookmark); + if (!bookmarkHandleFromBookmark.IsInvalid) + { + using (bookmarkHandleFromBookmark) + { + NativeWrapper.EvtSeek(handle, 1L, bookmarkHandleFromBookmark, 0, UnsafeNativeMethods.EvtSeekFlags.EvtSeekRelativeToBookmark); + } + } + } + + public EventLogReader(string path, PathType pathType) + : this(new EventLogQuery(path, pathType), null) + { + } + + // Properties + public int BatchSize + { + get + { + return batchSize; + } + set + { + if (value < 1) + { + throw new ArgumentOutOfRangeException(nameof(value)); + } + batchSize = value; + } + } + + public IList LogStatus + { + [SecurityCritical] + get + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + List list = null; + string[] strArray = null; + int[] numArray = null; + EventLogHandle handle = this.handle; + if (handle.IsInvalid) + { + throw new InvalidOperationException(); + } + strArray = (string[])NativeWrapper.EvtGetQueryInfo(handle, UnsafeNativeMethods.EvtQueryPropertyId.EvtQueryNames); + numArray = (int[])NativeWrapper.EvtGetQueryInfo(handle, UnsafeNativeMethods.EvtQueryPropertyId.EvtQueryStatuses); + if (strArray.Length != numArray.Length) + { + throw new InvalidOperationException(); + } + list = new List(strArray.Length); + for (int i = 0; i < strArray.Length; i++) + { + EventLogStatus item = new EventLogStatus(strArray[i], numArray[i]); + list.Add(item); + } + return list.AsReadOnly(); + } + } + + public void CancelReading() + { + NativeWrapper.EvtCancel(handle); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public EventRecord ReadEvent() => ReadEvent(TimeSpan.MaxValue); + + [SecurityCritical] + public EventRecord ReadEvent(TimeSpan timeout) + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + if (isEof) + { + throw new InvalidOperationException(); + } + if (currentIndex >= eventCount) + { + GetNextBatch(timeout); + if (currentIndex >= eventCount) + { + isEof = true; + return null; + } + } + EventLogRecord record = new EventLogRecord(new EventLogHandle(eventsBuffer[currentIndex], true), eventQuery.Session, cachedMetadataInformation); + currentIndex++; + return record; + } + + public void Seek(EventBookmark bookmark) + { + Seek(bookmark, 0L); + } + + [SecurityCritical] + public void Seek(EventBookmark bookmark, long offset) + { + if (bookmark == null) + { + throw new ArgumentNullException(nameof(bookmark)); + } + EventLogPermissionHolder.GetEventLogPermission().Demand(); + SeekReset(); + using (EventLogHandle handle = EventLogRecord.GetBookmarkHandleFromBookmark(bookmark)) + { + NativeWrapper.EvtSeek(this.handle, offset, handle, 0, UnsafeNativeMethods.EvtSeekFlags.EvtSeekRelativeToBookmark); + } + } + + [SecurityCritical] + public void Seek(SeekOrigin origin, long offset) + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + switch (origin) + { + case SeekOrigin.Begin: + SeekReset(); + NativeWrapper.EvtSeek(handle, offset, EventLogHandle.Zero, 0, UnsafeNativeMethods.EvtSeekFlags.EvtSeekRelativeToFirst); + return; + + case SeekOrigin.Current: + if (offset < 0L) + { + if ((currentIndex + offset) >= 0L) + { + SeekCommon(offset); + } + else + { + SeekCommon(offset); + } + return; + } + if ((currentIndex + offset) >= eventCount) + { + SeekCommon(offset); + return; + } + for (int i = currentIndex; i < (currentIndex + offset); i++) + { + NativeWrapper.EvtClose(eventsBuffer[i]); + } + currentIndex += (int)offset; + return; + + case SeekOrigin.End: + SeekReset(); + NativeWrapper.EvtSeek(handle, offset, EventLogHandle.Zero, 0, UnsafeNativeMethods.EvtSeekFlags.EvtSeekRelativeToLast); + return; + } + } + + [SecurityCritical] + internal void SeekCommon(long offset) + { + offset -= eventCount - currentIndex; + SeekReset(); + NativeWrapper.EvtSeek(handle, offset, EventLogHandle.Zero, 0, UnsafeNativeMethods.EvtSeekFlags.EvtSeekRelativeToCurrent); + } + + [SecurityCritical] + internal void SeekReset() + { + while (currentIndex < eventCount) + { + NativeWrapper.EvtClose(eventsBuffer[currentIndex]); + currentIndex++; + } + currentIndex = 0; + eventCount = 0; + isEof = false; + } + + [SecurityCritical] + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + } + while (currentIndex < eventCount) + { + NativeWrapper.EvtClose(eventsBuffer[currentIndex]); + currentIndex++; + } + if ((handle != null) && !handle.IsInvalid) + { + handle.Dispose(); + } + } + + [SecurityCritical] + private bool GetNextBatch(TimeSpan ts) + { + int totalMilliseconds; + if (ts == TimeSpan.MaxValue) + { + totalMilliseconds = -1; + } + else + { + totalMilliseconds = (int)ts.TotalMilliseconds; + } + if (batchSize != eventsBuffer.Length) + { + eventsBuffer = new IntPtr[batchSize]; + } + int returned = 0; + if (!NativeWrapper.EvtNext(handle, batchSize, eventsBuffer, totalMilliseconds, 0, ref returned)) + { + eventCount = 0; + currentIndex = 0; + return false; + } + currentIndex = 0; + eventCount = returned; + return true; + } + } + + [Serializable] + internal class EventLogReadingException : EventLogException + { + // Methods + public EventLogReadingException() + { + } + + public EventLogReadingException(string message) + : base(message) + { + } + + public EventLogReadingException(string message, Exception innerException) + : base(message, innerException) + { + } + + internal EventLogReadingException(int errorCode) + : base(errorCode) + { + } + + protected EventLogReadingException(SerializationInfo serializationInfo, StreamingContext streamingContext) + : base(serializationInfo, streamingContext) + { + } + } + + /// + /// Contains the status code or error code for a specific event log. This status can be used to determine if the event log is available for an operation. + /// + internal sealed class EventLogStatus + { + // Fields + private string channelName; + + private int win32ErrorCode; + + // Methods + internal EventLogStatus(string channelName, int win32ErrorCode) + { + this.channelName = channelName; + this.win32ErrorCode = win32ErrorCode; + } + + // Properties + /// Gets the name of the log. + /// The name of the log. + public string LogName => channelName; + + /// Gets the status code. + /// The status code. + public int StatusCode => win32ErrorCode; + } + + /// Used for subscribing to event record notifications from event log. + internal class EventLogWatcher : IDisposable + { + private EventLogException asyncException; + + private EventBookmark bookmark; + + /// Maintains cached display / metadata information returned from EventRecords that were obtained from this reader. + private ProviderMetadataCachedInformation cachedMetadataInformation; + + private int callbackThreadId; + + private EventLogQuery eventQuery; + + private IntPtr[] eventsBuffer; + + private EventLogHandle handle; + + private bool isSubscribing; + + private int numEventsInBuffer; + + private bool readExistingEvents; + + private RegisteredWaitHandle registeredWaitHandle; + + private AutoResetEvent subscriptionWaitHandle; + + private AutoResetEvent unregisterDoneHandle; + + /// Initializes a new instance of the class. + /// The path. + public EventLogWatcher(string path) + : this(new EventLogQuery(path, PathType.LogName), null, false) + { + } + + /// Initializes a new instance of the class. + /// The event query. + public EventLogWatcher(EventLogQuery eventQuery) + : this(eventQuery, null, false) + { + } + + /// Initializes a new instance of the class. + /// The event query. + /// The bookmark. + public EventLogWatcher(EventLogQuery eventQuery, EventBookmark bookmark) + : this(eventQuery, bookmark, false) + { + } + + /// Initializes a new instance of the class. + /// The event query. + /// The bookmark. + /// if set to true [read existing events]. + /// eventQuery + /// + public EventLogWatcher(EventLogQuery eventQuery, EventBookmark bookmark, bool readExistingEvents) + { + if (eventQuery == null) + throw new ArgumentNullException(nameof(eventQuery)); + + if (bookmark != null) + readExistingEvents = false; + + //explicit data + this.eventQuery = eventQuery; + this.readExistingEvents = readExistingEvents; + + if (this.eventQuery.ReverseDirection) + throw new InvalidOperationException(); + + eventsBuffer = new IntPtr[64]; + cachedMetadataInformation = new ProviderMetadataCachedInformation(eventQuery.Session, null, 50); + this.bookmark = bookmark; + } + + /// Occurs when [event record written]. + public event EventHandler EventRecordWritten; + + public bool Enabled + { + get + { + return isSubscribing; + } + set + { + if (value && !isSubscribing) + { + StartSubscribing(); + } + else if (!value && isSubscribing) + { + StopSubscribing(); + } + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + [System.Security.SecuritySafeCritical] + internal void StartSubscribing() + { + if (isSubscribing) + throw new InvalidOperationException(); + + int flag = 0; + if (bookmark != null) + flag |= (int)UnsafeNativeMethods.EvtSubscribeFlags.EvtSubscribeStartAfterBookmark; + else if (readExistingEvents) + flag |= (int)UnsafeNativeMethods.EvtSubscribeFlags.EvtSubscribeStartAtOldestRecord; + else + flag |= (int)UnsafeNativeMethods.EvtSubscribeFlags.EvtSubscribeToFutureEvents; + + if (eventQuery.TolerateQueryErrors) + flag |= (int)UnsafeNativeMethods.EvtSubscribeFlags.EvtSubscribeTolerateQueryErrors; + + EventLogPermissionHolder.GetEventLogPermission().Demand(); + + callbackThreadId = -1; + unregisterDoneHandle = new AutoResetEvent(false); + subscriptionWaitHandle = new AutoResetEvent(false); + + EventLogHandle bookmarkHandle = EventLogRecord.GetBookmarkHandleFromBookmark(bookmark); + + using (bookmarkHandle) + { + handle = NativeWrapper.EvtSubscribe(eventQuery.Session.Handle, + subscriptionWaitHandle.SafeWaitHandle, + eventQuery.Path, + eventQuery.Query, + bookmarkHandle, + IntPtr.Zero, + IntPtr.Zero, + flag); + } + + isSubscribing = true; + + RequestEvents(); + + registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject( + subscriptionWaitHandle, + new WaitOrTimerCallback(SubscribedEventsAvailableCallback), + null, + -1, + false); + } + + [System.Security.SecuritySafeCritical] + internal void StopSubscribing() + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + + // need to set isSubscribing to false before waiting for completion of callback. + isSubscribing = false; + + if (registeredWaitHandle != null) + { + registeredWaitHandle.Unregister(unregisterDoneHandle); + + if (callbackThreadId != Thread.CurrentThread.ManagedThreadId) + { + // not calling Stop from within callback - wait for any outstanding callbacks to complete. + if (unregisterDoneHandle != null) + unregisterDoneHandle.WaitOne(); + } + + registeredWaitHandle = null; + } + + if (unregisterDoneHandle != null) + { + unregisterDoneHandle.Close(); + unregisterDoneHandle = null; + } + + if (subscriptionWaitHandle != null) + { + subscriptionWaitHandle.Close(); + subscriptionWaitHandle = null; + } + + for (int i = 0; i < numEventsInBuffer; i++) + { + if (eventsBuffer[i] != IntPtr.Zero) + { + NativeWrapper.EvtClose(eventsBuffer[i]); + eventsBuffer[i] = IntPtr.Zero; + } + } + + numEventsInBuffer = 0; + + if (handle != null && !handle.IsInvalid) + handle.Dispose(); + } + + internal void SubscribedEventsAvailableCallback(object state, bool timedOut) + { + callbackThreadId = Thread.CurrentThread.ManagedThreadId; + try + { + RequestEvents(); + } + finally + { + callbackThreadId = -1; + } + } + + [System.Security.SecuritySafeCritical] + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + StopSubscribing(); + return; + } + + for (int i = 0; i < numEventsInBuffer; i++) + { + if (eventsBuffer[i] != IntPtr.Zero) + { + NativeWrapper.EvtClose(eventsBuffer[i]); + eventsBuffer[i] = IntPtr.Zero; + } + } + + numEventsInBuffer = 0; + } + + // marked as SecurityCritical because allocates SafeHandles. + [System.Security.SecurityCritical] + private void HandleEventsRequestCompletion() + { + if (asyncException != null) + { + EventRecordWrittenEventArgs args = new EventRecordWrittenEventArgs(asyncException); + IssueCallback(args); + } + + for (int i = 0; i < numEventsInBuffer; i++) + { + if (!isSubscribing) + break; + EventLogRecord record = new EventLogRecord(new EventLogHandle(eventsBuffer[i], true), eventQuery.Session, cachedMetadataInformation); + EventRecordWrittenEventArgs args = new EventRecordWrittenEventArgs(record); + eventsBuffer[i] = IntPtr.Zero; // user is responsible for calling Dispose(). + IssueCallback(args); + } + } + + private void IssueCallback(EventRecordWrittenEventArgs eventArgs) + { + EventRecordWritten?.Invoke(this, eventArgs); + } + + [System.Security.SecuritySafeCritical] + private void RequestEvents() + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + + asyncException = null; + Debug.Assert(numEventsInBuffer == 0); + + bool results = false; + + do + { + if (!isSubscribing) + break; + + try + { + results = NativeWrapper.EvtNext(handle, eventsBuffer.Length, eventsBuffer, 0, 0, ref numEventsInBuffer); + + if (!results) + return; + } + catch (EventLogException e) + { + asyncException = e; + } + + HandleEventsRequestCompletion(); + } while (results); + } + } + + internal class NativeWrapper + { + // Fields + private static bool s_platformNotSupported = (Environment.OSVersion.Version.Major < 6); + + // Methods + [SecurityCritical] + public static DateTime ConvertFileTimeToDateTime(UnsafeNativeMethods.EvtVariant val) + { + if (val.Type != 0x11) + { + throw new EventLogInvalidDataException(); + } + return DateTime.FromFileTime((long)val.FileTime); + } + + [SecurityCritical] + public static string ConvertToAnsiString(UnsafeNativeMethods.EvtVariant val) + { + if (val.Type != 2) + { + throw new EventLogInvalidDataException(); + } + if (val.AnsiString == IntPtr.Zero) + { + return string.Empty; + } + return Marshal.PtrToStringAuto(val.AnsiString); + } + + [SecurityCritical] + public static byte[] ConvertToBinaryArray(UnsafeNativeMethods.EvtVariant val) + { + if (val.Type != 14) + { + throw new EventLogInvalidDataException(); + } + if (val.Binary == IntPtr.Zero) + { + return new byte[0]; + } + IntPtr binary = val.Binary; + byte[] destination = new byte[val.Count]; + Marshal.Copy(binary, destination, 0, (int)val.Count); + return destination; + } + + [SecurityCritical] + public static Guid ConvertToGuid(UnsafeNativeMethods.EvtVariant val) + { + if (val.Type != 15) + { + throw new EventLogInvalidDataException(); + } + if (val.GuidReference == IntPtr.Zero) + { + return Guid.Empty; + } + return (Guid)Marshal.PtrToStructure(val.GuidReference, typeof(Guid)); + } + + [SecurityCritical] + public static int[] ConvertToIntArray(UnsafeNativeMethods.EvtVariant val) + { + if (val.Type != 0x88) + { + throw new EventLogInvalidDataException(); + } + if (val.Reference == IntPtr.Zero) + { + return new int[0]; + } + IntPtr reference = val.Reference; + int[] destination = new int[val.Count]; + Marshal.Copy(reference, destination, 0, (int)val.Count); + return destination; + } + + [SecurityCritical] + public static object ConvertToObject(UnsafeNativeMethods.EvtVariant val, UnsafeNativeMethods.EvtVariantType desiredType) + { + if (val.Type == 0) + { + return null; + } + if (val.Type != ((long)desiredType)) + { + throw new EventLogInvalidDataException(); + } + return ConvertToObject(val); + } + + [SecurityCritical] + public static EventLogHandle ConvertToSafeHandle(UnsafeNativeMethods.EvtVariant val) + { + if (val.Type != 0x20) + { + throw new EventLogInvalidDataException(); + } + if (val.Handle == IntPtr.Zero) + { + return EventLogHandle.Zero; + } + return new EventLogHandle(val.Handle, true); + } + + [SecurityCritical] + public static SecurityIdentifier ConvertToSid(UnsafeNativeMethods.EvtVariant val) + { + if (val.Type != 0x13) + { + throw new EventLogInvalidDataException(); + } + if (val.SidVal == IntPtr.Zero) + { + return null; + } + return new SecurityIdentifier(val.SidVal); + } + + [SecurityCritical] + public static string ConvertToString(UnsafeNativeMethods.EvtVariant val) + { + if (val.Type != 1) + { + throw new EventLogInvalidDataException(); + } + if (val.StringVal == IntPtr.Zero) + { + return string.Empty; + } + return Marshal.PtrToStringAuto(val.StringVal); + } + + [SecurityCritical] + public static string[] ConvertToStringArray(UnsafeNativeMethods.EvtVariant val) + { + if (val.Type != 0x81) + { + throw new EventLogInvalidDataException(); + } + if (val.Reference == IntPtr.Zero) + { + return new string[0]; + } + IntPtr reference = val.Reference; + IntPtr[] destination = new IntPtr[val.Count]; + Marshal.Copy(reference, destination, 0, (int)val.Count); + string[] strArray = new string[val.Count]; + for (int i = 0; i < val.Count; i++) + { + strArray[i] = Marshal.PtrToStringAuto(destination[i]); + } + return strArray; + } + + [SecurityCritical] + public static void EvtArchiveExportedLog(EventLogHandle session, string logFilePath, int locale, int flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogPermissionHolder.GetEventLogPermission().Demand(); + bool flag = UnsafeNativeMethods.EvtArchiveExportedLog(session, logFilePath, locale, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + } + + [SecurityCritical] + public static void EvtCancel(EventLogHandle handle) + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + if (!UnsafeNativeMethods.EvtCancel(handle)) + { + EventLogException.Throw(Marshal.GetLastWin32Error()); + } + } + + [SecurityCritical] + public static void EvtClearLog(EventLogHandle session, string channelPath, string targetFilePath, int flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogPermissionHolder.GetEventLogPermission().Demand(); + bool flag = UnsafeNativeMethods.EvtClearLog(session, channelPath, targetFilePath, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + } + + [SecurityCritical] + public static void EvtClose(IntPtr handle) + { + UnsafeNativeMethods.EvtClose(handle); + } + + [SecurityCritical] + public static EventLogHandle EvtCreateBookmark(string bookmarkXml) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogHandle handle = UnsafeNativeMethods.EvtCreateBookmark(bookmarkXml); + int errorCode = Marshal.GetLastWin32Error(); + if (handle.IsInvalid) + { + EventLogException.Throw(errorCode); + } + return handle; + } + + [SecurityCritical] + public static EventLogHandle EvtCreateRenderContext(int valuePathsCount, string[] valuePaths, UnsafeNativeMethods.EvtRenderContextFlags flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogHandle handle = UnsafeNativeMethods.EvtCreateRenderContext(valuePathsCount, valuePaths, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (handle.IsInvalid) + { + EventLogException.Throw(errorCode); + } + return handle; + } + + [SecurityCritical] + public static void EvtExportLog(EventLogHandle session, string channelPath, string query, string targetFilePath, int flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogPermissionHolder.GetEventLogPermission().Demand(); + bool flag = UnsafeNativeMethods.EvtExportLog(session, channelPath, query, targetFilePath, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + } + + [SecurityCritical] + public static string EvtFormatMessage(EventLogHandle handle, uint msgId) + { + int num; + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + StringBuilder buffer = new StringBuilder(null); + bool flag = UnsafeNativeMethods.EvtFormatMessage(handle, EventLogHandle.Zero, msgId, 0, null, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageId, 0, buffer, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x3ab5)) + { + if (errorCode == 0x3ab3) + { + return null; + } + if (errorCode != 0x7a) + { + EventLogException.Throw(errorCode); + } + } + buffer.EnsureCapacity(num); + flag = UnsafeNativeMethods.EvtFormatMessage(handle, EventLogHandle.Zero, msgId, 0, null, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageId, num, buffer, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x3ab5)) + { + if (errorCode == 0x3ab3) + { + return null; + } + if (errorCode == 0x3ab5) + { + return null; + } + EventLogException.Throw(errorCode); + } + return buffer.ToString(); + } + + [SecurityCritical] + public static string EvtFormatMessageFormatDescription(EventLogHandle handle, EventLogHandle eventHandle, string[] values) + { + int num; + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogPermissionHolder.GetEventLogPermission().Demand(); + UnsafeNativeMethods.EvtStringVariant[] variantArray = new UnsafeNativeMethods.EvtStringVariant[values.Length]; + for (int i = 0; i < values.Length; i++) + { + variantArray[i].Type = 1; + variantArray[i].StringVal = values[i]; + } + StringBuilder buffer = new StringBuilder(null); + bool flag = UnsafeNativeMethods.EvtFormatMessage(handle, eventHandle, uint.MaxValue, values.Length, variantArray, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageEvent, 0, buffer, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x3ab5)) + { + switch (errorCode) + { + case 0x3ab9: + case 0x3afc: + case 0x3ab3: + case 0x3ab4: + case 0x717: + return null; + } + if (errorCode != 0x7a) + { + EventLogException.Throw(errorCode); + } + } + buffer.EnsureCapacity(num); + flag = UnsafeNativeMethods.EvtFormatMessage(handle, eventHandle, uint.MaxValue, values.Length, variantArray, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageEvent, num, buffer, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x3ab5)) + { + if (errorCode == 0x3ab3) + { + return null; + } + EventLogException.Throw(errorCode); + } + return buffer.ToString(); + } + + [SecurityCritical] + public static IEnumerable EvtFormatMessageRenderKeywords(EventLogHandle pmHandle, EventLogHandle eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags flag) + { + IEnumerable enumerable; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + IntPtr zero = IntPtr.Zero; + try + { + int num; + List list = new List(); + bool flag2 = UnsafeNativeMethods.EvtFormatMessageBuffer(pmHandle, eventHandle, 0, 0, IntPtr.Zero, flag, 0, IntPtr.Zero, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag2) + { + switch (errorCode) + { + case 0x3ab9: + case 0x3afc: + case 0x3ab3: + case 0x3ab4: + case 0x717: + return list.AsReadOnly(); + } + if (errorCode != 0x7a) + { + EventLogException.Throw(errorCode); + } + } + zero = Marshal.AllocHGlobal((int)(num * 2)); + flag2 = UnsafeNativeMethods.EvtFormatMessageBuffer(pmHandle, eventHandle, 0, 0, IntPtr.Zero, flag, num, zero, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag2) + { + switch (errorCode) + { + case 0x3ab9: + case 0x3afc: + case 0x3ab3: + case 0x3ab4: + case 0x717: + return list; + } + EventLogException.Throw(errorCode); + } + IntPtr ptr = zero; + while (true) + { + string str = Marshal.PtrToStringAuto(ptr); + if (string.IsNullOrEmpty(str)) + { + break; + } + list.Add(str); + ptr = new IntPtr((((long)ptr) + (str.Length * 2)) + 2L); + } + enumerable = list.AsReadOnly(); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + return enumerable; + } + + [SecurityCritical] + public static string EvtFormatMessageRenderName(EventLogHandle pmHandle, EventLogHandle eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags flag) + { + int num; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + StringBuilder buffer = new StringBuilder(null); + bool flag2 = UnsafeNativeMethods.EvtFormatMessage(pmHandle, eventHandle, 0, 0, null, flag, 0, buffer, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag2 && (errorCode != 0x3ab5)) + { + switch (errorCode) + { + case 0x3ab9: + case 0x3afc: + case 0x3ab3: + case 0x3ab4: + case 0x717: + return null; + } + if (errorCode != 0x7a) + { + EventLogException.Throw(errorCode); + } + } + buffer.EnsureCapacity(num); + flag2 = UnsafeNativeMethods.EvtFormatMessage(pmHandle, eventHandle, 0, 0, null, flag, num, buffer, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag2 && (errorCode != 0x3ab5)) + { + switch (errorCode) + { + case 0x3ab9: + case 0x3afc: + case 0x3ab3: + case 0x3ab4: + case 0x717: + return null; + } + EventLogException.Throw(errorCode); + } + return buffer.ToString(); + } + + [SecurityCritical] + public static object EvtGetChannelConfigProperty(EventLogHandle handle, UnsafeNativeMethods.EvtChannelConfigPropertyId enumType) + { + object obj2; + IntPtr zero = IntPtr.Zero; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + try + { + int num; + bool flag = UnsafeNativeMethods.EvtGetChannelConfigProperty(handle, enumType, 0, 0, IntPtr.Zero, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x7a)) + { + EventLogException.Throw(errorCode); + } + zero = Marshal.AllocHGlobal(num); + flag = UnsafeNativeMethods.EvtGetChannelConfigProperty(handle, enumType, 0, num, zero, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + UnsafeNativeMethods.EvtVariant val = (UnsafeNativeMethods.EvtVariant)Marshal.PtrToStructure(zero, typeof(UnsafeNativeMethods.EvtVariant)); + obj2 = ConvertToObject(val); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + return obj2; + } + + [SecurityCritical] + public static object EvtGetEventInfo(EventLogHandle handle, UnsafeNativeMethods.EvtEventPropertyId enumType) + { + object obj2; + IntPtr zero = IntPtr.Zero; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + try + { + int num; + bool flag = UnsafeNativeMethods.EvtGetEventInfo(handle, enumType, 0, IntPtr.Zero, out num); + int errorCode = Marshal.GetLastWin32Error(); + if ((!flag && (errorCode != 0)) && (errorCode != 0x7a)) + { + EventLogException.Throw(errorCode); + } + zero = Marshal.AllocHGlobal(num); + flag = UnsafeNativeMethods.EvtGetEventInfo(handle, enumType, num, zero, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + UnsafeNativeMethods.EvtVariant val = (UnsafeNativeMethods.EvtVariant)Marshal.PtrToStructure(zero, typeof(UnsafeNativeMethods.EvtVariant)); + obj2 = ConvertToObject(val); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + return obj2; + } + + [SecurityCritical] + public static object EvtGetEventMetadataProperty(EventLogHandle handle, UnsafeNativeMethods.EvtEventMetadataPropertyId enumType) + { + object obj2; + IntPtr zero = IntPtr.Zero; + try + { + int num; + bool flag = UnsafeNativeMethods.EvtGetEventMetadataProperty(handle, enumType, 0, 0, IntPtr.Zero, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x7a)) + { + EventLogException.Throw(errorCode); + } + zero = Marshal.AllocHGlobal(num); + flag = UnsafeNativeMethods.EvtGetEventMetadataProperty(handle, enumType, 0, num, zero, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + UnsafeNativeMethods.EvtVariant val = (UnsafeNativeMethods.EvtVariant)Marshal.PtrToStructure(zero, typeof(UnsafeNativeMethods.EvtVariant)); + obj2 = ConvertToObject(val); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + return obj2; + } + + [SecurityCritical] + public static object EvtGetLogInfo(EventLogHandle handle, UnsafeNativeMethods.EvtLogPropertyId enumType) + { + object obj2; + IntPtr zero = IntPtr.Zero; + try + { + int num; + bool flag = UnsafeNativeMethods.EvtGetLogInfo(handle, enumType, 0, IntPtr.Zero, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x7a)) + { + EventLogException.Throw(errorCode); + } + zero = Marshal.AllocHGlobal(num); + flag = UnsafeNativeMethods.EvtGetLogInfo(handle, enumType, num, zero, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + UnsafeNativeMethods.EvtVariant val = (UnsafeNativeMethods.EvtVariant)Marshal.PtrToStructure(zero, typeof(UnsafeNativeMethods.EvtVariant)); + obj2 = ConvertToObject(val); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + return obj2; + } + + [SecurityCritical] + public static object EvtGetObjectArrayProperty(EventLogHandle objArrayHandle, int index, int thePropertyId) + { + object obj2; + IntPtr zero = IntPtr.Zero; + try + { + int num; + bool flag = UnsafeNativeMethods.EvtGetObjectArrayProperty(objArrayHandle, thePropertyId, index, 0, 0, IntPtr.Zero, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x7a)) + { + EventLogException.Throw(errorCode); + } + zero = Marshal.AllocHGlobal(num); + flag = UnsafeNativeMethods.EvtGetObjectArrayProperty(objArrayHandle, thePropertyId, index, 0, num, zero, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + UnsafeNativeMethods.EvtVariant val = (UnsafeNativeMethods.EvtVariant)Marshal.PtrToStructure(zero, typeof(UnsafeNativeMethods.EvtVariant)); + obj2 = ConvertToObject(val); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + return obj2; + } + + [SecurityCritical] + public static int EvtGetObjectArraySize(EventLogHandle objectArray) + { + int num; + bool flag = UnsafeNativeMethods.EvtGetObjectArraySize(objectArray, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + return num; + } + + [SecurityCritical] + public static object EvtGetPublisherMetadataProperty(EventLogHandle pmHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId thePropertyId) + { + object obj2; + IntPtr zero = IntPtr.Zero; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + try + { + int num; + bool flag = UnsafeNativeMethods.EvtGetPublisherMetadataProperty(pmHandle, thePropertyId, 0, 0, IntPtr.Zero, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x7a)) + { + EventLogException.Throw(errorCode); + } + zero = Marshal.AllocHGlobal(num); + flag = UnsafeNativeMethods.EvtGetPublisherMetadataProperty(pmHandle, thePropertyId, 0, num, zero, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + UnsafeNativeMethods.EvtVariant val = (UnsafeNativeMethods.EvtVariant)Marshal.PtrToStructure(zero, typeof(UnsafeNativeMethods.EvtVariant)); + obj2 = ConvertToObject(val); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + return obj2; + } + + [SecurityCritical] + public static object EvtGetQueryInfo(EventLogHandle handle, UnsafeNativeMethods.EvtQueryPropertyId enumType) + { + object obj2; + IntPtr zero = IntPtr.Zero; + int bufferRequired = 0; + try + { + bool flag = UnsafeNativeMethods.EvtGetQueryInfo(handle, enumType, 0, IntPtr.Zero, ref bufferRequired); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x7a)) + { + EventLogException.Throw(errorCode); + } + zero = Marshal.AllocHGlobal(bufferRequired); + flag = UnsafeNativeMethods.EvtGetQueryInfo(handle, enumType, bufferRequired, zero, ref bufferRequired); + errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + UnsafeNativeMethods.EvtVariant val = (UnsafeNativeMethods.EvtVariant)Marshal.PtrToStructure(zero, typeof(UnsafeNativeMethods.EvtVariant)); + obj2 = ConvertToObject(val); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + return obj2; + } + + [SecurityCritical] + public static bool EvtNext(EventLogHandle queryHandle, int eventSize, IntPtr[] events, int timeout, int flags, ref int returned) + { + bool flag = UnsafeNativeMethods.EvtNext(queryHandle, eventSize, events, timeout, flags, ref returned); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x103)) + { + EventLogException.Throw(errorCode); + } + return (errorCode == 0); + } + + [SecurityCritical] + public static string EvtNextChannelPath(EventLogHandle handle, ref bool finish) + { + int num; + StringBuilder channelPathBuffer = new StringBuilder(null); + bool flag = UnsafeNativeMethods.EvtNextChannelPath(handle, 0, channelPathBuffer, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + if (errorCode == 0x103) + { + finish = true; + return null; + } + if (errorCode != 0x7a) + { + EventLogException.Throw(errorCode); + } + } + channelPathBuffer.EnsureCapacity(num); + flag = UnsafeNativeMethods.EvtNextChannelPath(handle, num, channelPathBuffer, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + return channelPathBuffer.ToString(); + } + + [SecurityCritical] + public static EventLogHandle EvtNextEventMetadata(EventLogHandle eventMetadataEnum, int flags) + { + EventLogHandle handle = UnsafeNativeMethods.EvtNextEventMetadata(eventMetadataEnum, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (!handle.IsInvalid) + { + return handle; + } + if (errorCode != 0x103) + { + EventLogException.Throw(errorCode); + } + return null; + } + + [SecurityCritical] + public static string EvtNextPublisherId(EventLogHandle handle, ref bool finish) + { + int num; + StringBuilder publisherIdBuffer = new StringBuilder(null); + bool flag = UnsafeNativeMethods.EvtNextPublisherId(handle, 0, publisherIdBuffer, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + if (errorCode == 0x103) + { + finish = true; + return null; + } + if (errorCode != 0x7a) + { + EventLogException.Throw(errorCode); + } + } + publisherIdBuffer.EnsureCapacity(num); + flag = UnsafeNativeMethods.EvtNextPublisherId(handle, num, publisherIdBuffer, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + return publisherIdBuffer.ToString(); + } + + [SecurityCritical] + public static EventLogHandle EvtOpenChannelConfig(EventLogHandle session, string channelPath, int flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogHandle handle = UnsafeNativeMethods.EvtOpenChannelConfig(session, channelPath, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (handle.IsInvalid) + { + EventLogException.Throw(errorCode); + } + return handle; + } + + [SecurityCritical] + public static EventLogHandle EvtOpenChannelEnum(EventLogHandle session, int flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogHandle handle = UnsafeNativeMethods.EvtOpenChannelEnum(session, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (handle.IsInvalid) + { + EventLogException.Throw(errorCode); + } + return handle; + } + + [SecurityCritical] + public static EventLogHandle EvtOpenEventMetadataEnum(EventLogHandle ProviderMetadata, int flags) + { + EventLogHandle handle = UnsafeNativeMethods.EvtOpenEventMetadataEnum(ProviderMetadata, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (handle.IsInvalid) + { + EventLogException.Throw(errorCode); + } + return handle; + } + + [SecurityCritical] + public static EventLogHandle EvtOpenLog(EventLogHandle session, string path, PathType flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogHandle handle = UnsafeNativeMethods.EvtOpenLog(session, path, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (handle.IsInvalid) + { + EventLogException.Throw(errorCode); + } + return handle; + } + + [SecurityCritical] + public static EventLogHandle EvtOpenProviderEnum(EventLogHandle session, int flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogHandle handle = UnsafeNativeMethods.EvtOpenPublisherEnum(session, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (handle.IsInvalid) + { + EventLogException.Throw(errorCode); + } + return handle; + } + + [SecurityCritical] + public static EventLogHandle EvtOpenProviderMetadata(EventLogHandle session, string ProviderId, string logFilePath, int locale, int flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogHandle handle = UnsafeNativeMethods.EvtOpenPublisherMetadata(session, ProviderId, logFilePath, 0, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (handle.IsInvalid) + { + EventLogException.Throw(errorCode); + } + return handle; + } + + [SecurityCritical] + public static EventLogHandle EvtOpenSession(UnsafeNativeMethods.EvtLoginClass loginClass, ref UnsafeNativeMethods.EvtRpcLogin login, int timeout, int flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogHandle handle = UnsafeNativeMethods.EvtOpenSession(loginClass, ref login, timeout, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (handle.IsInvalid) + { + EventLogException.Throw(errorCode); + } + return handle; + } + + [SecurityCritical] + public static EventLogHandle EvtQuery(EventLogHandle session, string path, string query, int flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogHandle handle = UnsafeNativeMethods.EvtQuery(session, path, query, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (handle.IsInvalid) + { + EventLogException.Throw(errorCode); + } + return handle; + } + + [SecurityCritical] + public static void EvtRender(EventLogHandle context, EventLogHandle eventHandle, UnsafeNativeMethods.EvtRenderFlags flags, StringBuilder buffer) + { + int num; + int num2; + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + bool flag = UnsafeNativeMethods.EvtRender(context, eventHandle, flags, buffer.Capacity, buffer, out num, out num2); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + if (errorCode == 0x7a) + { + buffer.Capacity = num; + flag = UnsafeNativeMethods.EvtRender(context, eventHandle, flags, buffer.Capacity, buffer, out num, out num2); + errorCode = Marshal.GetLastWin32Error(); + } + if (!flag) + { + EventLogException.Throw(errorCode); + } + } + } + + [SecurityCritical] + public static string EvtRenderBookmark(EventLogHandle eventHandle) + { + string str; + IntPtr zero = IntPtr.Zero; + UnsafeNativeMethods.EvtRenderFlags evtRenderBookmark = UnsafeNativeMethods.EvtRenderFlags.EvtRenderBookmark; + try + { + int num; + int num2; + bool flag = UnsafeNativeMethods.EvtRender(EventLogHandle.Zero, eventHandle, evtRenderBookmark, 0, IntPtr.Zero, out num, out num2); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x7a)) + { + EventLogException.Throw(errorCode); + } + zero = Marshal.AllocHGlobal(num); + flag = UnsafeNativeMethods.EvtRender(EventLogHandle.Zero, eventHandle, evtRenderBookmark, num, zero, out num, out num2); + errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + str = Marshal.PtrToStringAuto(zero); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + return str; + } + + [SecurityCritical] + public static void EvtRenderBufferWithContextSystem(EventLogHandle contextHandle, EventLogHandle eventHandle, UnsafeNativeMethods.EvtRenderFlags flag, SystemProperties systemProperties, int SYSTEM_PROPERTY_COUNT) + { + IntPtr zero = IntPtr.Zero; + IntPtr ptr = IntPtr.Zero; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + try + { + int num; + int num2; + if (!UnsafeNativeMethods.EvtRender(contextHandle, eventHandle, flag, 0, IntPtr.Zero, out num, out num2)) + { + int num3 = Marshal.GetLastWin32Error(); + if (num3 != 0x7a) + { + EventLogException.Throw(num3); + } + } + zero = Marshal.AllocHGlobal(num); + bool flag2 = UnsafeNativeMethods.EvtRender(contextHandle, eventHandle, flag, num, zero, out num, out num2); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag2) + { + EventLogException.Throw(errorCode); + } + if (num2 != SYSTEM_PROPERTY_COUNT) + { + throw new InvalidOperationException("We do not have " + SYSTEM_PROPERTY_COUNT + " variants given for the UnsafeNativeMethods.EvtRenderFlags.EvtRenderEventValues flag. (System Properties)"); + } + ptr = zero; + for (int i = 0; i < num2; i++) + { + UnsafeNativeMethods.EvtVariant val = (UnsafeNativeMethods.EvtVariant)Marshal.PtrToStructure(ptr, typeof(UnsafeNativeMethods.EvtVariant)); + switch (i) + { + case 0: + systemProperties.ProviderName = (string)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeString); + break; + + case 1: + systemProperties.ProviderId = (Guid?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeGuid); + break; + + case 2: + systemProperties.Id = (ushort?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeUInt16); + break; + + case 3: + systemProperties.Qualifiers = (ushort?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeUInt16); + break; + + case 4: + systemProperties.Level = (byte?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeByte); + break; + + case 5: + systemProperties.Task = (ushort?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeUInt16); + break; + + case 6: + systemProperties.Opcode = (byte?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeByte); + break; + + case 7: + systemProperties.Keywords = (ulong?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeHexInt64); + break; + + case 8: + systemProperties.TimeCreated = (DateTime?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeFileTime); + break; + + case 9: + systemProperties.RecordId = (ulong?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeUInt64); + break; + + case 10: + systemProperties.ActivityId = (Guid?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeGuid); + break; + + case 11: + systemProperties.RelatedActivityId = (Guid?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeGuid); + break; + + case 12: + systemProperties.ProcessId = (uint?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeUInt32); + break; + + case 13: + systemProperties.ThreadId = (uint?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeUInt32); + break; + + case 14: + systemProperties.ChannelName = (string)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeString); + break; + + case 15: + systemProperties.ComputerName = (string)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeString); + break; + + case 0x10: + systemProperties.UserId = (SecurityIdentifier)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeSid); + break; + + case 0x11: + systemProperties.Version = (byte?)ConvertToObject(val, UnsafeNativeMethods.EvtVariantType.EvtVarTypeByte); + break; + } + ptr = new IntPtr(((long)ptr) + Marshal.SizeOf(val)); + } + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + } + + [SecurityCritical] + public static IList EvtRenderBufferWithContextUserOrValues(EventLogHandle contextHandle, EventLogHandle eventHandle) + { + IList list2; + IntPtr zero = IntPtr.Zero; + IntPtr ptr = IntPtr.Zero; + UnsafeNativeMethods.EvtRenderFlags evtRenderEventValues = UnsafeNativeMethods.EvtRenderFlags.EvtRenderEventValues; + EventLogPermissionHolder.GetEventLogPermission().Demand(); + try + { + int num; + int num2; + if (!UnsafeNativeMethods.EvtRender(contextHandle, eventHandle, evtRenderEventValues, 0, IntPtr.Zero, out num, out num2)) + { + int num3 = Marshal.GetLastWin32Error(); + if (num3 != 0x7a) + { + EventLogException.Throw(num3); + } + } + zero = Marshal.AllocHGlobal(num); + bool flag = UnsafeNativeMethods.EvtRender(contextHandle, eventHandle, evtRenderEventValues, num, zero, out num, out num2); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + List list = new List(num2); + if (num2 > 0) + { + ptr = zero; + for (int i = 0; i < num2; i++) + { + UnsafeNativeMethods.EvtVariant val = (UnsafeNativeMethods.EvtVariant)Marshal.PtrToStructure(ptr, typeof(UnsafeNativeMethods.EvtVariant)); + list.Add(ConvertToObject(val)); + ptr = new IntPtr(((long)ptr) + Marshal.SizeOf(val)); + } + } + list2 = list; + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + return list2; + } + + [SecurityCritical] + public static void EvtSaveChannelConfig(EventLogHandle channelConfig, int flags) + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + bool flag = UnsafeNativeMethods.EvtSaveChannelConfig(channelConfig, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + } + + [SecurityCritical] + public static void EvtSeek(EventLogHandle resultSet, long position, EventLogHandle bookmark, int timeout, UnsafeNativeMethods.EvtSeekFlags flags) + { + bool flag = UnsafeNativeMethods.EvtSeek(resultSet, position, bookmark, timeout, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + } + + [SecurityCritical] + public static void EvtSetChannelConfigProperty(EventLogHandle handle, UnsafeNativeMethods.EvtChannelConfigPropertyId enumType, object val) + { + EventLogPermissionHolder.GetEventLogPermission().Demand(); + UnsafeNativeMethods.EvtVariant propertyValue = new UnsafeNativeMethods.EvtVariant(); + CoTaskMemSafeHandle handle2 = new CoTaskMemSafeHandle(); + using (handle2) + { + bool flag; + if (val == null) + { + goto Label_017B; + } + switch (enumType) + { + case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigEnabled: + propertyValue.Type = 13; + if (!((bool)val)) + { + break; + } + propertyValue.Bool = 1; + goto Label_0183; + + case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigAccess: + propertyValue.Type = 1; + handle2.SetMemory(Marshal.StringToCoTaskMemAuto((string)val)); + propertyValue.StringVal = handle2.GetMemory(); + goto Label_0183; + + case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention: + propertyValue.Type = 13; + if (!((bool)val)) + { + goto Label_0146; + } + propertyValue.Bool = 1; + goto Label_0183; + + case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup: + propertyValue.Type = 13; + if (!((bool)val)) + { + goto Label_016B; + } + propertyValue.Bool = 1; + goto Label_0183; + + case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigMaxSize: + propertyValue.Type = 10; + propertyValue.ULong = (ulong)((long)val); + goto Label_0183; + + case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigLogFilePath: + propertyValue.Type = 1; + handle2.SetMemory(Marshal.StringToCoTaskMemAuto((string)val)); + propertyValue.StringVal = handle2.GetMemory(); + goto Label_0183; + + case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigLevel: + propertyValue.Type = 8; + propertyValue.UInteger = (uint)((int)val); + goto Label_0183; + + case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigKeywords: + propertyValue.Type = 10; + propertyValue.ULong = (ulong)((long)val); + goto Label_0183; + + default: + throw new InvalidOperationException(); + } + propertyValue.Bool = 0; + goto Label_0183; + Label_0146: + propertyValue.Bool = 0; + goto Label_0183; + Label_016B: + propertyValue.Bool = 0; + goto Label_0183; + Label_017B: + propertyValue.Type = 0; + Label_0183: + flag = UnsafeNativeMethods.EvtSetChannelConfigProperty(handle, enumType, 0, ref propertyValue); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + } + } + + [SecurityCritical] + public static EventLogHandle EvtSubscribe(EventLogHandle session, SafeWaitHandle signalEvent, string path, string query, EventLogHandle bookmark, IntPtr context, IntPtr callback, int flags) + { + if (s_platformNotSupported) + { + throw new PlatformNotSupportedException(); + } + EventLogHandle handle = UnsafeNativeMethods.EvtSubscribe(session, signalEvent, path, query, bookmark, context, callback, flags); + int errorCode = Marshal.GetLastWin32Error(); + if (handle.IsInvalid) + { + EventLogException.Throw(errorCode); + } + return handle; + } + + [SecurityCritical] + public static void EvtUpdateBookmark(EventLogHandle bookmark, EventLogHandle eventHandle) + { + bool flag = UnsafeNativeMethods.EvtUpdateBookmark(bookmark, eventHandle); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + } + + [SecurityCritical] + internal static EventLogHandle EvtGetPublisherMetadataPropertyHandle(EventLogHandle pmHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId thePropertyId) + { + EventLogHandle handle; + IntPtr zero = IntPtr.Zero; + try + { + int num; + bool flag = UnsafeNativeMethods.EvtGetPublisherMetadataProperty(pmHandle, thePropertyId, 0, 0, IntPtr.Zero, out num); + int errorCode = Marshal.GetLastWin32Error(); + if (!flag && (errorCode != 0x7a)) + { + EventLogException.Throw(errorCode); + } + zero = Marshal.AllocHGlobal(num); + flag = UnsafeNativeMethods.EvtGetPublisherMetadataProperty(pmHandle, thePropertyId, 0, num, zero, out num); + errorCode = Marshal.GetLastWin32Error(); + if (!flag) + { + EventLogException.Throw(errorCode); + } + UnsafeNativeMethods.EvtVariant val = (UnsafeNativeMethods.EvtVariant)Marshal.PtrToStructure(zero, typeof(UnsafeNativeMethods.EvtVariant)); + handle = ConvertToSafeHandle(val); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + } + return handle; + } + + [SecurityCritical] + private static object ConvertToObject(UnsafeNativeMethods.EvtVariant val) + { + switch (val.Type) + { + case 0: + return null; + + case 1: + return ConvertToString(val); + + case 2: + return ConvertToAnsiString(val); + + case 3: + return val.SByte; + + case 4: + return val.UInt8; + + case 5: + return val.SByte; + + case 6: + return val.UShort; + + case 7: + return val.Integer; + + case 8: + return val.UInteger; + + case 9: + return val.Long; + + case 10: + return val.ULong; + + case 12: + return val.Double; + + case 13: + if (val.Bool == 0) + { + return false; + } + return true; + + case 14: + return ConvertToBinaryArray(val); + + case 15: + return ConvertToGuid(val); + + case 0x11: + return ConvertFileTimeToDateTime(val); + + case 0x13: + return ConvertToSid(val); + + case 20: + return val.Integer; + + case 0x15: + return val.ULong; + + case 0x20: + return ConvertToSafeHandle(val); + + case 0x81: + return ConvertToStringArray(val); + + case 0x88: + return ConvertToIntArray(val); + } + throw new EventLogInvalidDataException(); + } + + // Nested Types + + internal class SystemProperties + { + // Fields + public Guid? ActivityId = null; + + public string ChannelName; + public string ComputerName; + public bool filled; + public ushort? Id = null; + public ulong? Keywords = null; + public byte? Level = null; + public byte? Opcode = null; + public uint? ProcessId = null; + public Guid? ProviderId = null; + public string ProviderName; + public ushort? Qualifiers = null; + public ulong? RecordId = null; + public Guid? RelatedActivityId = null; + public ushort? Task = null; + public uint? ThreadId = null; + public DateTime? TimeCreated = null; + public SecurityIdentifier UserId; + public byte? Version = null; + } + } + + internal class ProviderMetadataCachedInformation + { + // Fields + private Dictionary cache; + + private string logfile; + private int maximumCacheSize; + private EventLogSession session; + + // Methods + public ProviderMetadataCachedInformation(EventLogSession session, string logfile, int maximumCacheSize) + { + this.session = session; + this.logfile = logfile; + cache = new Dictionary(); + this.maximumCacheSize = maximumCacheSize; + } + + public string GetFormatDescription(string ProviderName, EventLogHandle eventHandle) + { + string str; + lock (this) + { + ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); + try + { + str = NativeWrapper.EvtFormatMessageRenderName(GetProviderMetadata(key).Handle, eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageEvent); + } + catch (EventLogNotFoundException) + { + str = null; + } + } + return str; + } + + public string GetFormatDescription(string ProviderName, EventLogHandle eventHandle, string[] values) + { + string str; + lock (this) + { + ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); + ProviderMetadata providerMetadata = GetProviderMetadata(key); + try + { + str = NativeWrapper.EvtFormatMessageFormatDescription(providerMetadata.Handle, eventHandle, values); + } + catch (EventLogNotFoundException) + { + str = null; + } + } + return str; + } + + public IEnumerable GetKeywordDisplayNames(string ProviderName, EventLogHandle eventHandle) + { + lock (this) + { + ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); + return NativeWrapper.EvtFormatMessageRenderKeywords(GetProviderMetadata(key).Handle, eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageKeyword); + } + } + + public string GetLevelDisplayName(string ProviderName, EventLogHandle eventHandle) + { + lock (this) + { + ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); + return NativeWrapper.EvtFormatMessageRenderName(GetProviderMetadata(key).Handle, eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageLevel); + } + } + + public string GetOpcodeDisplayName(string ProviderName, EventLogHandle eventHandle) + { + lock (this) + { + ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); + return NativeWrapper.EvtFormatMessageRenderName(GetProviderMetadata(key).Handle, eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageOpcode); + } + } + + public string GetTaskDisplayName(string ProviderName, EventLogHandle eventHandle) + { + lock (this) + { + ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); + return NativeWrapper.EvtFormatMessageRenderName(GetProviderMetadata(key).Handle, eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageTask); + } + } + + private static void UpdateCacheValueInfoForHit(CacheItem cacheItem) + { + cacheItem.TheTime = DateTime.Now; + } + + private void AddCacheEntry(ProviderMetadataId key, ProviderMetadata pm) + { + if (IsCacheFull()) + { + FlushOldestEntry(); + } + CacheItem item = new CacheItem(pm); + cache.Add(key, item); + } + + private void DeleteCacheEntry(ProviderMetadataId key) + { + if (IsProviderinCache(key)) + { + CacheItem item = cache[key]; + cache.Remove(key); + item.ProviderMetadata.Dispose(); + } + } + + private void FlushOldestEntry() + { + double totalMilliseconds = -10.0; + DateTime now = DateTime.Now; + ProviderMetadataId key = null; + foreach (KeyValuePair pair in cache) + { + TimeSpan span = now.Subtract(pair.Value.TheTime); + if (span.TotalMilliseconds >= totalMilliseconds) + { + totalMilliseconds = span.TotalMilliseconds; + key = pair.Key; + } + } + if (key != null) + { + DeleteCacheEntry(key); + } + } + + private ProviderMetadata GetProviderMetadata(ProviderMetadataId key) + { + if (!IsProviderinCache(key)) + { + ProviderMetadata metadata; + try + { + metadata = new ProviderMetadata(key.ProviderName, session, key.TheCultureInfo, logfile); + } + catch (EventLogNotFoundException) + { + metadata = new ProviderMetadata(key.ProviderName, session, key.TheCultureInfo); + } + AddCacheEntry(key, metadata); + return metadata; + } + CacheItem cacheItem = cache[key]; + ProviderMetadata providerMetadata = cacheItem.ProviderMetadata; + try + { + providerMetadata.CheckReleased(); + UpdateCacheValueInfoForHit(cacheItem); + } + catch (EventLogException) + { + DeleteCacheEntry(key); + try + { + providerMetadata = new ProviderMetadata(key.ProviderName, session, key.TheCultureInfo, logfile); + } + catch (EventLogNotFoundException) + { + providerMetadata = new ProviderMetadata(key.ProviderName, session, key.TheCultureInfo); + } + AddCacheEntry(key, providerMetadata); + } + return providerMetadata; + } + + private bool IsCacheFull() => (cache.Count == maximumCacheSize); + + private bool IsProviderinCache(ProviderMetadataId key) => cache.ContainsKey(key); + + // Nested Types + private class CacheItem + { + // Fields + private ProviderMetadata pm; + + private DateTime theTime; + + // Methods + public CacheItem(ProviderMetadata pm) + { + this.pm = pm; + theTime = DateTime.Now; + } + + // Properties + public ProviderMetadata ProviderMetadata => pm; + + public DateTime TheTime + { + get + { + return theTime; + } + set + { + theTime = value; + } + } + } + + private class ProviderMetadataId + { + // Fields + private CultureInfo cultureInfo; + + private string providerName; + + // Methods + public ProviderMetadataId(string providerName, CultureInfo cultureInfo) + { + this.providerName = providerName; + this.cultureInfo = cultureInfo; + } + + // Properties + public string ProviderName => providerName; + + public CultureInfo TheCultureInfo => cultureInfo; + + public override bool Equals(object obj) + { + ProviderMetadataCachedInformation.ProviderMetadataId id = obj as ProviderMetadataCachedInformation.ProviderMetadataId; + if (id == null) + { + return false; + } + return (providerName.Equals(id.providerName) && (cultureInfo == id.cultureInfo)); + } + + public override int GetHashCode() => (providerName.GetHashCode() ^ cultureInfo.GetHashCode()); + } + } +} + +#endif \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/ExtensionAttributeFor.NET_2.0.cs b/FlashPatcher/TaskService/Native/ExtensionAttributeFor.NET_2.0.cs new file mode 100644 index 0000000..a975a38 --- /dev/null +++ b/FlashPatcher/TaskService/Native/ExtensionAttributeFor.NET_2.0.cs @@ -0,0 +1,11 @@ +#if NET20 +namespace System.Runtime.CompilerServices +{ + /// + /// Attribute allowing extenders to be used with .NET Framework 2.0. + /// + internal sealed class ExtensionAttribute : Attribute + { + } +} +#endif \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/Func.Net2.cs b/FlashPatcher/TaskService/Native/Func.Net2.cs new file mode 100644 index 0000000..91da29c --- /dev/null +++ b/FlashPatcher/TaskService/Native/Func.Net2.cs @@ -0,0 +1,32 @@ +#if (NET20) +namespace System +{ + /// Encapsulates a method that has one parameter and returns a value of the type specified by the TResult parameter. + /// The type of the return value of the method that this delegate encapsulates. + /// The return value of the method that this delegate encapsulates. + internal delegate TResult Func(); + + /// Encapsulates a method that has one parameter and returns a value of the type specified by the TResult parameter. + /// The type of the parameter of the method that this delegate encapsulates. + /// The type of the return value of the method that this delegate encapsulates. + /// The parameter of the method that this delegate encapsulates. + /// The return value of the method that this delegate encapsulates. + internal delegate TResult Func(T arg); + + /// Encapsulates a method that has two parameters and returns a value of the type specified by the TResult parameter. + /// The type of the first parameter of the method that this delegate encapsulates. + /// The type of the second parameter of the method that this delegate encapsulates. + /// The type of the return value of the method that this delegate encapsulates. + /// The first parameter of the method that this delegate encapsulates. + /// The second parameter of the method that this delegate encapsulates. + /// The return value of the method that this delegate encapsulates. + internal delegate TResult Func(T1 arg1, T2 arg2); + + /// Encapsulates a method that has two parameters and does not return a value. + /// The type of the first parameter of the method that this delegate encapsulates. + /// The type of the second parameter of the method that this delegate encapsulates. + /// The first parameter of the method that this delegate encapsulates. + /// The second parameter of the method that this delegate encapsulates. + internal delegate void Action(T1 arg1, T2 arg2); +} +#endif \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/InteropUtil.cs b/FlashPatcher/TaskService/Native/InteropUtil.cs new file mode 100644 index 0000000..dfbe65f --- /dev/null +++ b/FlashPatcher/TaskService/Native/InteropUtil.cs @@ -0,0 +1,143 @@ +using System.Collections; +using System.Collections.Generic; + +// ReSharper disable once CheckNamespace +namespace System.Runtime.InteropServices +{ + internal static class InteropUtil + { + private const int cbBuffer = 256; + + public static T ToStructure(IntPtr ptr) => (T)Marshal.PtrToStructure(ptr, typeof(T)); + + public static IntPtr StructureToPtr(object value) + { + IntPtr ret = Marshal.AllocHGlobal(Marshal.SizeOf(value)); + Marshal.StructureToPtr(value, ret, false); + return ret; + } + + public static void AllocString(ref IntPtr ptr, ref uint size) + { + FreeString(ref ptr, ref size); + if (size == 0) size = cbBuffer; + ptr = Marshal.AllocHGlobal(cbBuffer); + } + + public static void FreeString(ref IntPtr ptr, ref uint size) + { + if (ptr != IntPtr.Zero) + { + Marshal.FreeHGlobal(ptr); + ptr = IntPtr.Zero; + size = 0; + } + } + + public static string GetString(IntPtr pString) => Marshal.PtrToStringUni(pString); + + public static bool SetString(ref IntPtr ptr, ref uint size, string value = null) + { + string s = GetString(ptr); + if (value == string.Empty) value = null; + if (string.CompareOrdinal(s, value) != 0) + { + FreeString(ref ptr, ref size); + if (value != null) + { + ptr = Marshal.StringToHGlobalUni(value); + size = (uint)value.Length + 1; + } + return true; + } + return false; + } + + /// + /// Converts an that points to a C-style array into a CLI array. + /// + /// Type of native structure used by the C-style array. + /// Output type for the CLI array. must be able to convert to . + /// The pointing to the native array. + /// The number of items in the native array. + /// An array of type containing the converted elements of the native array. + public static T[] ToArray(IntPtr ptr, int count) where TS : IConvertible + { + var ret = new T[count]; + var stSize = Marshal.SizeOf(typeof(TS)); + for (var i = 0; i < count; i++) + { + var tempPtr = new IntPtr(ptr.ToInt64() + (i * stSize)); + var val = ToStructure(tempPtr); + ret[i] = (T)Convert.ChangeType(val, typeof(T)); + } + return ret; + } + + /// + /// Converts an that points to a C-style array into a CLI array. + /// + /// Type of native structure used by the C-style array. + /// The pointing to the native array. + /// The number of items in the native array. + /// An array of type containing the elements of the native array. + public static T[] ToArray(IntPtr ptr, int count) + { + var ret = new T[count]; + var stSize = Marshal.SizeOf(typeof(T)); + for (var i = 0; i < count; i++) + { + var tempPtr = new IntPtr(ptr.ToInt64() + (i * stSize)); + ret[i] = ToStructure(tempPtr); + } + return ret; + } + } + + internal class ComEnumerator : IEnumerator where T : class where TIn : class + { + protected readonly Func converter; + protected IEnumerator iEnum; + + public ComEnumerator(Func getCount, Func indexer, Func converter) + { + IEnumerator Enumerate() + { + for (var x = 1; x <= getCount(); x++) + yield return indexer(x); + } + + this.converter = converter; + iEnum = Enumerate(); + } + + public ComEnumerator(Func getCount, Func indexer, Func converter) + { + IEnumerator Enumerate() + { + for (var x = 1; x <= getCount(); x++) + yield return indexer(x); + } + + this.converter = converter; + iEnum = Enumerate(); + } + + object IEnumerator.Current => Current; + + public virtual T Current => converter(iEnum?.Current); + + public virtual void Dispose() + { + iEnum?.Dispose(); + iEnum = null; + } + + public virtual bool MoveNext() => iEnum?.MoveNext() ?? false; + + public virtual void Reset() + { + iEnum?.Reset(); + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/KERNEL32.cs b/FlashPatcher/TaskService/Native/KERNEL32.cs new file mode 100644 index 0000000..09a5278 --- /dev/null +++ b/FlashPatcher/TaskService/Native/KERNEL32.cs @@ -0,0 +1,59 @@ +using System; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; + +namespace Microsoft.Win32 +{ + internal static partial class NativeMethods + { + const string KERNEL32 = "Kernel32.dll"; + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport(KERNEL32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CloseHandle(IntPtr handle); + + [DllImport(KERNEL32, CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr GetCurrentProcess(); + + [DllImport(KERNEL32, CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr GetCurrentThread(); + + /// + /// The GlobalLock function locks a global memory object and returns a pointer to the first byte of the object's memory block. + /// GlobalLock function increments the lock count by one. + /// Needed for the clipboard functions when getting the data from IDataObject + /// + /// + /// + [DllImport(KERNEL32, SetLastError = true)] + public static extern IntPtr GlobalLock(IntPtr hMem); + + /// + /// The GlobalUnlock function decrements the lock count associated with a memory object. + /// + /// + /// + [DllImport(KERNEL32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GlobalUnlock(IntPtr hMem); + + [DllImport(KERNEL32, CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr LoadLibrary(string filename); + + [DllImport(KERNEL32, CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool FreeLibrary(IntPtr lib); + + public partial class SafeTokenHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid + { + private SafeTokenHandle() : base(true) { } + + internal SafeTokenHandle(IntPtr handle, bool own = true) : base(own) + { + SetHandle(handle); + } + + protected override bool ReleaseHandle() => CloseHandle(handle); + } + } +} diff --git a/FlashPatcher/TaskService/Native/Linq.Net2.cs b/FlashPatcher/TaskService/Native/Linq.Net2.cs new file mode 100644 index 0000000..12b1c80 --- /dev/null +++ b/FlashPatcher/TaskService/Native/Linq.Net2.cs @@ -0,0 +1,338 @@ +#if (NET20) +using System.Collections; +using System.Collections.Generic; + +namespace System.Linq +{ + /// Provides a set of static (Shared in Visual Basic) methods for querying objects that implement . + internal static class Enumerable + { + /// Determines whether any element of a sequence satisfies a condition. + /// The type of the elements of . + /// An whose elements to apply the predicate to. + /// A function to test each element for a condition. + /// true if any elements in the source sequence pass the test in the specified predicate; otherwise, false. + public static bool Any(this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + foreach (TSource element in source) + if (predicate(element)) return true; + return false; + } + + /// Casts the elements of an to the specified type. + /// The type to cast the elements of source to. + /// The that contains the elements to be cast to type . + /// An that contains each element of the source sequence cast to the specified type. + public static IEnumerable Cast(this IEnumerable source) + { + foreach (var i in source) + yield return (TResult)i; + } + + /// Determines whether a sequence contains a specified element by using the default equality comparer. + /// The type of the elements of . + /// A sequence in which to locate a value. + /// The value to locate in the sequence. + /// true if the source sequence contains an element that has the specified value; otherwise, false. + public static bool Contains(this IEnumerable source, TSource value) + { + foreach (var i in source) + if (i.Equals(value)) return true; + return false; + } + + /// Returns the number of elements in a sequence. + /// The type of the elements of . + /// A sequence that contains elements to be counted. + /// The number of elements in the input sequence. + public static int Count(this IEnumerable source) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (source is ICollection c) return c.Count; + if (source is ICollection ngc) return ngc.Count; + var i = 0; + foreach (var e in source) i++; + return i; + } + + /// Returns distinct elements from a sequence by using the default equality comparer to compare values. + /// The type of the elements of . + /// The sequence to remove duplicate elements from. + /// An that contains distinct elements from the source sequence. + public static IEnumerable Distinct(this IEnumerable source) + { + var set = new Hashtable(); + foreach (var element in source) + if (!set.ContainsKey(element)) + { + set.Add(element, null); + yield return element; + } + } + + /// Returns the first element of a sequence. + /// The type of the elements of . + /// The to return the first element of. + /// The first element in the specified sequence. + public static TSource First(this IEnumerable source) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (source is IList list) + { + if (list.Count > 0) return list[0]; + } + else + { + using (var e = source.GetEnumerator()) + { + if (e.MoveNext()) return e.Current; + } + } + throw new InvalidOperationException(@"No elements"); + } + + /// Returns the first element of a sequence that satisfies a specified condition. + /// The type of the elements of . + /// The to return the first element of. + /// A function to test each element for a condition. + /// The first element in the sequence that passes the test in the specified predicate function. + public static TSource First(this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + foreach (var element in source) + if (predicate(element)) return element; + throw new InvalidOperationException(@"No match"); + } + + /// Returns the first element of a sequence, or a default value if the sequence contains no elements. + /// The type of the elements of . + /// The to return the first element of. + /// default( ) if is empty; otherwise, the first element in . + public static TSource FirstOrDefault(this IEnumerable source) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (source is IList list) + { + if (list.Count > 0) return list[0]; + } + else + { + using (var e = source.GetEnumerator()) + { + if (e.MoveNext()) return e.Current; + } + } + return default(TSource); + } + + /// Returns the first element of the sequence that satisfies a condition or a default value if no such element is found. + /// The type of the elements of source. + /// An to return an element from. + /// A function to test each element for a condition. + /// default() if is empty or if no element passes the test specified by ; otherwise, the first element in that passes the test specified by . + public static TSource FirstOrDefault(this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + foreach (var element in source) + if (predicate(element)) return element; + return default(TSource); + } + + /// Returns the minimum value in a generic sequence. + /// The type of the elements of source. + /// A sequence of values to determine the minimum value of. + /// The minimum value in the sequence. + public static TSource Min(this IEnumerable source) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + var comparer = Comparer.Default; + var value = default(TSource); + if (value == null) + { + foreach (var x in source) + { + if (x != null && (value == null || comparer.Compare(x, value) < 0)) + value = x; + } + return value; + } + + var hasValue = false; + foreach (var x in source) + { + if (hasValue) + { + if (comparer.Compare(x, value) < 0) + value = x; + } + else + { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new InvalidOperationException("No elements"); + } + + /// Returns the maximum value in a generic sequence. + /// The type of the elements of source. + /// A sequence of values to determine the maximum value of. + /// The maximum value in the sequence. + public static TSource Max(this IEnumerable source) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + var comparer = Comparer.Default; + var value = default(TSource); + if (value == null) { + foreach (var x in source) { + if (x != null && (value == null || comparer.Compare(x, value) > 0)) + value = x; + } + return value; + } + var hasValue = false; + foreach (var x in source) { + if (hasValue) { + if (comparer.Compare(x, value) > 0) + value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new InvalidOperationException("No elements"); + } + + /// Sorts the elements of a sequence in ascending order according to a key. + /// The type of the elements of . + /// The type of the key returned by . + /// A sequence of values to order. + /// A function to extract a key from an element. + /// An whose elements are sorted according to a key. + public static IEnumerable OrderBy(this IEnumerable source, Func keySelector) + { + var d = new SortedDictionary(); + foreach (var item in source) + d.Add(keySelector(item), item); + return d.Values; + } + + /// Projects each element of a sequence into a new form. + /// The type of the elements of . + /// The type of the value returned by . + /// A sequence of values to invoke a transform function on. + /// A transform function to apply to each element. + /// An whose elements are the result of invoking the transform function on each element of . + public static IEnumerable Select(this IEnumerable source, Func selector) + { + if (selector == null) throw new ArgumentNullException(nameof(selector)); + foreach (var i in source) + yield return selector(i); + } + + /// Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists. + /// The type of the elements of . + /// An to return a single element from. + /// A function to test an element for a condition. + /// The single element of the input sequence that satisfies a condition. + public static TSource Single(this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + var result = default(TSource); + long count = 0; + foreach (var element in source) + { + if (!predicate(element)) continue; + result = element; + checked { count++; } + } + if (count == 0) throw new InvalidOperationException(@"No matches"); + if (count != 1) throw new InvalidOperationException(@"More than one match."); + return result; + } + + /// Computes the sum of a sequence of nullable values. + /// A sequence of nullable values to calculate the sum of. + /// The sum of the values in the sequence. + public static int Sum(this IEnumerable source) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + int sum = 0; + checked + { + foreach (int v in source) sum += v; + } + return sum; + } + + /// + /// Computes the sum of the sequence of nullable values that are obtained by invoking a transform function on each element of the input sequence. + /// + /// The type of the elements of . + /// A sequence of values that are used to calculate a sum. + /// A transform function to apply to each element. + /// The sum of the projected values. + public static int Sum(this IEnumerable source, Func selector) => Sum(Select(source, selector)); + + /// Creates an array from a . + /// The type of the elements of . + /// An to create an array from. + /// An array that contains the elements from the input sequence. + public static TSource[] ToArray(this IEnumerable source) => ToList(source).ToArray(); + + /// + /// Creates a from an according to a specified key selector function, a comparer, and + /// an element selector function. + /// + /// The type of the elements of . + /// The type of the key returned by . + /// The type of the value returned by . + /// An to create a from. + /// A function to extract a key from each element. + /// A transform function to produce a result element value from each element. + /// An to compare keys. + /// A that contains values of type TElement selected from the input sequence. + public static Dictionary ToDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); + if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector)); + var d = new Dictionary(comparer); + foreach (var element in source) d.Add(keySelector(element), elementSelector(element)); + return d; + } + + /// Creates a from an . + /// The type of the elements of . + /// An to create a from. + /// A that contains elements from the input sequence. + public static List ToList(this IEnumerable source) + { + var l = new List(); + foreach (var i in source) + l.Add(i); + return l; + } + + /// Filters a sequence of values based on a predicate. + /// The type of the elements of . + /// An to filter. + /// A function to test each element for a condition. + /// An that contains elements from the input sequence that satisfy the condition. + public static IEnumerable Where(this IEnumerable source, Func predicate) + { + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + foreach (var i in source) + if (predicate(i)) yield return i; + } + } +} +#endif \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/NTDSAPI.cs b/FlashPatcher/TaskService/Native/NTDSAPI.cs new file mode 100644 index 0000000..c3f3cf9 --- /dev/null +++ b/FlashPatcher/TaskService/Native/NTDSAPI.cs @@ -0,0 +1,230 @@ +using System; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; +using System.Security; + +namespace Microsoft.Win32 +{ + internal static partial class NativeMethods + { + private const string NTDSAPI = "ntdsapi.dll"; + + /// + /// Defines the errors returned by the status member of the DS_NAME_RESULT_ITEM structure. These are potential errors that may be encountered while a name is converted by the DsCrackNames function. + /// + public enum DS_NAME_ERROR : uint + { + /// The conversion was successful. + DS_NAME_NO_ERROR = 0, + + ///Generic processing error occurred. + DS_NAME_ERROR_RESOLVING = 1, + + ///The name cannot be found or the caller does not have permission to access the name. + DS_NAME_ERROR_NOT_FOUND = 2, + + ///The input name is mapped to more than one output name or the desired format did not have a single, unique value for the object found. + DS_NAME_ERROR_NOT_UNIQUE = 3, + + ///The input name was found, but the associated output format cannot be found. This can occur if the object does not have all the required attributes. + DS_NAME_ERROR_NO_MAPPING = 4, + + ///Unable to resolve entire name, but was able to determine in which domain object resides. The caller is expected to retry the call at a domain controller for the specified domain. The entire name cannot be resolved, but the domain that the object resides in could be determined. The pDomain member of the DS_NAME_RESULT_ITEM contains valid data when this error is specified. + DS_NAME_ERROR_DOMAIN_ONLY = 5, + + ///A syntactical mapping cannot be performed on the client without transmitting over the network. + DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING = 6, + + ///The name is from an external trusted forest. + DS_NAME_ERROR_TRUST_REFERRAL = 7 + } + + /// + /// Used to define how the name syntax will be cracked. These flags are used by the DsCrackNames function. + /// + [Flags] + public enum DS_NAME_FLAGS + { + /// Indicate that there are no associated flags. + DS_NAME_NO_FLAGS = 0x0, + + ///Perform a syntactical mapping at the client without transferring over the network. The only syntactic mapping supported is from DS_FQDN_1779_NAME to DS_CANONICAL_NAME or DS_CANONICAL_NAME_EX. + DS_NAME_FLAG_SYNTACTICAL_ONLY = 0x1, + + ///Force a trip to the DC for evaluation, even if this could be locally cracked syntactically. + DS_NAME_FLAG_EVAL_AT_DC = 0x2, + + ///The call fails if the domain controller is not a global catalog server. + DS_NAME_FLAG_GCVERIFY = 0x4, + + ///Enable cross forest trust referral. + DS_NAME_FLAG_TRUST_REFERRAL = 0x8 + } + + /// + /// Provides formats to use for input and output names for the DsCrackNames function. + /// + public enum DS_NAME_FORMAT + { + ///Indicates the name is using an unknown name type. This format can impact performance because it forces the server to attempt to match all possible formats. Only use this value if the input format is unknown. + DS_UNKNOWN_NAME = 0, + + ///Indicates that the fully qualified distinguished name is used. For example: "CN = someone, OU = Users, DC = Engineering, DC = Fabrikam, DC = Com" + DS_FQDN_1779_NAME = 1, + + ///Indicates a Windows NT 4.0 account name. For example: "Engineering\someone" The domain-only version includes two trailing backslashes (\\). + DS_NT4_ACCOUNT_NAME = 2, + + ///Indicates a user-friendly display name, for example, Jeff Smith. The display name is not necessarily the same as relative distinguished name (RDN). + DS_DISPLAY_NAME = 3, + + ///Indicates a GUID string that the IIDFromString function returns. For example: "{4fa050f0-f561-11cf-bdd9-00aa003a77b6}" + DS_UNIQUE_ID_NAME = 6, + + ///Indicates a complete canonical name. For example: "engineering.fabrikam.com/software/someone" The domain-only version includes a trailing forward slash (/). + DS_CANONICAL_NAME = 7, + + ///Indicates that it is using the user principal name (UPN). For example: "someone@engineering.fabrikam.com" + DS_USER_PRINCIPAL_NAME = 8, + + ///This element is the same as DS_CANONICAL_NAME except that the rightmost forward slash (/) is replaced with a newline character (\n), even in a domain-only case. For example: "engineering.fabrikam.com/software\nsomeone" + DS_CANONICAL_NAME_EX = 9, + + ///Indicates it is using a generalized service principal name. For example: "www/www.fabrikam.com@fabrikam.com" + DS_SERVICE_PRINCIPAL_NAME = 10, + + ///Indicates a Security Identifier (SID) for the object. This can be either the current SID or a SID from the object SID history. The SID string can use either the standard string representation of a SID, or one of the string constants defined in Sddl.h. For more information about converting a binary SID into a SID string, see SID Strings. The following is an example of a SID string: "S-1-5-21-397955417-626881126-188441444-501" + DS_SID_OR_SID_HISTORY_NAME = 11, + } + + /// + /// Class that provides methods against a AD domain service. + /// + /// + [SuppressUnmanagedCodeSecurity, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public class DomainService : IDisposable + { + IntPtr handle = IntPtr.Zero; + + /// + /// Initializes a new instance of the class. + /// + /// Name of the domain controller. + /// Name of the DNS domain. + /// + public DomainService(string domainControllerName = null, string dnsDomainName = null) + { + DsBind(domainControllerName, dnsDomainName, out handle); + } + + /// + /// Converts a directory service object name from any format to the UPN. + /// + /// The name to convert. + /// The corresponding UPN. + /// Unable to resolve user name. + public string CrackName(string name) + { + var res = CrackNames(new string[] { name }); + if (res == null || res.Length == 0 || res[0].status != NativeMethods.DS_NAME_ERROR.DS_NAME_NO_ERROR) + throw new SecurityException("Unable to resolve user name."); + return res[0].pName; + } + + /// + /// Converts an array of directory service object names from one format to another. Name conversion enables client applications to map between the multiple names used to identify various directory service objects. + /// + /// The names to convert. + /// Values used to determine how the name syntax will be cracked. + /// Format of the input names. + /// Desired format for the output names. + /// An array of DS_NAME_RESULT_ITEM structures. Each element of this array represents a single converted name. + public DS_NAME_RESULT_ITEM[] CrackNames(string[] names = null, DS_NAME_FLAGS flags = DS_NAME_FLAGS.DS_NAME_NO_FLAGS, DS_NAME_FORMAT formatOffered = DS_NAME_FORMAT.DS_UNKNOWN_NAME, DS_NAME_FORMAT formatDesired = DS_NAME_FORMAT.DS_USER_PRINCIPAL_NAME) + { + IntPtr pResult; + uint err = DsCrackNames(handle, flags, formatOffered, formatDesired, (uint)(names?.Length ?? 0), names, out pResult); + if (err != (uint)DS_NAME_ERROR.DS_NAME_NO_ERROR) + throw new System.ComponentModel.Win32Exception((int)err); + try + { + // Next convert the returned structure to managed environment + DS_NAME_RESULT Result = (DS_NAME_RESULT)Marshal.PtrToStructure(pResult, typeof(DS_NAME_RESULT)); + return Result.Items; + } + finally + { + DsFreeNameResult(pResult); + } + } + + public void Dispose() + { + uint ret = DsUnBind(ref handle); + System.Diagnostics.Debug.WriteLineIf(ret != 0, "Error unbinding :\t" + ret.ToString()); + } + } + + [DllImport(NTDSAPI, CharSet = CharSet.Auto, PreserveSig = false)] + public static extern void DsBind( + string DomainControllerName, // in, optional + string DnsDomainName, // in, optional + out IntPtr phDS); + + [DllImport(NTDSAPI, CharSet = CharSet.Auto)] + public static extern uint DsCrackNames( + IntPtr hDS, + DS_NAME_FLAGS flags, + DS_NAME_FORMAT formatOffered, + DS_NAME_FORMAT formatDesired, + uint cNames, + [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPTStr, SizeParamIndex = 4)] string[] rpNames, + out IntPtr ppResult); + + [DllImport(NTDSAPI, CharSet = CharSet.Auto)] + public static extern void DsFreeNameResult(IntPtr pResult /* DS_NAME_RESULT* */); + + [DllImport(NTDSAPI, CharSet = CharSet.Auto)] + public static extern uint DsUnBind(ref IntPtr phDS); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public struct DS_NAME_RESULT + { + public uint cItems; + internal IntPtr rItems; // PDS_NAME_RESULT_ITEM + + public DS_NAME_RESULT_ITEM[] Items + { + get + { + if (rItems == IntPtr.Zero) + return new DS_NAME_RESULT_ITEM[0]; + var ResultArray = new DS_NAME_RESULT_ITEM[cItems]; + Type strType = typeof(DS_NAME_RESULT_ITEM); + int stSize = Marshal.SizeOf(strType); + IntPtr curptr; + for (uint i = 0; i < cItems; i++) + { + curptr = new IntPtr(rItems.ToInt64() + (i * stSize)); + ResultArray[i] = (DS_NAME_RESULT_ITEM)Marshal.PtrToStructure(curptr, strType); + } + return ResultArray; + } + } + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public struct DS_NAME_RESULT_ITEM + { + public DS_NAME_ERROR status; + public string pDomain; + public string pName; + + public override string ToString() + { + if (status == DS_NAME_ERROR.DS_NAME_NO_ERROR) + return pName; + return string.Empty; + } + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/NetServerEnum.cs b/FlashPatcher/TaskService/Native/NetServerEnum.cs new file mode 100644 index 0000000..da92254 --- /dev/null +++ b/FlashPatcher/TaskService/Native/NetServerEnum.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Security; + +namespace Microsoft.Win32 +{ + internal static partial class NativeMethods + { + const int MAX_PREFERRED_LENGTH = -1; + + [Flags] + public enum ServerTypes : uint + { + Workstation = 0x00000001, + Server = 0x00000002, + SqlServer = 0x00000004, + DomainCtrl= 0x00000008, + BackupDomainCtrl= 0x00000010, + TimeSource= 0x00000020, + AppleFilingProtocol = 0x00000040, + Novell= 0x00000080, + DomainMember = 0x00000100, + PrintQueueServer = 0x00000200, + DialinServer = 0x00000400, + XenixServer = 0x00000800, + UnixServer = 0x00000800, + NT = 0x00001000, + WindowsForWorkgroups = 0x00002000, + MicrosoftFileAndPrintServer= 0x00004000, + NTServer = 0x00008000, + BrowserService = 0x00010000, + BackupBrowserService= 0x00020000, + MasterBrowserService= 0x00040000, + DomainMaster = 0x00080000, + OSF1Server = 0x00100000, + VMSServer = 0x00200000, + Windows = 0x00400000, + DFS = 0x00800000, + NTCluster = 0x01000000, + TerminalServer= 0x02000000, + VirtualNTCluster = 0x04000000, + DCE = 0x10000000, + AlternateTransport = 0x20000000, + LocalListOnly = 0x40000000, + PrimaryDomain = 0x80000000, + All = 0xFFFFFFFF + }; + + public enum ServerPlatform + { + DOS = 300, + OS2 = 400, + NT = 500, + OSF = 600, + VMS = 700 + } + + [DllImport("Netapi32", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int NetServerGetInfo(string serverName, int level, out IntPtr pSERVER_INFO_XXX); + + [DllImport("Netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute] + private static extern int NetServerEnum( + [MarshalAs(UnmanagedType.LPWStr)] string servernane, // must be null + int level, + out IntPtr bufptr, + int prefmaxlen, + out int entriesread, + out int totalentries, + ServerTypes servertype, + [MarshalAs(UnmanagedType.LPWStr)] string domain, // null for login domain + IntPtr resume_handle // Must be IntPtr.Zero + ); + + [DllImport("Netapi32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute] + private static extern int NetApiBufferFree(IntPtr pBuf); + + [StructLayout(LayoutKind.Sequential)] + public struct SERVER_INFO_100 + { + public ServerPlatform PlatformId; + [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] + public string Name; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SERVER_INFO_101 + { + public ServerPlatform PlatformId; + [MarshalAs(UnmanagedType.LPWStr)] + public string Name; + public int VersionMajor; + public int VersionMinor; + public ServerTypes Type; + [MarshalAs(UnmanagedType.LPWStr)] + public string Comment; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SERVER_INFO_102 + { + public ServerPlatform PlatformId; + [MarshalAs(UnmanagedType.LPWStr)] + public string Name; + public int VersionMajor; + public int VersionMinor; + public ServerTypes Type; + [MarshalAs(UnmanagedType.LPWStr)] + public string Comment; + public int MaxUsers; + public int AutoDisconnectMinutes; + [MarshalAs(UnmanagedType.Bool)] + public bool Hidden; + public int NetworkAnnounceRate; + public int NetworkAnnounceRateDelta; + public int UsersPerLicense; + [MarshalAs(UnmanagedType.LPWStr)] + public string UserDirectoryPath; + } + + [StructLayout(LayoutKind.Sequential)] + public struct NetworkComputerInfo // SERVER_INFO_101 + { + ServerPlatform sv101_platform_id; + [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] + string sv101_name; + int sv101_version_major; + int sv101_version_minor; + ServerTypes sv101_type; + [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] + string sv101_comment; + + public ServerPlatform Platform => sv101_platform_id; + public string Name => sv101_name; + public string Comment => sv101_comment; + public ServerTypes ServerTypes => sv101_type; + public Version Version => new Version(sv101_version_major, sv101_version_minor); + }; + + public static IEnumerable GetNetworkComputerNames(ServerTypes serverTypes = ServerTypes.Workstation | ServerTypes.Server, string domain = null) => + Array.ConvertAll(NetServerEnum(serverTypes, domain), si => si.Name); + + public static IEnumerable GetNetworkComputerInfo(ServerTypes serverTypes = ServerTypes.Workstation | ServerTypes.Server, string domain = null) => + NetServerEnum(serverTypes, domain, 101); + + public static T[] NetServerEnum(ServerTypes serverTypes = ServerTypes.Workstation | ServerTypes.Server, string domain = null, int level = 0) where T : struct + { + if (level == 0) + level = int.Parse(System.Text.RegularExpressions.Regex.Replace(typeof(T).Name, @"[^\d]", "")); + + IntPtr bufptr = IntPtr.Zero; + try + { + int entriesRead, totalEntries; + IntPtr resumeHandle = IntPtr.Zero; + + int ret = NetServerEnum(null, level, out bufptr, MAX_PREFERRED_LENGTH, out entriesRead, out totalEntries, serverTypes, domain, resumeHandle); + if (ret == 0) + return InteropUtil.ToArray(bufptr, entriesRead); + throw new System.ComponentModel.Win32Exception(ret); + } + finally + { + NetApiBufferFree(bufptr); + } + } + + public static T NetServerGetInfo(string serverName, int level = 0) where T : struct + { + if (level == 0) + level = int.Parse(System.Text.RegularExpressions.Regex.Replace(typeof(T).Name, @"[^\d]", "")); + + IntPtr ptr = IntPtr.Zero; + try + { + int ret = NetServerGetInfo(serverName, level, out ptr); + if (ret != 0) + throw new System.ComponentModel.Win32Exception(ret); + return (T)Marshal.PtrToStructure(ptr, typeof(T)); + } + finally + { + if (ptr != IntPtr.Zero) + NetApiBufferFree(ptr); + } + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/SYSTEMTIME.cs b/FlashPatcher/TaskService/Native/SYSTEMTIME.cs new file mode 100644 index 0000000..cede40c --- /dev/null +++ b/FlashPatcher/TaskService/Native/SYSTEMTIME.cs @@ -0,0 +1,116 @@ +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.Win32 +{ + internal static partial class NativeMethods + { + [StructLayout(LayoutKind.Sequential, Pack = 2)] + internal struct SYSTEMTIME : IConvertible + { + public ushort Year; + public ushort Month; + public ushort DayOfWeek; + public ushort Day; + public ushort Hour; + public ushort Minute; + public ushort Second; + public ushort Milliseconds; + + public SYSTEMTIME(DateTime dt) + { + dt = dt.ToLocalTime(); + Year = Convert.ToUInt16(dt.Year); + Month = Convert.ToUInt16(dt.Month); + DayOfWeek = Convert.ToUInt16(dt.DayOfWeek); + Day = Convert.ToUInt16(dt.Day); + Hour = Convert.ToUInt16(dt.Hour); + Minute = Convert.ToUInt16(dt.Minute); + Second = Convert.ToUInt16(dt.Second); + Milliseconds = Convert.ToUInt16(dt.Millisecond); + } + + public SYSTEMTIME(ushort year, ushort month, ushort day, ushort hour = 0, ushort minute = 0, ushort second = 0, ushort millisecond = 0) + { + Year = year; + Month = month; + Day = day; + Hour = hour; + Minute = minute; + Second = second; + Milliseconds = millisecond; + DayOfWeek = 0; + } + + public static implicit operator DateTime(SYSTEMTIME st) + { + if (st.Year == 0 || st == MinValue) + return DateTime.MinValue; + if (st == MaxValue) + return DateTime.MaxValue; + return new DateTime(st.Year, st.Month, st.Day, st.Hour, st.Minute, st.Second, st.Milliseconds, DateTimeKind.Local); + } + + public static implicit operator SYSTEMTIME(DateTime dt) => new SYSTEMTIME(dt); + + public static bool operator ==(SYSTEMTIME s1, SYSTEMTIME s2) => (s1.Year == s2.Year && s1.Month == s2.Month && s1.Day == s2.Day && s1.Hour == s2.Hour && s1.Minute == s2.Minute && s1.Second == s2.Second && s1.Milliseconds == s2.Milliseconds); + + public static bool operator !=(SYSTEMTIME s1, SYSTEMTIME s2) => !(s1 == s2); + + public static readonly SYSTEMTIME MinValue, MaxValue; + + static SYSTEMTIME() + { + MinValue = new SYSTEMTIME(1601, 1, 1); + MaxValue = new SYSTEMTIME(30827, 12, 31, 23, 59, 59, 999); + } + + public override bool Equals(object obj) + { + if (obj is SYSTEMTIME) + return ((SYSTEMTIME)obj) == this; + if (obj is DateTime) + return ((DateTime)this).Equals(obj); + return base.Equals(obj); + } + + public override int GetHashCode() => ((DateTime)this).GetHashCode(); + + public override string ToString() => ((DateTime)this).ToString(); + + TypeCode IConvertible.GetTypeCode() => ((IConvertible)(DateTime)this).GetTypeCode(); + + bool IConvertible.ToBoolean(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToBoolean(provider); + + byte IConvertible.ToByte(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToByte(provider); + + char IConvertible.ToChar(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToChar(provider); + + DateTime IConvertible.ToDateTime(IFormatProvider provider) => (DateTime)this; + + decimal IConvertible.ToDecimal(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToDecimal(provider); + + double IConvertible.ToDouble(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToDouble(provider); + + short IConvertible.ToInt16(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToInt16(provider); + + int IConvertible.ToInt32(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToInt32(provider); + + long IConvertible.ToInt64(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToInt64(provider); + + sbyte IConvertible.ToSByte(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToSByte(provider); + + float IConvertible.ToSingle(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToSingle(provider); + + string IConvertible.ToString(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToString(provider); + + object IConvertible.ToType(Type conversionType, IFormatProvider provider) => ((IConvertible)(DateTime)this).ToType(conversionType, provider); + + ushort IConvertible.ToUInt16(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToUInt16(provider); + + uint IConvertible.ToUInt32(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToUInt32(provider); + + ulong IConvertible.ToUInt64(IFormatProvider provider) => ((IConvertible)(DateTime)this).ToUInt64(provider); + } + } +} diff --git a/FlashPatcher/TaskService/Native/System.Collections.Generic.PreNet45.cs b/FlashPatcher/TaskService/Native/System.Collections.Generic.PreNet45.cs new file mode 100644 index 0000000..7ddc04e --- /dev/null +++ b/FlashPatcher/TaskService/Native/System.Collections.Generic.PreNet45.cs @@ -0,0 +1,25 @@ +#if (NET20 || NET35 || NET40) +namespace System.Collections.Generic +{ + /// Represents a strongly-typed, read-only collection of elements. + /// The type of the elements. + /// + public interface IReadOnlyCollection : IEnumerable + { + /// Gets the number of elements in the collection. + /// The number of elements in the collection. + int Count { get; } + } + + /// Represents a read-only collection of elements that can be accessed by index. + /// The type of elements in the read-only list. + /// + public interface IReadOnlyList : IReadOnlyCollection + { + /// Gets the element at the specified index in the read-only list. + /// The element at the specified index in the read-only list. + /// The zero-based index of the element to get. + T this[int index] { get; } + } +} +#endif \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/System.Collections.Specialized.Net20.cs b/FlashPatcher/TaskService/Native/System.Collections.Specialized.Net20.cs new file mode 100644 index 0000000..de5b575 --- /dev/null +++ b/FlashPatcher/TaskService/Native/System.Collections.Specialized.Net20.cs @@ -0,0 +1,142 @@ +#if (NET20 || NET35) +namespace System.Collections.Specialized +{ + /// + /// Stub + /// + public interface INotifyCollectionChanged + { + /// + /// Stub + /// + event NotifyCollectionChangedEventHandler CollectionChanged; + } + + /// + /// Stub + /// + /// The sender. + /// The instance containing the event data. + public delegate void NotifyCollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs e); + + /// + /// Stub + /// + public class NotifyCollectionChangedEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The action. + /// The new items. + /// The old items. + /// The new index. + /// The old index. + internal NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int newIndex, int oldIndex) + { + Action = action; + NewItems = newItems; + NewStartingIndex = newIndex; + OldItems = oldItems; + OldStartingIndex = oldIndex; + } + + /// + /// Initializes a new instance of the class. + /// + /// The action. + public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action) : + this(action, null, null, -1, -1) { } + + /// + /// Initializes a new instance of the class. + /// + /// The action. + /// The item. + /// The index. + public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object item, int idx = -1) : + this(action, new object[] { item }, null, idx, -1) { } + + /// + /// Initializes a new instance of the class. + /// + /// The action. + /// The item. + /// The item2. + /// The index. + public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object item, object item2, int idx) : + this(action, new object[] { item }, new object[] { item2 }, idx, -1) { } + + /// + /// Initializes a new instance of the class. + /// + /// The action. + /// The new items. + public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems) : + this(action, newItems, null, -1, -1) { } + + /// + /// Gets the action. + /// + /// + /// The action. + /// + public NotifyCollectionChangedAction Action { get; } + /// + /// Gets the new items. + /// + /// + /// The new items. + /// + public IList NewItems { get; } + /// + /// Gets the new index of the starting. + /// + /// + /// The new index of the starting. + /// + public int NewStartingIndex { get; } + /// + /// Gets the old items. + /// + /// + /// The old items. + /// + public IList OldItems { get; } + /// + /// Gets the old index of the starting. + /// + /// + /// The old index of the starting. + /// + public int OldStartingIndex { get; } + } + + /// + /// Stub + /// + public enum NotifyCollectionChangedAction + { + /// + /// The add + /// + Add = 0, + /// + /// The move + /// + Move = 3, + /// + /// The remove + /// + Remove = 1, + /// + /// The replace + /// + Replace = 2, + /// + /// The reset + /// + Reset = 4 + } +} +#endif \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/System.Runtime.CompilerServices.CallerXXAttribute.PreNet45.cs b/FlashPatcher/TaskService/Native/System.Runtime.CompilerServices.CallerXXAttribute.PreNet45.cs new file mode 100644 index 0000000..165dd4f --- /dev/null +++ b/FlashPatcher/TaskService/Native/System.Runtime.CompilerServices.CallerXXAttribute.PreNet45.cs @@ -0,0 +1,27 @@ +#if (NET20 || NET35 || NET40) +namespace System.Runtime.CompilerServices +{ + /// + /// Allows you to obtain the full path of the source file that contains the caller. This is the file path at the time of compile. + /// + /// + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + public class CallerFilePathAttribute : Attribute + { + } + + /// Allows you to obtain the line number in the source file at which the method is called. + /// + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + public class CallerLineNumberAttribute : Attribute + { + } + + /// Allows you to obtain the method or property name of the caller to the method. + /// + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + public class CallerMemberNameAttribute : Attribute + { + } +} +#endif \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/ThreadLocal.PreNet40.cs b/FlashPatcher/TaskService/Native/ThreadLocal.PreNet40.cs new file mode 100644 index 0000000..5a8bfea --- /dev/null +++ b/FlashPatcher/TaskService/Native/ThreadLocal.PreNet40.cs @@ -0,0 +1,810 @@ +#if (NET20 || NET35) +#pragma warning disable 0420 +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// ThreadLocal.cs +// +// Microsoft +// +// A class that provides a simple, lightweight implementation of thread-local lazy-initialization, where a value is initialized once per accessing +// thread; this provides an alternative to using a ThreadStatic static variable and having +// to check the variable prior to every access to see if it's been initialized. +// +// +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System.Diagnostics; +using System.Collections.Generic; +using System.Security.Permissions; + +namespace System.Threading +{ + /// + /// Provides thread-local storage of data. + /// + /// Specifies the type of data stored per-thread. + /// + /// + /// With the exception of , all public and protected members of + /// are thread-safe and may be used + /// concurrently from multiple threads. + /// + /// + [DebuggerTypeProxy(typeof(SystemThreading_ThreadLocalDebugView<>))] + [DebuggerDisplay("IsValueCreated={IsValueCreated}, Value={ValueForDebugDisplay}, Count={ValuesCountForDebugDisplay}")] + [HostProtection(Synchronization = true, ExternalThreading = true)] + internal class ThreadLocal : IDisposable + { + private const int MaxArrayLength = 0X7FEFFFFF; + + // a delegate that returns the created value, if null the created value will be default(T) + private Func m_valueFactory; + + // + // ts_slotArray is a table of thread-local values for all ThreadLocal instances + // + // So, when a thread reads ts_slotArray, it gets back an array of *all* ThreadLocal values for this thread and this T. + // The slot relevant to this particular ThreadLocal instance is determined by the m_idComplement instance field stored in + // the ThreadLocal instance. + // + [ThreadStatic] + static LinkedSlotVolatile[] ts_slotArray; + + [ThreadStatic] + static FinalizationHelper ts_finalizationHelper; + + // Slot ID of this ThreadLocal<> instance. We store a bitwise complement of the ID (that is ~ID), which allows us to distinguish + // between the case when ID is 0 and an incompletely initialized object, either due to a thread abort in the constructor, or + // possibly due to a memory model issue in user code. + private int m_idComplement; + + // This field is set to true when the constructor completes. That is helpful for recognizing whether a constructor + // threw an exception - either due to invalid argument or due to a thread abort. Finally, the field is set to false + // when the instance is disposed. + private volatile bool m_initialized; + + // IdManager assigns and reuses slot IDs. Additionally, the object is also used as a global lock. + private static IdManager s_idManager = new IdManager(); + + // A linked list of all values associated with this ThreadLocal instance. + // We create a dummy head node. That allows us to remove any (non-dummy) node without having to locate the m_linkedSlot field. + private LinkedSlot m_linkedSlot = new LinkedSlot(null); + + // Whether the Values property is supported + private bool m_trackAllValues; + + /// + /// Initializes the instance. + /// + public ThreadLocal() + { + Initialize(null, false); + } + + /// + /// Initializes the instance. + /// + /// Whether to track all values set on the instance and expose them through the Values property. + public ThreadLocal(bool trackAllValues) + { + Initialize(null, trackAllValues); + } + + /// + /// Initializes the instance with the + /// specified function. + /// + /// + /// The invoked to produce a lazily-initialized value when + /// an attempt is made to retrieve without it having been previously initialized. + /// + /// + /// is a null reference (Nothing in Visual Basic). + /// + public ThreadLocal(Func valueFactory) + { + if (valueFactory == null) + throw new ArgumentNullException("valueFactory"); + + Initialize(valueFactory, false); + } + + /// + /// Initializes the instance with the + /// specified function. + /// + /// + /// The invoked to produce a lazily-initialized value when + /// an attempt is made to retrieve without it having been previously initialized. + /// + /// Whether to track all values set on the instance and expose them via the Values property. + /// + /// is a null reference (Nothing in Visual Basic). + /// + public ThreadLocal(Func valueFactory, bool trackAllValues) + { + if (valueFactory == null) + throw new ArgumentNullException("valueFactory"); + + Initialize(valueFactory, trackAllValues); + } + + private void Initialize(Func valueFactory, bool trackAllValues) + { + m_valueFactory = valueFactory; + m_trackAllValues = trackAllValues; + + // Assign the ID and mark the instance as initialized. To avoid leaking IDs, we assign the ID and set m_initialized + // in a finally block, to avoid a thread abort in between the two statements. + try { } + finally + { + m_idComplement = ~s_idManager.GetId(); + + // As the last step, mark the instance as fully initialized. (Otherwise, if m_initialized=false, we know that an exception + // occurred in the constructor.) + m_initialized = true; + } + } + + /// + /// Releases the resources used by this instance. + /// + ~ThreadLocal() + { + // finalizer to return the type combination index to the pool + Dispose(false); + } + + #region IDisposable Members + + /// + /// Releases the resources used by this instance. + /// + /// + /// Unlike most of the members of , this method is not thread-safe. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases the resources used by this instance. + /// + /// + /// A Boolean value that indicates whether this method is being called due to a call to . + /// + /// + /// Unlike most of the members of , this method is not thread-safe. + /// + protected virtual void Dispose(bool disposing) + { + int id; + + lock (s_idManager) + { + id = ~m_idComplement; + m_idComplement = 0; + + if (id < 0 || !m_initialized) + { + // Handle double Dispose calls or disposal of an instance whose constructor threw an exception. + return; + } + m_initialized = false; + + for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next) + { + LinkedSlotVolatile[] slotArray = linkedSlot.SlotArray; + + if (slotArray == null) + { + // The thread that owns this slotArray has already finished. + continue; + } + + // Remove the reference from the LinkedSlot to the slot table. + linkedSlot.SlotArray = null; + + // And clear the references from the slot table to the linked slot and the value so that + // both can get garbage collected. + slotArray[id].Value.Value = default(T); + slotArray[id].Value = null; + } + } + m_linkedSlot = null; + s_idManager.ReturnId(id); + } + + #endregion + + /// Creates and returns a string representation of this instance for the current thread. + /// The result of calling on the . + /// + /// The for the current thread is a null reference (Nothing in Visual Basic). + /// + /// + /// The initialization function referenced in an improper manner. + /// + /// + /// The instance has been disposed. + /// + /// + /// Calling this method forces initialization for the current thread, as is the + /// case with accessing directly. + /// + public override string ToString() + { + return Value.ToString(); + } + + /// + /// Gets or sets the value of this instance for the current thread. + /// + /// + /// The initialization function referenced in an improper manner. + /// + /// + /// The instance has been disposed. + /// + /// + /// If this instance was not previously initialized for the current thread, + /// accessing will attempt to initialize it. If an initialization function was + /// supplied during the construction, that initialization will happen by invoking the function + /// to retrieve the initial value for . Otherwise, the default value of + /// will be used. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + public T Value + { + get + { + LinkedSlotVolatile[] slotArray = ts_slotArray; + LinkedSlot slot; + int id = ~m_idComplement; + + // + // Attempt to get the value using the fast path + // + if (slotArray != null // Has the slot array been initialized? + && id >= 0 // Is the ID non-negative (i.e., instance is not disposed)? + && id < slotArray.Length // Is the table large enough? + && (slot = slotArray[id].Value) != null // Has a LinkedSlot object has been allocated for this ID? + && m_initialized // Has the instance *still* not been disposed (important for ----s with Dispose)? + ) + { + // We verified that the instance has not been disposed *after* we got a reference to the slot. + // This guarantees that we have a reference to the right slot. + // + // Volatile read of the LinkedSlotVolatile.Value property ensures that the m_initialized read + // will not be reordered before the read of slotArray[id]. + return slot.Value; + } + + return GetValueSlow(); + } + set + { + LinkedSlotVolatile[] slotArray = ts_slotArray; + LinkedSlot slot; + int id = ~m_idComplement; + + // + // Attempt to set the value using the fast path + // + if (slotArray != null // Has the slot array been initialized? + && id >= 0 // Is the ID non-negative (i.e., instance is not disposed)? + && id < slotArray.Length // Is the table large enough? + && (slot = slotArray[id].Value) != null // Has a LinkedSlot object has been allocated for this ID? + && m_initialized // Has the instance *still* not been disposed (important for ----s with Dispose)? + ) + { + // We verified that the instance has not been disposed *after* we got a reference to the slot. + // This guarantees that we have a reference to the right slot. + // + // Volatile read of the LinkedSlotVolatile.Value property ensures that the m_initialized read + // will not be reordered before the read of slotArray[id]. + slot.Value = value; + } + else + { + SetValueSlow(value, slotArray); + } + } + } + + private T GetValueSlow() + { + // If the object has been disposed, the id will be -1. + int id = ~m_idComplement; + if (id < 0) + { + throw new ObjectDisposedException("The ThreadLocal instance has been disposed."); + } + + // Determine the initial value + T value; + if (m_valueFactory == null) + { + value = default(T); + } + else + { + value = m_valueFactory(); + + if (IsValueCreated) + { + throw new InvalidOperationException("The initialization function attempted to reference Value recursively."); + } + } + + // Since the value has been previously uninitialized, we also need to set it (according to the ThreadLocal semantics). + Value = value; + return value; + } + + private void SetValueSlow(T value, LinkedSlotVolatile[] slotArray) + { + int id = ~m_idComplement; + + // If the object has been disposed, id will be -1. + if (id < 0) + { + throw new ObjectDisposedException("The ThreadLocal instance has been disposed."); + } + + // If a slot array has not been created on this thread yet, create it. + if (slotArray == null) + { + slotArray = new LinkedSlotVolatile[GetNewTableSize(id + 1)]; + ts_finalizationHelper = new FinalizationHelper(slotArray, m_trackAllValues); + ts_slotArray = slotArray; + } + + // If the slot array is not big enough to hold this ID, increase the table size. + if (id >= slotArray.Length) + { + GrowTable(ref slotArray, id + 1); + ts_finalizationHelper.SlotArray = slotArray; + ts_slotArray = slotArray; + } + + // If we are using the slot in this table for the first time, create a new LinkedSlot and add it into + // the linked list for this ThreadLocal instance. + if (slotArray[id].Value == null) + { + CreateLinkedSlot(slotArray, id, value); + } + else + { + // Volatile read of the LinkedSlotVolatile.Value property ensures that the m_initialized read + // that follows will not be reordered before the read of slotArray[id]. + LinkedSlot slot = slotArray[id].Value; + + // It is important to verify that the ThreadLocal instance has not been disposed. The check must come + // after capturing slotArray[id], but before assigning the value into the slot. This ensures that + // if this ThreadLocal instance was disposed on another thread and another ThreadLocal instance was + // created, we definitely won't assign the value into the wrong instance. + + if (!m_initialized) + { + throw new ObjectDisposedException("The ThreadLocal instance has been disposed."); + } + + slot.Value = value; + } + } + + /// + /// Creates a LinkedSlot and inserts it into the linked list for this ThreadLocal instance. + /// + private void CreateLinkedSlot(LinkedSlotVolatile[] slotArray, int id, T value) + { + // Create a LinkedSlot + var linkedSlot = new LinkedSlot(slotArray); + + // Insert the LinkedSlot into the linked list maintained by this ThreadLocal<> instance and into the slot array + lock (s_idManager) + { + // Check that the instance has not been disposed. It is important to check this under a lock, since + // Dispose also executes under a lock. + if (!m_initialized) + { + throw new ObjectDisposedException("The ThreadLocal instance has been disposed."); + } + + LinkedSlot firstRealNode = m_linkedSlot.Next; + + // + // Insert linkedSlot between nodes m_linkedSlot and firstRealNode. + // (m_linkedSlot is the dummy head node that should always be in the front.) + // + linkedSlot.Next = firstRealNode; + linkedSlot.Previous = m_linkedSlot; + linkedSlot.Value = value; + + if (firstRealNode != null) + { + firstRealNode.Previous = linkedSlot; + } + m_linkedSlot.Next = linkedSlot; + + // Assigning the slot under a lock prevents a ---- with Dispose (dispose also acquires the lock). + // Otherwise, it would be possible that the ThreadLocal instance is disposed, another one gets created + // with the same ID, and the write would go to the wrong instance. + slotArray[id].Value = linkedSlot; + } + } + + /// + /// Gets a list for all of the values currently stored by all of the threads that have accessed this instance. + /// + /// + /// The instance has been disposed. + /// + public IList Values + { + get + { + if (!m_trackAllValues) + { + throw new InvalidOperationException("Values stored by all threads are not available because this instance was initialized with the trackAllValues argument set to false in the call to a class constructor."); + } + + var list = GetValuesAsList(); // returns null if disposed + if (list == null) throw new ObjectDisposedException("The ThreadLocal instance has been disposed."); + return list; + } + } + + /// Gets all of the threads' values in a list. + private List GetValuesAsList() + { + List valueList = new List(); + int id = ~m_idComplement; + if (id == -1) + { + return null; + } + + // Walk over the linked list of slots and gather the values associated with this ThreadLocal instance. + for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next) + { + // We can safely read linkedSlot.Value. Even if this ThreadLocal has been disposed in the meantime, the LinkedSlot + // objects will never be assigned to another ThreadLocal instance. + valueList.Add(linkedSlot.Value); + } + + return valueList; + } + + /// Gets the number of threads that have data in this instance. + private int ValuesCountForDebugDisplay + { + get + { + int count = 0; + for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next) + { + count++; + } + return count; + } + } + + /// + /// Gets whether is initialized on the current thread. + /// + /// + /// The instance has been disposed. + /// + public bool IsValueCreated + { + get + { + int id = ~m_idComplement; + if (id < 0) + { + throw new ObjectDisposedException("The ThreadLocal instance has been disposed."); + } + + LinkedSlotVolatile[] slotArray = ts_slotArray; + return slotArray != null && id < slotArray.Length && slotArray[id].Value != null; + } + } + + + /// Gets the value of the ThreadLocal<T> for debugging display purposes. It takes care of getting + /// the value for the current thread in the ThreadLocal mode. + internal T ValueForDebugDisplay + { + get + { + LinkedSlotVolatile[] slotArray = ts_slotArray; + int id = ~m_idComplement; + + LinkedSlot slot; + if (slotArray == null || id >= slotArray.Length || (slot = slotArray[id].Value) == null || !m_initialized) + return default(T); + return slot.Value; + } + } + + /// Gets the values of all threads that accessed the ThreadLocal<T>. + internal List ValuesForDebugDisplay // same as Values property, but doesn't throw if disposed + { + get { return GetValuesAsList(); } + } + + /// + /// Resizes a table to a certain length (or larger). + /// + private void GrowTable(ref LinkedSlotVolatile[] table, int minLength) + { + // Determine the size of the new table and allocate it. + int newLen = GetNewTableSize(minLength); + LinkedSlotVolatile[] newTable = new LinkedSlotVolatile[newLen]; + + // + // The lock is necessary to avoid a race with ThreadLocal.Dispose. GrowTable has to point all + // LinkedSlot instances referenced in the old table to reference the new table. Without locking, + // Dispose could use a stale SlotArray reference and clear out a slot in the old array only, while + // the value continues to be referenced from the new (larger) array. + // + lock (s_idManager) + { + for (int i = 0; i < table.Length; i++) + { + LinkedSlot linkedSlot = table[i].Value; + if (linkedSlot != null && linkedSlot.SlotArray != null) + { + linkedSlot.SlotArray = newTable; + newTable[i] = table[i]; + } + } + } + + table = newTable; + } + + /// + /// Chooses the next larger table size + /// + private static int GetNewTableSize(int minSize) + { + if ((uint)minSize > MaxArrayLength) + { + // Intentionally return a value that will result in an OutOfMemoryException + return int.MaxValue; + } + + // + // Round up the size to the next power of 2 + // + // The algorithm takes three steps: + // input -> subtract one -> propagate 1-bits to the right -> add one + // + // Let's take a look at the 3 steps in both interesting cases: where the input + // is (Example 1) and isn't (Example 2) a power of 2. + // + // Example 1: 100000 -> 011111 -> 011111 -> 100000 + // Example 2: 011010 -> 011001 -> 011111 -> 100000 + // + int newSize = minSize; + + // Step 1: Decrement + newSize--; + + // Step 2: Propagate 1-bits to the right. + newSize |= newSize >> 1; + newSize |= newSize >> 2; + newSize |= newSize >> 4; + newSize |= newSize >> 8; + newSize |= newSize >> 16; + + // Step 3: Increment + newSize++; + + // Don't set newSize to more than Array.MaxArrayLength + if ((uint)newSize > MaxArrayLength) + { + newSize = MaxArrayLength; + } + + return newSize; + } + + /// + /// A wrapper struct used as LinkedSlotVolatile[] - an array of LinkedSlot instances, but with volatile semantics + /// on array accesses. + /// + private struct LinkedSlotVolatile + { + internal volatile LinkedSlot Value; + } + + /// + /// A node in the doubly-linked list stored in the ThreadLocal instance. + /// + /// The value is stored in one of two places: + /// + /// 1. If SlotArray is not null, the value is in SlotArray.Table[id] + /// 2. If SlotArray is null, the value is in FinalValue. + /// + private sealed class LinkedSlot + { + internal LinkedSlot(LinkedSlotVolatile[] slotArray) + { + SlotArray = slotArray; + } + + // The next LinkedSlot for this ThreadLocal<> instance + internal volatile LinkedSlot Next; + + // The previous LinkedSlot for this ThreadLocal<> instance + internal volatile LinkedSlot Previous; + + // The SlotArray that stores this LinkedSlot at SlotArray.Table[id]. + internal volatile LinkedSlotVolatile[] SlotArray; + + // The value for this slot. + internal T Value; + } + + /// + /// A manager class that assigns IDs to ThreadLocal instances + /// + private class IdManager + { + // The next ID to try + private int m_nextIdToTry = 0; + + // Stores whether each ID is free or not. Additionally, the object is also used as a lock for the IdManager. + private List m_freeIds = new List(); + + internal int GetId() + { + lock (m_freeIds) + { + int availableId = m_nextIdToTry; + while (availableId < m_freeIds.Count) + { + if (m_freeIds[availableId]) { break; } + availableId++; + } + + if (availableId == m_freeIds.Count) + { + m_freeIds.Add(false); + } + else + { + m_freeIds[availableId] = false; + } + + m_nextIdToTry = availableId + 1; + + return availableId; + } + } + + // Return an ID to the pool + internal void ReturnId(int id) + { + lock (m_freeIds) + { + m_freeIds[id] = true; + if (id < m_nextIdToTry) m_nextIdToTry = id; + } + } + } + + /// + /// A class that facilitates ThreadLocal cleanup after a thread exits. + /// + /// After a thread with an associated thread-local table has exited, the FinalizationHelper + /// is responsible for removing back-references to the table. Since an instance of FinalizationHelper + /// is only referenced from a single thread-local slot, the FinalizationHelper will be GC'd once + /// the thread has exited. + /// + /// The FinalizationHelper then locates all LinkedSlot instances with back-references to the table + /// (all those LinkedSlot instances can be found by following references from the table slots) and + /// releases the table so that it can get GC'd. + /// + private class FinalizationHelper + { + internal LinkedSlotVolatile[] SlotArray; + private bool m_trackAllValues; + + internal FinalizationHelper(LinkedSlotVolatile[] slotArray, bool trackAllValues) + { + SlotArray = slotArray; + m_trackAllValues = trackAllValues; + } + + ~FinalizationHelper() + { + LinkedSlotVolatile[] slotArray = SlotArray; + + for (int i = 0; i < slotArray.Length; i++) + { + LinkedSlot linkedSlot = slotArray[i].Value; + if (linkedSlot == null) + { + // This slot in the table is empty + continue; + } + + if (m_trackAllValues) + { + // Set the SlotArray field to null to release the slot array. + linkedSlot.SlotArray = null; + } + else + { + // Remove the LinkedSlot from the linked list. Once the FinalizationHelper is done, all back-references to + // the table will be have been removed, and so the table can get GC'd. + lock (s_idManager) + { + if (linkedSlot.Next != null) + { + linkedSlot.Next.Previous = linkedSlot.Previous; + } + + // Since the list uses a dummy head node, the Previous reference should never be null. + linkedSlot.Previous.Next = linkedSlot.Next; + } + } + } + } + } + } + + /// A debugger view of the ThreadLocal<T> to surface additional debugging properties and + /// to ensure that the ThreadLocal<T> does not become initialized if it was not already. + internal sealed class SystemThreading_ThreadLocalDebugView + { + //The ThreadLocal object being viewed. + private readonly ThreadLocal m_tlocal; + + /// Constructs a new debugger view object for the provided ThreadLocal object. + /// A ThreadLocal object to browse in the debugger. + public SystemThreading_ThreadLocalDebugView(ThreadLocal tlocal) + { + m_tlocal = tlocal; + } + + /// Returns whether the ThreadLocal object is initialized or not. + public bool IsValueCreated + { + get { return m_tlocal.IsValueCreated; } + } + + /// Returns the value of the ThreadLocal object. + public T Value + { + get + { + return m_tlocal.ValueForDebugDisplay; + } + } + + /// Return all values for all threads that have accessed this instance. + public List Values + { + get + { + return m_tlocal.ValuesForDebugDisplay; + } + } + } +} +#endif \ No newline at end of file diff --git a/FlashPatcher/TaskService/Native/WindowsImpersonatedIdentity.cs b/FlashPatcher/TaskService/Native/WindowsImpersonatedIdentity.cs new file mode 100644 index 0000000..cdaa7af --- /dev/null +++ b/FlashPatcher/TaskService/Native/WindowsImpersonatedIdentity.cs @@ -0,0 +1,80 @@ +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Security.Principal; + +namespace Microsoft.Win32 +{ + /// + /// Impersonation of a user. Allows to execute code under another + /// user context. + /// Please note that the account that instantiates the Impersonator class + /// needs to have the 'Act as part of operating system' privilege set. + /// + internal class WindowsImpersonatedIdentity : IDisposable, IIdentity + { + private const int LOGON_TYPE_NEW_CREDENTIALS = 9; + private const int LOGON32_LOGON_INTERACTIVE = 2; + private const int LOGON32_PROVIDER_DEFAULT = 0; + private const int LOGON32_PROVIDER_WINNT50 = 3; + +#if NETSTANDARD || NETCOREAPP +#else + private WindowsImpersonationContext impersonationContext = null; +#endif + NativeMethods.SafeTokenHandle token; + private WindowsIdentity identity = null; + + /// + /// Constructor. Starts the impersonation with the given credentials. + /// Please note that the account that instantiates the Impersonator class + /// needs to have the 'Act as part of operating system' privilege set. + /// + /// The name of the user to act as. + /// The domain name of the user to act as. + /// The password of the user to act as. + public WindowsImpersonatedIdentity(string userName, string domainName, string password) + { + if (string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(domainName) && string.IsNullOrEmpty(password)) + { + identity = WindowsIdentity.GetCurrent(); + } + else + { + if (NativeMethods.LogonUser(userName, domainName, password, domainName == null ? LOGON_TYPE_NEW_CREDENTIALS : LOGON32_LOGON_INTERACTIVE, domainName == null ? LOGON32_PROVIDER_WINNT50 : LOGON32_PROVIDER_DEFAULT, out token) != 0) + { +#if NETSTANDARD || NETCOREAPP + if (!NativeMethods.ImpersonateLoggedOnUser(token.DangerousGetHandle())) + throw new Win32Exception(); +#else + identity = new WindowsIdentity(token.DangerousGetHandle()); + impersonationContext = identity.Impersonate(); +#endif + } + else + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + } + } + + public string AuthenticationType => identity?.AuthenticationType; + + public bool IsAuthenticated => identity == null ? false : identity.IsAuthenticated; + + public string Name => identity == null ? null : identity.Name; + + public void Dispose() + { +#if NETSTANDARD || NETCOREAPP + NativeMethods.RevertToSelf(); +#else + if (impersonationContext != null) + impersonationContext.Undo(); +#endif + token?.Dispose(); + if (identity != null) + identity.Dispose(); + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/NotV1SupportedException.cs b/FlashPatcher/TaskService/NotV1SupportedException.cs new file mode 100644 index 0000000..9d05447 --- /dev/null +++ b/FlashPatcher/TaskService/NotV1SupportedException.cs @@ -0,0 +1,128 @@ +using System; +using System.Diagnostics; +using System.Runtime.Serialization; +using System.Security; +using System.Security.Permissions; +using JetBrains.Annotations; + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Abstract class for throwing a method specific exception. + /// + [DebuggerStepThrough, Serializable] + [PublicAPI] + public abstract class TSNotSupportedException : Exception + { + /// Defines the minimum supported version for the action not allowed by this exception. + protected readonly TaskCompatibility min; + private readonly string myMessage; + + /// + /// Initializes a new instance of the class. + /// + /// The serialization information. + /// The streaming context. + protected TSNotSupportedException(SerializationInfo serializationInfo, StreamingContext streamingContext) + : base(serializationInfo, streamingContext) + { + try { min = (TaskCompatibility)serializationInfo.GetValue("min", typeof(TaskCompatibility)); } + catch { min = TaskCompatibility.V1; } + } + + internal TSNotSupportedException(TaskCompatibility minComp) + { + min = minComp; + var stackTrace = new StackTrace(); + var stackFrame = stackTrace.GetFrame(2); + var methodBase = stackFrame.GetMethod(); + myMessage = $"{methodBase.DeclaringType?.Name}.{methodBase.Name} is not supported on {LibName}"; + } + + internal TSNotSupportedException(string message, TaskCompatibility minComp) + { + myMessage = message; + min = minComp; + } + + /// + /// Gets a message that describes the current exception. + /// + public override string Message => myMessage; + + /// + /// Gets the minimum supported TaskScheduler version required for this method or property. + /// + public TaskCompatibility MinimumSupportedVersion => min; + + internal abstract string LibName { get; } + + /// + /// Gets the object data. + /// + /// The information. + /// The context. + [SecurityCritical, SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException(nameof(info)); + info.AddValue("min", min); + base.GetObjectData(info, context); + } + } + + /// + /// Thrown when the calling method is not supported by Task Scheduler 1.0. + /// + [DebuggerStepThrough, Serializable] + public class NotV1SupportedException : TSNotSupportedException + { + /// + /// Initializes a new instance of the class. + /// + /// The serialization information. + /// The streaming context. + protected NotV1SupportedException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) { } + internal NotV1SupportedException() : base(TaskCompatibility.V2) { } + /// + /// Initializes a new instance of the class. + /// + /// The message. + public NotV1SupportedException(string message) : base(message, TaskCompatibility.V2) { } + internal override string LibName => "Task Scheduler 1.0"; + } + + /// + /// Thrown when the calling method is not supported by Task Scheduler 2.0. + /// + [DebuggerStepThrough, Serializable] + public class NotV2SupportedException : TSNotSupportedException + { + /// + /// Initializes a new instance of the class. + /// + /// The serialization information. + /// The streaming context. + protected NotV2SupportedException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) { } + internal NotV2SupportedException() : base(TaskCompatibility.V1) { } + internal NotV2SupportedException(string message) : base(message, TaskCompatibility.V1) { } + internal override string LibName => "Task Scheduler 2.0 (1.2)"; + } + + /// + /// Thrown when the calling method is not supported by Task Scheduler versions prior to the one specified. + /// + [DebuggerStepThrough, Serializable] + public class NotSupportedPriorToException : TSNotSupportedException + { + /// + /// Initializes a new instance of the class. + /// + /// The serialization information. + /// The streaming context. + protected NotSupportedPriorToException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) { } + internal NotSupportedPriorToException(TaskCompatibility supportedVersion) : base(supportedVersion) { } + internal override string LibName => $"Task Scheduler versions prior to 2.{((int)min) - 2} (1.{(int)min})"; + } +} diff --git a/FlashPatcher/TaskService/Properties/Resources.Designer.cs b/FlashPatcher/TaskService/Properties/Resources.Designer.cs new file mode 100644 index 0000000..3ad5c6c --- /dev/null +++ b/FlashPatcher/TaskService/Properties/Resources.Designer.cs @@ -0,0 +1,702 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.Win32.TaskScheduler.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Win32.TaskScheduler.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Call a COM object. + /// + internal static string ActionTypeComHandler { + get { + return ResourceManager.GetString("ActionTypeComHandler", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start a program. + /// + internal static string ActionTypeExecute { + get { + return ResourceManager.GetString("ActionTypeExecute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Send an e-mail. + /// + internal static string ActionTypeSendEmail { + get { + return ResourceManager.GetString("ActionTypeSendEmail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Display a message. + /// + internal static string ActionTypeShowMessage { + get { + return ResourceManager.GetString("ActionTypeShowMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {3} {0:P}. + /// + internal static string ComHandlerAction { + get { + return ResourceManager.GetString("ComHandlerAction", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to every day. + /// + internal static string DOWAllDays { + get { + return ResourceManager.GetString("DOWAllDays", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {1} {0}. + /// + internal static string EmailAction { + get { + return ResourceManager.GetString("EmailAction", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to .. + /// + internal static string EndSentence { + get { + return ResourceManager.GetString("EndSentence", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The date and time a trigger expires must be later than the time time it starts or is activated.. + /// + internal static string Error_TriggerEndBeforeStart { + get { + return ResourceManager.GetString("Error_TriggerEndBeforeStart", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} {1}. + /// + internal static string ExecAction { + get { + return ResourceManager.GetString("ExecAction", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to -. + /// + internal static string HyphenSeparator { + get { + return ResourceManager.GetString("HyphenSeparator", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ,. + /// + internal static string ListSeparator { + get { + return ResourceManager.GetString("ListSeparator", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to every month. + /// + internal static string MOYAllMonths { + get { + return ResourceManager.GetString("MOYAllMonths", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Multiple actions defined. + /// + internal static string MultipleActions { + get { + return ResourceManager.GetString("MultipleActions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Multiple triggers defined. + /// + internal static string MultipleTriggers { + get { + return ResourceManager.GetString("MultipleTriggers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}. + /// + internal static string ShowMessageAction { + get { + return ResourceManager.GetString("ShowMessageAction", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Author. + /// + internal static string TaskDefaultPrincipal { + get { + return ResourceManager.GetString("TaskDefaultPrincipal", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disabled. + /// + internal static string TaskStateDisabled { + get { + return ResourceManager.GetString("TaskStateDisabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Queued. + /// + internal static string TaskStateQueued { + get { + return ResourceManager.GetString("TaskStateQueued", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ready. + /// + internal static string TaskStateReady { + get { + return ResourceManager.GetString("TaskStateReady", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Running. + /// + internal static string TaskStateRunning { + get { + return ResourceManager.GetString("TaskStateRunning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown. + /// + internal static string TaskStateUnknown { + get { + return ResourceManager.GetString("TaskStateUnknown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to any user. + /// + internal static string TriggerAnyUser { + get { + return ResourceManager.GetString("TriggerAnyUser", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At system startup. + /// + internal static string TriggerBoot1 { + get { + return ResourceManager.GetString("TriggerBoot1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom Trigger. + /// + internal static string TriggerCustom1 { + get { + return ResourceManager.GetString("TriggerCustom1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At {0:t} every day. + /// + internal static string TriggerDaily1 { + get { + return ResourceManager.GetString("TriggerDaily1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At {0:t} every {1} days. + /// + internal static string TriggerDaily2 { + get { + return ResourceManager.GetString("TriggerDaily2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to indefinitely. + /// + internal static string TriggerDuration0 { + get { + return ResourceManager.GetString("TriggerDuration0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to for a duration of {0}. + /// + internal static string TriggerDurationNot0 { + get { + return ResourceManager.GetString("TriggerDurationNot0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to for {0}. + /// + internal static string TriggerDurationNot0Short { + get { + return ResourceManager.GetString("TriggerDurationNot0Short", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trigger expires at {0:G}.. + /// + internal static string TriggerEndBoundary { + get { + return ResourceManager.GetString("TriggerEndBoundary", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom event filter. + /// + internal static string TriggerEvent1 { + get { + return ResourceManager.GetString("TriggerEvent1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On event - Log: {0}. + /// + internal static string TriggerEventBasic1 { + get { + return ResourceManager.GetString("TriggerEventBasic1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to , Source: {0}. + /// + internal static string TriggerEventBasic2 { + get { + return ResourceManager.GetString("TriggerEventBasic2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to , EventID: {0}. + /// + internal static string TriggerEventBasic3 { + get { + return ResourceManager.GetString("TriggerEventBasic3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to When computer is idle. + /// + internal static string TriggerIdle1 { + get { + return ResourceManager.GetString("TriggerIdle1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At log on of {0}. + /// + internal static string TriggerLogon1 { + get { + return ResourceManager.GetString("TriggerLogon1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At {0:t} on day {1} of {2}, starting {0:d}. + /// + internal static string TriggerMonthly1 { + get { + return ResourceManager.GetString("TriggerMonthly1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At {0:t} on {1} {2:f} each {3}, starting {0:d}. + /// + internal static string TriggerMonthlyDOW1 { + get { + return ResourceManager.GetString("TriggerMonthlyDOW1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to When the task is created or modified. + /// + internal static string TriggerRegistration1 { + get { + return ResourceManager.GetString("TriggerRegistration1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to After triggered, repeat every {0} {1}.. + /// + internal static string TriggerRepetition { + get { + return ResourceManager.GetString("TriggerRepetition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Every {0} {1}.. + /// + internal static string TriggerRepetitionShort { + get { + return ResourceManager.GetString("TriggerRepetitionShort", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On local connection to {0}.. + /// + internal static string TriggerSessionConsoleConnect { + get { + return ResourceManager.GetString("TriggerSessionConsoleConnect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On local disconnect from {0}.. + /// + internal static string TriggerSessionConsoleDisconnect { + get { + return ResourceManager.GetString("TriggerSessionConsoleDisconnect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On remote connection to {0}.. + /// + internal static string TriggerSessionRemoteConnect { + get { + return ResourceManager.GetString("TriggerSessionRemoteConnect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On remote disconnect from {0}.. + /// + internal static string TriggerSessionRemoteDisconnect { + get { + return ResourceManager.GetString("TriggerSessionRemoteDisconnect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On workstation lock of {0}.. + /// + internal static string TriggerSessionSessionLock { + get { + return ResourceManager.GetString("TriggerSessionSessionLock", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On workstation unlock of {0}.. + /// + internal static string TriggerSessionSessionUnlock { + get { + return ResourceManager.GetString("TriggerSessionSessionUnlock", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to user session of {0}. + /// + internal static string TriggerSessionUserSession { + get { + return ResourceManager.GetString("TriggerSessionUserSession", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At {0:t} on {0:d}. + /// + internal static string TriggerTime1 { + get { + return ResourceManager.GetString("TriggerTime1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At startup. + /// + internal static string TriggerTypeBoot { + get { + return ResourceManager.GetString("TriggerTypeBoot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom Trigger. + /// + internal static string TriggerTypeCustom { + get { + return ResourceManager.GetString("TriggerTypeCustom", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Daily. + /// + internal static string TriggerTypeDaily { + get { + return ResourceManager.GetString("TriggerTypeDaily", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On an event. + /// + internal static string TriggerTypeEvent { + get { + return ResourceManager.GetString("TriggerTypeEvent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On idle. + /// + internal static string TriggerTypeIdle { + get { + return ResourceManager.GetString("TriggerTypeIdle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At log on. + /// + internal static string TriggerTypeLogon { + get { + return ResourceManager.GetString("TriggerTypeLogon", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Monthly. + /// + internal static string TriggerTypeMonthly { + get { + return ResourceManager.GetString("TriggerTypeMonthly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Monthly. + /// + internal static string TriggerTypeMonthlyDOW { + get { + return ResourceManager.GetString("TriggerTypeMonthlyDOW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At task creation/modification. + /// + internal static string TriggerTypeRegistration { + get { + return ResourceManager.GetString("TriggerTypeRegistration", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On state change. + /// + internal static string TriggerTypeSessionStateChange { + get { + return ResourceManager.GetString("TriggerTypeSessionStateChange", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to One time. + /// + internal static string TriggerTypeTime { + get { + return ResourceManager.GetString("TriggerTypeTime", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Weekly. + /// + internal static string TriggerTypeWeekly { + get { + return ResourceManager.GetString("TriggerTypeWeekly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At {0:t} every {1} of every week, starting {0:d}. + /// + internal static string TriggerWeekly1Week { + get { + return ResourceManager.GetString("TriggerWeekly1Week", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At {0:t} every {1} of every {2} weeks, starting {0:d}. + /// + internal static string TriggerWeeklyMultWeeks { + get { + return ResourceManager.GetString("TriggerWeeklyMultWeeks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to every. + /// + internal static string WWAllWeeks { + get { + return ResourceManager.GetString("WWAllWeeks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to fifth. + /// + internal static string WWFifthWeek { + get { + return ResourceManager.GetString("WWFifthWeek", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to first. + /// + internal static string WWFirstWeek { + get { + return ResourceManager.GetString("WWFirstWeek", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to fourth. + /// + internal static string WWFourthWeek { + get { + return ResourceManager.GetString("WWFourthWeek", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to last. + /// + internal static string WWLastWeek { + get { + return ResourceManager.GetString("WWLastWeek", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to second. + /// + internal static string WWSecondWeek { + get { + return ResourceManager.GetString("WWSecondWeek", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to third. + /// + internal static string WWThirdWeek { + get { + return ResourceManager.GetString("WWThirdWeek", resourceCulture); + } + } + } +} diff --git a/FlashPatcher/TaskService/Properties/Resources.resx b/FlashPatcher/TaskService/Properties/Resources.resx new file mode 100644 index 0000000..5857096 --- /dev/null +++ b/FlashPatcher/TaskService/Properties/Resources.resx @@ -0,0 +1,357 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Call a COM object + + + Start a program + + + Send an e-mail + + + Display a message + + + {3} {0:P} + 0 = Class GUID; 1 = Data; 2 = Id; 3 = Name + + + every day + + + {1} {0} + 0 = Subject; 1 = To; 2 = Cc, 3 = Bcc, 4 = From, 5 = ReplyTo, 6 = Body, 7 = Server, 8 = Id + + + . + + + {0} {1} + 0 = Executable Path; 1 = Arguments; 2 = WorkingDirectory; 3 = Id + + + - + + + , + + + every month + + + Multiple actions defined + + + Multiple triggers defined + + + {0} + 0 = Title; 1 = MessageBody; 2 = Id + + + Author + + + Disabled + + + Queued + + + Ready + + + Running + + + Unknown + + + any user + + + At system startup + + + Custom Trigger + + + At {0:t} every day + + + At {0:t} every {1} days + + + indefinitely + + + for a duration of {0} + 0 = Duration + + + for {0} + 0 = Duration + + + Trigger expires at {0:G}. + 0 = EndBoundary + + + Custom event filter + + + On event - Log: {0} + 0 = Log name + + + , Source: {0} + 0 = Source name (appended after log) + + + , EventID: {0} + 0 = Event ID (appended after log or source) + + + When computer is idle + + + At log on of {0} + + + At {0:t} on day {1} of {2}, starting {0:d} + 0 = StartBoundary; 1 = list of Days; 2 = list of Months + + + At {0:t} on {1} {2:f} each {3}, starting {0:d} + 0 = StartBoundary; 1 = list of weeks of Month; 2 = list of Week Days; 3 = list of Months + + + When the task is created or modified + + + After triggered, repeat every {0} {1}. + 0 = Interval; 1= Duration string + + + Every {0} {1}. + 0 = Interval; 1= Duration string + + + On local connection to {0}. + 0 = UserId + + + On local disconnect from {0}. + 0 = UserId + + + On remote connection to {0}. + 0 = UserId + + + On remote disconnect from {0}. + 0 = UserId + + + On workstation lock of {0}. + 0 = UserId + + + On workstation unlock of {0}. + 0 = UserId + + + user session of {0} + 0 = UserId + + + At {0:t} on {0:d} + 0 = StartBoundary + + + At startup + + + Custom Trigger + + + Daily + + + On an event + + + On idle + + + At log on + + + Monthly + + + Monthly + + + At task creation/modification + + + On state change + + + One time + + + Weekly + + + At {0:t} every {1} of every week, starting {0:d} + 0 = StartBoundary; 1 = list of Week Days + + + At {0:t} every {1} of every {2} weeks, starting {0:d} + 0 = StartBoundary; 1 = list of Week Days; 2 = WeekInterval + + + every + + + fifth + + + first + + + fourth + + + last + + + second + + + third + + + The date and time a trigger expires must be later than the time time it starts or is activated. + + \ No newline at end of file diff --git a/FlashPatcher/TaskService/ReflectionHelper.cs b/FlashPatcher/TaskService/ReflectionHelper.cs new file mode 100644 index 0000000..f79b9b3 --- /dev/null +++ b/FlashPatcher/TaskService/ReflectionHelper.cs @@ -0,0 +1,132 @@ +namespace System.Reflection +{ + /// Extensions related to System.Reflection + internal static class ReflectionHelper + { + /// Loads a type from a named assembly. + /// Name of the type. + /// The name or path of the file that contains the manifest of the assembly. + /// The reference, or null if type or assembly not found. + public static Type LoadType(string typeName, string asmRef) + { + Type ret = null; + if (!TryGetType(Assembly.GetCallingAssembly(), typeName, ref ret)) + if (!TryGetType(asmRef, typeName, ref ret)) + if (!TryGetType(Assembly.GetExecutingAssembly(), typeName, ref ret)) + TryGetType(Assembly.GetEntryAssembly(), typeName, ref ret); + return ret; + } + + /// Tries the retrieve a reference from an assembly. + /// Name of the type. + /// The assembly reference name from which to load the type. + /// The reference, if found. + /// true if the type was found in the assembly; otherwise, false. + private static bool TryGetType(string asmRef, string typeName, ref Type type) + { + try + { + if (System.IO.File.Exists(asmRef)) + return TryGetType(Assembly.LoadFrom(asmRef), typeName, ref type); + } + catch { } + return false; + } + + /// Tries the retrieve a reference from an assembly. + /// Name of the type. + /// The assembly from which to load the type. + /// The reference, if found. + /// true if the type was found in the assembly; otherwise, false. + private static bool TryGetType(Assembly asm, string typeName, ref Type type) + { + if (asm != null) + { + try + { + type = asm.GetType(typeName, false, false); + return (type != null); + } + catch { } + } + return false; + } + + /// Invokes a named method on a created instance of a type with parameters. + /// The expected type of the method's return value. + /// The type to be instantiated and then used to invoke the method. This method assumes the type has a default public constructor. + /// Name of the method. + /// The arguments to provide to the method invocation. + /// The value returned from the method. + public static T InvokeMethod(Type type, string methodName, params object[] args) + { + object o = Activator.CreateInstance(type); + return InvokeMethod(o, methodName, args); + } + + /// Invokes a named method on a created instance of a type with parameters. + /// The expected type of the method's return value. + /// The type to be instantiated and then used to invoke the method. + /// The arguments to supply to the constructor. + /// Name of the method. + /// The arguments to provide to the method invocation. + /// The value returned from the method. + public static T InvokeMethod(Type type, object[] instArgs, string methodName, params object[] args) + { + object o = Activator.CreateInstance(type, instArgs); + return InvokeMethod(o, methodName, args); + } + + /// Invokes a named method on an object with parameters and no return value. + /// The object on which to invoke the method. + /// Name of the method. + /// The arguments to provide to the method invocation. + public static T InvokeMethod(object obj, string methodName, params object[] args) + { + Type[] argTypes = (args == null || args.Length == 0) ? Type.EmptyTypes : Array.ConvertAll(args, delegate(object o) { return o == null ? typeof(object) : o.GetType(); }); + return InvokeMethod(obj, methodName, argTypes, args); + } + + /// Invokes a named method on an object with parameters and no return value. + /// The expected type of the method's return value. + /// The object on which to invoke the method. + /// Name of the method. + /// The types of the . + /// The arguments to provide to the method invocation. + /// The value returned from the method. + public static T InvokeMethod(object obj, string methodName, Type[] argTypes, object[] args) + { + MethodInfo mi = obj?.GetType().GetMethod(methodName, argTypes); + if (mi != null) + return (T)Convert.ChangeType(mi.Invoke(obj, args), typeof(T)); + return default(T); + } + + /// Gets a named property value from an object. + /// The expected type of the property to be returned. + /// The object from which to retrieve the property. + /// Name of the property. + /// The default value to return in the instance that the property is not found. + /// The property value, if found, or the if not. + public static T GetProperty(object obj, string propName, T defaultValue = default(T)) + { + if (obj != null) + { + try { return (T)Convert.ChangeType(obj.GetType().InvokeMember(propName, BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, obj, null, null), typeof(T)); } + catch { } + } + return defaultValue; + } + + /// Sets a named property on an object. + /// The type of the property to be set. + /// The object on which to set the property. + /// Name of the property. + /// The property value to set on the object. + public static void SetProperty(object obj, string propName, T value) + { + try { obj?.GetType().InvokeMember(propName, BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, obj, new object[] { value }, null); } + catch { } + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/ResourceReferenceValue.cs b/FlashPatcher/TaskService/ResourceReferenceValue.cs new file mode 100644 index 0000000..66a0c9e --- /dev/null +++ b/FlashPatcher/TaskService/ResourceReferenceValue.cs @@ -0,0 +1,124 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; +using JetBrains.Annotations; + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Some string values of properties can be set to retrieve their value from existing DLLs as a resource. This class facilitates creating those reference strings. + /// + [PublicAPI] + public class ResourceReferenceValue + { + /// + /// Initializes a new instance of the class. + /// + /// The DLL path. + /// The resource identifier. + public ResourceReferenceValue([NotNull] string dllPath, int resourceId) + { + ResourceFilePath = dllPath; + ResourceIdentifier = resourceId; + } + + /// + /// Gets or sets the resource file path. This can be a relative path, full path or lookup path (e.g. %SystemRoot%\System32\ResourceName.dll). + /// + /// + /// The resource file path. + /// + public string ResourceFilePath { get; set; } + + /// + /// Gets or sets the resource identifier. + /// + /// The resource identifier. + public int ResourceIdentifier { get; set; } + + /// + /// Performs an implicit conversion from to . + /// + /// The value. + /// The result of the conversion. + public static implicit operator string(ResourceReferenceValue value) => value.ToString(); + + /// + /// Parses the input string. String must be in the format "$(@ [Dll], [ResourceID])". + /// + /// The input string value. + /// A new instance on success or null on failure. + /// is null + /// is not in the format "$(@ [Dll], [ResourceID])" + [NotNull] + public static ResourceReferenceValue Parse([NotNull] string value) + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + ResourceReferenceValue r; + if (!TryParse(value, out r)) + throw new FormatException(); + return r; + } + + /// + /// Tries to parse to input string. String must be in the format "$(@ [Dll], [ResourceID])". + /// + /// The input string value. + /// The resource reference to be returned. On failure, this value equals null. + /// A new instance on success or null on failure. + public static bool TryParse(string value, out ResourceReferenceValue resourceRef) + { + if (!string.IsNullOrEmpty(value)) + { + var m = System.Text.RegularExpressions.Regex.Match(value, @"^\$\(\@ (?[^,]+), (?-?\d+)\)$"); + if (m.Success) + { + resourceRef = new ResourceReferenceValue(m.Groups["x"].Value, int.Parse(m.Groups["i"].Value)); + return true; + } + } + resourceRef = null; + return false; + } + + /// + /// Gets the result of pulling the string from the resource file using the identifier. + /// + /// from resource file. + /// cannot be found. + /// Unable to load or string identified by . + [NotNull] + public string GetResolvedString() + { + if (!System.IO.File.Exists(ResourceFilePath)) + throw new System.IO.FileNotFoundException("Invalid resource file path.", ResourceFilePath); + IntPtr hLib = IntPtr.Zero; + try + { + hLib = NativeMethods.LoadLibrary(ResourceFilePath); + if (hLib == IntPtr.Zero) + throw new System.ComponentModel.Win32Exception(); + var sb = new StringBuilder(8192); + int l = LoadString(hLib, ResourceIdentifier, sb, sb.Capacity); + if (l == 0) + throw new System.ComponentModel.Win32Exception(); + return sb.ToString(0, l); + } + finally + { + if (hLib != IntPtr.Zero) + NativeMethods.FreeLibrary(hLib); + } + } + + /// + /// Returns a in the format required by the Task Scheduler to reference a string in a DLL. + /// + /// A formatted in the format $(@ [Dll], [ResourceID]). + public override string ToString() => $"$(@ {ResourceFilePath}, {ResourceIdentifier})"; + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] + private static extern int LoadString(IntPtr hInstance, int wID, StringBuilder lpBuffer, int nBufferMax); + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/Snapshot.cs b/FlashPatcher/TaskService/Snapshot.cs new file mode 100644 index 0000000..9131abf --- /dev/null +++ b/FlashPatcher/TaskService/Snapshot.cs @@ -0,0 +1,409 @@ +#if !(NET20 || NET35 || NET40) +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Security.AccessControl; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +namespace Microsoft.Win32.TaskScheduler +{ + /// Abstract class representing a secured item for storage in a . + public abstract class SnapshotItem + { + /// Initializes a new instance of the class. + /// The path to the item. + /// The SDDL for the item. + internal SnapshotItem(string path, string sddl) { Path = path; Sddl = sddl; } + + /// Gets the path to the item. + /// The path to the item. + public string Path { get; private set; } + + /// Gets the SDDL for the item. + /// The SDDL for the item. + public string Sddl { get; private set; } + } + + /// Represents a instance and captures its name and security. + public sealed class TaskFolderSnapshot : SnapshotItem + { + /// Initializes a new instance of the class. + /// The path to the item. + /// The SDDL for the item. + internal TaskFolderSnapshot(string path, string sddl) : base(path, sddl) { } + } + + /// + /// Represents all the information about the tasks and folders from a instance that can be used to reconstitute tasks and folders + /// on the same or different systems. This class and related classes are only available under the .NET 4.5.2 build and later .NET versions due to + /// dependencies on threading and compressed (zip) files. + /// + public sealed class TaskSchedulerSnapshot : IXmlSerializable + { + private const string hdrfile = ".metadata.xml"; + private List items; + + /// Creates a new instance of from an existing snapshot. + /// The zip file snapshot created by the method. + public TaskSchedulerSnapshot(string path) + { + if (path == null) throw new ArgumentNullException(nameof(path)); + if (!File.Exists(path)) throw new FileNotFoundException("Invalid file location.", nameof(path)); + try + { + using (var zip = ZipFile.OpenRead(path)) + zip.GetEntry(hdrfile); + } + catch + { + throw new InvalidOperationException("Invalid file format."); + } + Path = path; + } + + internal TaskSchedulerSnapshot() { } + + /// + /// Gets a list of and instances the represent the tasks and folders from a Task Scheduler instance. + /// + public List Items + { + get => items ?? (items = (Path == null ? new List() : GetArchiveItems(Path))); + internal set => items = value; + } + + /// Gets the path of the file based snapshot. + public string Path { get; private set; } + + /// Gets the machine name of the server from which the snapshot was taken. + /// The target server name. + public string TargetServer { get; private set; } + + /// Gets the UTC time stamp for when the snapshot was taken. + /// The time stamp. + public DateTime TimeStamp { get; private set; } = DateTime.UtcNow; + + /// + /// Creates a compressed zip file that contains all the information accessible to the user from the instance necessary to + /// reconstitute its tasks and folders. This method can take many seconds to execute. It is recommended to call the asynchronous + /// version.This method will execute without error even if the user does not have permissions to see all tasks and folders. + /// It is imperative that the developer ensures that the user has Administrator or equivalent rights before calling this method. + /// + /// The from which to pull the tasks and folders. + /// The output zip file in which to place the snapshot information. + /// A instance with the contents of the specified Task Scheduler connection. + public static TaskSchedulerSnapshot Create(TaskService ts, string path) + { + var c = new System.Threading.CancellationTokenSource(); + return InternalCreate(ts.Token, path, c.Token, null); + } + + /// + /// Creates a compressed zip file that contains all the information accessible to the user from the instance necessary to + /// reconstitute its tasks and folders. This method will execute without error even if the user does not have permissions to see all + /// tasks and folders. It is imperative that the developer ensures that the user has Administrator or equivalent rights before calling this method. + /// + /// The from which to pull the tasks and folders. + /// The output zip file in which to place the snapshot information. + /// A cancellation token to use to cancel this asynchronous operation. + /// An optional instance to use to report progress of the asynchronous operation. + /// An asynchronous instance with the contents of the specified Task Scheduler connection. + public static async System.Threading.Tasks.Task Create(TaskService.ConnectionToken tsToken, string path, System.Threading.CancellationToken cancelToken, IProgress> progress) + { + return await System.Threading.Tasks.Task.Run(() => InternalCreate(tsToken, path, cancelToken, progress), cancelToken); + } + + /// Opens an existing snapshot and returns a new instance of . + /// The zip file snapshot created by the method. + /// A instance with the contents of the specified snapshot file. + public static TaskSchedulerSnapshot Open(string path) => new TaskSchedulerSnapshot(path); + + /// Register a list of snapshot items (tasks and folders) into the specified Task Scheduler. + /// The into which the tasks and folders are registered. + /// + /// The list of paths representing the tasks and folders from this snapshot that should be registered on the instance. + /// + /// + /// If true, takes the access rights from the snapshot item and applies it to both new and existing tasks and folders. + /// + /// + /// If true, overwrite any existing tasks and folders found in the target Task Scheduler that match the path of the snapshot item. + /// + /// + /// Lookup table for password. Provide pairs of the user/group account name and the associated passwords for any task that requires a password. + /// + /// A cancellation token to use to cancel this asynchronous operation. + /// An optional instance to use to report progress of the asynchronous operation. + /// An asynchronous instance. + public async System.Threading.Tasks.Task Restore(TaskService.ConnectionToken tsToken, IEnumerable itemPaths, bool applyAccessRights, bool overwriteExisting, IDictionary passwords, System.Threading.CancellationToken cancelToken, IProgress> progress) + { + if (itemPaths == null) throw new ArgumentNullException(nameof(itemPaths)); + var items = Items.Where(i => i is TaskSnapshot).Join(itemPaths, a => a.Path, b => b, (a, b) => a).ToList(); + if (items.Count != itemPaths.Count()) throw new ArgumentException($"Unable to locate matching tasks to all values of {nameof(itemPaths)}.", nameof(itemPaths)); + await System.Threading.Tasks.Task.Run(() => InternalRestore(tsToken, items, applyAccessRights, overwriteExisting, passwords, cancelToken, progress)); + } + + /// Register a list of snapshot items (tasks and folders) into the specified Task Scheduler. + /// The into which the tasks and folders are registered. + /// + /// The list of instances representing the tasks and folders from this snapshot that should be registered on the + /// instance. + /// + /// + /// If true, takes the access rights from the snapshot item and applies it to both new and existing tasks and folders. + /// + /// + /// If true, overwrite any existing tasks and folders found in the target Task Scheduler that match the path of the snapshot item. + /// + /// + /// Lookup table for password. Provide pairs of the user/group account name and the associated passwords for any task that requires a password. + /// + /// A cancellation token to use to cancel this asynchronous operation. + /// An optional instance to use to report progress of the asynchronous operation. + /// An asynchronous instance. + public async System.Threading.Tasks.Task Restore(TaskService.ConnectionToken tsToken, ICollection items, bool applyAccessRights, bool overwriteExisting, IDictionary passwords, System.Threading.CancellationToken cancelToken, IProgress> progress) + { + if (items == null) throw new ArgumentNullException(nameof(items)); + await System.Threading.Tasks.Task.Run(() => InternalRestore(tsToken, items, applyAccessRights, overwriteExisting, passwords, cancelToken, progress)); + } + + /// Register a list of snapshot items (tasks and folders) into the specified Task Scheduler. + /// The into which the tasks and folders are registered. + /// + /// The list of instances representing the tasks and folders from this snapshot that should be registered on the + /// instance. + /// + /// + /// If true, takes the access rights from the snapshot item and applies it to both new and existing tasks and folders. + /// + /// + /// If true, overwrite any existing tasks and folders found in the target Task Scheduler that match the path of the snapshot item. + /// + /// + /// Lookup table for password. Provide pairs of the user/group account name and the associated passwords for any task that requires a password. + /// + public void Restore(TaskService ts, ICollection items, bool applyAccessRights, bool overwriteExisting, IDictionary passwords) + { + var c = new System.Threading.CancellationTokenSource(); + InternalRestore(ts.Token, items, applyAccessRights, overwriteExisting, passwords, c.Token, null); + } + + XmlSchema IXmlSerializable.GetSchema() => null; + + void IXmlSerializable.ReadXml(XmlReader reader) + { + reader.MoveToContent(); + if (DateTime.TryParseExact(reader.GetAttribute("timestamp"), "o", CultureInfo.CurrentCulture.DateTimeFormat, DateTimeStyles.AssumeUniversal, out DateTime dt)) + TimeStamp = dt; + TargetServer = reader.GetAttribute("machine"); + reader.GetAttribute("version"); + while (reader.Read()) + { + if (reader.Name == "Task") + { + var tsnap = new TaskSnapshot(reader.GetAttribute("path"), reader.GetAttribute("sddl"), true); + var e = reader.GetAttribute("enabled"); + if (e != null && e == "false") tsnap.Enabled = false; + Items.Add(tsnap); + } + else if (reader.Name == "TaskFolder") + Items.Add(new TaskFolderSnapshot(reader.GetAttribute("path"), reader.GetAttribute("sddl"))); + } + } + + void IXmlSerializable.WriteXml(XmlWriter writer) + { + writer.WriteAttributeString("timestamp", TimeStamp.ToString("o")); + if (TargetServer != null) + writer.WriteAttributeString("machine", TargetServer); + writer.WriteAttributeString("version", "1.0"); + foreach (var i in items) + { + if (i is TaskSnapshot t) + { + writer.WriteStartElement("Task"); + writer.WriteAttributeString("path", t.Path); + writer.WriteAttributeString("sddl", t.Sddl); + if (!t.Enabled) + writer.WriteAttributeString("enabled", "false"); + writer.WriteEndElement(); + } + else if (i is TaskFolderSnapshot f) + { + writer.WriteStartElement("TaskFolder"); + writer.WriteAttributeString("path", f.Path); + writer.WriteAttributeString("sddl", f.Sddl); + writer.WriteEndElement(); + } + } + } + + private static List GetArchiveItems(string archiveFile) + { + TaskSchedulerSnapshot ret = null; + using (var zip = ZipFile.OpenRead(archiveFile)) + { + using (var hdrStr = zip.GetEntry(hdrfile).Open()) + ret = new XmlSerializer(typeof(TaskSchedulerSnapshot)).Deserialize(hdrStr) as TaskSchedulerSnapshot; + if (ret == null) return null; + for (int i = 0; i < ret.Items.Count; i++) + { + if (ret.Items[i] is TaskSnapshot t) + { + var xml = zip.GetEntry(t.Path.TrimStart('\\') + ".xml"); + using (var str = new StreamReader(xml.Open(), Encoding.UTF8)) + t.TaskDefinitionXml = str.ReadToEnd(); + } + } + } + return ret?.Items; + } + + private static TaskSchedulerSnapshot InternalCreate(TaskService.ConnectionToken token, string path, System.Threading.CancellationToken cancelToken, IProgress> progress) + { + var ts = TaskService.CreateFromToken(token); + const SecurityInfos siall = SecurityInfos.DiscretionaryAcl | SecurityInfos.SystemAcl | SecurityInfos.Group | SecurityInfos.Owner; + if (File.Exists(path)) throw new ArgumentException("Output file already exists.", nameof(path)); + int i = 0, count = 0; + using (var zipstr = new FileStream(path, FileMode.CreateNew)) + using (var zip = new ZipArchive(zipstr, ZipArchiveMode.Create)) + { + GetCount(ts.RootFolder); + var snapshot = new TaskSchedulerSnapshot { TargetServer = ts.TargetServer ?? Environment.MachineName }; + GetContents(ts.RootFolder, snapshot.Items, zip); + snapshot.Items.Sort((t1, t2) => String.Compare(t1.Path, t2.Path, StringComparison.InvariantCultureIgnoreCase)); + using (var hdr = new StreamWriter(zip.CreateEntry(hdrfile).Open(), Encoding.UTF8)) + new XmlSerializer(snapshot.GetType()).Serialize(hdr, snapshot); + snapshot.Path = path; + return snapshot; + } + + void GetCount(TaskFolder f) + { + count += f.Tasks.Count; + foreach (var sf in f.SubFolders) + { + count++; + GetCount(sf); + } + } + + void GetContents(TaskFolder f, List list, ZipArchive zip) + { + cancelToken.ThrowIfCancellationRequested(); + foreach (var t in f.Tasks) + { + list.Add(new TaskSnapshot(t.Path, t.GetSecurityDescriptorSddlForm(siall), t.Enabled, t.Xml)); + using (var wr = new StreamWriter(zip.CreateEntry(t.Path.TrimStart('\\') + ".xml").Open(), Encoding.Unicode)) + wr.Write(t.Xml); + cancelToken.ThrowIfCancellationRequested(); + progress?.Report(new Tuple(++i * 100 / count, t.Path)); + } + foreach (var sf in f.SubFolders) + { + list.Add(new TaskFolderSnapshot(sf.Path, sf.GetSecurityDescriptorSddlForm(siall))); + zip.CreateEntry(sf.Path.TrimStart('\\') + "\\"); + GetContents(sf, list, zip); + cancelToken.ThrowIfCancellationRequested(); + progress?.Report(new Tuple(++i * 100 / count, sf.Path)); + } + } + } + + private void InternalRestore(TaskService.ConnectionToken token, ICollection items, bool applyAccessRights, bool overwriteExisting, IDictionary passwords, System.Threading.CancellationToken cancelToken, IProgress> progress) + { + var ts = TaskService.CreateFromToken(token); + var i = 0; + progress?.Report(new Tuple(0, "")); + foreach (var item in items) + { + cancelToken.ThrowIfCancellationRequested(); + if (item is TaskSnapshot t) + { + var td = ts.NewTask(); + td.XmlText = t.TaskDefinitionXml; + var pwd = td.Principal.RequiresPassword() ? passwords?[td.Principal.ToString()] : null; + var st = ts.GetTask(t.Path); + if (st == null) + { + CreateTask(t, td, pwd); + } + else if (overwriteExisting) + { + st = st.Folder.RegisterTaskDefinition(System.IO.Path.GetFileName(t.Path), td, TaskCreation.CreateOrUpdate, td.Principal.ToString(), pwd, td.Principal.LogonType, applyAccessRights ? t.Sddl : null); + if (!t.Enabled) st.Enabled = false; + } + } + else if (item is TaskFolderSnapshot f) + { + var sf = ts.GetFolder(f.Path); + if (sf == null) + sf = EnsureFolder(f.Path); + else if (overwriteExisting && applyAccessRights) + sf.SetSecurityDescriptorSddlForm(f.Sddl); + } + progress?.Report(new Tuple(++i * 100 / items.Count, item.Path)); + } + progress?.Report(new Tuple(100, "")); + + void CreateTask(TaskSnapshot task, TaskDefinition td, string password) + { + var fpath = System.IO.Path.GetDirectoryName(task.Path); + var fld = EnsureFolder(fpath); + var t = fld.RegisterTaskDefinition(System.IO.Path.GetFileName(task.Path), td, TaskCreation.CreateOrUpdate, td.Principal.ToString(), password, td.Principal.LogonType, applyAccessRights ? task.Sddl : null); + if (!task.Enabled) t.Enabled = false; + } + + TaskFolder EnsureFolder(string fpath) + { + if (!overwriteExisting) + { + var f = ts.GetFolder(fpath); + if (f != null) return f; + } + var flds = fpath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); + var fld = ts.RootFolder; + var sfpath = ""; + for (var j = 0; j < flds.Length; j++) + { + sfpath += "\\" + flds[j]; + var sf = fld.SubFolders.Exists(flds[j]) ? fld.SubFolders[flds[j]] : null; + if (sf == null) + sf = fld.CreateFolder(flds[j], GetFolderSddl(sfpath), false); + else if (overwriteExisting) + sf.SetSecurityDescriptorSddlForm(GetFolderSddl(sfpath)); + fld = sf; + } + return fld; + } + + string GetFolderSddl(string path) => Items?.Find(tci => String.Equals(tci.Path, path, StringComparison.OrdinalIgnoreCase)).Sddl; + } + } + + /// Represents a instance and captures its details. + public sealed class TaskSnapshot : SnapshotItem + { + /// Initializes a new instance of the class. + /// The path to the item. + /// The SDDL for the item. + /// If set to true task is enabled. + /// The XML for the . + internal TaskSnapshot(string path, string sddl, bool enabled, string xml = null) : base(path, sddl) { Enabled = enabled; TaskDefinitionXml = xml; } + + /// Gets a value indicating whether th is enabled. + /// true if enabled; otherwise, false. + public bool Enabled { get; internal set; } = true; + + /// Gets the XML. + /// The XML. + public string TaskDefinitionXml { get; internal set; } + } +} +#endif \ No newline at end of file diff --git a/FlashPatcher/TaskService/Task.cs b/FlashPatcher/TaskService/Task.cs new file mode 100644 index 0000000..e846c09 --- /dev/null +++ b/FlashPatcher/TaskService/Task.cs @@ -0,0 +1,3760 @@ +using JetBrains.Annotations; +using Microsoft.Win32.TaskScheduler.V1Interop; +using Microsoft.Win32.TaskScheduler.V2Interop; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using System.Runtime.Serialization.Formatters.Binary; +using System.Security; +using System.Security.AccessControl; +using System.Security.Principal; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using IPrincipal = Microsoft.Win32.TaskScheduler.V2Interop.IPrincipal; + +// ReSharper disable UnusedMember.Global + +// ReSharper disable InconsistentNaming ReSharper disable SuspiciousTypeConversion.Global + +namespace Microsoft.Win32.TaskScheduler +{ + /// Defines what versions of Task Scheduler or the AT command that the task is compatible with. + public enum TaskCompatibility + { + /// The task is compatible with the AT command. + AT, + + /// + /// The task is compatible with Task Scheduler 1.0 (Windows Server™ 2003, Windows® XP, or Windows® 2000). + /// Items not available when compared to V2: + /// + /// + /// TaskDefinition.Principal.GroupId - All account information can be retrieved via the UserId property. + /// + /// + /// TaskLogonType values Group, None and S4U are not supported. + /// + /// + /// TaskDefinition.Principal.RunLevel == TaskRunLevel.Highest is not supported. + /// + /// + /// + /// Assigning access security to a task is not supported using TaskDefinition.RegistrationInfo.SecurityDescriptorSddlForm or in RegisterTaskDefinition. + /// + /// + /// + /// + /// TaskDefinition.RegistrationInfo.Documentation, Source, URI and Version properties are only supported using this library. See + /// details in the remarks for . + /// + /// + /// + /// TaskDefinition.Settings.AllowDemandStart cannot be false. + /// + /// + /// TaskDefinition.Settings.AllowHardTerminate cannot be false. + /// + /// + /// TaskDefinition.Settings.MultipleInstances can only be IgnoreNew. + /// + /// + /// TaskDefinition.Settings.NetworkSettings cannot have any values. + /// + /// + /// TaskDefinition.Settings.RestartCount can only be 0. + /// + /// + /// TaskDefinition.Settings.StartWhenAvailable can only be false. + /// + /// + /// + /// TaskDefinition.Actions can only contain ExecAction instances unless the TaskDefinition.Actions.PowerShellConversion property has + /// the Version1 flag set. + /// + /// + /// + /// + /// TaskDefinition.Triggers cannot contain CustomTrigger, EventTrigger, SessionStateChangeTrigger, or RegistrationTrigger instances. + /// + /// + /// + /// TaskDefinition.Triggers cannot contain instances with delays set. + /// + /// + /// TaskDefinition.Triggers cannot contain instances with ExecutionTimeLimit or Id properties set. + /// + /// + /// TaskDefinition.Triggers cannot contain LogonTriggers instances with the UserId property set. + /// + /// + /// TaskDefinition.Triggers cannot contain MonthlyDOWTrigger instances with the RunOnLastWeekOfMonth property set to true. + /// + /// + /// TaskDefinition.Triggers cannot contain MonthlyTrigger instances with the RunOnDayWeekOfMonth property set to true. + /// + /// + /// + V1, + + /// + /// The task is compatible with Task Scheduler 2.0 (Windows Vista™, Windows Server™ 2008). + /// + /// This version is the baseline for the new, non-file based Task Scheduler. See remarks for + /// functionality that was not forward-compatible. + /// + /// + V2, + + /// + /// The task is compatible with Task Scheduler 2.1 (Windows® 7, Windows Server™ 2008 R2). + /// Changes from V2: + /// + /// + /// TaskDefinition.Principal.ProcessTokenSidType can be defined as a value other than Default. + /// + /// + /// + /// TaskDefinition.Actions may not contain EmailAction or ShowMessageAction instances unless the + /// TaskDefinition.Actions.PowerShellConversion property has the Version2 flag set. + /// + /// + /// + /// TaskDefinition.Principal.RequiredPrivileges can have privilege values assigned. + /// + /// + /// TaskDefinition.Settings.DisallowStartOnRemoteAppSession can be set to true. + /// + /// + /// TaskDefinition.UseUnifiedSchedulingEngine can be set to true. + /// + /// + /// + V2_1, + + /// + /// The task is compatible with Task Scheduler 2.2 (Windows® 8.x, Windows Server™ 2012). + /// Changes from V2_1: + /// + /// + /// + /// TaskDefinition.Settings.MaintenanceSettings can have Period or Deadline be values other than TimeSpan.Zero or the Exclusive + /// property set to true. + /// + /// + /// + /// TaskDefinition.Settings.Volatile can be set to true. + /// + /// + /// + V2_2, + + /// + /// The task is compatible with Task Scheduler 2.3 (Windows® 10, Windows Server™ 2016). + /// Changes from V2_2: + /// + /// + /// None published. + /// + /// + /// + V2_3 + } + + /// Defines how the Task Scheduler service creates, updates, or disables the task. + [DefaultValue(CreateOrUpdate)] + public enum TaskCreation + { + /// The Task Scheduler service registers the task as a new task. + Create = 2, + + /// + /// The Task Scheduler service either registers the task as a new task or as an updated version if the task already exists. + /// Equivalent to Create | Update. + /// + CreateOrUpdate = 6, + + /// + /// The Task Scheduler service registers the disabled task. A disabled task cannot run until it is enabled. For more information, + /// see Enabled Property of TaskSettings and Enabled Property of RegisteredTask. + /// + Disable = 8, + + /// + /// The Task Scheduler service is prevented from adding the allow access-control entry (ACE) for the context principal. When the + /// TaskFolder.RegisterTaskDefinition or TaskFolder.RegisterTask functions are called with this flag to update a task, the Task + /// Scheduler service does not add the ACE for the new context principal and does not remove the ACE from the old context principal. + /// + DontAddPrincipalAce = 0x10, + + /// + /// The Task Scheduler service creates the task, but ignores the registration triggers in the task. By ignoring the registration + /// triggers, the task will not execute when it is registered unless a time-based trigger causes it to execute on registration. + /// + IgnoreRegistrationTriggers = 0x20, + + /// + /// The Task Scheduler service registers the task as an updated version of an existing task. When a task with a registration trigger + /// is updated, the task will execute after the update occurs. + /// + Update = 4, + + /// + /// The Task Scheduler service checks the syntax of the XML that describes the task but does not register the task. This constant + /// cannot be combined with the Create, Update, or CreateOrUpdate values. + /// + ValidateOnly = 1 + } + + /// Defines how the Task Scheduler handles existing instances of the task when it starts a new instance of the task. + [DefaultValue(IgnoreNew)] + public enum TaskInstancesPolicy + { + /// Starts new instance while an existing instance is running. + Parallel, + + /// Starts a new instance of the task after all other instances of the task are complete. + Queue, + + /// Does not start a new instance if an existing instance of the task is running. + IgnoreNew, + + /// Stops an existing instance of the task before it starts a new instance. + StopExisting + } + + /// Defines what logon technique is required to run a task. + [DefaultValue(S4U)] + public enum TaskLogonType + { + /// The logon method is not specified. Used for non-NT credentials. + None, + + /// Use a password for logging on the user. The password must be supplied at registration time. + Password, + + /// + /// Use an existing interactive token to run a task. The user must log on using a service for user (S4U) logon. When an S4U logon is + /// used, no password is stored by the system and there is no access to either the network or to encrypted files. + /// + S4U, + + /// User must already be logged on. The task will be run only in an existing interactive session. + InteractiveToken, + + /// Group activation. The groupId field specifies the group. + Group, + + /// + /// Indicates that a Local System, Local Service, or Network Service account is being used as a security context to run the task. + /// + ServiceAccount, + + /// + /// First use the interactive token. If the user is not logged on (no interactive token is available), then the password is used. + /// The password must be specified when a task is registered. This flag is not recommended for new tasks because it is less reliable + /// than Password. + /// + InteractiveTokenOrPassword + } + + /// Defines which privileges must be required for a secured task. + public enum TaskPrincipalPrivilege + { + /// Required to create a primary token. User Right: Create a token object. + SeCreateTokenPrivilege = 1, + + /// Required to assign the primary token of a process. User Right: Replace a process-level token. + SeAssignPrimaryTokenPrivilege, + + /// Required to lock physical pages in memory. User Right: Lock pages in memory. + SeLockMemoryPrivilege, + + /// Required to increase the quota assigned to a process. User Right: Adjust memory quotas for a process. + SeIncreaseQuotaPrivilege, + + /// Required to read unsolicited input from a terminal device. User Right: Not applicable. + SeUnsolicitedInputPrivilege, + + /// Required to create a computer account. User Right: Add workstations to domain. + SeMachineAccountPrivilege, + + /// + /// This privilege identifies its holder as part of the trusted computer base. Some trusted protected subsystems are granted this + /// privilege. User Right: Act as part of the operating system. + /// + SeTcbPrivilege, + + /// + /// Required to perform a number of security-related functions, such as controlling and viewing audit messages. This privilege + /// identifies its holder as a security operator. User Right: Manage auditing and the security log. + /// + SeSecurityPrivilege, + + /// + /// Required to take ownership of an object without being granted discretionary access. This privilege allows the owner value to be + /// set only to those values that the holder may legitimately assign as the owner of an object. User Right: Take ownership of files + /// or other objects. + /// + SeTakeOwnershipPrivilege, + + /// Required to load or unload a device driver. User Right: Load and unload device drivers. + SeLoadDriverPrivilege, + + /// Required to gather profiling information for the entire system. User Right: Profile system performance. + SeSystemProfilePrivilege, + + /// Required to modify the system time. User Right: Change the system time. + SeSystemtimePrivilege, + + /// Required to gather profiling information for a single process. User Right: Profile single process. + SeProfileSingleProcessPrivilege, + + /// Required to increase the base priority of a process. User Right: Increase scheduling priority. + SeIncreaseBasePriorityPrivilege, + + /// Required to create a paging file. User Right: Create a pagefile. + SeCreatePagefilePrivilege, + + /// Required to create a permanent object. User Right: Create permanent shared objects. + SeCreatePermanentPrivilege, + + /// + /// Required to perform backup operations. This privilege causes the system to grant all read access control to any file, regardless + /// of the access control list (ACL) specified for the file. Any access request other than read is still evaluated with the ACL. + /// This privilege is required by the RegSaveKey and RegSaveKeyExfunctions. The following access rights are granted if this + /// privilege is held: READ_CONTROL, ACCESS_SYSTEM_SECURITY, FILE_GENERIC_READ, FILE_TRAVERSE. User Right: Back up files and directories. + /// + SeBackupPrivilege, + + /// + /// Required to perform restore operations. This privilege causes the system to grant all write access control to any file, + /// regardless of the ACL specified for the file. Any access request other than write is still evaluated with the ACL. Additionally, + /// this privilege enables you to set any valid user or group security identifier (SID) as the owner of a file. This privilege is + /// required by the RegLoadKey function. The following access rights are granted if this privilege is held: WRITE_DAC, WRITE_OWNER, + /// ACCESS_SYSTEM_SECURITY, FILE_GENERIC_WRITE, FILE_ADD_FILE, FILE_ADD_SUBDIRECTORY, DELETE. User Right: Restore files and directories. + /// + SeRestorePrivilege, + + /// Required to shut down a local system. User Right: Shut down the system. + SeShutdownPrivilege, + + /// Required to debug and adjust the memory of a process owned by another account. User Right: Debug programs. + SeDebugPrivilege, + + /// Required to generate audit-log entries. Give this privilege to secure servers. User Right: Generate security audits. + SeAuditPrivilege, + + /// + /// Required to modify the nonvolatile RAM of systems that use this type of memory to store configuration information. User Right: + /// Modify firmware environment values. + /// + SeSystemEnvironmentPrivilege, + + /// + /// Required to receive notifications of changes to files or directories. This privilege also causes the system to skip all + /// traversal access checks. It is enabled by default for all users. User Right: Bypass traverse checking. + /// + SeChangeNotifyPrivilege, + + /// Required to shut down a system by using a network request. User Right: Force shutdown from a remote system. + SeRemoteShutdownPrivilege, + + /// Required to undock a laptop. User Right: Remove computer from docking station. + SeUndockPrivilege, + + /// + /// Required for a domain controller to use the LDAP directory synchronization services. This privilege allows the holder to read + /// all objects and properties in the directory, regardless of the protection on the objects and properties. By default, it is + /// assigned to the Administrator and LocalSystem accounts on domain controllers. User Right: Synchronize directory service data. + /// + SeSyncAgentPrivilege, + + /// + /// Required to mark user and computer accounts as trusted for delegation. User Right: Enable computer and user accounts to be + /// trusted for delegation. + /// + SeEnableDelegationPrivilege, + + /// Required to enable volume management privileges. User Right: Manage the files on a volume. + SeManageVolumePrivilege, + + /// + /// Required to impersonate. User Right: Impersonate a client after authentication. Windows XP/2000: This privilege is not + /// supported. Note that this value is supported starting with Windows Server 2003, Windows XP with SP2, and Windows 2000 with SP4. + /// + SeImpersonatePrivilege, + + /// + /// Required to create named file mapping objects in the global namespace during Terminal Services sessions. This privilege is + /// enabled by default for administrators, services, and the local system account. User Right: Create global objects. Windows + /// XP/2000: This privilege is not supported. Note that this value is supported starting with Windows Server 2003, Windows XP with + /// SP2, and Windows 2000 with SP4. + /// + SeCreateGlobalPrivilege, + + /// Required to access Credential Manager as a trusted caller. User Right: Access Credential Manager as a trusted caller. + SeTrustedCredManAccessPrivilege, + + /// Required to modify the mandatory integrity level of an object. User Right: Modify an object label. + SeRelabelPrivilege, + + /// + /// Required to allocate more memory for applications that run in the context of users. User Right: Increase a process working set. + /// + SeIncreaseWorkingSetPrivilege, + + /// Required to adjust the time zone associated with the computer's internal clock. User Right: Change the time zone. + SeTimeZonePrivilege, + + /// Required to create a symbolic link. User Right: Create symbolic links. + SeCreateSymbolicLinkPrivilege + } + + /// + /// Defines the types of process security identifier (SID) that can be used by tasks. These changes are used to specify the type of + /// process SID in the IPrincipal2 interface. + /// + public enum TaskProcessTokenSidType + { + /// No changes will be made to the process token groups list. + None = 0, + + /// + /// A task SID that is derived from the task name will be added to the process token groups list, and the token default + /// discretionary access control list (DACL) will be modified to allow only the task SID and local system full control and the + /// account SID read control. + /// + Unrestricted = 1, + + /// A Task Scheduler will apply default settings to the task process. + Default = 2 + } + + /// Defines how a task is run. + [Flags] + public enum TaskRunFlags + { + /// The task is run with all flags ignored. + NoFlags = 0, + + /// The task is run as the user who is calling the Run method. + AsSelf = 1, + + /// The task is run regardless of constraints such as "do not run on batteries" or "run only if idle". + IgnoreConstraints = 2, + + /// The task is run using a terminal server session identifier. + UseSessionId = 4, + + /// The task is run using a security identifier. + UserSID = 8 + } + + /// Defines LUA elevation flags that specify with what privilege level the task will be run. + public enum TaskRunLevel + { + /// Tasks will be run with the least privileges. + [XmlEnum("LeastPrivilege")] + LUA, + + /// Tasks will be run with the highest privileges. + [XmlEnum("HighestAvailable")] + Highest + } + + /// + /// Defines what kind of Terminal Server session state change you can use to trigger a task to start. These changes are used to specify + /// the type of state change in the SessionStateChangeTrigger. + /// + public enum TaskSessionStateChangeType + { + /// + /// Terminal Server console connection state change. For example, when you connect to a user session on the local computer by + /// switching users on the computer. + /// + ConsoleConnect = 1, + + /// + /// Terminal Server console disconnection state change. For example, when you disconnect to a user session on the local computer by + /// switching users on the computer. + /// + ConsoleDisconnect = 2, + + /// + /// Terminal Server remote connection state change. For example, when a user connects to a user session by using the Remote Desktop + /// Connection program from a remote computer. + /// + RemoteConnect = 3, + + /// + /// Terminal Server remote disconnection state change. For example, when a user disconnects from a user session while using the + /// Remote Desktop Connection program from a remote computer. + /// + RemoteDisconnect = 4, + + /// + /// Terminal Server session locked state change. For example, this state change causes the task to run when the computer is locked. + /// + SessionLock = 7, + + /// + /// Terminal Server session unlocked state change. For example, this state change causes the task to run when the computer is unlocked. + /// + SessionUnlock = 8 + } + + /// Options for use when calling the SetSecurityDescriptorSddlForm methods. + [Flags] + public enum TaskSetSecurityOptions + { + /// No special handling. + None = 0, + + /// The Task Scheduler service is prevented from adding the allow access-control entry (ACE) for the context principal. + DontAddPrincipalAce = 0x10 + } + + /***** WAITING TO DETERMINE USE CASE ***** + /// Success and error codes that some methods will expose through . + public enum TaskResultCode + { + /// The task is ready to run at its next scheduled time. + TaskReady = 0x00041300, + /// The task is currently running. + TaskRunning = 0x00041301, + /// The task will not run at the scheduled times because it has been disabled. + TaskDisabled = 0x00041302, + /// The task has not yet run. + TaskHasNotRun = 0x00041303, + /// There are no more runs scheduled for this task. + TaskNoMoreRuns = 0x00041304, + /// One or more of the properties that are needed to run this task on a schedule have not been set. + TaskNotScheduled = 0x00041305, + /// The last run of the task was terminated by the user. + TaskTerminated = 0x00041306, + /// Either the task has no triggers or the existing triggers are disabled or not set. + TaskNoValidTriggers = 0x00041307, + /// Event triggers do not have set run times. + EventTrigger = 0x00041308, + /// A task's trigger is not found. + TriggerNotFound = 0x80041309, + /// One or more of the properties required to run this task have not been set. + TaskNotReady = 0x8004130A, + /// There is no running instance of the task. + TaskNotRunning = 0x8004130B, + /// The Task Scheduler service is not installed on this computer. + ServiceNotInstalled = 0x8004130C, + /// The task object could not be opened. + CannotOpenTask = 0x8004130D, + /// The object is either an invalid task object or is not a task object. + InvalidTask = 0x8004130E, + /// No account information could be found in the Task Scheduler security database for the task indicated. + AccountInformationNotSet = 0x8004130F, + /// Unable to establish existence of the account specified. + AccountNameNotFound = 0x80041310, + /// Corruption was detected in the Task Scheduler security database; the database has been reset. + AccountDbaseCorrupt = 0x80041311, + /// Task Scheduler security services are available only on Windows NT. + NoSecurityServices = 0x80041312, + /// The task object version is either unsupported or invalid. + UnknownObjectVersion = 0x80041313, + /// The task has been configured with an unsupported combination of account settings and run time options. + UnsupportedAccountOption = 0x80041314, + /// The Task Scheduler Service is not running. + ServiceNotRunning = 0x80041315, + /// The task XML contains an unexpected node. + UnexpectedNode = 0x80041316, + /// The task XML contains an element or attribute from an unexpected namespace. + Namespace = 0x80041317, + /// The task XML contains a value which is incorrectly formatted or out of range. + InvalidValue = 0x80041318, + /// The task XML is missing a required element or attribute. + MissingNode = 0x80041319, + /// The task XML is malformed. + MalformedXml = 0x8004131A, + /// The task is registered, but not all specified triggers will start the task. + SomeTriggersFailed = 0x0004131B, + /// The task is registered, but may fail to start. Batch logon privilege needs to be enabled for the task principal. + BatchLogonProblem = 0x0004131C, + /// The task XML contains too many nodes of the same type. + TooManyNodes = 0x8004131D, + /// The task cannot be started after the trigger end boundary. + PastEndBoundary = 0x8004131E, + /// An instance of this task is already running. + AlreadyRunning = 0x8004131F, + /// The task will not run because the user is not logged on. + UserNotLoggedOn = 0x80041320, + /// The task image is corrupt or has been tampered with. + InvalidTaskHash = 0x80041321, + /// The Task Scheduler service is not available. + ServiceNotAvailable = 0x80041322, + /// The Task Scheduler service is too busy to handle your request. Please try again later. + ServiceTooBusy = 0x80041323, + /// + /// The Task Scheduler service attempted to run the task, but the task did not run due to one of the constraints in the task definition. + /// + TaskAttempted = 0x80041324, + /// The Task Scheduler service has asked the task to run. + TaskQueued = 0x00041325, + /// The task is disabled. + TaskDisabled = 0x80041326, + /// The task has properties that are not compatible with earlier versions of Windows. + TaskNotV1Compatible = 0x80041327, + /// The task settings do not allow the task to start on demand. + StartOnDemand = 0x80041328, + } + */ + + /// Defines the different states that a registered task can be in. + public enum TaskState + { + /// The state of the task is unknown. + Unknown, + + /// + /// The task is registered but is disabled and no instances of the task are queued or running. The task cannot be run until it is enabled. + /// + Disabled, + + /// Instances of the task are queued. + Queued, + + /// The task is ready to be executed, but no instances are queued or running. + Ready, + + /// One or more instances of the task is running. + Running + } + + /// + /// Specifies how the Task Scheduler performs tasks when the computer is in an idle condition. For information about idle conditions, + /// see Task Idle Conditions. + /// + [PublicAPI] + public sealed class IdleSettings : IDisposable, INotifyPropertyChanged + { + private readonly IIdleSettings v2Settings; + private ITask v1Task; + + internal IdleSettings([NotNull] IIdleSettings iSettings) => v2Settings = iSettings; + + internal IdleSettings([NotNull] ITask iTask) => v1Task = iTask; + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Gets or sets a value that indicates the amount of time that the computer must be in an idle state before the task is run. + /// + /// + /// A value that indicates the amount of time that the computer must be in an idle state before the task is run. The minimum value + /// is one minute. If this value is TimeSpan.Zero, then the delay will be set to the default of 10 minutes. + /// + [DefaultValue(typeof(TimeSpan), "00:10:00")] + [XmlElement("Duration")] + public TimeSpan IdleDuration + { + get + { + if (v2Settings != null) + return Task.StringToTimeSpan(v2Settings.IdleDuration); + v1Task.GetIdleWait(out var _, out var deadMin); + return TimeSpan.FromMinutes(deadMin); + } + set + { + if (v2Settings != null) + { + if (value != TimeSpan.Zero && value < TimeSpan.FromMinutes(1)) + throw new ArgumentOutOfRangeException(nameof(IdleDuration)); + v2Settings.IdleDuration = Task.TimeSpanToString(value); + } + else + { + v1Task.SetIdleWait((ushort)WaitTimeout.TotalMinutes, (ushort)value.TotalMinutes); + } + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a Boolean value that indicates whether the task is restarted when the computer cycles into an idle condition more + /// than once. + /// + [DefaultValue(false)] + public bool RestartOnIdle + { + get => v2Settings?.RestartOnIdle ?? v1Task.HasFlags(TaskFlags.RestartOnIdleResume); + set + { + if (v2Settings != null) + v2Settings.RestartOnIdle = value; + else + v1Task.SetFlags(TaskFlags.RestartOnIdleResume, value); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a Boolean value that indicates that the Task Scheduler will terminate the task if the idle condition ends before + /// the task is completed. + /// + [DefaultValue(true)] + public bool StopOnIdleEnd + { + get => v2Settings?.StopOnIdleEnd ?? v1Task.HasFlags(TaskFlags.KillOnIdleEnd); + set + { + if (v2Settings != null) + v2Settings.StopOnIdleEnd = value; + else + v1Task.SetFlags(TaskFlags.KillOnIdleEnd, value); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a value that indicates the amount of time that the Task Scheduler will wait for an idle condition to occur. If no + /// value is specified for this property, then the Task Scheduler service will wait indefinitely for an idle condition to occur. + /// + /// + /// A value that indicates the amount of time that the Task Scheduler will wait for an idle condition to occur. The minimum time + /// allowed is 1 minute. If this value is TimeSpan.Zero, then the delay will be set to the default of 1 hour. + /// + [DefaultValue(typeof(TimeSpan), "01:00:00")] + public TimeSpan WaitTimeout + { + get + { + if (v2Settings != null) + return Task.StringToTimeSpan(v2Settings.WaitTimeout); + v1Task.GetIdleWait(out var idleMin, out var _); + return TimeSpan.FromMinutes(idleMin); + } + set + { + if (v2Settings != null) + { + if (value != TimeSpan.Zero && value < TimeSpan.FromMinutes(1)) + throw new ArgumentOutOfRangeException(nameof(WaitTimeout)); + v2Settings.WaitTimeout = Task.TimeSpanToString(value); + } + else + { + v1Task.SetIdleWait((ushort)value.TotalMinutes, (ushort)IdleDuration.TotalMinutes); + } + OnNotifyPropertyChanged(); + } + } + + /// Releases all resources used by this class. + public void Dispose() + { + if (v2Settings != null) + Marshal.ReleaseComObject(v2Settings); + v1Task = null; + } + + /// Returns a that represents this instance. + /// A that represents this instance. + public override string ToString() + { + if (v2Settings != null || v1Task != null) + return DebugHelper.GetDebugString(this); + return base.ToString(); + } + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + /// Specifies the task settings the Task scheduler will use to start task during Automatic maintenance. + [XmlType(IncludeInSchema = false)] + [PublicAPI] + public sealed class MaintenanceSettings : IDisposable, INotifyPropertyChanged + { + private readonly ITaskSettings3 iSettings; + private IMaintenanceSettings iMaintSettings; + + internal MaintenanceSettings([CanBeNull] ITaskSettings3 iSettings3) + { + iSettings = iSettings3; + if (iSettings3 != null) + iMaintSettings = iSettings.MaintenanceSettings; + } + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Gets or sets the amount of time after which the Task scheduler attempts to run the task during emergency Automatic maintenance, + /// if the task failed to complete during regular Automatic maintenance. The minimum value is one day. The value of the property should be greater than the value of the property. If the deadline is not + /// specified the task will not be started during emergency Automatic maintenance. + /// + /// Property set for a task on a Task Scheduler version prior to 2.2. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + public TimeSpan Deadline + { + get => iMaintSettings != null ? Task.StringToTimeSpan(iMaintSettings.Deadline) : TimeSpan.Zero; + set + { + if (iSettings != null) + { + if (iMaintSettings == null && value != TimeSpan.Zero) + iMaintSettings = iSettings.CreateMaintenanceSettings(); + if (iMaintSettings != null) + iMaintSettings.Deadline = Task.TimeSpanToString(value); + } + else + throw new NotSupportedPriorToException(TaskCompatibility.V2_2); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a value indicating whether the Task Scheduler must start the task during the Automatic maintenance in exclusive + /// mode. The exclusivity is guaranteed only between other maintenance tasks and doesn't grant any ordering priority of the task. If + /// exclusivity is not specified, the task is started in parallel with other maintenance tasks. + /// + /// Property set for a task on a Task Scheduler version prior to 2.2. + [DefaultValue(false)] + public bool Exclusive + { + get => iMaintSettings != null && iMaintSettings.Exclusive; + set + { + if (iSettings != null) + { + if (iMaintSettings == null && value) + iMaintSettings = iSettings.CreateMaintenanceSettings(); + if (iMaintSettings != null) + iMaintSettings.Exclusive = value; + } + else + throw new NotSupportedPriorToException(TaskCompatibility.V2_2); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets the amount of time the task needs to be started during Automatic maintenance. The minimum value is one minute. + /// + /// Property set for a task on a Task Scheduler version prior to 2.2. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + public TimeSpan Period + { + get => iMaintSettings != null ? Task.StringToTimeSpan(iMaintSettings.Period) : TimeSpan.Zero; + set + { + if (iSettings != null) + { + if (iMaintSettings == null && value != TimeSpan.Zero) + iMaintSettings = iSettings.CreateMaintenanceSettings(); + if (iMaintSettings != null) + iMaintSettings.Period = Task.TimeSpanToString(value); + } + else + throw new NotSupportedPriorToException(TaskCompatibility.V2_2); + OnNotifyPropertyChanged(); + } + } + + /// Releases all resources used by this class. + public void Dispose() + { + if (iMaintSettings != null) + Marshal.ReleaseComObject(iMaintSettings); + } + + /// Returns a that represents this instance. + /// A that represents this instance. + public override string ToString() => iMaintSettings != null ? DebugHelper.GetDebugString(this) : base.ToString(); + + internal bool IsSet() => iMaintSettings != null && (iMaintSettings.Period != null || iMaintSettings.Deadline != null || iMaintSettings.Exclusive); + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + /// Provides the settings that the Task Scheduler service uses to obtain a network profile. + [XmlType(IncludeInSchema = false)] + [PublicAPI] + public sealed class NetworkSettings : IDisposable, INotifyPropertyChanged + { + private readonly INetworkSettings v2Settings; + + internal NetworkSettings([CanBeNull] INetworkSettings iSettings) => v2Settings = iSettings; + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// Gets or sets a GUID value that identifies a network profile. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(Guid), "00000000-0000-0000-0000-000000000000")] + public Guid Id + { + get + { + string id = null; + if (v2Settings != null) + id = v2Settings.Id; + return string.IsNullOrEmpty(id) ? Guid.Empty : new Guid(id); + } + set + { + if (v2Settings != null) + v2Settings.Id = value == Guid.Empty ? null : value.ToString(); + else + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the name of a network profile. The name is used for display purposes. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(null)] + public string Name + { + get => v2Settings?.Name; + set + { + if (v2Settings != null) + v2Settings.Name = value; + else + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// Releases all resources used by this class. + public void Dispose() + { + if (v2Settings != null) + Marshal.ReleaseComObject(v2Settings); + } + + /// Returns a that represents this instance. + /// A that represents this instance. + public override string ToString() + { + if (v2Settings != null) + return DebugHelper.GetDebugString(this); + return base.ToString(); + } + + internal bool IsSet() => v2Settings != null && (!string.IsNullOrEmpty(v2Settings.Id) || !string.IsNullOrEmpty(v2Settings.Name)); + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + /// Provides the methods to get information from and control a running task. + [XmlType(IncludeInSchema = false)] + [PublicAPI] + public sealed class RunningTask : Task + { + private readonly IRunningTask v2RunningTask; + + internal RunningTask([NotNull] TaskService svc, [NotNull] IRegisteredTask iTask, [NotNull] IRunningTask iRunningTask) + : base(svc, iTask) => v2RunningTask = iRunningTask; + + internal RunningTask([NotNull] TaskService svc, [NotNull] ITask iTask) + : base(svc, iTask) + { + } + + /// Gets the process ID for the engine (process) which is running the task. + /// Not supported under Task Scheduler 1.0. + public uint EnginePID + { + get + { + if (v2RunningTask != null) + return v2RunningTask.EnginePID; + throw new NotV1SupportedException(); + } + } + + /// Gets the name of the current action that the running task is performing. + public string CurrentAction => v2RunningTask != null ? v2RunningTask.CurrentAction : v1Task.GetApplicationName(); + + /// Gets the GUID identifier for this instance of the task. + public Guid InstanceGuid => v2RunningTask != null ? new Guid(v2RunningTask.InstanceGuid) : Guid.Empty; + + /// Gets the operational state of the running task. + public override TaskState State => v2RunningTask?.State ?? base.State; + + /// Releases all resources used by this class. + public new void Dispose() + { + base.Dispose(); + if (v2RunningTask != null) Marshal.ReleaseComObject(v2RunningTask); + } + + /// Refreshes all of the local instance variables of the task. + /// Thrown if task is no longer running. + public void Refresh() + { + try { v2RunningTask?.Refresh(); } + catch (COMException ce) when ((uint)ce.ErrorCode == 0x8004130B) + { + throw new InvalidOperationException("The current task is no longer running.", ce); + } + } + } + + /// + /// Provides the methods that are used to run the task immediately, get any running instances of the task, get or set the credentials + /// that are used to register the task, and the properties that describe the task. + /// + [XmlType(IncludeInSchema = false)] + [PublicAPI] + public class Task : IDisposable, IComparable, IComparable, INotifyPropertyChanged + { + internal const AccessControlSections defaultAccessControlSections = AccessControlSections.Owner | AccessControlSections.Group | AccessControlSections.Access; + internal const SecurityInfos defaultSecurityInfosSections = SecurityInfos.Owner | SecurityInfos.Group | SecurityInfos.DiscretionaryAcl; + internal ITask v1Task; + + private static readonly int osLibMinorVer = GetOSLibraryMinorVersion(); + private static readonly DateTime v2InvalidDate = new DateTime(1899, 12, 30); + private readonly IRegisteredTask v2Task; + private TaskDefinition myTD; + + internal Task([NotNull] TaskService svc, [NotNull] ITask iTask) + { + TaskService = svc; + v1Task = iTask; + ReadOnly = false; + } + + internal Task([NotNull] TaskService svc, [NotNull] IRegisteredTask iTask, ITaskDefinition iDef = null) + { + TaskService = svc; + v2Task = iTask; + if (iDef != null) + myTD = new TaskDefinition(iDef); + ReadOnly = false; + } + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// Gets the definition of the task. + [NotNull] + public TaskDefinition Definition => myTD ??= v2Task != null ? new TaskDefinition(GetV2Definition(TaskService, v2Task, true)) : new TaskDefinition(v1Task, Name); + + /// Gets or sets a Boolean value that indicates if the registered task is enabled. + /// + /// As of version 1.8.1, under V1 systems (prior to Vista), this property will immediately update the Disabled state and re-save the + /// current task. If changes have been made to the , then those changes will be saved. + /// + public bool Enabled + { + get => v2Task?.Enabled ?? Definition.Settings.Enabled; + set + { + if (v2Task != null) + v2Task.Enabled = value; + else + { + Definition.Settings.Enabled = value; + Definition.V1Save(null); + } + OnNotifyPropertyChanged(); + } + } + + /// Gets an instance of the parent folder. + /// A object representing the parent folder of this task. + [NotNull] + public TaskFolder Folder + { + get + { + if (v2Task == null) + return TaskService.RootFolder; + + var path = v2Task.Path; + var parentPath = System.IO.Path.GetDirectoryName(path); + if (string.IsNullOrEmpty(parentPath) || parentPath == TaskFolder.rootString) + return TaskService.RootFolder; + return TaskService.GetFolder(parentPath) ?? throw new DirectoryNotFoundException(); + } + } + + /// Gets a value indicating whether this task instance is active. + /// true if this task instance is active; otherwise, false. + public bool IsActive + { + get + { + var now = DateTime.Now; + if (!Definition.Settings.Enabled) return false; + foreach (var trigger in Definition.Triggers) + { + if (!trigger.Enabled || now < trigger.StartBoundary || now > trigger.EndBoundary) continue; + if (!(trigger is ICalendarTrigger) || DateTime.MinValue != NextRunTime || trigger is TimeTrigger) + return true; + } + return false; + } + } + + /// Gets the time the registered task was last run. + /// Returns if there are no prior run times. + public DateTime LastRunTime + { + get + { + if (v2Task == null) return v1Task.GetMostRecentRunTime(); + var dt = v2Task.LastRunTime; + return dt == v2InvalidDate ? DateTime.MinValue : dt; + } + } + + /// Gets the results that were returned the last time the registered task was run. + /// The value returned is the last exit code of the last program run via an . + /// + /// + /// + /// + /// + public int LastTaskResult + { + get + { + if (v2Task != null) + return v2Task.LastTaskResult; + return (int)v1Task.GetExitCode(); + } + } + + /// Gets the time when the registered task is next scheduled to run. + /// Returns if there are no future run times. + /// + /// Potentially breaking change in release 1.8.2. For Task Scheduler 2.0, the return value prior to 1.8.2 would be Dec 30, 1899 if + /// there were no future run times. For 1.0, that value would have been DateTime.MinValue. In release 1.8.2 and later, all + /// versions will return DateTime.MinValue if there are no future run times. While this is different from the native 2.0 + /// library, it was deemed more appropriate to have consistency between the two libraries and with other .NET libraries. + /// + public DateTime NextRunTime + { + get + { + if (v2Task == null) return v1Task.GetNextRunTime(); + var ret = v2Task.NextRunTime; + if (ret != DateTime.MinValue && ret != v2InvalidDate) return ret == v2InvalidDate ? DateTime.MinValue : ret; + var nrts = GetRunTimes(DateTime.Now, DateTime.MaxValue, 1); + ret = nrts.Length > 0 ? nrts[0] : DateTime.MinValue; + return ret == v2InvalidDate ? DateTime.MinValue : ret; + } + } + + /// + /// Gets a value indicating whether this task is read only. Only available if is true. + /// + /// true if read only; otherwise, false. + public bool ReadOnly { get; internal set; } + + /// Gets or sets the security descriptor for the task. + /// The security descriptor. + [Obsolete("This property will be removed in deference to the GetAccessControl, GetSecurityDescriptorSddlForm, SetAccessControl and SetSecurityDescriptorSddlForm methods.")] + public GenericSecurityDescriptor SecurityDescriptor + { + get + { + var sddl = GetSecurityDescriptorSddlForm(); + return new RawSecurityDescriptor(sddl); + } + set => SetSecurityDescriptorSddlForm(value.GetSddlForm(defaultAccessControlSections)); + } + + /// Gets the operational state of the registered task. + public virtual TaskState State + { + get + { + if (v2Task != null) + return v2Task.State; + + V1Reactivate(); + if (!Enabled) + return TaskState.Disabled; + switch (v1Task.GetStatus()) + { + case TaskStatus.Ready: + case TaskStatus.NeverRun: + case TaskStatus.NoMoreRuns: + case TaskStatus.Terminated: + return TaskState.Ready; + + case TaskStatus.Running: + return TaskState.Running; + + case TaskStatus.Disabled: + return TaskState.Disabled; + // case TaskStatus.NotScheduled: case TaskStatus.NoTriggers: case TaskStatus.NoTriggerTime: + default: + return TaskState.Unknown; + } + } + } + + /// Gets or sets the that manages this task. + /// The task service. + public TaskService TaskService { get; } + + /// Gets the name of the registered task. + [NotNull] + public string Name => v2Task != null ? v2Task.Name : System.IO.Path.GetFileNameWithoutExtension(GetV1Path(v1Task)); + + /// Gets the number of times the registered task has missed a scheduled run. + /// Not supported under Task Scheduler 1.0. + public int NumberOfMissedRuns => v2Task?.NumberOfMissedRuns ?? throw new NotV1SupportedException(); + + /// Gets the path to where the registered task is stored. + [NotNull] + public string Path => v2Task != null ? v2Task.Path : "\\" + Name; + + /// Gets the XML-formatted registration information for the registered task. + public string Xml => v2Task != null ? v2Task.Xml : Definition.XmlText; + + /// + /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current + /// instance precedes, follows, or occurs in the same position in the sort order as the other object. + /// + /// An object to compare with this instance. + /// A value that indicates the relative order of the objects being compared. + public int CompareTo(Task other) => string.Compare(Path, other?.Path, StringComparison.InvariantCulture); + + /// Releases all resources used by this class. + public void Dispose() + { + if (v2Task != null) + Marshal.ReleaseComObject(v2Task); + v1Task = null; + } + + /// Exports the task to the specified file in XML. + /// Name of the output file. + public void Export([NotNull] string outputFileName) => File.WriteAllText(outputFileName, Xml, Encoding.Unicode); + + /// + /// Gets a object that encapsulates the specified type of access control list (ACL) entries for the task + /// described by the current object. + /// + /// A object that encapsulates the access control rules for the current task. + public TaskSecurity GetAccessControl() => GetAccessControl(defaultAccessControlSections); + + /// + /// Gets a object that encapsulates the specified type of access control list (ACL) entries for the task + /// described by the current object. + /// + /// + /// One of the values that specifies which group of access control + /// entries to retrieve. + /// + /// A object that encapsulates the access control rules for the current task. + public TaskSecurity GetAccessControl(AccessControlSections includeSections) => new TaskSecurity(this, includeSections); + + /// Gets all instances of the currently running registered task. + /// A with all instances of current task. + /// Not supported under Task Scheduler 1.0. + [NotNull, ItemNotNull] + public RunningTaskCollection GetInstances() => v2Task != null + ? new RunningTaskCollection(TaskService, v2Task.GetInstances(0)) + : throw new NotV1SupportedException(); + + /// + /// Gets the last registration time, looking first at the value and then looking for the + /// most recent registration event in the Event Log. + /// + /// of the last registration or if no value can be found. + public DateTime GetLastRegistrationTime() + { + var ret = Definition.RegistrationInfo.Date; + if (ret != DateTime.MinValue) return ret; + var log = new TaskEventLog(Path, new[] { (int)StandardTaskEventId.JobRegistered }, null, TaskService.TargetServer, TaskService.UserAccountDomain, TaskService.UserName, TaskService.UserPassword); + if (!log.Enabled) return ret; + foreach (var item in log) + { + if (item.TimeCreated.HasValue) + return item.TimeCreated.Value; + } + return ret; + } + + /// Gets the times that the registered task is scheduled to run during a specified time. + /// The starting time for the query. + /// The ending time for the query. + /// The requested number of runs. A value of 0 will return all times requested. + /// The scheduled times that the task will run. + [NotNull] + public DateTime[] GetRunTimes(DateTime start, DateTime end, uint count = 0) + { + const ushort TASK_MAX_RUN_TIMES = 1440; + + NativeMethods.SYSTEMTIME stStart = start; + NativeMethods.SYSTEMTIME stEnd = end; + var runTimes = IntPtr.Zero; + var ret = new DateTime[0]; + try + { + if (v2Task != null) + v2Task.GetRunTimes(ref stStart, ref stEnd, ref count, ref runTimes); + else + { + var count1 = count > 0 && count <= TASK_MAX_RUN_TIMES ? (ushort)count : TASK_MAX_RUN_TIMES; + v1Task.GetRunTimes(ref stStart, ref stEnd, ref count1, ref runTimes); + count = count1; + } + ret = InteropUtil.ToArray(runTimes, (int)count); + } + catch (Exception ex) + { + Debug.WriteLine($"Task.GetRunTimes failed: Error {ex}."); + } + finally + { + Marshal.FreeCoTaskMem(runTimes); + } + Debug.WriteLine($"Task.GetRunTimes ({(v2Task != null ? "V2" : "V1")}): Returned {count} items from {stStart} to {stEnd}."); + return ret; + } + + /// Gets the security descriptor for the task. Not available to Task Scheduler 1.0. + /// Section(s) of the security descriptor to return. + /// The security descriptor for the task. + /// Not supported under Task Scheduler 1.0. + public string GetSecurityDescriptorSddlForm(SecurityInfos includeSections = defaultSecurityInfosSections) => v2Task != null ? v2Task.GetSecurityDescriptor((int)includeSections) : throw new NotV1SupportedException(); + + /// + /// Updates the task with any changes made to the by calling from the currently registered folder using the currently + /// registered name. + /// + /// Thrown if task was previously registered with a password. + public void RegisterChanges() + { + if (Definition.Principal.RequiresPassword()) + throw new SecurityException("Tasks which have been registered previously with stored passwords must use the TaskFolder.RegisterTaskDefinition method for updates."); + if (v2Task != null) + TaskService.GetFolder(System.IO.Path.GetDirectoryName(Path)).RegisterTaskDefinition(Name, Definition, TaskCreation.Update, null, null, Definition.Principal.LogonType); + else + TaskService.RootFolder.RegisterTaskDefinition(Name, Definition); + } + + /// Runs the registered task immediately. + /// + /// + /// The parameters used as values in the task actions. A maximum of 32 parameters can be supplied. To run a task with no parameters, + /// call this method without any values (e.g. + /// Run() + /// ). + /// + /// + /// The string values that you specify are paired with names and stored as name-value pairs. If you specify a single string value, + /// then Arg0 will be the name assigned to the value. The value can be used in the task action where the $(Arg0) variable is used in + /// the action properties. + /// + /// + /// If you pass in values such as "0", "100", and "250" as an array of string values, then "0" will replace the $(Arg0) variables, + /// "100" will replace the $(Arg1) variables, and "250" will replace the $(Arg2) variables used in the action properties. + /// + /// + /// For more information and a list of action properties that can use $(Arg0), $(Arg1), ..., $(Arg32) variables in their values, see + /// Task Actions. + /// + /// + /// A instance that defines the new instance of the task. + /// + /// + /// + /// + /// + public RunningTask Run(params string[] parameters) + { + if (v2Task != null) + { + if (parameters.Length > 32) + throw new ArgumentOutOfRangeException(nameof(parameters), "A maximum of 32 values is allowed."); + if (TaskService.HighestSupportedVersion < TaskServiceVersion.V1_5 && parameters.Any(p => (p?.Length ?? 0) >= 260)) + throw new ArgumentOutOfRangeException(nameof(parameters), "On systems prior to Windows 10, all individual parameters must be less than 260 characters."); + var irt = v2Task.Run(parameters.Length == 0 ? null : parameters); + return irt != null ? new RunningTask(TaskService, v2Task, irt) : null; + } + + v1Task.Run(); + return new RunningTask(TaskService, v1Task); + } + + /// Runs the registered task immediately using specified flags and a session identifier. + /// Defines how the task is run. + /// + /// The terminal server session in which you want to start the task. + /// + /// If the value is not passed into the parameter, then the value + /// specified in this parameter is ignored.If the value is passed into the flags parameter + /// and the sessionID value is less than or equal to 0, then an invalid argument error will be returned. + /// + /// + /// If the value is passed into the parameter and the sessionID + /// value is a valid session ID greater than 0 and if no value is specified for the user parameter, then the Task Scheduler service + /// will try to start the task interactively as the user who is logged on to the specified session. + /// + /// + /// If the value is passed into the parameter and the sessionID + /// value is a valid session ID greater than 0 and if a user is specified in the user parameter, then the Task Scheduler service + /// will try to start the task interactively as the user who is specified in the user parameter. + /// + /// + /// The user for which the task runs. + /// + /// + /// The parameters used as values in the task actions. A maximum of 32 parameters can be supplied. To run a task with no parameters, + /// call this method without any values (e.g. + /// RunEx(0, 0, "MyUserName") + /// ). + /// + /// + /// The string values that you specify are paired with names and stored as name-value pairs. If you specify a single string value, + /// then Arg0 will be the name assigned to the value. The value can be used in the task action where the $(Arg0) variable is used in + /// the action properties. + /// + /// + /// If you pass in values such as "0", "100", and "250" as an array of string values, then "0" will replace the $(Arg0) variables, + /// "100" will replace the $(Arg1) variables, and "250" will replace the $(Arg2) variables used in the action properties. + /// + /// + /// For more information and a list of action properties that can use $(Arg0), $(Arg1), ..., $(Arg32) variables in their values, see + /// Task Actions. + /// + /// + /// A instance that defines the new instance of the task. + /// + /// + /// This method will return without error, but the task will not run if the AllowDemandStart property of ITaskSettings is set to + /// false for the task. + /// + /// If RunEx is invoked from a disabled task, it will return null and the task will not be run. + /// + /// Not supported under Task Scheduler 1.0. + /// + /// + /// + /// + /// + public RunningTask RunEx(TaskRunFlags flags, int sessionID, string user, params string[] parameters) + { + if (v2Task == null) throw new NotV1SupportedException(); + if (parameters == null || parameters.Any(s => s == null)) + throw new ArgumentNullException(nameof(parameters), "The array and none of the values passed as parameters may be `null`."); + if (parameters.Length > 32) + throw new ArgumentOutOfRangeException(nameof(parameters), "A maximum of 32 parameters can be supplied to RunEx."); + if (TaskService.HighestSupportedVersion < TaskServiceVersion.V1_5 && parameters.Any(p => (p?.Length ?? 0) >= 260)) + throw new ArgumentOutOfRangeException(nameof(parameters), "On systems prior to Windows 10, no individual parameter may be more than 260 characters."); + var irt = v2Task.RunEx(parameters.Length == 0 ? null : parameters, (int)flags, sessionID, user); + return irt != null ? new RunningTask(TaskService, v2Task, irt) : null; + } + + /// + /// Applies access control list (ACL) entries described by a object to the file described by the current + /// object. + /// + /// + /// A object that describes an access control list (ACL) entry to apply to the current task. + /// + /// + /// Give read access to all authenticated users for a task. + /// + /// + /// + /// + public void SetAccessControl([NotNull] TaskSecurity taskSecurity) => taskSecurity.Persist(this); + + /// Sets the security descriptor for the task. Not available to Task Scheduler 1.0. + /// The security descriptor for the task. + /// Flags that specify how to set the security descriptor. + /// Not supported under Task Scheduler 1.0. + public void SetSecurityDescriptorSddlForm([NotNull] string sddlForm, TaskSetSecurityOptions options = TaskSetSecurityOptions.None) + { + if (v2Task != null) + v2Task.SetSecurityDescriptor(sddlForm, (int)options); + else + throw new NotV1SupportedException(); + } + + /// Dynamically tries to load the assembly for the editor and displays it as editable for this task. + /// true if editor returns with OK response; false otherwise. + /// + /// The Microsoft.Win32.TaskSchedulerEditor.dll assembly must reside in the same directory as the Microsoft.Win32.TaskScheduler.dll + /// or in the GAC. + /// + public bool ShowEditor() + { + try + { + var t = ReflectionHelper.LoadType("Microsoft.Win32.TaskScheduler.TaskEditDialog", "Microsoft.Win32.TaskSchedulerEditor.dll"); + if (t != null) + return ReflectionHelper.InvokeMethod(t, new object[] { this, true, true }, "ShowDialog") == 1; + } + catch { } + return false; + } + + /// Shows the property page for the task (v1.0 only). + public void ShowPropertyPage() + { + if (v1Task != null) + v1Task.EditWorkItem(IntPtr.Zero, 0); + else + throw new NotV2SupportedException(); + } + + /// Stops the registered task immediately. + /// + /// The Stop method stops all instances of the task. + /// + /// System account users can stop a task, users with Administrator group privileges can stop a task, and if a user has rights to + /// execute and read a task, then the user can stop the task. A user can stop the task instances that are running under the same + /// credentials as the user account. In all other cases, the user is denied access to stop the task. + /// + /// + public void Stop() + { + if (v2Task != null) + v2Task.Stop(0); + else + v1Task.Terminate(); + } + + /// Returns a that represents this instance. + /// A that represents this instance. + public override string ToString() => Name; + + int IComparable.CompareTo(object other) => CompareTo(other as Task); + + internal static Task CreateTask(TaskService svc, IRegisteredTask iTask, bool throwError = false) + { + var iDef = GetV2Definition(svc, iTask, throwError); + if (iDef != null || !svc.AllowReadOnlyTasks) return new Task(svc, iTask, iDef); + iDef = GetV2StrippedDefinition(svc, iTask); + return new Task(svc, iTask, iDef) { ReadOnly = true }; + } + + internal static int GetOSLibraryMinorVersion() => TaskService.LibraryVersion.Minor; + + [NotNull] + internal static string GetV1Path(ITask v1Task) + { + var iFile = (IPersistFile)v1Task; + iFile.GetCurFile(out var fileName); + return fileName ?? string.Empty; + } + + /// + /// Gets the ITaskDefinition for a V2 task and prevents the errors that come when connecting remotely to a higher version of the + /// Task Scheduler. + /// + /// The local task service. + /// The task instance. + /// if set to true this method will throw an exception if unable to get the task definition. + /// A valid ITaskDefinition that should not throw errors on the local instance. + /// Unable to get a compatible task definition for this version of the library. + internal static ITaskDefinition GetV2Definition(TaskService svc, IRegisteredTask iTask, bool throwError = false) + { + var xmlVer = new Version(); + try + { + var dd = new DefDoc(iTask.Xml); + xmlVer = dd.Version; + if (xmlVer.Minor > osLibMinorVer) + { + var newMinor = xmlVer.Minor; + if (!dd.Contains("Volatile", "false", true) && + !dd.Contains("MaintenanceSettings")) + newMinor = 3; + if (!dd.Contains("UseUnifiedSchedulingEngine", "false", true) && + !dd.Contains("DisallowStartOnRemoteAppSession", "false", true) && + !dd.Contains("RequiredPrivileges") && + !dd.Contains("ProcessTokenSidType", "Default", true)) + newMinor = 2; + if (!dd.Contains("DisplayName") && + !dd.Contains("GroupId") && + !dd.Contains("RunLevel", "LeastPrivilege", true) && + !dd.Contains("SecurityDescriptor") && + !dd.Contains("Source") && + !dd.Contains("URI") && + !dd.Contains("AllowStartOnDemand", "true", true) && + !dd.Contains("AllowHardTerminate", "true", true) && + !dd.Contains("MultipleInstancesPolicy", "IgnoreNew", true) && + !dd.Contains("NetworkSettings") && + !dd.Contains("StartWhenAvailable", "false", true) && + !dd.Contains("SendEmail") && + !dd.Contains("ShowMessage") && + !dd.Contains("ComHandler") && + !dd.Contains("EventTrigger") && + !dd.Contains("SessionStateChangeTrigger") && + !dd.Contains("RegistrationTrigger") && + !dd.Contains("RestartOnFailure") && + !dd.Contains("LogonType", "None", true)) + newMinor = 1; + + if (newMinor > osLibMinorVer && throwError) + throw new InvalidOperationException($"The current version of the native library (1.{osLibMinorVer}) does not support the original or minimum version of the \"{iTask.Name}\" task ({xmlVer}/1.{newMinor}). This is likely due to attempting to read the remote tasks of a newer version of Windows from a down-level client."); + + if (newMinor != xmlVer.Minor) + { + dd.Version = new Version(1, newMinor); + var def = svc.v2TaskService.NewTask(0); + def.XmlText = dd.Xml; + return def; + } + } + return iTask.Definition; + } + catch (COMException comEx) + { + if (throwError) + { + if ((uint)comEx.ErrorCode == 0x80041318 && xmlVer.Minor != osLibMinorVer) // Incorrect XML value + throw new InvalidOperationException($"The current version of the native library (1.{osLibMinorVer}) does not support the version of the \"{iTask.Name}\" task ({xmlVer})"); + throw; + } + } + catch + { + if (throwError) + throw; + } + return null; + } + + internal static ITaskDefinition GetV2StrippedDefinition(TaskService svc, IRegisteredTask iTask) + { + try + { + var dd = new DefDoc(iTask.Xml); + var xmlVer = dd.Version; + if (xmlVer.Minor > osLibMinorVer) + { + if (osLibMinorVer < 4) + { + dd.RemoveTag("Volatile"); + dd.RemoveTag("MaintenanceSettings"); + } + if (osLibMinorVer < 3) + { + dd.RemoveTag("UseUnifiedSchedulingEngine"); + dd.RemoveTag("DisallowStartOnRemoteAppSession"); + dd.RemoveTag("RequiredPrivileges"); + dd.RemoveTag("ProcessTokenSidType"); + } + if (osLibMinorVer < 2) + { + dd.RemoveTag("DisplayName"); + dd.RemoveTag("GroupId"); + dd.RemoveTag("RunLevel"); + dd.RemoveTag("SecurityDescriptor"); + dd.RemoveTag("Source"); + dd.RemoveTag("URI"); + dd.RemoveTag("AllowStartOnDemand"); + dd.RemoveTag("AllowHardTerminate"); + dd.RemoveTag("MultipleInstancesPolicy"); + dd.RemoveTag("NetworkSettings"); + dd.RemoveTag("StartWhenAvailable"); + dd.RemoveTag("SendEmail"); + dd.RemoveTag("ShowMessage"); + dd.RemoveTag("ComHandler"); + dd.RemoveTag("EventTrigger"); + dd.RemoveTag("SessionStateChangeTrigger"); + dd.RemoveTag("RegistrationTrigger"); + dd.RemoveTag("RestartOnFailure"); + dd.RemoveTag("LogonType"); + } + dd.RemoveTag("WnfStateChangeTrigger"); // Remove custom triggers that can't be sent to Xml + dd.Version = new Version(1, osLibMinorVer); + var def = svc.v2TaskService.NewTask(0); +#if DEBUG + var path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), + $"TS_Stripped_Def_{xmlVer.Minor}-{osLibMinorVer}_{iTask.Name}.xml"); + File.WriteAllText(path, dd.Xml, Encoding.Unicode); +#endif + def.XmlText = dd.Xml; + return def; + } + } + catch (Exception ex) + { + Debug.WriteLine($"Error in GetV2StrippedDefinition: {ex}"); +#if DEBUG + throw; +#endif + } + return iTask.Definition; + } + + internal static TimeSpan StringToTimeSpan(string input) + { + if (!string.IsNullOrEmpty(input)) + try { return XmlConvert.ToTimeSpan(input); } catch { } + return TimeSpan.Zero; + } + + internal static string TimeSpanToString(TimeSpan span) + { + if (span != TimeSpan.Zero) + try { return XmlConvert.ToString(span); } catch { } + return null; + } + + internal void V1Reactivate() + { + var iTask = TaskService.GetTask(TaskService.v1TaskScheduler, Name); + if (iTask != null) + v1Task = iTask; + } + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + protected void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + + private class DefDoc + { + private readonly XmlDocument doc; + + public DefDoc(string xml) + { + doc = new XmlDocument(); + doc.LoadXml(xml); + } + + public Version Version + { + get + { + try + { + return new Version(doc["Task"].Attributes["version"].Value); + } + catch + { + throw new InvalidOperationException("Task definition does not contain a version."); + } + } + set + { + var task = doc["Task"]; + if (task != null) task.Attributes["version"].Value = value.ToString(2); + } + } + + public string Xml => doc.OuterXml; + + public bool Contains(string tag, string defaultVal = null, bool removeIfFound = false) + { + var nl = doc.GetElementsByTagName(tag); + while (nl.Count > 0) + { + var e = nl[0]; + if (e.InnerText != defaultVal || !removeIfFound || e.ParentNode == null) + return true; + e.ParentNode?.RemoveChild(e); + nl = doc.GetElementsByTagName(tag); + } + return false; + } + + public void RemoveTag(string tag) + { + var nl = doc.GetElementsByTagName(tag); + while (nl.Count > 0) + { + var e = nl[0]; + e.ParentNode?.RemoveChild(e); + nl = doc.GetElementsByTagName(tag); + } + } + } + } + + /// Contains information about the compatibility of the current configuration with a specified version. + [PublicAPI] + public class TaskCompatibilityEntry + { + internal TaskCompatibilityEntry(TaskCompatibility comp, string prop, string reason) + { + CompatibilityLevel = comp; + Property = prop; + Reason = reason; + } + + /// Gets the compatibility level. + /// The compatibility level. + public TaskCompatibility CompatibilityLevel { get; } + + /// Gets the property name with the incompatibility. + /// The property name. + public string Property { get; } + + /// Gets the reason for the incompatibility. + /// The reason. + public string Reason { get; } + } + + /// Defines all the components of a task, such as the task settings, triggers, actions, and registration information. + [XmlRoot("Task", Namespace = tns, IsNullable = false)] + [XmlSchemaProvider("GetV1SchemaFile")] + [PublicAPI, Serializable] + public sealed class TaskDefinition : IDisposable, IXmlSerializable, INotifyPropertyChanged + { + internal const string tns = "http://schemas.microsoft.com/windows/2004/02/mit/task"; + + internal string v1Name = string.Empty; + internal ITask v1Task; + internal ITaskDefinition v2Def; + + private ActionCollection actions; + private TaskPrincipal principal; + private TaskRegistrationInfo regInfo; + private TaskSettings settings; + private TriggerCollection triggers; + + internal TaskDefinition([NotNull] ITask iTask, string name) + { + v1Task = iTask; + v1Name = name; + } + + internal TaskDefinition([NotNull] ITaskDefinition iDef) => v2Def = iDef; + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// Gets a collection of actions that are performed by the task. + [XmlArrayItem(ElementName = "Exec", IsNullable = true, Type = typeof(ExecAction))] + [XmlArrayItem(ElementName = "ShowMessage", IsNullable = true, Type = typeof(ShowMessageAction))] + [XmlArrayItem(ElementName = "ComHandler", IsNullable = true, Type = typeof(ComHandlerAction))] + [XmlArrayItem(ElementName = "SendEmail", IsNullable = true, Type = typeof(EmailAction))] + [XmlArray] + [NotNull, ItemNotNull] + public ActionCollection Actions => actions ??= v2Def != null ? new ActionCollection(v2Def) : new ActionCollection(v1Task); + + /// + /// Gets or sets the data that is associated with the task. This data is ignored by the Task Scheduler service, but is used by + /// third-parties who wish to extend the task format. + /// + /// + /// For V1 tasks, this library makes special use of the SetWorkItemData and GetWorkItemData methods and does not expose that data + /// stream directly. Instead, it uses that data stream to hold a dictionary of properties that are not supported under V1, but can + /// have values under V2. An example of this is the value which is stored in the data stream. + /// + /// The library does not provide direct access to the V1 work item data. If using V2 properties with a V1 task, programmatic access + /// to the task using the native API will retrieve unreadable results from GetWorkItemData and will eliminate those property values + /// if SetWorkItemData is used. + /// + /// + [CanBeNull] + public string Data + { + get => v2Def != null ? v2Def.Data : v1Task.GetDataItem(nameof(Data)); + set + { + if (v2Def != null) + v2Def.Data = value; + else + v1Task.SetDataItem(nameof(Data), value); + OnNotifyPropertyChanged(); + } + } + + /// Gets the lowest supported version that supports the settings for this . + [XmlIgnore] + public TaskCompatibility LowestSupportedVersion => GetLowestSupportedVersion(); + + /// Gets a collection of triggers that are used to start a task. + [XmlArrayItem(ElementName = "BootTrigger", IsNullable = true, Type = typeof(BootTrigger))] + [XmlArrayItem(ElementName = "CalendarTrigger", IsNullable = true, Type = typeof(CalendarTrigger))] + [XmlArrayItem(ElementName = "IdleTrigger", IsNullable = true, Type = typeof(IdleTrigger))] + [XmlArrayItem(ElementName = "LogonTrigger", IsNullable = true, Type = typeof(LogonTrigger))] + [XmlArrayItem(ElementName = "TimeTrigger", IsNullable = true, Type = typeof(TimeTrigger))] + [XmlArray] + [NotNull, ItemNotNull] + public TriggerCollection Triggers => triggers ??= v2Def != null ? new TriggerCollection(v2Def) : new TriggerCollection(v1Task); + + /// Gets or sets the XML-formatted definition of the task. + [XmlIgnore] + public string XmlText + { + get => v2Def != null ? v2Def.XmlText : XmlSerializationHelper.WriteObjectToXmlText(this); + set + { + if (v2Def != null) + v2Def.XmlText = value; + else + XmlSerializationHelper.ReadObjectFromXmlText(value, this); + OnNotifyPropertyChanged(); + } + } + + /// Gets the principal for the task that provides the security credentials for the task. + [NotNull] + public TaskPrincipal Principal => principal ??= v2Def != null ? new TaskPrincipal(v2Def.Principal, () => XmlText) : new TaskPrincipal(v1Task); + + /// + /// Gets a class instance of registration information that is used to describe a task, such as the description of the task, the + /// author of the task, and the date the task is registered. + /// + public TaskRegistrationInfo RegistrationInfo => regInfo ??= v2Def != null ? new TaskRegistrationInfo(v2Def.RegistrationInfo) : new TaskRegistrationInfo(v1Task); + + /// Gets the settings that define how the Task Scheduler service performs the task. + [NotNull] + public TaskSettings Settings => settings ??= v2Def != null ? new TaskSettings(v2Def.Settings) : new TaskSettings(v1Task); + + /// Gets the XML Schema file for V1 tasks. + /// The for V1 tasks. + /// An object containing the XML Schema for V1 tasks. + public static XmlSchemaComplexType GetV1SchemaFile([NotNull] XmlSchemaSet xs) + { + XmlSchema schema; + using (var xsdFile = Assembly.GetAssembly(typeof(TaskDefinition)).GetManifestResourceStream("Microsoft.Win32.TaskScheduler.V1.TaskSchedulerV1Schema.xsd")) + { + var schemaSerializer = new XmlSerializer(typeof(XmlSchema)); + schema = (XmlSchema)schemaSerializer.Deserialize(XmlReader.Create(xsdFile)); + xs.Add(schema); + } + + // target namespace + var name = new XmlQualifiedName("taskType", tns); + var productType = (XmlSchemaComplexType)schema.SchemaTypes[name]; + + return productType; + } + + /// + /// Determines whether this can use the Unified Scheduling Engine or if it contains unsupported properties. + /// + /// + /// if set to true throws an with details about unsupported properties in the Data + /// property of the exception. + /// + /// + /// true if this can use the Unified Scheduling Engine; otherwise, false. + public bool CanUseUnifiedSchedulingEngine(bool throwExceptionWithDetails = false, Version taskSchedulerVersion = null) + { + var tsVer = taskSchedulerVersion ?? TaskService.LibraryVersion; + if (tsVer < TaskServiceVersion.V1_3) return false; + var ex = new InvalidOperationException { HelpLink = "http://msdn.microsoft.com/en-us/library/windows/desktop/aa384138(v=vs.85).aspx" }; + var bad = false; + /*if (Principal.LogonType == TaskLogonType.InteractiveTokenOrPassword) + { + bad = true; + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, "Principal.LogonType", "== TaskLogonType.InteractiveTokenOrPassword"); + } + if (Settings.MultipleInstances == TaskInstancesPolicy.StopExisting) + { + bad = true; + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, "Settings.MultipleInstances", "== TaskInstancesPolicy.StopExisting"); + }*/ + if (Settings.NetworkSettings.Id != Guid.Empty && tsVer >= TaskServiceVersion.V1_5) + { + bad = true; + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, "Settings.NetworkSettings.Id", "!= Guid.Empty"); + } + /*if (!Settings.AllowHardTerminate) + { + bad = true; + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, "Settings.AllowHardTerminate", "== false"); + }*/ + if (!Actions.PowerShellConversion.IsFlagSet(PowerShellActionPlatformOption.Version2)) + for (var i = 0; i < Actions.Count; i++) + { + var a = Actions[i]; + switch (a) + { + case EmailAction _: + bad = true; + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, $"Actions[{i}]", "== typeof(EmailAction)"); + break; + + case ShowMessageAction _: + bad = true; + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, $"Actions[{i}]", "== typeof(ShowMessageAction)"); + break; + } + } + if (tsVer == TaskServiceVersion.V1_3) + for (var i = 0; i < Triggers.Count; i++) + { + Trigger t; + try { t = Triggers[i]; } + catch + { + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, $"Triggers[{i}]", "is irretrievable."); + continue; + } + switch (t) + { + case MonthlyTrigger _: + bad = true; + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, $"Triggers[{i}]", "== typeof(MonthlyTrigger)"); + break; + + case MonthlyDOWTrigger _: + bad = true; + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, $"Triggers[{i}]", "== typeof(MonthlyDOWTrigger)"); + break; + /*case ICalendarTrigger _ when t.Repetition.IsSet(): + bad = true; + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, $"Triggers[{i}].Repetition", ""); + break; + + case EventTrigger _ when ((EventTrigger)t).ValueQueries.Count > 0: + bad = true; + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, $"Triggers[{i}].ValueQueries.Count", "!= 0"); + break;*/ + } + if (t.ExecutionTimeLimit != TimeSpan.Zero) + { + bad = true; + if (!throwExceptionWithDetails) return false; + TryAdd(ex.Data, $"Triggers[{i}].ExecutionTimeLimit", "!= TimeSpan.Zero"); + } + } + if (bad && throwExceptionWithDetails) + throw ex; + return !bad; + } + + /// Releases all resources used by this class. + public void Dispose() + { + regInfo = null; + triggers = null; + settings = null; + principal = null; + actions = null; + if (v2Def != null) Marshal.ReleaseComObject(v2Def); + v1Task = null; + } + + /// Validates the current . + /// + /// if set to true throw a with details about invalid properties. + /// + /// true if current is valid; false if not. + public bool Validate(bool throwException = false) + { + var ex = new InvalidOperationException(); + if (Settings.UseUnifiedSchedulingEngine) + { + try { CanUseUnifiedSchedulingEngine(throwException); } + catch (InvalidOperationException iox) + { + foreach (DictionaryEntry kvp in iox.Data) + TryAdd(ex.Data, (kvp.Key as ICloneable)?.Clone() ?? kvp.Key, (kvp.Value as ICloneable)?.Clone() ?? kvp.Value); + } + } + + if (Settings.Compatibility >= TaskCompatibility.V2_2) + { + var PT1D = TimeSpan.FromDays(1); + if (Settings.MaintenanceSettings.IsSet() && (Settings.MaintenanceSettings.Period < PT1D || Settings.MaintenanceSettings.Deadline < PT1D || Settings.MaintenanceSettings.Deadline <= Settings.MaintenanceSettings.Period)) + TryAdd(ex.Data, "Settings.MaintenanceSettings", "Period or Deadline must be at least 1 day and Deadline must be greater than Period."); + } + + var list = new List(); + if (GetLowestSupportedVersion(list) > Settings.Compatibility) + foreach (var item in list) + TryAdd(ex.Data, item.Property, item.Reason); + + var startWhenAvailable = Settings.StartWhenAvailable; + var delOldTask = Settings.DeleteExpiredTaskAfter != TimeSpan.Zero; + var v1 = Settings.Compatibility < TaskCompatibility.V2; + var hasEndBound = false; + for (var i = 0; i < Triggers.Count; i++) + { + Trigger trigger; + try { trigger = Triggers[i]; } + catch + { + TryAdd(ex.Data, $"Triggers[{i}]", "is irretrievable."); + continue; + } + if (startWhenAvailable && trigger.Repetition.Duration != TimeSpan.Zero && trigger.EndBoundary == DateTime.MaxValue) + TryAdd(ex.Data, "Settings.StartWhenAvailable", "== true requires time-based tasks with an end boundary or time-based tasks that are set to repeat infinitely."); + if (v1 && trigger.Repetition.Interval != TimeSpan.Zero && trigger.Repetition.Interval >= trigger.Repetition.Duration) + TryAdd(ex.Data, "Trigger.Repetition.Interval", ">= Trigger.Repetition.Duration under Task Scheduler 1.0."); + if (trigger.EndBoundary <= trigger.StartBoundary) + TryAdd(ex.Data, "Trigger.StartBoundary", ">= Trigger.EndBoundary is not allowed."); + if (delOldTask && trigger.EndBoundary != DateTime.MaxValue) + hasEndBound = true; + } + if (delOldTask && !hasEndBound) + TryAdd(ex.Data, "Settings.DeleteExpiredTaskAfter", "!= TimeSpan.Zero requires at least one trigger with an end boundary."); + + if (throwException && ex.Data.Count > 0) + throw ex; + return ex.Data.Count == 0; + } + + /// Implements the operator + for triggers on a definition, effectively adding the trigger to the definition. + /// The definition to which the trigger is to be added. + /// The trigger to add. + /// The definition with the added trigger. + public static TaskDefinition operator +(TaskDefinition definition, Trigger trigger) + { + definition.Triggers.Add(trigger); + return definition; + } + + /// Implements the operator + for actions on a definition, effectively adding the action to the definition. + /// The definition to which the action is to be added. + /// The action to add. + /// The definition with the added action. + public static TaskDefinition operator +(TaskDefinition definition, Action action) + { + definition.Actions.Add(action); + return definition; + } + + XmlSchema IXmlSerializable.GetSchema() => null; + + void IXmlSerializable.ReadXml(XmlReader reader) + { + reader.ReadStartElement(XmlSerializationHelper.GetElementName(this), tns); + XmlSerializationHelper.ReadObjectProperties(reader, this); + reader.ReadEndElement(); + } + + void IXmlSerializable.WriteXml(XmlWriter writer) => + // TODO:FIX writer.WriteAttributeString("version", "1.1"); + XmlSerializationHelper.WriteObjectProperties(writer, this); + + internal static Dictionary GetV1TaskDataDictionary(ITask v1Task) + { + Dictionary dict; + var o = GetV1TaskData(v1Task); + if (o is string) + dict = new Dictionary(2) { { "Data", o.ToString() }, { "Documentation", o.ToString() } }; + else + dict = o as Dictionary; + return dict ?? new Dictionary(); + } + + internal static void SetV1TaskData(ITask v1Task, object value) + { + if (value == null) + v1Task.SetWorkItemData(0, null); + else + { + var b = new BinaryFormatter(); + var stream = new MemoryStream(); + b.Serialize(stream, value); + v1Task.SetWorkItemData((ushort)stream.Length, stream.ToArray()); + } + } + + internal void V1Save(string newName) + { + if (v1Task != null) + { + Triggers.Bind(); + + var iFile = (IPersistFile)v1Task; + if (string.IsNullOrEmpty(newName) || newName == v1Name) + { + try + { + iFile.Save(null, false); + iFile = null; + return; + } + catch { } + } + + iFile.GetCurFile(out var path); + File.Delete(path); + path = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + newName + Path.GetExtension(path); + File.Delete(path); + iFile.Save(path, true); + } + } + + private static object GetV1TaskData(ITask v1Task) + { + var Data = IntPtr.Zero; + try + { + v1Task.GetWorkItemData(out var DataLen, out Data); + if (DataLen == 0) + return null; + var bytes = new byte[DataLen]; + Marshal.Copy(Data, bytes, 0, DataLen); + var stream = new MemoryStream(bytes, false); + var b = new BinaryFormatter(); + return b.Deserialize(stream); + } + catch { } + finally + { + if (Data != IntPtr.Zero) + Marshal.FreeCoTaskMem(Data); + } + return null; + } + + private static void TryAdd(IDictionary d, object k, object v) + { + if (!d.Contains(k)) + d.Add(k, v); + } + + /// Gets the lowest supported version. + /// The output list. + /// + private TaskCompatibility GetLowestSupportedVersion(IList outputList = null) + { + var res = TaskCompatibility.V1; + var list = new List(); + + //if (Principal.DisplayName != null) + // { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Principal.DisplayName", "cannot have a value.")); } + if (Principal.GroupId != null) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Principal.GroupId", "cannot have a value.")); } + //this.Principal.Id != null || + if (Principal.LogonType == TaskLogonType.Group || Principal.LogonType == TaskLogonType.None || Principal.LogonType == TaskLogonType.S4U) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Principal.LogonType", "cannot be Group, None or S4U.")); } + if (Principal.RunLevel == TaskRunLevel.Highest) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Principal.RunLevel", "cannot be set to Highest.")); } + if (RegistrationInfo.SecurityDescriptorSddlForm != null) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "RegistrationInfo.SecurityDescriptorSddlForm", "cannot have a value.")); } + //if (RegistrationInfo.Source != null) + // { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "RegistrationInfo.Source", "cannot have a value.")); } + //if (RegistrationInfo.URI != null) + // { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "RegistrationInfo.URI", "cannot have a value.")); } + //if (RegistrationInfo.Version != new Version(1, 0)) + // { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "RegistrationInfo.Version", "cannot be set or equal 1.0.")); } + if (Settings.AllowDemandStart == false) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Settings.AllowDemandStart", "must be true.")); } + if (Settings.AllowHardTerminate == false) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Settings.AllowHardTerminate", "must be true.")); } + if (Settings.MultipleInstances != TaskInstancesPolicy.IgnoreNew) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Settings.MultipleInstances", "must be set to IgnoreNew.")); } + if (Settings.NetworkSettings.IsSet()) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Settings.NetworkSetting", "cannot have a value.")); } + if (Settings.RestartCount != 0) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Settings.RestartCount", "must be 0.")); } + if (Settings.RestartInterval != TimeSpan.Zero) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Settings.RestartInterval", "must be 0 (TimeSpan.Zero).")); } + if (Settings.StartWhenAvailable) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Settings.StartWhenAvailable", "must be false.")); } + + if ((Actions.PowerShellConversion & PowerShellActionPlatformOption.Version1) != PowerShellActionPlatformOption.Version1 && (Actions.ContainsType(typeof(EmailAction)) || Actions.ContainsType(typeof(ShowMessageAction)) || Actions.ContainsType(typeof(ComHandlerAction)))) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Actions", "may only contain ExecAction types unless Actions.PowerShellConversion includes Version1.")); } + if ((Actions.PowerShellConversion & PowerShellActionPlatformOption.Version2) != PowerShellActionPlatformOption.Version2 && (Actions.ContainsType(typeof(EmailAction)) || Actions.ContainsType(typeof(ShowMessageAction)))) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2_1, "Actions", "may only contain ExecAction and ComHanlderAction types unless Actions.PowerShellConversion includes Version2.")); } + + try + { + if (null != Triggers.Find(t => t is ITriggerDelay && ((ITriggerDelay)t).Delay != TimeSpan.Zero)) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Triggers", "cannot contain delays.")); } + if (null != Triggers.Find(t => t.ExecutionTimeLimit != TimeSpan.Zero || t.Id != null)) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Triggers", "cannot contain an ExecutionTimeLimit or Id.")); } + if (null != Triggers.Find(t => (t as LogonTrigger)?.UserId != null)) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Triggers", "cannot contain a LogonTrigger with a UserId.")); } + if (null != Triggers.Find(t => t is MonthlyDOWTrigger && ((MonthlyDOWTrigger)t).RunOnLastWeekOfMonth || t is MonthlyDOWTrigger && (((MonthlyDOWTrigger)t).WeeksOfMonth & (((MonthlyDOWTrigger)t).WeeksOfMonth - 1)) != 0)) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Triggers", "cannot contain a MonthlyDOWTrigger with RunOnLastWeekOfMonth set or multiple WeeksOfMonth.")); } + if (null != Triggers.Find(t => t is MonthlyTrigger && ((MonthlyTrigger)t).RunOnLastDayOfMonth)) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Triggers", "cannot contain a MonthlyTrigger with RunOnLastDayOfMonth set.")); } + if (Triggers.ContainsType(typeof(EventTrigger)) || Triggers.ContainsType(typeof(SessionStateChangeTrigger)) || Triggers.ContainsType(typeof(RegistrationTrigger))) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Triggers", "cannot contain EventTrigger, SessionStateChangeTrigger, or RegistrationTrigger types.")); } + } + catch + { + list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Triggers", "cannot contain Custom triggers.")); + } + + if (Principal.ProcessTokenSidType != TaskProcessTokenSidType.Default) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2_1, "Principal.ProcessTokenSidType", "must be Default.")); } + if (Principal.RequiredPrivileges.Count > 0) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2_1, "Principal.RequiredPrivileges", "must be empty.")); } + if (Settings.DisallowStartOnRemoteAppSession) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2_1, "Settings.DisallowStartOnRemoteAppSession", "must be false.")); } + if (Settings.UseUnifiedSchedulingEngine) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2_1, "Settings.UseUnifiedSchedulingEngine", "must be false.")); } + + if (Settings.MaintenanceSettings.IsSet()) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2_2, "this.Settings.MaintenanceSettings", "must have no values set.")); } + if (Settings.Volatile) + { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2_2, " this.Settings.Volatile", "must be false.")); } + + foreach (var item in list) + { + if (res < item.CompatibilityLevel) res = item.CompatibilityLevel; + outputList?.Add(item); + } + return res; + } + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + /// + /// Provides the security credentials for a principal. These security credentials define the security context for the tasks that are + /// associated with the principal. + /// + [XmlRoot("Principals", Namespace = TaskDefinition.tns, IsNullable = true)] + [PublicAPI] + public sealed class TaskPrincipal : IDisposable, IXmlSerializable, INotifyPropertyChanged + { + private const string localSystemAcct = "SYSTEM"; + private readonly IPrincipal v2Principal; + private readonly IPrincipal2 v2Principal2; + private readonly Func xmlFunc; + private TaskPrincipalPrivileges reqPriv; + private string v1CachedAcctInfo; + private ITask v1Task; + + internal TaskPrincipal([NotNull] IPrincipal iPrincipal, Func defXml) + { + xmlFunc = defXml; + v2Principal = iPrincipal; + try { if (Environment.OSVersion.Version >= new Version(6, 1)) v2Principal2 = (IPrincipal2)v2Principal; } + catch { } + } + + internal TaskPrincipal([NotNull] ITask iTask) => v1Task = iTask; + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Gets the account associated with this principal. This value is pulled from the TaskDefinition's XMLText property if set. + /// + /// The account. + [DefaultValue(null), Browsable(false)] + public string Account + { + get + { + try + { + var xml = xmlFunc?.Invoke(); + if (!string.IsNullOrEmpty(xml)) + { + var doc = new XmlDocument(); + doc.LoadXml(xml); + var pn = doc.DocumentElement?["Principals"]?["Principal"]; + if (pn != null) + { + var un = pn["UserId"] ?? pn["GroupId"]; + if (un != null) + try { return User.FromSidString(un.InnerText).Name; } + catch + { + try { return new User(un.InnerText).Name; } + catch { } + } + } + } + return new User(ToString()).Name; + } + catch + { + return null; + } + } + } + + /// Gets or sets the name of the principal that is displayed in the Task Scheduler UI. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(null)] + public string DisplayName + { + get => v2Principal != null ? v2Principal.DisplayName : v1Task.GetDataItem("PrincipalDisplayName"); + set + { + if (v2Principal != null) + v2Principal.DisplayName = value; + else + v1Task.SetDataItem("PrincipalDisplayName", value); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets the identifier of the user group that is required to run the tasks that are associated with the principal. Setting + /// this property to something other than a null or empty string, will set the property to NULL and will set + /// the property to TaskLogonType.Group; + /// + /// Not supported under Task Scheduler 1.0. + [DefaultValue(null)] + [XmlIgnore] + public string GroupId + { + get => v2Principal?.GroupId; + set + { + if (v2Principal != null) + { + if (string.IsNullOrEmpty(value)) + value = null; + else + { + v2Principal.UserId = null; + v2Principal.LogonType = TaskLogonType.Group; + } + v2Principal.GroupId = value; + } + else + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the identifier of the principal. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(null)] + [XmlAttribute(AttributeName = "id", DataType = "ID")] + public string Id + { + get => v2Principal != null ? v2Principal.Id : v1Task.GetDataItem("PrincipalId"); + set + { + if (v2Principal != null) + v2Principal.Id = value; + else + v1Task.SetDataItem("PrincipalId", value); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the security logon method that is required to run the tasks that are associated with the principal. + /// + /// TaskLogonType values of Group, None, or S4UNot are not supported under Task Scheduler 1.0. + /// + [DefaultValue(typeof(TaskLogonType), "None")] + public TaskLogonType LogonType + { + get + { + if (v2Principal != null) + return v2Principal.LogonType; + if (UserId == localSystemAcct) + return TaskLogonType.ServiceAccount; + if (v1Task.HasFlags(TaskFlags.RunOnlyIfLoggedOn)) + return TaskLogonType.InteractiveToken; + return TaskLogonType.InteractiveTokenOrPassword; + } + set + { + if (v2Principal != null) + v2Principal.LogonType = value; + else + { + if (value == TaskLogonType.Group || value == TaskLogonType.None || value == TaskLogonType.S4U) + throw new NotV1SupportedException(); + v1Task.SetFlags(TaskFlags.RunOnlyIfLoggedOn, value == TaskLogonType.InteractiveToken); + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the task process security identifier (SID) type. + /// One of the enumeration constants. + /// Setting this value appears to break the Task Scheduler MMC and does not output in XML. Removed to prevent problems. + /// Not supported under Task Scheduler versions prior to 2.1. + [XmlIgnore, DefaultValue(typeof(TaskProcessTokenSidType), "Default")] + public TaskProcessTokenSidType ProcessTokenSidType + { + get => v2Principal2?.ProcessTokenSidType ?? TaskProcessTokenSidType.Default; + set + { + if (v2Principal2 != null) + v2Principal2.ProcessTokenSidType = value; + else + throw new NotSupportedPriorToException(TaskCompatibility.V2_1); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets the security credentials for a principal. These security credentials define the security context for the tasks that are + /// associated with the principal. + /// + /// Setting this value appears to break the Task Scheduler MMC and does not output in XML. Removed to prevent problems. + [XmlIgnore] + public TaskPrincipalPrivileges RequiredPrivileges => reqPriv ??= new TaskPrincipalPrivileges(v2Principal2); + + /// + /// Gets or sets the identifier that is used to specify the privilege level that is required to run the tasks that are associated + /// with the principal. + /// + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TaskRunLevel), "LUA")] + [XmlIgnore] + public TaskRunLevel RunLevel + { + get => v2Principal?.RunLevel ?? TaskRunLevel.LUA; + set + { + if (v2Principal != null) + v2Principal.RunLevel = value; + else if (value != TaskRunLevel.LUA) + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets the user identifier that is required to run the tasks that are associated with the principal. Setting this property + /// to something other than a null or empty string, will set the property to NULL; + /// + [DefaultValue(null)] + public string UserId + { + get + { + if (v2Principal != null) + return v2Principal.UserId; + if (v1CachedAcctInfo == null) + { + try + { + string acct = v1Task.GetAccountInformation(); + v1CachedAcctInfo = string.IsNullOrEmpty(acct) ? localSystemAcct : acct; + } + catch { v1CachedAcctInfo = string.Empty; } + } + return v1CachedAcctInfo == string.Empty ? null : v1CachedAcctInfo; + } + set + { + if (v2Principal != null) + { + if (string.IsNullOrEmpty(value)) + value = null; + else + { + v2Principal.GroupId = null; + //if (value.Contains(@"\") && !value.Contains(@"\\")) + // value = value.Replace(@"\", @"\\"); + } + v2Principal.UserId = value; + } + else + { + if (value.Equals(localSystemAcct, StringComparison.CurrentCultureIgnoreCase)) + value = ""; + v1Task.SetAccountInformation(value, IntPtr.Zero); + v1CachedAcctInfo = null; + } + OnNotifyPropertyChanged(); + } + } + + /// Validates the supplied account against the supplied . + /// The user or group account name. + /// The SID type for the process. + /// true if supplied account can be used for the supplied SID type. + public static bool ValidateAccountForSidType(string acct, TaskProcessTokenSidType sidType) + { + string[] validUserIds = { "NETWORK SERVICE", "LOCAL SERVICE", "S-1-5-19", "S-1-5-20" }; + return sidType == TaskProcessTokenSidType.Default || Array.Find(validUserIds, id => id.Equals(acct, StringComparison.InvariantCultureIgnoreCase)) != null; + } + + /// Releases all resources used by this class. + public void Dispose() + { + if (v2Principal != null) + Marshal.ReleaseComObject(v2Principal); + v1Task = null; + } + + /// Gets a value indicating whether current Principal settings require a password to be provided. + /// true if settings requires a password to be provided; otherwise, false. + public bool RequiresPassword() => LogonType == TaskLogonType.InteractiveTokenOrPassword || + LogonType == TaskLogonType.Password || LogonType == TaskLogonType.S4U && UserId != null && string.Compare(UserId, WindowsIdentity.GetCurrent().Name, StringComparison.OrdinalIgnoreCase) != 0; + + /// Returns a that represents this instance. + /// A that represents this instance. + public override string ToString() => LogonType == TaskLogonType.Group ? GroupId : UserId; + + XmlSchema IXmlSerializable.GetSchema() => null; + + void IXmlSerializable.ReadXml(XmlReader reader) + { + reader.ReadStartElement(XmlSerializationHelper.GetElementName(this), TaskDefinition.tns); + if (reader.HasAttributes) + Id = reader.GetAttribute("id"); + reader.Read(); + while (reader.MoveToContent() == XmlNodeType.Element) + { + switch (reader.LocalName) + { + case "Principal": + reader.Read(); + XmlSerializationHelper.ReadObjectProperties(reader, this); + reader.ReadEndElement(); + break; + + default: + reader.Skip(); + break; + } + } + reader.ReadEndElement(); + } + + void IXmlSerializable.WriteXml(XmlWriter writer) + { + if (string.IsNullOrEmpty(ToString()) && LogonType == TaskLogonType.None) return; + writer.WriteStartElement("Principal"); + if (!string.IsNullOrEmpty(Id)) + writer.WriteAttributeString("id", Id); + XmlSerializationHelper.WriteObjectProperties(writer, this); + writer.WriteEndElement(); + } + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + /// + /// List of security credentials for a principal under version 1.3 of the Task Scheduler. These security credentials define the security + /// context for the tasks that are associated with the principal. + /// + [PublicAPI] + public sealed class TaskPrincipalPrivileges : IList + { + private readonly IPrincipal2 v2Principal2; + + internal TaskPrincipalPrivileges(IPrincipal2 iPrincipal2 = null) => v2Principal2 = iPrincipal2; + + /// Gets the number of elements contained in the . + /// The number of elements contained in the . + public int Count => v2Principal2?.RequiredPrivilegeCount ?? 0; + + /// Gets a value indicating whether the is read-only. + /// true if the is read-only; otherwise, false. + public bool IsReadOnly => false; + + /// Gets or sets the element at the specified index. + /// The element at the specified index. + /// is not a valid index in the . + /// + /// The property is set and the is read-only. + /// + public TaskPrincipalPrivilege this[int index] + { + get + { + if (v2Principal2 != null) + return (TaskPrincipalPrivilege)Enum.Parse(typeof(TaskPrincipalPrivilege), v2Principal2[index + 1]); + throw new IndexOutOfRangeException(); + } + set => throw new NotImplementedException(); + } + + /// Adds an item to the . + /// The object to add to the . + /// The is read-only. + public void Add(TaskPrincipalPrivilege item) + { + if (v2Principal2 != null) + v2Principal2.AddRequiredPrivilege(item.ToString()); + else + throw new NotSupportedPriorToException(TaskCompatibility.V2_1); + } + + /// Determines whether the contains a specific value. + /// The object to locate in the . + /// + /// true if is found in the ; otherwise, false. + /// + public bool Contains(TaskPrincipalPrivilege item) => IndexOf(item) != -1; + + /// Copies to. + /// The array. + /// Index of the array. + public void CopyTo(TaskPrincipalPrivilege[] array, int arrayIndex) + { + using var pEnum = GetEnumerator(); + for (var i = arrayIndex; i < array.Length; i++) + { + if (!pEnum.MoveNext()) + break; + array[i] = pEnum.Current; + } + } + + /// Returns an enumerator that iterates through the collection. + /// A that can be used to iterate through the collection. + public IEnumerator GetEnumerator() => new TaskPrincipalPrivilegesEnumerator(v2Principal2); + + /// Determines the index of a specific item in the . + /// The object to locate in the . + /// The index of if found in the list; otherwise, -1. + public int IndexOf(TaskPrincipalPrivilege item) + { + for (var i = 0; i < Count; i++) + { + if (item == this[i]) + return i; + } + return -1; + } + + /// Removes all items from the . + /// The is read-only. + void ICollection.Clear() => throw new NotImplementedException(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + /// Inserts an item to the at the specified index. + /// The zero-based index at which should be inserted. + /// The object to insert into the . + /// is not a valid index in the . + /// The is read-only. + void IList.Insert(int index, TaskPrincipalPrivilege item) => throw new NotImplementedException(); + + /// Removes the first occurrence of a specific object from the . + /// The object to remove from the . + /// + /// true if was successfully removed from the ; + /// otherwise, false. This method also returns false if is not found in the original . + /// + /// The is read-only. + bool ICollection.Remove(TaskPrincipalPrivilege item) => throw new NotImplementedException(); + + /// Removes the item at the specified index. + /// The zero-based index of the item to remove. + /// is not a valid index in the . + /// The is read-only. + void IList.RemoveAt(int index) => throw new NotImplementedException(); + + /// Enumerates the privileges set for a principal under version 1.3 of the Task Scheduler. + public sealed class TaskPrincipalPrivilegesEnumerator : IEnumerator + { + private readonly IPrincipal2 v2Principal2; + private int cur; + + internal TaskPrincipalPrivilegesEnumerator(IPrincipal2 iPrincipal2 = null) + { + v2Principal2 = iPrincipal2; + Reset(); + } + + /// Gets the element in the collection at the current position of the enumerator. + /// The element in the collection at the current position of the enumerator. + public TaskPrincipalPrivilege Current { get; private set; } + + object IEnumerator.Current => Current; + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public void Dispose() { } + + /// Advances the enumerator to the next element of the collection. + /// + /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. + /// + /// The collection was modified after the enumerator was created. + public bool MoveNext() + { + if (v2Principal2 != null && cur < v2Principal2.RequiredPrivilegeCount) + { + cur++; + Current = (TaskPrincipalPrivilege)Enum.Parse(typeof(TaskPrincipalPrivilege), v2Principal2[cur]); + return true; + } + Current = 0; + return false; + } + + /// Sets the enumerator to its initial position, which is before the first element in the collection. + /// The collection was modified after the enumerator was created. + public void Reset() + { + cur = 0; + Current = 0; + } + } + } + + /// + /// Provides the administrative information that can be used to describe the task. This information includes details such as a + /// description of the task, the author of the task, the date the task is registered, and the security descriptor of the task. + /// + [XmlRoot("RegistrationInfo", Namespace = TaskDefinition.tns, IsNullable = true)] + [PublicAPI] + public sealed class TaskRegistrationInfo : IDisposable, IXmlSerializable, INotifyPropertyChanged + { + private readonly IRegistrationInfo v2RegInfo; + private ITask v1Task; + + internal TaskRegistrationInfo([NotNull] IRegistrationInfo iRegInfo) => v2RegInfo = iRegInfo; + + internal TaskRegistrationInfo([NotNull] ITask iTask) => v1Task = iTask; + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// Gets or sets the author of the task. + [DefaultValue(null)] + public string Author + { + get => v2RegInfo != null ? v2RegInfo.Author : v1Task.GetCreator(); + set + { + if (v2RegInfo != null) + v2RegInfo.Author = value; + else + v1Task.SetCreator(value); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the date and time when the task is registered. + [DefaultValue(typeof(DateTime), "0001-01-01T00:00:00")] + public DateTime Date + { + get + { + if (v2RegInfo != null) + { + if (DateTime.TryParse(v2RegInfo.Date, Trigger.DefaultDateCulture, DateTimeStyles.AssumeLocal, out var ret)) + return ret; + } + else + { + var v1Path = Task.GetV1Path(v1Task); + if (!string.IsNullOrEmpty(v1Path) && File.Exists(v1Path)) + return File.GetLastWriteTime(v1Path); + } + return DateTime.MinValue; + } + set + { + if (v2RegInfo != null) + v2RegInfo.Date = value == DateTime.MinValue ? null : value.ToString(Trigger.V2BoundaryDateFormat, Trigger.DefaultDateCulture); + else + { + var v1Path = Task.GetV1Path(v1Task); + if (!string.IsNullOrEmpty(v1Path) && File.Exists(v1Path)) + File.SetLastWriteTime(v1Path, value); + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the description of the task. + [DefaultValue(null)] + public string Description + { + get => v2RegInfo != null ? FixCrLf(v2RegInfo.Description) : v1Task.GetComment(); + set + { + if (v2RegInfo != null) + v2RegInfo.Description = value; + else + v1Task.SetComment(value); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets any additional documentation for the task. + [DefaultValue(null)] + public string Documentation + { + get => v2RegInfo != null ? FixCrLf(v2RegInfo.Documentation) : v1Task.GetDataItem(nameof(Documentation)); + set + { + if (v2RegInfo != null) + v2RegInfo.Documentation = value; + else + v1Task.SetDataItem(nameof(Documentation), value); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the security descriptor of the task. + /// The security descriptor. + [XmlIgnore] + public GenericSecurityDescriptor SecurityDescriptor + { + get => new RawSecurityDescriptor(SecurityDescriptorSddlForm); + set => SecurityDescriptorSddlForm = value?.GetSddlForm(Task.defaultAccessControlSections); + } + + /// Gets or sets the security descriptor of the task. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(null)] + [XmlIgnore] + public string SecurityDescriptorSddlForm + { + get + { + object sddl = null; + if (v2RegInfo != null) + sddl = v2RegInfo.SecurityDescriptor; + return sddl?.ToString(); + } + set + { + if (v2RegInfo != null) + v2RegInfo.SecurityDescriptor = value; + else + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets where the task originated from. For example, a task may originate from a component, service, application, or user. + /// + [DefaultValue(null)] + public string Source + { + get => v2RegInfo != null ? v2RegInfo.Source : v1Task.GetDataItem(nameof(Source)); + set + { + if (v2RegInfo != null) + v2RegInfo.Source = value; + else + v1Task.SetDataItem(nameof(Source), value); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the URI of the task. + /// + /// Note: Breaking change in version 2.0. This property was previously of type . It was found that in + /// Windows 8, many of the native tasks use this property in a string format rather than in a URI format. + /// + [DefaultValue(null)] + public string URI + { + get + { + var uri = v2RegInfo != null ? v2RegInfo.URI : v1Task.GetDataItem(nameof(URI)); + return string.IsNullOrEmpty(uri) ? null : uri; + } + set + { + if (v2RegInfo != null) + v2RegInfo.URI = value; + else + v1Task.SetDataItem(nameof(URI), value); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the version number of the task. + [DefaultValueEx(typeof(Version), "1.0")] + public Version Version + { + get + { + var sver = v2RegInfo != null ? v2RegInfo.Version : v1Task.GetDataItem(nameof(Version)); + if (sver != null) try { return new Version(sver); } catch { } + return new Version(1, 0); + } + set + { + if (v2RegInfo != null) + v2RegInfo.Version = value?.ToString(); + else + v1Task.SetDataItem(nameof(Version), value.ToString()); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets an XML-formatted version of the registration information for the task. + [XmlIgnore] + public string XmlText + { + get => v2RegInfo != null ? v2RegInfo.XmlText : XmlSerializationHelper.WriteObjectToXmlText(this); + set + { + if (v2RegInfo != null) + v2RegInfo.XmlText = value; + else + XmlSerializationHelper.ReadObjectFromXmlText(value, this); + OnNotifyPropertyChanged(); + } + } + + /// Releases all resources used by this class. + public void Dispose() + { + v1Task = null; + if (v2RegInfo != null) + Marshal.ReleaseComObject(v2RegInfo); + } + + /// Returns a that represents this instance. + /// A that represents this instance. + public override string ToString() + { + if (v2RegInfo != null || v1Task != null) + return DebugHelper.GetDebugString(this); + return base.ToString(); + } + + XmlSchema IXmlSerializable.GetSchema() => null; + + void IXmlSerializable.ReadXml(XmlReader reader) + { + if (!reader.IsEmptyElement) + { + reader.ReadStartElement(XmlSerializationHelper.GetElementName(this), TaskDefinition.tns); + XmlSerializationHelper.ReadObjectProperties(reader, this, ProcessVersionXml); + reader.ReadEndElement(); + } + else + reader.Skip(); + } + + void IXmlSerializable.WriteXml(XmlWriter writer) => XmlSerializationHelper.WriteObjectProperties(writer, this, ProcessVersionXml); + + internal static string FixCrLf(string text) => text == null ? null : Regex.Replace(text, "(?Called when a property has changed to notify any attached elements. + /// Name of the property. + private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + + private bool ProcessVersionXml(PropertyInfo pi, object obj, ref object value) + { + if (pi.Name != "Version" || value == null) return false; + if (value is Version) + value = value.ToString(); + else if (value is string) + value = new Version(value.ToString()); + return true; + } + } + + /// Provides the settings that the Task Scheduler service uses to perform the task. + [XmlRoot("Settings", Namespace = TaskDefinition.tns, IsNullable = true)] + [PublicAPI] + public sealed class TaskSettings : IDisposable, IXmlSerializable, INotifyPropertyChanged + { + private const uint InfiniteRunTimeV1 = 0xFFFFFFFF; + + private readonly ITaskSettings v2Settings; + private readonly ITaskSettings2 v2Settings2; + private readonly ITaskSettings3 v2Settings3; + private IdleSettings idleSettings; + private MaintenanceSettings maintenanceSettings; + private NetworkSettings networkSettings; + private ITask v1Task; + + internal TaskSettings([NotNull] ITaskSettings iSettings) + { + v2Settings = iSettings; + try { if (Environment.OSVersion.Version >= new Version(6, 1)) v2Settings2 = (ITaskSettings2)v2Settings; } + catch { } + try { if (Environment.OSVersion.Version >= new Version(6, 2)) v2Settings3 = (ITaskSettings3)v2Settings; } + catch { } + } + + internal TaskSettings([NotNull] ITask iTask) => v1Task = iTask; + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Gets or sets a Boolean value that indicates that the task can be started by using either the Run command or the Context menu. + /// + /// Not supported under Task Scheduler 1.0. + [DefaultValue(true)] + [XmlElement("AllowStartOnDemand")] + [XmlIgnore] + public bool AllowDemandStart + { + get => v2Settings == null || v2Settings.AllowDemandStart; + set + { + if (v2Settings != null) + v2Settings.AllowDemandStart = value; + else + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a Boolean value that indicates that the task may be terminated by using TerminateProcess. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(true)] + [XmlIgnore] + public bool AllowHardTerminate + { + get => v2Settings == null || v2Settings.AllowHardTerminate; + set + { + if (v2Settings != null) + v2Settings.AllowHardTerminate = value; + else + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets an integer value that indicates which version of Task Scheduler a task is compatible with. + /// Not supported under Task Scheduler 1.0. + [XmlIgnore] + public TaskCompatibility Compatibility + { + get => v2Settings?.Compatibility ?? TaskCompatibility.V1; + set + { + if (v2Settings != null) + v2Settings.Compatibility = value; + else + if (value != TaskCompatibility.V1) + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets the amount of time that the Task Scheduler will wait before deleting the task after it expires. If no value is + /// specified for this property, then the Task Scheduler service will not delete the task. + /// + /// + /// Gets and sets the amount of time that the Task Scheduler will wait before deleting the task after it expires. A TimeSpan value + /// of 1 second indicates the task is set to delete when done. A value of TimeSpan.Zero indicates that the task should not be deleted. + /// + /// + /// A task expires after the end boundary has been exceeded for all triggers associated with the task. The end boundary for a + /// trigger is specified by the EndBoundary property of all trigger types. + /// + [DefaultValue(typeof(TimeSpan), "12:00:00")] + public TimeSpan DeleteExpiredTaskAfter + { + get + { + if (v2Settings != null) + return v2Settings.DeleteExpiredTaskAfter == "PT0S" ? TimeSpan.FromSeconds(1) : Task.StringToTimeSpan(v2Settings.DeleteExpiredTaskAfter); + return v1Task.HasFlags(TaskFlags.DeleteWhenDone) ? TimeSpan.FromSeconds(1) : TimeSpan.Zero; + } + set + { + if (v2Settings != null) + v2Settings.DeleteExpiredTaskAfter = value == TimeSpan.FromSeconds(1) ? "PT0S" : Task.TimeSpanToString(value); + else + v1Task.SetFlags(TaskFlags.DeleteWhenDone, value >= TimeSpan.FromSeconds(1)); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a Boolean value that indicates that the task will not be started if the computer is running on battery power. + /// + [DefaultValue(true)] + public bool DisallowStartIfOnBatteries + { + get => v2Settings?.DisallowStartIfOnBatteries ?? v1Task.HasFlags(TaskFlags.DontStartIfOnBatteries); + set + { + if (v2Settings != null) + v2Settings.DisallowStartIfOnBatteries = value; + else + v1Task.SetFlags(TaskFlags.DontStartIfOnBatteries, value); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a Boolean value that indicates that the task will not be started if the task is triggered to run in a Remote + /// Applications Integrated Locally (RAIL) session. + /// + /// Property set for a task on a Task Scheduler version prior to 2.1. + [DefaultValue(false)] + [XmlIgnore] + public bool DisallowStartOnRemoteAppSession + { + get + { + if (v2Settings2 != null) + return v2Settings2.DisallowStartOnRemoteAppSession; + if (v2Settings3 != null) + return v2Settings3.DisallowStartOnRemoteAppSession; + return false; + } + set + { + if (v2Settings2 != null) + v2Settings2.DisallowStartOnRemoteAppSession = value; + else if (v2Settings3 != null) + v2Settings3.DisallowStartOnRemoteAppSession = value; + else + throw new NotSupportedPriorToException(TaskCompatibility.V2_1); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a Boolean value that indicates that the task is enabled. The task can be performed only when this setting is TRUE. + /// + [DefaultValue(true)] + public bool Enabled + { + get => v2Settings?.Enabled ?? !v1Task.HasFlags(TaskFlags.Disabled); + set + { + if (v2Settings != null) + v2Settings.Enabled = value; + else + v1Task.SetFlags(TaskFlags.Disabled, !value); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets the amount of time that is allowed to complete the task. By default, a task will be stopped 72 hours after it + /// starts to run. + /// + /// + /// The amount of time that is allowed to complete the task. When this parameter is set to , the + /// execution time limit is infinite. + /// + /// + /// If a task is started on demand, the ExecutionTimeLimit setting is bypassed. Therefore, a task that is started on demand will not + /// be terminated if it exceeds the ExecutionTimeLimit. + /// + [DefaultValue(typeof(TimeSpan), "3")] + public TimeSpan ExecutionTimeLimit + { + get + { + if (v2Settings != null) + return Task.StringToTimeSpan(v2Settings.ExecutionTimeLimit); + var ms = v1Task.GetMaxRunTime(); + return ms == InfiniteRunTimeV1 ? TimeSpan.Zero : TimeSpan.FromMilliseconds(ms); + } + set + { + if (v2Settings != null) + v2Settings.ExecutionTimeLimit = value == TimeSpan.Zero ? "PT0S" : Task.TimeSpanToString(value); + else + { + // Due to an issue introduced in Vista, and propagated to Windows 7, setting the MaxRunTime to INFINITE results in the + // task only running for 72 hours. For these operating systems, setting the RunTime to "INFINITE - 1" gets the desired + // behavior of allowing an "infinite" run of the task. + var ms = value == TimeSpan.Zero ? InfiniteRunTimeV1 : Convert.ToUInt32(value.TotalMilliseconds); + v1Task.SetMaxRunTime(ms); + if (value == TimeSpan.Zero && v1Task.GetMaxRunTime() != InfiniteRunTimeV1) + v1Task.SetMaxRunTime(InfiniteRunTimeV1 - 1); + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a Boolean value that indicates that the task will not be visible in the UI by default. + [DefaultValue(false)] + public bool Hidden + { + get => v2Settings?.Hidden ?? v1Task.HasFlags(TaskFlags.Hidden); + set + { + if (v2Settings != null) + v2Settings.Hidden = value; + else + v1Task.SetFlags(TaskFlags.Hidden, value); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the information that the Task Scheduler uses during Automatic maintenance. + [XmlIgnore] + [NotNull] + public MaintenanceSettings MaintenanceSettings => maintenanceSettings ??= new MaintenanceSettings(v2Settings3); + + /// Gets or sets the policy that defines how the Task Scheduler handles multiple instances of the task. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TaskInstancesPolicy), "IgnoreNew")] + [XmlIgnore] + public TaskInstancesPolicy MultipleInstances + { + get => v2Settings?.MultipleInstances ?? TaskInstancesPolicy.IgnoreNew; + set + { + if (v2Settings != null) + v2Settings.MultipleInstances = value; + else + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the priority level of the task. + /// The priority. + /// Value set to AboveNormal or BelowNormal on Task Scheduler 1.0. + [DefaultValue(typeof(ProcessPriorityClass), "Normal")] + public ProcessPriorityClass Priority + { + get => v2Settings != null ? GetPriorityFromInt(v2Settings.Priority) : (ProcessPriorityClass)v1Task.GetPriority(); + set + { + if (v2Settings != null) + { + v2Settings.Priority = GetPriorityAsInt(value); + } + else + { + if (value == ProcessPriorityClass.AboveNormal || value == ProcessPriorityClass.BelowNormal) + throw new NotV1SupportedException("Unsupported priority level on Task Scheduler 1.0."); + v1Task.SetPriority((uint)value); + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the number of times that the Task Scheduler will attempt to restart the task. + /// + /// The number of times that the Task Scheduler will attempt to restart the task. If this property is set, the property must also be set. + /// + /// Not supported under Task Scheduler 1.0. + [DefaultValue(0)] + [XmlIgnore] + public int RestartCount + { + get => v2Settings?.RestartCount ?? 0; + set + { + if (v2Settings != null) + v2Settings.RestartCount = value; + else + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a value that specifies how long the Task Scheduler will attempt to restart the task. + /// + /// A value that specifies how long the Task Scheduler will attempt to restart the task. If this property is set, the property must also be set. The maximum time allowed is 31 days, and the minimum time allowed is 1 minute. + /// + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + [XmlIgnore] + public TimeSpan RestartInterval + { + get => v2Settings != null ? Task.StringToTimeSpan(v2Settings.RestartInterval) : TimeSpan.Zero; + set + { + if (v2Settings != null) + v2Settings.RestartInterval = Task.TimeSpanToString(value); + else + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a Boolean value that indicates that the Task Scheduler will run the task only if the computer is in an idle condition. + /// + [DefaultValue(false)] + public bool RunOnlyIfIdle + { + get => v2Settings?.RunOnlyIfIdle ?? v1Task.HasFlags(TaskFlags.StartOnlyIfIdle); + set + { + if (v2Settings != null) + v2Settings.RunOnlyIfIdle = value; + else + v1Task.SetFlags(TaskFlags.StartOnlyIfIdle, value); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a Boolean value that indicates that the Task Scheduler will run the task only if the user is logged on (v1.0 only) + /// + /// Property set for a task on a Task Scheduler version other than 1.0. + [XmlIgnore] + public bool RunOnlyIfLoggedOn + { + get => v2Settings != null || v1Task.HasFlags(TaskFlags.RunOnlyIfLoggedOn); + set + { + if (v1Task != null) + v1Task.SetFlags(TaskFlags.RunOnlyIfLoggedOn, value); + else if (v2Settings != null) + throw new NotV2SupportedException("Task Scheduler 2.0 (1.2) does not support setting this property. You must use an InteractiveToken in order to have the task run in the current user session."); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a Boolean value that indicates that the Task Scheduler will run the task only when a network is available. + [DefaultValue(false)] + public bool RunOnlyIfNetworkAvailable + { + get => v2Settings?.RunOnlyIfNetworkAvailable ?? v1Task.HasFlags(TaskFlags.RunIfConnectedToInternet); + set + { + if (v2Settings != null) + v2Settings.RunOnlyIfNetworkAvailable = value; + else + v1Task.SetFlags(TaskFlags.RunIfConnectedToInternet, value); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a Boolean value that indicates that the Task Scheduler can start the task at any time after its scheduled time has passed. + /// + /// Not supported under Task Scheduler 1.0. + [DefaultValue(false)] + [XmlIgnore] + public bool StartWhenAvailable + { + get => v2Settings != null && v2Settings.StartWhenAvailable; + set + { + if (v2Settings != null) + v2Settings.StartWhenAvailable = value; + else + throw new NotV1SupportedException(); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a Boolean value that indicates that the task will be stopped if the computer switches to battery power. + [DefaultValue(true)] + public bool StopIfGoingOnBatteries + { + get => v2Settings?.StopIfGoingOnBatteries ?? v1Task.HasFlags(TaskFlags.KillIfGoingOnBatteries); + set + { + if (v2Settings != null) + v2Settings.StopIfGoingOnBatteries = value; + else + v1Task.SetFlags(TaskFlags.KillIfGoingOnBatteries, value); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a Boolean value that indicates that the Unified Scheduling Engine will be utilized to run this task. + /// Property set for a task on a Task Scheduler version prior to 2.1. + [DefaultValue(false)] + [XmlIgnore] + public bool UseUnifiedSchedulingEngine + { + get + { + if (v2Settings2 != null) + return v2Settings2.UseUnifiedSchedulingEngine; + if (v2Settings3 != null) + return v2Settings3.UseUnifiedSchedulingEngine; + return false; + } + set + { + if (v2Settings2 != null) + v2Settings2.UseUnifiedSchedulingEngine = value; + else if (v2Settings3 != null) + v2Settings3.UseUnifiedSchedulingEngine = value; + else + throw new NotSupportedPriorToException(TaskCompatibility.V2_1); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a boolean value that indicates whether the task is automatically disabled every time Windows starts. + /// Property set for a task on a Task Scheduler version prior to 2.2. + [DefaultValue(false)] + [XmlIgnore] + public bool Volatile + { + get => v2Settings3 != null && v2Settings3.Volatile; + set + { + if (v2Settings3 != null) + v2Settings3.Volatile = value; + else + throw new NotSupportedPriorToException(TaskCompatibility.V2_2); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a Boolean value that indicates that the Task Scheduler will wake the computer when it is time to run the task. + /// + [DefaultValue(false)] + public bool WakeToRun + { + get => v2Settings?.WakeToRun ?? v1Task.HasFlags(TaskFlags.SystemRequired); + set + { + if (v2Settings != null) + v2Settings.WakeToRun = value; + else + v1Task.SetFlags(TaskFlags.SystemRequired, value); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets an XML-formatted definition of the task settings. + [XmlIgnore] + public string XmlText + { + get => v2Settings != null ? v2Settings.XmlText : XmlSerializationHelper.WriteObjectToXmlText(this); + set + { + if (v2Settings != null) + v2Settings.XmlText = value; + else + XmlSerializationHelper.ReadObjectFromXmlText(value, this); + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets the information that specifies how the Task Scheduler performs tasks when the computer is in an idle state. + /// + [NotNull] + public IdleSettings IdleSettings => idleSettings ??= v2Settings != null ? new IdleSettings(v2Settings.IdleSettings) : new IdleSettings(v1Task); + + /// + /// Gets or sets the network settings object that contains a network profile identifier and name. If the RunOnlyIfNetworkAvailable + /// property of ITaskSettings is true and a network profile is specified in the NetworkSettings property, then the task will run + /// only if the specified network profile is available. + /// + [XmlIgnore] + [NotNull] + public NetworkSettings NetworkSettings => networkSettings ??= new NetworkSettings(v2Settings?.NetworkSettings); + + /// Releases all resources used by this class. + public void Dispose() + { + if (v2Settings != null) + Marshal.ReleaseComObject(v2Settings); + idleSettings = null; + networkSettings = null; + v1Task = null; + } + + /// Returns a that represents this instance. + /// A that represents this instance. + public override string ToString() + { + if (v2Settings != null || v1Task != null) + return DebugHelper.GetDebugString(this); + return base.ToString(); + } + + XmlSchema IXmlSerializable.GetSchema() => null; + + void IXmlSerializable.ReadXml(XmlReader reader) + { + if (!reader.IsEmptyElement) + { + reader.ReadStartElement(XmlSerializationHelper.GetElementName(this), TaskDefinition.tns); + XmlSerializationHelper.ReadObjectProperties(reader, this, ConvertXmlProperty); + reader.ReadEndElement(); + } + else + reader.Skip(); + } + + void IXmlSerializable.WriteXml(XmlWriter writer) => XmlSerializationHelper.WriteObjectProperties(writer, this, ConvertXmlProperty); + + private bool ConvertXmlProperty(PropertyInfo pi, object obj, ref object value) + { + if (pi.Name == "Priority" && value != null) + { + if (value is int) + value = GetPriorityFromInt((int)value); + else if (value is ProcessPriorityClass) + value = GetPriorityAsInt((ProcessPriorityClass)value); + return true; + } + return false; + } + + private int GetPriorityAsInt(ProcessPriorityClass value) + { + // Check for back-door case where exact value is being passed and cast to ProcessPriorityClass + if ((int)value <= 10 && value >= 0) return (int)value; + var p = 7; + switch (value) + { + case ProcessPriorityClass.AboveNormal: + p = 3; + break; + + case ProcessPriorityClass.High: + p = 1; + break; + + case ProcessPriorityClass.Idle: + p = 10; + break; + + case ProcessPriorityClass.Normal: + p = 5; + break; + + case ProcessPriorityClass.RealTime: + p = 0; + break; + // case ProcessPriorityClass.BelowNormal: default: break; + } + return p; + } + + private ProcessPriorityClass GetPriorityFromInt(int value) + { + switch (value) + { + case 0: + return ProcessPriorityClass.RealTime; + + case 1: + return ProcessPriorityClass.High; + + case 2: + case 3: + return ProcessPriorityClass.AboveNormal; + + case 4: + case 5: + case 6: + return ProcessPriorityClass.Normal; + // case 7: case 8: + default: + return ProcessPriorityClass.BelowNormal; + + case 9: + case 10: + return ProcessPriorityClass.Idle; + } + } + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + internal static class DebugHelper + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Language", "CSE0003:Use expression-bodied members", Justification = "")] + public static string GetDebugString(object inst) + { +#if DEBUG + var sb = new StringBuilder(); + foreach (var pi in inst.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) + { + if (pi.Name.StartsWith("Xml")) + continue; + var outval = pi.GetValue(inst, null); + if (outval != null) + { + var defval = XmlSerializationHelper.GetDefaultValue(pi); + if (!outval.Equals(defval)) + { + var s = $"{pi.Name}:{outval}"; + if (s.Length > 30) s = s.Remove(30); + sb.Append(s + "; "); + } + } + } + return sb.ToString(); +#else + return inst.GetType().ToString(); +#endif + } + } + + internal static class TSInteropExt + { + public static string GetDataItem(this ITask v1Task, string name) + { + TaskDefinition.GetV1TaskDataDictionary(v1Task).TryGetValue(name, out var ret); + return ret; + } + + public static bool HasFlags(this ITask v1Task, TaskFlags flags) => v1Task.GetFlags().IsFlagSet(flags); + + public static void SetDataItem(this ITask v1Task, string name, string value) + { + var d = TaskDefinition.GetV1TaskDataDictionary(v1Task); + d[name] = value; + TaskDefinition.SetV1TaskData(v1Task, d); + } + + public static void SetFlags(this ITask v1Task, TaskFlags flags, bool value = true) => v1Task.SetFlags(v1Task.GetFlags().SetFlags(flags, value)); + } + + internal class DefaultValueExAttribute : DefaultValueAttribute + { + public DefaultValueExAttribute(Type type, string value) : base(null) + { + try + { + if (type == typeof(Version)) + { + SetValue(new Version(value)); + return; + } + SetValue(TypeDescriptor.GetConverter(type).ConvertFromInvariantString(value)); + } + catch + { + Debug.Fail("Default value attribute of type " + type.FullName + " threw converting from the string '" + value + "'."); + } + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/TaskCollection.cs b/FlashPatcher/TaskService/TaskCollection.cs new file mode 100644 index 0000000..2e21a4d --- /dev/null +++ b/FlashPatcher/TaskService/TaskCollection.cs @@ -0,0 +1,400 @@ +using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Collection of running tasks in a . This class has no public constructor and can only be accessed via the + /// properties and functions within . + /// + public sealed class RunningTaskCollection : IReadOnlyList, IDisposable + { + private readonly TaskService svc; + private readonly V2Interop.IRunningTaskCollection v2Coll; + + internal RunningTaskCollection([NotNull] TaskService svc) => this.svc = svc; + + internal RunningTaskCollection([NotNull] TaskService svc, [NotNull] V2Interop.IRunningTaskCollection iTaskColl) + { + this.svc = svc; + v2Coll = iTaskColl; + } + + /// Gets the number of registered tasks in the collection. + public int Count + { + get + { + if (v2Coll != null) + return v2Coll.Count; + var i = 0; + var v1Enum = new V1RunningTaskEnumerator(svc); + while (v1Enum.MoveNext()) + i++; + return i; + } + } + + /// Gets the specified running task from the collection. + /// The index of the running task to be retrieved. + /// A instance. + public RunningTask this[int index] + { + get + { + if (v2Coll != null) + { + var irt = v2Coll[++index]; + return new RunningTask(svc, TaskService.GetTask(svc.v2TaskService, irt.Path), irt); + } + + var i = 0; + var v1Enum = new V1RunningTaskEnumerator(svc); + while (v1Enum.MoveNext()) + if (i++ == index) + return v1Enum.Current; + throw new ArgumentOutOfRangeException(nameof(index)); + } + } + + /// Releases all resources used by this class. + public void Dispose() + { + if (v2Coll != null) + Marshal.ReleaseComObject(v2Coll); + } + + /// Gets an IEnumerator instance for this collection. + /// An enumerator. + public IEnumerator GetEnumerator() + { + if (v2Coll != null) + return new ComEnumerator(() => v2Coll.Count, (object o) => v2Coll[o], o => + { + V2Interop.IRegisteredTask task = null; + try { task = TaskService.GetTask(svc.v2TaskService, o.Path); } catch { } + return task == null ? null : new RunningTask(svc, task, o); + }); + return new V1RunningTaskEnumerator(svc); + } + + /// Returns a that represents this instance. + /// A that represents this instance. + public override string ToString() => $"RunningTaskCollection; Count: {Count}"; + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); + + private class V1RunningTaskEnumerator : IEnumerator + { + private readonly TaskService svc; + private readonly TaskCollection.V1TaskEnumerator tEnum; + + internal V1RunningTaskEnumerator([NotNull] TaskService svc) + { + this.svc = svc; + tEnum = new TaskCollection.V1TaskEnumerator(svc); + } + + public RunningTask Current => new RunningTask(svc, tEnum.ICurrent); + + object System.Collections.IEnumerator.Current => Current; + + /// Releases all resources used by this class. + public void Dispose() => tEnum.Dispose(); + + public bool MoveNext() => tEnum.MoveNext() && (tEnum.Current?.State == TaskState.Running || MoveNext()); + + public void Reset() => tEnum.Reset(); + } + } + + /// + /// Contains all the tasks that are registered within a . This class has no public constructor and can only be + /// accessed via the properties and functions within . + /// + /// + /// Potentially breaking change in 1.6.2 and later where under V1 the list previously included the '.job' extension on the task name. + /// This has been removed so that it is consistent with V2. + /// + /// + /// public class Program + /// { + /// bool RootFolderHasTask(string taskName) + /// { + /// if (TaskService.Instance.RootFolder.Tasks.Count > 0) + /// { + /// return TaskService.Instance.RootFolder.Tasks.Exists(taskName); + /// } + /// return false; + /// } + /// + /// TaskCollection GetRootTasksStartingWith(string value) + /// { + /// var pattern = $"^{Regex.Escape(value)}.*$"; + /// return TaskService.Instance.RootFolder.GetTasks(new Regex(pattern)); + /// } + /// + /// public static void Main() + /// { + /// foreach (var task in GetRootTasksStartingWith("MyCo")) + /// if (RootFolderHasTask(task.Name)) + /// Console.WriteLine(task.Name); + /// } + /// } + /// + [PublicAPI] + public sealed class TaskCollection : IReadOnlyList, IDisposable + { + private readonly TaskFolder fld; + private readonly TaskService svc; + private readonly V2Interop.IRegisteredTaskCollection v2Coll; + private Regex filter; + private V1Interop.ITaskScheduler v1TS; + + internal TaskCollection([NotNull] TaskService svc, Regex filter = null) + { + this.svc = svc; + Filter = filter; + v1TS = svc.v1TaskScheduler; + } + + internal TaskCollection([NotNull] TaskFolder folder, [NotNull] V2Interop.IRegisteredTaskCollection iTaskColl, Regex filter = null) + { + svc = folder.TaskService; + Filter = filter; + fld = folder; + v2Coll = iTaskColl; + } + + /// Gets the number of registered tasks in the collection. + public int Count + { + get + { + var i = 0; + if (v2Coll != null) + { + var v2Enum = new V2TaskEnumerator(fld, v2Coll, filter); + while (v2Enum.MoveNext()) + i++; + } + else + { + var v1Enum = new V1TaskEnumerator(svc, filter); + return v1Enum.Count; + } + return i; + } + } + + /// Gets or sets the regular expression filter for task names. + /// The regular expression filter. + private Regex Filter + { + get => filter; + set + { + var sfilter = value?.ToString().TrimStart('^').TrimEnd('$') ?? string.Empty; + if (sfilter == string.Empty || sfilter == "*") + filter = null; + else + { + if (value != null && value.ToString().TrimEnd('$').EndsWith("\\.job", StringComparison.InvariantCultureIgnoreCase)) + filter = new Regex(value.ToString().Replace("\\.job", "")); + else + filter = value; + } + } + } + + /// Gets the specified registered task from the collection. + /// The index of the registered task to be retrieved. + /// A instance that contains the requested context. + public Task this[int index] + { + get + { + var i = 0; + var te = GetEnumerator(); + while (te.MoveNext()) + if (i++ == index) + return te.Current; + throw new ArgumentOutOfRangeException(nameof(index)); + } + } + + /// Gets the named registered task from the collection. + /// The name of the registered task to be retrieved. + /// A instance that contains the requested context. + public Task this[string name] + { + get + { + if (v2Coll != null) + return Task.CreateTask(svc, v2Coll[name]); + + var v1Task = svc.GetTask(name); + if (v1Task != null) + return v1Task; + + throw new ArgumentOutOfRangeException(nameof(name)); + } + } + + /// Releases all resources used by this class. + public void Dispose() + { + v1TS = null; + if (v2Coll != null) + Marshal.ReleaseComObject(v2Coll); + } + + /// Determines whether the specified task exists. + /// The name of the task. + /// true if task exists; otherwise, false. + public bool Exists([NotNull] string taskName) + { + try + { + if (v2Coll != null) + return v2Coll[taskName] != null; + + return svc.GetTask(taskName) != null; + } + catch { } + return false; + } + + /// Gets the collection enumerator for the register task collection. + /// An for this collection. + public IEnumerator GetEnumerator() + { + if (v1TS != null) + return new V1TaskEnumerator(svc, filter); + return new V2TaskEnumerator(fld, v2Coll, filter); + } + + /// Returns a that represents this instance. + /// A that represents this instance. + public override string ToString() => $"TaskCollection; Count: {Count}"; + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); + + internal class V1TaskEnumerator : IEnumerator + { + private readonly Regex filter; + private readonly TaskService svc; + private readonly V1Interop.IEnumWorkItems wienum; + private string curItem; + private V1Interop.ITaskScheduler ts; + + /// Internal constructor + /// TaskService instance + /// The filter. + internal V1TaskEnumerator(TaskService svc, Regex filter = null) + { + this.svc = svc; + this.filter = filter; + ts = svc.v1TaskScheduler; + wienum = ts?.Enum(); + Reset(); + } + + /// Retrieves the current task. See for more information. + public Task Current => new Task(svc, ICurrent); + + object System.Collections.IEnumerator.Current => Current; + + internal int Count + { + get + { + var i = 0; + Reset(); + while (MoveNext()) + i++; + Reset(); + return i; + } + } + + internal V1Interop.ITask ICurrent => TaskService.GetTask(ts, curItem); + + /// Releases all resources used by this class. + public void Dispose() + { + if (wienum != null) Marshal.ReleaseComObject(wienum); + ts = null; + } + + /// Moves to the next task. See MoveNext for more information. + /// true if next task found, false if no more tasks. + public bool MoveNext() + { + var names = IntPtr.Zero; + var valid = false; + do + { + curItem = null; + uint uFetched = 0; + try + { + wienum?.Next(1, out names, out uFetched); + if (uFetched != 1) + break; + using (var name = new V1Interop.CoTaskMemString(Marshal.ReadIntPtr(names))) + curItem = name.ToString(); + if (curItem != null && curItem.EndsWith(".job", StringComparison.InvariantCultureIgnoreCase)) + curItem = curItem.Remove(curItem.Length - 4); + } + catch { } + finally { Marshal.FreeCoTaskMem(names); names = IntPtr.Zero; } + + // If name doesn't match filter, look for next item + if (filter != null && curItem != null) + { + if (!filter.IsMatch(curItem)) + continue; + } + + V1Interop.ITask itask = null; + try { itask = ICurrent; valid = true; } + catch { valid = false; } + finally { Marshal.ReleaseComObject(itask); } + } while (!valid); + + return (curItem != null); + } + + /// Reset task enumeration. See Reset for more information. + public void Reset() + { + curItem = null; + wienum?.Reset(); + } + } + + private class V2TaskEnumerator : ComEnumerator + { + private readonly Regex filter; + + internal V2TaskEnumerator(TaskFolder folder, V2Interop.IRegisteredTaskCollection iTaskColl, Regex filter = null) : + base(() => iTaskColl.Count, (object o) => iTaskColl[o], o => Task.CreateTask(folder.TaskService, o)) => this.filter = filter; + + public override bool MoveNext() + { + var hasNext = base.MoveNext(); + while (hasNext) + { + if (filter == null || filter.IsMatch(iEnum?.Current?.Name ?? "")) + break; + hasNext = base.MoveNext(); + } + return hasNext; + } + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/TaskEvent.cs b/FlashPatcher/TaskService/TaskEvent.cs new file mode 100644 index 0000000..9ae3462 --- /dev/null +++ b/FlashPatcher/TaskService/TaskEvent.cs @@ -0,0 +1,879 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.Eventing.Reader; +using JetBrains.Annotations; + +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Changes to tasks and the engine that cause events. + /// + public enum StandardTaskEventId + { + /// Task Scheduler started an instance of a task for a user. + /// For detailed information, see the documentation for Event ID 100 on TechNet. + JobStart = 100, + /// Task Scheduler failed to start a task for a user. + /// For detailed information, see the documentation for Event ID 101 on TechNet. + JobStartFailed = 101, + /// Task Scheduler successfully finished an instance of a task for a user. + /// For detailed information, see the documentation for Event ID 102 on TechNet. + JobSuccess = 102, + /// Task Scheduler failed to start an instance of a task for a user. + /// For detailed information, see the documentation for Event ID 103 on TechNet. + JobFailure = 103, + /// Task Scheduler failed to log on the user. + /// For detailed information, see the documentation for Event ID 104 on TechNet. + LogonFailure = 104, + /// Task Scheduler failed to impersonate a user. + /// For detailed information, see the documentation for Event ID 105 on TechNet. + ImpersonationFailure = 105, + /// The a user registered the Task Scheduler a task. + /// For detailed information, see the documentation for Event ID 106 on TechNet. + JobRegistered = 106, + /// Task Scheduler launched an instance of a task due to a time trigger. + /// For detailed information, see the documentation for Event ID 107 on TechNet. + TimeTrigger = 107, + /// Task Scheduler launched an instance of a task due to an event trigger. + /// For detailed information, see the documentation for Event ID 108 on TechNet. + EventTrigger = 108, + /// Task Scheduler launched an instance of a task due to a registration trigger. + /// For detailed information, see the documentation for Event ID 109 on TechNet. + ImmediateTrigger = 109, + /// Task Scheduler launched an instance of a task for a user. + /// For detailed information, see the documentation for Event ID 110 on TechNet. + Run = 110, + /// Task Scheduler terminated an instance of a task due to exceeding the time allocated for execution, as configured in the task definition. + /// For detailed information, see the documentation for Event ID 111 on TechNet. + JobTermination = 111, + /// Task Scheduler could not start a task because the network was unavailable. Ensure the computer is connected to the required network as specified in the task. + /// For detailed information, see the documentation for Event ID 112 on TechNet. + JobNoStartWithoutNetwork = 112, + /// The Task Scheduler registered the a task, but not all the specified triggers will start the task. Ensure all the task triggers are valid. + /// For detailed information, see the documentation for Event ID 113 on TechNet. + TaskRegisteredWithoutSomeTriggers = 113, + /// Task Scheduler could not launch a task as scheduled. Instance is started now as required by the configuration option to start the task when available, if the scheduled time is missed. + /// For detailed information, see the documentation for Event ID 114 on TechNet. + MissedTaskLaunched = 114, + /// Task Scheduler failed to roll back a transaction when updating or deleting a task. + /// For detailed information, see the documentation for Event ID 115 on TechNet. + TransactionRollbackFailure = 115, + /// Task Scheduler saved the configuration for a task, but the credentials used to run the task could not be stored. + /// For detailed information, see the documentation for Event ID 116 on TechNet. + TaskRegisteredWithoutCredentials = 116, + /// Task Scheduler launched an instance of a task due to an idle condition. + /// For detailed information, see the documentation for Event ID 117 on TechNet. + IdleTrigger = 117, + /// Task Scheduler launched an instance of a task due to system startup. + /// For detailed information, see the documentation for Event ID 118 on TechNet. + BootTrigger = 118, + /// Task Scheduler launched an instance of a task due to a user logon. + /// For detailed information, see the documentation for Event ID 119 on TechNet. + LogonTrigger = 119, + /// Task Scheduler launched an instance of a task due to a user connecting to the console. + /// For detailed information, see the documentation for Event ID 120 on TechNet. + ConsoleConnectTrigger = 120, + /// Task Scheduler launched an instance of a task due to a user disconnecting from the console. + /// For detailed information, see the documentation for Event ID 121 on TechNet. + ConsoleDisconnectTrigger = 121, + /// Task Scheduler launched an instance of a task due to a user remotely connecting. + /// For detailed information, see the documentation for Event ID 122 on TechNet. + RemoteConnectTrigger = 122, + /// Task Scheduler launched an instance of a task due to a user remotely disconnecting. + /// For detailed information, see the documentation for Event ID 123 on TechNet. + RemoteDisconnectTrigger = 123, + /// Task Scheduler launched an instance of a task due to a user locking the computer. + /// For detailed information, see the documentation for Event ID 124 on TechNet. + SessionLockTrigger = 124, + /// Task Scheduler launched an instance of a task due to a user unlocking the computer. + /// For detailed information, see the documentation for Event ID 125 on TechNet. + SessionUnlockTrigger = 125, + /// Task Scheduler failed to execute a task. Task Scheduler is attempting to restart the task. + /// For detailed information, see the documentation for Event ID 126 on TechNet. + FailedTaskRestart = 126, + /// Task Scheduler failed to execute a task due to a shutdown race condition. Task Scheduler is attempting to restart the task. + /// For detailed information, see the documentation for Event ID 127 on TechNet. + RejectedTaskRestart = 127, + /// Task Scheduler did not launch a task because the current time exceeds the configured task end time. + /// For detailed information, see the documentation for Event ID 128 on TechNet. + IgnoredTaskStart = 128, + /// Task Scheduler launched an instance of a task in a new process. + /// For detailed information, see the documentation for Event ID 129 on TechNet. + CreatedTaskProcess = 129, + /// The Task Scheduler service failed to start a task due to the service being busy. + /// For detailed information, see the documentation for Event ID 130 on TechNet. + TaskNotRunServiceBusy = 130, + /// Task Scheduler failed to start a task because the number of tasks in the task queue exceeds the quota currently configured. + /// For detailed information, see the documentation for Event ID 131 on TechNet. + TaskNotStartedTaskQueueQuotaExceeded = 131, + /// The Task Scheduler task launching queue quota is approaching its preset limit of tasks currently configured. + /// For detailed information, see the documentation for Event ID 132 on TechNet. + TaskQueueQuotaApproaching = 132, + /// Task Scheduler failed to start a task in the task engine for a user. + /// For detailed information, see the documentation for Event ID 133 on TechNet. + TaskNotStartedEngineQuotaExceeded = 133, + /// Task Engine for a user is approaching its preset limit of tasks. + /// For detailed information, see the documentation for Event ID 134 on TechNet. + EngineQuotaApproaching = 134, + /// Task Scheduler did not launch a task because launch condition not met, machine not idle. + /// For detailed information, see the documentation for Event ID 135 on TechNet. + NotStartedWithoutIdle = 135, + /// A user updated Task Scheduler a task + /// For detailed information, see the documentation for Event ID 140 on TechNet. + TaskUpdated = 140, + /// A user deleted Task Scheduler a task + /// For detailed information, see the documentation for Event ID 141 on TechNet. + TaskDeleted = 141, + /// A user disabled Task Scheduler a task + /// For detailed information, see the documentation for Event ID 142 on TechNet. + TaskDisabled = 142, + /// Task Scheduler woke up the computer to run a task. + /// For detailed information, see the documentation for Event ID 145 on TechNet. + TaskStartedOnComputerWakeup = 145, + /// Task Scheduler failed to subscribe the event trigger for a task. + /// For detailed information, see the documentation for Event ID 150 on TechNet. + TaskEventSubscriptionFailed = 150, + /// Task Scheduler launched an action in an instance of a task. + /// For detailed information, see the documentation for Event ID 200 on TechNet. + ActionStart = 200, + /// Task Scheduler successfully completed a task instance and action. + /// For detailed information, see the documentation for Event ID 201 on TechNet. + ActionSuccess = 201, + /// Task Scheduler failed to complete an instance of a task with an action. + /// For detailed information, see the documentation for Event ID 202 on TechNet. + ActionFailure = 202, + /// Task Scheduler failed to launch an action in a task instance. + /// For detailed information, see the documentation for Event ID 203 on TechNet. + ActionLaunchFailure = 203, + /// Task Scheduler failed to retrieve the event triggering values for a task . The event will be ignored. + /// For detailed information, see the documentation for Event ID 204 on TechNet. + EventRenderFailed = 204, + /// Task Scheduler failed to match the pattern of events for a task. The events will be ignored. + /// For detailed information, see the documentation for Event ID 205 on TechNet. + EventAggregateFailed = 205, + /// Task Scheduler is shutting down the a task engine. + /// For detailed information, see the documentation for Event ID 301 on TechNet. + SessionExit = 301, + /// Task Scheduler is shutting down the a task engine due to an error. + /// For detailed information, see the documentation for Event ID 303 on TechNet. + SessionError = 303, + /// Task Scheduler sent a task to a task engine. + /// For detailed information, see the documentation for Event ID 304 on TechNet. + SessionSentJob = 304, + /// Task Scheduler did not send a task to a task engine. + /// For detailed information, see the documentation for Event ID 305 on TechNet. + SessionSentJobFailed = 305, + /// For a Task Scheduler task engine, the thread pool failed to process the message. + /// For detailed information, see the documentation for Event ID 306 on TechNet. + SessionFailedToProcessMessage = 306, + /// The Task Scheduler service failed to connect to a task engine process. + /// For detailed information, see the documentation for Event ID 307 on TechNet. + SessionManagerConnectFailed = 307, + /// Task Scheduler connected to a task engine process. + /// For detailed information, see the documentation for Event ID 308 on TechNet. + SessionConnected = 308, + /// There are Task Scheduler tasks orphaned during a task engine shutdown. + /// For detailed information, see the documentation for Event ID 309 on TechNet. + SessionJobsOrphaned = 309, + /// Task Scheduler started a task engine process. + /// For detailed information, see the documentation for Event ID 310 on TechNet. + SessionProcessStarted = 310, + /// Task Scheduler failed to start a task engine process due to an error. + /// For detailed information, see the documentation for Event ID 311 on TechNet. + SessionProcessLaunchFailed = 311, + /// Task Scheduler created the Win32 job object for a task engine. + /// For detailed information, see the documentation for Event ID 312 on TechNet. + SessionWin32ObjectCreated = 312, + /// The Task Scheduler channel is ready to send and receive messages. + /// For detailed information, see the documentation for Event ID 313 on TechNet. + SessionChannelReady = 313, + /// Task Scheduler has no tasks running for a task engine, and the idle timer has started. + /// For detailed information, see the documentation for Event ID 314 on TechNet. + SessionIdle = 314, + /// A task engine process failed to connect to the Task Scheduler service. + /// For detailed information, see the documentation for Event ID 315 on TechNet. + SessionProcessConnectFailed = 315, + /// A task engine failed to send a message to the Task Scheduler service. + /// For detailed information, see the documentation for Event ID 316 on TechNet. + SessionMessageSendFailed = 316, + /// Task Scheduler started a task engine process. + /// For detailed information, see the documentation for Event ID 317 on TechNet. + SessionProcessMainStarted = 317, + /// Task Scheduler shut down a task engine process. + /// For detailed information, see the documentation for Event ID 318 on TechNet. + SessionProcessMainShutdown = 318, + /// A task engine received a message from the Task Scheduler service requesting to launch a task. + /// For detailed information, see the documentation for Event ID 319 on TechNet. + SessionProcessReceivedStartJob = 319, + /// A task engine received a message from the Task Scheduler service requesting to stop a task instance. + /// For detailed information, see the documentation for Event ID 320 on TechNet. + SessionProcessReceivedStopJob = 320, + /// Task Scheduler did not launch a task because an instance of the same task is already running. + /// For detailed information, see the documentation for Event ID 322 on TechNet. + NewInstanceIgnored = 322, + /// Task Scheduler stopped an instance of a task in order to launch a new instance. + /// For detailed information, see the documentation for Event ID 323 on TechNet. + RunningInstanceStopped = 323, + /// Task Scheduler queued an instance of a task and will launch it as soon as another instance completes. + /// For detailed information, see the documentation for Event ID 324 on TechNet. + NewInstanceQueued = 324, + /// Task Scheduler queued an instance of a task that will launch immediately. + /// For detailed information, see the documentation for Event ID 325 on TechNet. + InstanceQueued = 325, + /// Task Scheduler did not launch a task because the computer is running on batteries. If launching the task on batteries is required, change the respective flag in the task configuration. + /// For detailed information, see the documentation for Event ID 326 on TechNet. + NoStartOnBatteries = 326, + /// Task Scheduler stopped an instance of a task because the computer is switching to battery power. + /// For detailed information, see the documentation for Event ID 327 on TechNet. + StoppingOnBatteries = 327, + /// Task Scheduler stopped an instance of a task because the computer is no longer idle. + /// For detailed information, see the documentation for Event ID 328 on TechNet. + StoppingOffIdle = 328, + /// Task Scheduler stopped an instance of a task because the task timed out. + /// For detailed information, see the documentation for Event ID 329 on TechNet. + StoppingOnTimeout = 329, + /// Task Scheduler stopped an instance of a task as request by a user . + /// For detailed information, see the documentation for Event ID 330 on TechNet. + StoppingOnRequest = 330, + /// Task Scheduler will continue to execute an instance of a task even after the designated timeout, due to a failure to create the timeout mechanism. + /// For detailed information, see the documentation for Event ID 331 on TechNet. + TimeoutWontWork = 331, + /// Task Scheduler did not launch a task because a user was not logged on when the launching conditions were met. Ensure the user is logged on or change the task definition to allow the task to launch when the user is logged off. + /// For detailed information, see the documentation for Event ID 332 on TechNet. + NoStartUserNotLoggedOn = 332, + /// The Task Scheduler service has started. + /// For detailed information, see the documentation for Event ID 400 on TechNet. + ScheduleServiceStart = 400, + /// The Task Scheduler service failed to start due to an error. + /// For detailed information, see the documentation for Event ID 401 on TechNet. + ScheduleServiceStartFailed = 401, + /// Task Scheduler service is shutting down. + /// For detailed information, see the documentation for Event ID 402 on TechNet. + ScheduleServiceStop = 402, + /// The Task Scheduler service has encountered an error. + /// For detailed information, see the documentation for Event ID 403 on TechNet. + ScheduleServiceError = 403, + /// The Task Scheduler service has encountered an RPC initialization error. + /// For detailed information, see the documentation for Event ID 404 on TechNet. + ScheduleServiceRpcInitError = 404, + /// The Task Scheduler service has failed to initialize COM. + /// For detailed information, see the documentation for Event ID 405 on TechNet. + ScheduleServiceComInitError = 405, + /// The Task Scheduler service failed to initialize the credentials store. + /// For detailed information, see the documentation for Event ID 406 on TechNet. + ScheduleServiceCredStoreInitError = 406, + /// Task Scheduler service failed to initialize LSA. + /// For detailed information, see the documentation for Event ID 407 on TechNet. + ScheduleServiceLsaInitError = 407, + /// Task Scheduler service failed to initialize idle state detection module. Idle tasks may not be started as required. + /// For detailed information, see the documentation for Event ID 408 on TechNet. + ScheduleServiceIdleServiceInitError = 408, + /// The Task Scheduler service failed to initialize a time change notification. System time updates may not be picked by the service and task schedules may not be updated. + /// For detailed information, see the documentation for Event ID 409 on TechNet. + ScheduleServiceTimeChangeInitError = 409, + /// Task Scheduler service received a time system change notification. + /// For detailed information, see the documentation for Event ID 411 on TechNet. + ScheduleServiceTimeChangeSignaled = 411, + /// Task Scheduler service failed to launch tasks triggered by computer startup. Restart the Task Scheduler service. + /// For detailed information, see the documentation for Event ID 412 on TechNet. + ScheduleServiceRunBootJobsFailed = 412, + /// Task Scheduler service started Task Compatibility module. + /// For detailed information, see the documentation for Event ID 700 on TechNet. + CompatStart = 700, + /// Task Scheduler service failed to start Task Compatibility module. Tasks may not be able to register on previous Window versions. + /// For detailed information, see the documentation for Event ID 701 on TechNet. + CompatStartFailed = 701, + /// Task Scheduler failed to initialize the RPC server for starting the Task Compatibility module. Tasks may not be able to register on previous Window versions. + /// For detailed information, see the documentation for Event ID 702 on TechNet. + CompatStartRpcFailed = 702, + /// Task Scheduler failed to initialize Net Schedule API for starting the Task Compatibility module. Tasks may not be able to register on previous Window versions. + /// For detailed information, see the documentation for Event ID 703 on TechNet. + CompatStartNetscheduleFailed = 703, + /// Task Scheduler failed to initialize LSA for starting the Task Compatibility module. Tasks may not be able to register on previous Window versions. + /// For detailed information, see the documentation for Event ID 704 on TechNet. + CompatStartLsaFailed = 704, + /// Task Scheduler failed to start directory monitoring for the Task Compatibility module. + /// For detailed information, see the documentation for Event ID 705 on TechNet. + CompatDirectoryMonitorFailed = 705, + /// Task Compatibility module failed to update a task to the required status. + /// For detailed information, see the documentation for Event ID 706 on TechNet. + CompatTaskStatusUpdateFailed = 706, + /// Task Compatibility module failed to delete a task. + /// For detailed information, see the documentation for Event ID 707 on TechNet. + CompatTaskDeleteFailed = 707, + /// Task Compatibility module failed to set a security descriptor for a task. + /// For detailed information, see the documentation for Event ID 708 on TechNet. + CompatTaskSetSdFailed = 708, + /// Task Compatibility module failed to update a task. + /// For detailed information, see the documentation for Event ID 709 on TechNet. + CompatTaskUpdateFailed = 709, + /// Task Compatibility module failed to upgrade existing tasks. Upgrade will be attempted again next time 'Task Scheduler' service starts. + /// For detailed information, see the documentation for Event ID 710 on TechNet. + CompatUpgradeStartFailed = 710, + /// Task Compatibility module failed to upgrade NetSchedule account. + /// For detailed information, see the documentation for Event ID 711 on TechNet. + CompatUpgradeNsAccountFailed = 711, + /// Task Compatibility module failed to read existing store to upgrade tasks. + /// For detailed information, see the documentation for Event ID 712 on TechNet. + CompatUpgradeStoreEnumFailed = 712, + /// Task Compatibility module failed to load a task for upgrade. + /// For detailed information, see the documentation for Event ID 713 on TechNet. + CompatUpgradeTaskLoadFailed = 713, + /// Task Compatibility module failed to register a task for upgrade. + /// For detailed information, see the documentation for Event ID 714 on TechNet. + CompatUpgradeTaskRegistrationFailed = 714, + /// Task Compatibility module failed to delete LSA store for upgrade. + /// For detailed information, see the documentation for Event ID 715 on TechNet. + CompatUpgradeLsaCleanupFailed = 715, + /// Task Compatibility module failed to upgrade existing scheduled tasks. + /// For detailed information, see the documentation for Event ID 716 on TechNet. + CompatUpgradeFailed = 716, + /// Task Compatibility module failed to determine if upgrade is needed. + /// For detailed information, see the documentation for Event ID 717 on TechNet. + CompatUpgradeNeedNotDetermined = 717, + /// Task scheduler was unable to upgrade the credential store from the Beta 2 version. You may need to re-register any tasks that require passwords. + /// For detailed information, see the documentation for Event ID 718 on TechNet. + VistaBeta2CredstoreUpgradeFailed = 718, + /// A unknown value. + Unknown = -2 + } + + /// + /// Historical event information for a task. This class wraps and extends the class. + /// + /// + /// For events on systems prior to Windows Vista, this class will only have information for the TaskPath, TimeCreated and EventId properties. + /// + [PublicAPI] + public sealed class TaskEvent : IComparable + { + internal TaskEvent([NotNull] EventRecord rec) + { + EventId = rec.Id; + EventRecord = rec; + Version = rec.Version; + TaskCategory = rec.TaskDisplayName; + OpCode = rec.OpcodeDisplayName; + TimeCreated = rec.TimeCreated; + RecordId = rec.RecordId; + ActivityId = rec.ActivityId; + Level = rec.LevelDisplayName; + UserId = rec.UserId; + ProcessId = rec.ProcessId; + TaskPath = rec.Properties.Count > 0 ? rec.Properties[0]?.Value?.ToString() : null; + DataValues = new EventDataValues(rec as EventLogRecord); + } + + internal TaskEvent([NotNull] string taskPath, StandardTaskEventId id, DateTime time) + { + EventId = (int)id; + TaskPath = taskPath; + TimeCreated = time; + } + + /// + /// Gets the activity id. This value is null for V1 events. + /// + public Guid? ActivityId { get; internal set; } + + /// + /// An indexer that gets the value of each of the data item values. This value is null for V1 events. + /// + /// + /// The data values. + /// + public EventDataValues DataValues { get; } + + /// + /// Gets the event id. + /// + public int EventId { get; internal set; } + + /// + /// Gets the underlying . This value is null for V1 events. + /// + public EventRecord EventRecord { get; internal set; } + + /// + /// Gets the from the . + /// + /// + /// The . If not found, returns . + /// + public StandardTaskEventId StandardEventId + { + get + { + if (Enum.IsDefined(typeof(StandardTaskEventId), EventId)) + return (StandardTaskEventId)EventId; + return StandardTaskEventId.Unknown; + } + } + + /// + /// Gets the level. This value is null for V1 events. + /// + public string Level { get; internal set; } + + /// + /// Gets the op code. This value is null for V1 events. + /// + public string OpCode { get; internal set; } + + /// + /// Gets the process id. This value is null for V1 events. + /// + public int? ProcessId { get; internal set; } + + /// + /// Gets the record id. This value is null for V1 events. + /// + public long? RecordId { get; internal set; } + + /// + /// Gets the task category. This value is null for V1 events. + /// + public string TaskCategory { get; internal set; } + + /// + /// Gets the task path. + /// + public string TaskPath { get; internal set; } + + /// + /// Gets the time created. + /// + public DateTime? TimeCreated { get; internal set; } + + /// + /// Gets the user id. This value is null for V1 events. + /// + public System.Security.Principal.SecurityIdentifier UserId { get; internal set; } + + /// + /// Gets the version. This value is null for V1 events. + /// + public byte? Version { get; internal set; } + + /// + /// Gets the data value from the task specific event data item list. + /// + /// The name of the data element. + /// Contents of the requested data element if found. null if no value found. + [Obsolete("Use the DataVales property instead.")] + public string GetDataValue(string name) => DataValues?[name]; + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() => EventRecord?.FormatDescription() ?? TaskPath; + + /// + /// Compares the current object with another object of the same type. + /// + /// An object to compare with this object. + /// + /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the other parameter.Zero This object is equal to other. Greater than zero This object is greater than other. + /// + public int CompareTo(TaskEvent other) + { + int i = string.Compare(TaskPath, other.TaskPath, StringComparison.Ordinal); + if (i == 0 && EventRecord != null) + { + i = string.Compare(ActivityId.ToString(), other.ActivityId.ToString(), StringComparison.Ordinal); + if (i == 0) + i = Convert.ToInt32(RecordId - other.RecordId); + } + return i; + } + + /// + /// Get indexer class for data values. + /// + public class EventDataValues + { + private readonly EventLogRecord rec; + + internal EventDataValues(EventLogRecord eventRec) + { + rec = eventRec; + } + + /// + /// Gets the value of the specified property name. + /// + /// + /// The value. + /// + /// Name of the property. + /// Value of the specified property name. null if property does not exist. + public string this[string propertyName] + { + get + { + var propsel = new EventLogPropertySelector(new[] {$"Event/EventData/Data[@Name='{propertyName}']"}); + try + { + var logEventProps = rec.GetPropertyValues(propsel); + return logEventProps[0].ToString(); + } + catch { } + return null; + } + } + } + } + + /// + /// An enumerator over a task's history of events. + /// + public sealed class TaskEventEnumerator : IEnumerator + { + private EventRecord curRec; + private EventLogReader log; + + internal TaskEventEnumerator([NotNull] EventLogReader log) + { + this.log = log; + } + + /// + /// Gets the element in the collection at the current position of the enumerator. + /// + /// + /// The element in the collection at the current position of the enumerator. + /// + public TaskEvent Current => new TaskEvent(curRec); + + /// + /// Gets the element in the collection at the current position of the enumerator. + /// + /// + /// The element in the collection at the current position of the enumerator. + /// + object System.Collections.IEnumerator.Current => Current; + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + log.CancelReading(); + log.Dispose(); + log = null; + } + + /// + /// Advances the enumerator to the next element of the collection. + /// + /// + /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. + /// + /// + /// The collection was modified after the enumerator was created. + /// + public bool MoveNext() => (curRec = log.ReadEvent()) != null; + + /// + /// Sets the enumerator to its initial position, which is before the first element in the collection. + /// + /// + /// The collection was modified after the enumerator was created. + /// + public void Reset() + { + log.Seek(System.IO.SeekOrigin.Begin, 0L); + } + + /// + /// Seeks the specified bookmark. + /// + /// The bookmark. + /// The offset. + public void Seek(EventBookmark bookmark, long offset = 0L) + { + log.Seek(bookmark, offset); + } + + /// + /// Seeks the specified origin. + /// + /// The origin. + /// The offset. + public void Seek(System.IO.SeekOrigin origin, long offset) + { + log.Seek(origin, offset); + } + } + + /// + /// Historical event log for a task. Only available for Windows Vista and Windows Server 2008 and later systems. + /// + /// Many applications have the need to audit the execution of the tasks they supply. To enable this, the library provides the TaskEventLog class that allows for TaskEvent instances to be enumerated. This can be done for single tasks or the entire system. It can also be filtered by specific events or criticality. + /// + public sealed class TaskEventLog : IEnumerable + { + private const string TSEventLogPath = "Microsoft-Windows-TaskScheduler/Operational"; + private static readonly bool IsVistaOrLater = Environment.OSVersion.Version.Major >= 6; + + /// + /// Initializes a new instance of the class. + /// + /// The task path. This can be retrieved using the property. + /// Thrown when instantiated on an OS prior to Windows Vista. + public TaskEventLog([CanBeNull] string taskPath) : this(".", taskPath) + { + Initialize(".", BuildQuery(taskPath), true); + } + + /// + /// Initializes a new instance of the class. + /// + /// Name of the machine. + /// The task path. This can be retrieved using the property. + /// The domain. + /// The user. + /// The password. + /// Thrown when instantiated on an OS prior to Windows Vista. + public TaskEventLog([NotNull] string machineName, [CanBeNull] string taskPath, string domain = null, string user = null, string password = null) + { + Initialize(machineName, BuildQuery(taskPath), true, domain, user, password); + } + + /// + /// Initializes a new instance of the class that looks at all task events from a specified time. + /// + /// The start time. + /// Name of the task. + /// Name of the machine (optional). + /// The domain. + /// The user. + /// The password. + public TaskEventLog(DateTime startTime, string taskName = null, string machineName = null, string domain = null, string user = null, string password = null) + { + int[] numArray = new int[] { 100, 102, 103, 107, 108, 109, 111, 117, 118, 119, 120, 121, 122, 123, 124, 125 }; + Initialize(machineName, BuildQuery(taskName, numArray, startTime), false, domain, user, password); + } + + /// + /// Initializes a new instance of the class. + /// + /// Name of the task. + /// The event ids. + /// The start time. + /// Name of the machine (optional). + /// The domain. + /// The user. + /// The password. + public TaskEventLog(string taskName = null, int[] eventIDs = null, DateTime? startTime = null, string machineName = null, string domain = null, string user = null, string password = null) + { + Initialize(machineName, BuildQuery(taskName, eventIDs, startTime), true, domain, user, password); + } + + /// + /// Initializes a new instance of the class. + /// + /// Name of the task. + /// The event ids. + /// The levels. + /// The start time. + /// Name of the machine (optional). + /// The domain. + /// The user. + /// The password. + public TaskEventLog(string taskName = null, int[] eventIDs = null, int[] levels = null, DateTime? startTime = null, string machineName = null, string domain = null, string user = null, string password = null) + { + Initialize(machineName, BuildQuery(taskName, eventIDs, startTime, levels), true, domain, user, password); + } + + internal static string BuildQuery(string taskName = null, int[] eventIDs = null, DateTime? startTime = null, int[] levels = null) + { + const string queryString = + "" + + " " + + " " + + " " + + ""; + const string OR = " or "; + const string AND = " and "; + + System.Text.StringBuilder sb = new System.Text.StringBuilder("*"); + if (eventIDs != null && eventIDs.Length > 0) + { + if (sb.Length > 1) sb.Append(AND); + sb.AppendFormat("({0})", string.Join(OR, Array.ConvertAll(eventIDs, i => $"EventID={i}"))); + } + if (levels != null && levels.Length > 0) + { + if (sb.Length > 1) sb.Append(AND); + sb.AppendFormat("({0})", string.Join(OR, Array.ConvertAll(levels, i => $"Level={i}"))); + } + if (startTime.HasValue) + { + if (sb.Length > 1) sb.Append(AND); + sb.AppendFormat("TimeCreated[@SystemTime>='{0}']", System.Xml.XmlConvert.ToString(startTime.Value, System.Xml.XmlDateTimeSerializationMode.RoundtripKind)); + } + if (sb.Length > 1) + { + sb.Insert(1, "[System[Provider[@Name='Microsoft-Windows-TaskScheduler'] and "); + sb.Append(']'); + } + if (!string.IsNullOrEmpty(taskName)) + { + if (sb.Length == 1) + sb.Append('['); + else + sb.Append("]" + AND + "*["); + sb.AppendFormat("EventData[Data[@Name='TaskName']='{0}']", taskName); + } + if (sb.Length > 1) + sb.Append(']'); + return string.Format(queryString, sb); + } + + private void Initialize(string machineName, string query, bool revDir, string domain = null, string user = null, string password = null) + { + if (!IsVistaOrLater) + throw new NotSupportedException("Enumeration of task history not available on systems prior to Windows Vista and Windows Server 2008."); + + System.Security.SecureString spwd = null; + if (password != null) + { + spwd = new System.Security.SecureString(); + foreach (char c in password) + spwd.AppendChar(c); + } + + Query = new EventLogQuery(TSEventLogPath, PathType.LogName, query) { ReverseDirection = revDir }; + if (machineName != null && machineName != "." && !machineName.Equals(Environment.MachineName, StringComparison.InvariantCultureIgnoreCase)) + Query.Session = new EventLogSession(machineName, domain, user, spwd, SessionAuthentication.Default); + } + + /// + /// Gets the total number of events for this task. + /// + public long Count + { + get + { + using (EventLogReader log = new EventLogReader(Query)) + { + long seed = 64L, l = 0L, h = seed; + while (log.ReadEvent() != null) + log.Seek(System.IO.SeekOrigin.Begin, l += seed); + bool foundLast = false; + while (l > 0L && h >= 1L) + { + if (foundLast) + l += (h /= 2L); + else + l -= (h /= 2L); + log.Seek(System.IO.SeekOrigin.Begin, l); + foundLast = (log.ReadEvent() != null); + } + return foundLast ? l + 1L : l; + } + } + } + + /// + /// Gets or sets a value indicating whether this is enabled. + /// + /// + /// true if enabled; otherwise, false. + /// + public bool Enabled + { + get + { + if (!IsVistaOrLater) + return false; + using (var cfg = new EventLogConfiguration(TSEventLogPath, Query.Session)) + return cfg.IsEnabled; + } + set + { + if (!IsVistaOrLater) + throw new NotSupportedException("Task history not available on systems prior to Windows Vista and Windows Server 2008."); + using (var cfg = new EventLogConfiguration(TSEventLogPath, Query.Session)) + { + if (cfg.IsEnabled != value) + { + cfg.IsEnabled = value; + cfg.SaveChanges(); + } + } + } + } + + /// + /// Gets or sets a value indicating whether to enumerate in reverse when calling the default enumerator (typically with foreach statement). + /// + /// + /// true if enumerates in reverse (newest to oldest) by default; otherwise, false to enumerate oldest to newest. + /// + [System.ComponentModel.DefaultValue(false)] + public bool EnumerateInReverse { get; set; } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// A that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(EnumerateInReverse); + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// if set to true reverse. + /// + /// A that can be used to iterate through the collection. + /// + [NotNull] + public TaskEventEnumerator GetEnumerator(bool reverse) + { + Query.ReverseDirection = !reverse; + return new TaskEventEnumerator(new EventLogReader(Query)); + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(false); + + internal EventLogQuery Query { get; private set; } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/TaskEventWatcher.cs b/FlashPatcher/TaskService/TaskEventWatcher.cs new file mode 100644 index 0000000..052d7ad --- /dev/null +++ b/FlashPatcher/TaskService/TaskEventWatcher.cs @@ -0,0 +1,815 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Diagnostics.Eventing.Reader; +using System.IO; +using JetBrains.Annotations; + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Information about the task event. + /// + [PublicAPI] + public class TaskEventArgs : EventArgs + { + private readonly TaskService taskService; + + internal TaskEventArgs([NotNull] TaskEvent evt, TaskService ts = null) + { + TaskEvent = evt; + TaskPath = evt.TaskPath; + taskService = ts; + } + + /// + /// If possible, gets the task associated with this event. + /// + /// + /// The task or null if unable to retrieve. + /// + public Task Task + { + get { try { return taskService?.GetTask(TaskPath); } catch { return null; } } + } + + /// + /// Gets the . + /// + /// + /// The TaskEvent. + /// + [NotNull] + public TaskEvent TaskEvent { get; } + + /// + /// Gets the task name. + /// + /// + /// The task name. + /// + public string TaskName => Path.GetFileName(TaskPath); + + /// + /// Gets the task path. + /// + /// + /// The task path. + /// + public string TaskPath { get; } + } + + /// + /// Watches system events related to tasks and issues a event when the filtered conditions are met. + /// Only available for Task Scheduler 2.0 on Windows Vista or Windows Server 2003 and later. + /// + /// Sometimes, a developer will need to know about events as they occur. In this case, they can use the TaskEventWatcher component that enables the developer to watch a task, a folder, or the entire system for filtered events. + /// + /// Below is information on how to watch a folder for all task events. For a complete example, look at this sample project: TestTaskWatcher.zip + /// + [DefaultEvent(nameof(EventRecorded)), DefaultProperty(nameof(Folder))] +#if DESIGNER + [Designer(typeof(Design.TaskEventWatcherDesigner))] +#endif + [ToolboxItem(true), Serializable] + [PublicAPI] + public class TaskEventWatcher : Component, ISupportInitialize + { + private const string root = "\\"; + private const string star = "*"; + + private static readonly TimeSpan MaxV1EventLapse = TimeSpan.FromSeconds(1); + + private bool disposed; + private bool enabled; + private string folder = root; + private bool includeSubfolders; + private bool initializing; + private StandardTaskEventId lastId = 0; + private DateTime lastIdTime = DateTime.MinValue; + private TaskService ts; + private FileSystemWatcher v1Watcher; + private EventLogWatcher watcher; + private ISynchronizeInvoke synchronizingObject; + + /// + /// Initializes a new instance of the class. If other + /// properties are not set, this will watch for all events for all tasks on the local machine. + /// + public TaskEventWatcher() : this(TaskService.Instance) + { + } + + /// + /// Initializes a new instance of the class watching only + /// those events for the task with the provided path on the local machine. + /// + /// The full path (folders and name) of the task to watch. + /// The task service. + /// $Invalid task name: {taskPath} + public TaskEventWatcher(string taskPath, TaskService taskService = null) : this(taskService ?? TaskService.Instance) + { + InitTask(taskPath); + } + + /// + /// Initializes a new instance of the class watching only + /// those events for the specified task. + /// + /// The task to watch. + /// Occurs if the is null. + public TaskEventWatcher([NotNull] Task task) : this(task?.TaskService) + { + if (task == null) + throw new ArgumentNullException(nameof(task)); + InitTask(task); + } + + /// + /// Initializes a new instance of the class watching only those events for + /// the tasks whose name matches the in the specified + /// and optionally all subfolders. + /// + /// The task folder to watch. + /// The filter for task names using standard file system wildcards. Use "*" to include all tasks. + /// if set to true include events from tasks subfolders. + /// Occurs if the is null. + public TaskEventWatcher([NotNull] TaskFolder taskFolder, string taskFilter = "*", bool includeSubfolders = false) : this(taskFolder?.TaskService) + { + if (taskFolder == null) + throw new ArgumentNullException(nameof(taskFolder)); + InitTask(taskFolder, taskFilter, includeSubfolders); + } + + /// + /// Initializes a new instance of the class. + /// + /// The task folder to watch. + /// The filter for task names using standard file system wildcards. Use "*" to include all tasks. + /// if set to true include events from tasks subfolders. + /// The task service. + public TaskEventWatcher(string folder, string taskFilter, bool includeSubfolders, TaskService taskService = null) : this(taskService ?? TaskService.Instance) + { + InitTask(folder, taskFilter, includeSubfolders); + } + + /// + /// Initializes a new instance of the class on a remote machine. + /// + /// Name of the remote machine. + /// The task path. + /// The domain of the user account. + /// The user name with permissions on the remote machine. + /// The password for the user. + public TaskEventWatcher(string machineName, string taskPath, string domain = null, string user = null, string password = null) : this(new TaskService(machineName, user, domain, password)) + { + InitTask(taskPath); + } + + /// + /// Initializes a new instance of the class on a remote machine. + /// + /// Name of the remote machine. + /// The task folder to watch. + /// The filter for task names using standard file system wildcards. Use "*" to include all tasks. + /// if set to true include events from tasks subfolders. + /// The domain of the user account. + /// The user name with permissions on the remote machine. + /// The password for the user. + public TaskEventWatcher(string machineName, string folder, string taskFilter = "*", bool includeSubfolders = false, string domain = null, string user = null, string password = null) : this(new TaskService(machineName, user, domain, password)) + { + InitTask(folder, taskFilter, includeSubfolders); + } + + private TaskEventWatcher(TaskService ts) + { + TaskService = ts; + Filter = new EventFilter(this); + } + + /// + /// Occurs when a task or the task engine records an event. + /// + [Category("Action"), Description("Event recorded by a task or the task engine.")] + public event EventHandler EventRecorded; + + /// + /// Gets or sets a value indicating whether the component is enabled. + /// + /// + /// true if enabled; otherwise, false. + /// + [DefaultValue(false), Category("Behavior"), Description("Indicates whether the component is enabled.")] + public bool Enabled + { + get { return enabled; } + set + { + if (enabled != value) + { + System.Diagnostics.Debug.WriteLine($"TaskEventWather: Set {nameof(Enabled)} = {value}"); + enabled = value; + if (!IsSuspended()) + { + if (enabled) + StartRaisingEvents(); + else + StopRaisingEvents(); + } + } + } + } + + /// + /// Gets the filter for this . + /// + /// + /// The filter. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Category("Behavior"), Description("Indicates the filter for the watcher.")] + public EventFilter Filter { get; } + + /// + /// Gets or sets the folder to watch. + /// + /// + /// The folder path to watch. This value should include the leading "\" to indicate the root folder. + /// + /// Thrown if the folder specified does not exist or contains invalid characters. + [DefaultValue(root), Category("Behavior"), Description("Indicates the folder to watch.")] + public string Folder + { + get { return folder; } + set + { + if (string.IsNullOrEmpty(value)) + value = root; + if (!value.EndsWith("\\")) + value += "\\"; + if (string.Compare(folder, value, StringComparison.OrdinalIgnoreCase) == 0) return; + if ((DesignMode && (value.IndexOfAny(new[] { '*', '?' }) != -1 || value.IndexOfAny(Path.GetInvalidPathChars()) != -1)) || (TaskService.GetFolder(value == root ? value : value.TrimEnd('\\')) == null)) + throw new ArgumentException($"Invalid folder name: {value}"); + folder = value; + } + } + + /// + /// Gets or sets a value indicating whether to include events from subfolders when the + /// property is set. If the property is set, + /// this property is ignored. + /// + /// true if include events from subfolders; otherwise, false. + [DefaultValue(false), Category("Behavior"), Description("Indicates whether to include events from subfolders.")] + public bool IncludeSubfolders + { + get { return includeSubfolders; } + set + { + if (includeSubfolders == value) return; + includeSubfolders = value; + Restart(); + } + } + + /// + /// Gets or sets the synchronizing object. + /// + /// + /// The synchronizing object. + /// + [Browsable(false), DefaultValue(null)] + public ISynchronizeInvoke SynchronizingObject + { + get + { + if (synchronizingObject == null && DesignMode) + { + var so = ((IDesignerHost)GetService(typeof(IDesignerHost)))?.RootComponent as ISynchronizeInvoke; + if (so != null) + synchronizingObject = so; + } + return synchronizingObject; + } + set { synchronizingObject = value; } + } + + /// + /// Gets or sets the name of the computer that is running the Task Scheduler service that the user is connected to. + /// + [Category("Connection"), Description("The name of the computer to connect to."), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string TargetServer + { + get { return TaskService.TargetServer; } + set + { + if (value == null || value.Trim() == string.Empty) value = null; + if (string.Compare(value, TaskService.TargetServer, StringComparison.OrdinalIgnoreCase) == 0) return; + TaskService.TargetServer = value; + Restart(); + } + } + + /// + /// Gets or sets the instance associated with this event watcher. Setting this value + /// will override any values set for , , + /// , and and set them to those values in the supplied + /// instance. + /// + /// The TaskService. + [Category("Data"), Description("The TaskService for this event watcher.")] + public TaskService TaskService + { + get { return ts; } + set { ts = value; Restart(); } + } + + /// + /// Gets or sets the user account domain to be used when connecting to the . + /// + /// The user account domain. + [Category("Connection"), Description("The user account domain to be used when connecting."), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string UserAccountDomain + { + get { return TaskService.UserAccountDomain; } + set + { + if (value == null || value.Trim() == string.Empty) value = null; + if (string.Compare(value, TaskService.UserAccountDomain, StringComparison.OrdinalIgnoreCase) == 0) return; + TaskService.UserAccountDomain = value; + Restart(); + } + } + + /// + /// Gets or sets the user name to be used when connecting to the . + /// + /// The user name. + [Category("Connection"), Description("The user name to be used when connecting."), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string UserName + { + get { return TaskService.UserName; } + set + { + if (value == null || value.Trim() == string.Empty) value = null; + if (string.Compare(value, TaskService.UserName, StringComparison.OrdinalIgnoreCase) == 0) return; + TaskService.UserName = value; + Restart(); + } + } + + /// + /// Gets or sets the user password to be used when connecting to the . + /// + /// The user password. + [Category("Connection"), Description("The user password to be used when connecting."), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string UserPassword + { + get { return TaskService.UserPassword; } + set + { + if (value == null || value.Trim() == string.Empty) value = null; + if (string.Compare(value, TaskService.UserPassword, StringComparison.OrdinalIgnoreCase) == 0) return; + TaskService.UserPassword = value; + Restart(); + } + } + + /// + /// Gets a value indicating if watching is available. + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + private bool IsHandleInvalid => IsV1 ? v1Watcher == null : watcher == null; + + private static bool IsV1 => Environment.OSVersion.Version.Major < 6; + + /// + /// Signals the object that initialization is starting. + /// + public void BeginInit() + { + System.Diagnostics.Debug.WriteLine($"TaskEventWather: {nameof(BeginInit)}"); + initializing = true; + var localEnabled = enabled; + StopRaisingEvents(); + enabled = localEnabled; + TaskService.BeginInit(); + } + + /// + /// Signals the object that initialization is complete. + /// + public void EndInit() + { + System.Diagnostics.Debug.WriteLine($"TaskEventWather: {nameof(EndInit)}"); + initializing = false; + TaskService.EndInit(); + if (enabled) + StartRaisingEvents(); + } + + /// + /// Releases the unmanaged resources used by the FileSystemWatcher and optionally releases the managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected override void Dispose(bool disposing) + { + try + { + if (disposing) + { + StopRaisingEvents(); + TaskService = null; + } + else + { + StopListening(); + } + } + finally + { + disposed = true; + base.Dispose(disposing); + } + } + + /// + /// Fires the event. + /// + /// The sender. + /// The instance containing the event data. + protected virtual void OnEventRecorded(object sender, TaskEventArgs e) + { + var h = EventRecorded; + if (h == null) return; + if (SynchronizingObject != null && SynchronizingObject.InvokeRequired) + SynchronizingObject.BeginInvoke(h, new object[] { this, e }); + else + h(sender, e); + } + + private void InitTask([NotNull] Task task) + { + Filter.TaskName = task.Name; + Folder = task.Folder.Path; + } + + private void InitTask(TaskFolder taskFolder, string taskFilter, bool includeSubfolders) + { + this.includeSubfolders = includeSubfolders; + Filter.TaskName = taskFilter; + Folder = taskFolder?.Path; + } + + private void InitTask(string taskFolder, string taskFilter, bool includeSubfolders) + { + this.includeSubfolders = includeSubfolders; + Filter.TaskName = taskFilter; + Folder = taskFolder; + } + + private void InitTask(string taskPath) + { + Filter.TaskName = Path.GetFileNameWithoutExtension(taskPath); + Folder = Path.GetDirectoryName(taskPath); + } + + private bool IsSuspended() => initializing || DesignMode; + + private void ReleaseWatcher() + { + if (IsV1) + { + if (v1Watcher == null) return; + v1Watcher.EnableRaisingEvents = false; + v1Watcher.Changed -= Watcher_DirectoryChanged; + v1Watcher.Created -= Watcher_DirectoryChanged; + v1Watcher.Deleted -= Watcher_DirectoryChanged; + v1Watcher.Renamed -= Watcher_DirectoryChanged; + v1Watcher = null; + } + else + { + if (watcher == null) return; + watcher.Enabled = false; + watcher.EventRecordWritten -= Watcher_EventRecordWritten; + watcher = null; + } + } + + private void ResetTaskService() { ts = TaskService.Instance; } + + private void Restart() + { + if (IsSuspended() || !enabled) return; + System.Diagnostics.Debug.WriteLine($"TaskEventWather: {nameof(Restart)}"); + StopRaisingEvents(); + StartRaisingEvents(); + } + + private void SetupWatcher() + { + ReleaseWatcher(); + string taskPath = null; + if (Filter.Wildcard == null) + taskPath = Path.Combine(folder, Filter.TaskName); + if (IsV1) + { + var di = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.System)); + string dir = di.Parent != null ? Path.Combine(di.Parent.FullName, "Tasks") : "Tasks"; + v1Watcher = new FileSystemWatcher(dir, "*.job") { NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.Attributes }; + v1Watcher.Changed += Watcher_DirectoryChanged; + v1Watcher.Created += Watcher_DirectoryChanged; + v1Watcher.Deleted += Watcher_DirectoryChanged; + v1Watcher.Renamed += Watcher_DirectoryChanged; + } + else + { + var log = new TaskEventLog(taskPath, Filter.EventIds, Filter.EventLevels, DateTime.UtcNow, TargetServer, UserAccountDomain, UserName, UserPassword); + log.Query.ReverseDirection = false; + watcher = new EventLogWatcher(log.Query); + watcher.EventRecordWritten += Watcher_EventRecordWritten; + } + } + + private bool ShouldSerializeFilter() => Filter.ShouldSerialize(); + + private bool ShouldSerializeTaskService() => !Equals(TaskService, TaskService.Instance); + + private void StartRaisingEvents() + { + if (disposed) + throw new ObjectDisposedException(GetType().Name); + + if (IsSuspended()) return; + System.Diagnostics.Debug.WriteLine($"TaskEventWather: {nameof(StartRaisingEvents)}"); + enabled = true; + SetupWatcher(); + if (IsV1) + try { v1Watcher.EnableRaisingEvents = true; } catch { } + else + try { watcher.Enabled = true; } catch { } + } + + private void StopListening() + { + enabled = false; + ReleaseWatcher(); + } + + private void StopRaisingEvents() + { + System.Diagnostics.Debug.WriteLine($"TaskEventWather: {nameof(StopRaisingEvents)}"); + if (IsSuspended()) + enabled = false; + else if (!IsHandleInvalid) + StopListening(); + } + + private void Watcher_DirectoryChanged(object sender, FileSystemEventArgs e) + { + StandardTaskEventId id = StandardTaskEventId.TaskUpdated; + if (e.ChangeType == WatcherChangeTypes.Deleted) + id = StandardTaskEventId.TaskDeleted; + else if (e.ChangeType == WatcherChangeTypes.Created) + id = StandardTaskEventId.JobRegistered; + if (lastId == id && DateTime.Now.Subtract(lastIdTime) <= MaxV1EventLapse) return; + OnEventRecorded(this, new TaskEventArgs(new TaskEvent(Path.Combine("\\", e.Name.Replace(".job", "")), id, DateTime.Now), TaskService)); + lastId = id; + lastIdTime = DateTime.Now; + } + + private void Watcher_EventRecordWritten(object sender, EventRecordWrittenEventArgs e) + { + try + { + var taskEvent = new TaskEvent(e.EventRecord); + System.Diagnostics.Debug.WriteLine("Task event: " + taskEvent.ToString()); + + // Get the task name and folder + if (string.IsNullOrEmpty(taskEvent.TaskPath)) return; + int cpos = taskEvent.TaskPath.LastIndexOf('\\'); + string name = taskEvent.TaskPath.Substring(cpos + 1); + string fld = taskEvent.TaskPath.Substring(0, cpos + 1); + + // Check folder and name filters + if (!string.IsNullOrEmpty(Filter.TaskName) && string.Compare(Filter.TaskName, taskEvent.TaskPath, StringComparison.OrdinalIgnoreCase) != 0) + { + if (Filter.Wildcard != null && !Filter.Wildcard.IsMatch(name)) + return; + if (IncludeSubfolders && !fld.StartsWith(folder, StringComparison.OrdinalIgnoreCase)) + return; + if (!IncludeSubfolders && string.Compare(folder, fld, StringComparison.OrdinalIgnoreCase) != 0) + return; + } + + OnEventRecorded(this, new TaskEventArgs(taskEvent, TaskService)); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"{nameof(Watcher_EventRecordWritten)} has failed. Error: {ex.ToString()}"); + } + } + + /// + /// Holds filter information for a . + /// + [TypeConverter(typeof(ExpandableObjectConverter)), Serializable] + [PublicAPI] + public class EventFilter + { + private string filter = star; + private int[] ids; + private int[] levels; + private readonly TaskEventWatcher parent; + + internal EventFilter([NotNull] TaskEventWatcher parent) + { + this.parent = parent; + } + + /// + /// Gets or sets an optional array of event identifiers to use when filtering those events that will fire a event. + /// + /// + /// The array of event identifier filters. All know task event identifiers are declared in the enumeration. + /// + [DefaultValue(null), Category("Filter"), Description("An array of event identifiers to use when filtering.")] + public int[] EventIds + { + get { return ids; } + set + { + if (ids != value) + { + ids = value; + parent.Restart(); + } + } + } + + /// + /// Gets or sets an optional array of event levels to use when filtering those events that will fire a event. + /// + /// + /// The array of event levels. While event providers can define custom levels, most will use integers defined in the System.Diagnostics.Eventing.Reader.StandardEventLevel enumeration. + /// + [DefaultValue(null), Category("Filter"), Description("An array of event levels to use when filtering.")] + public int[] EventLevels + { + get { return levels; } + set + { + if (levels != value) + { + levels = value; + parent.Restart(); + } + } + } + + /// + /// Gets or sets the task name, which can utilize wildcards, to look for when watching a folder. + /// + /// A task name or wildcard. + [DefaultValue(star), Category("Filter"), Description("A task name, which can utilize wildcards, for filtering.")] + public string TaskName + { + get { return filter; } + set + { + if (string.IsNullOrEmpty(value)) + value = star; + if (string.Compare(filter, value, StringComparison.OrdinalIgnoreCase) != 0) + { + filter = value; + Wildcard = (value.IndexOfAny(new[] { '?', '*' }) == -1) ? null : new Wildcard(value); + parent.Restart(); + } + } + } + + internal Wildcard Wildcard { get; private set; } = new Wildcard(star); + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() => filter + (levels == null ? "" : " +levels") + (ids == null ? "" : " +id's"); + + internal bool ShouldSerialize() => ids != null || levels != null || filter != star; + } + } + +#if DESIGNER + namespace Design + { + internal class TaskEventWatcherDesigner : ComponentDesigner + { + public override void InitializeNewComponent(IDictionary defaultValues) + { + base.InitializeNewComponent(defaultValues); + var refs = GetService(); + var tsColl = refs?.GetReferences(typeof(TaskService)); + System.Diagnostics.Debug.Assert(refs != null && tsColl != null && tsColl.Length > 0, "Designer couldn't find host, reference service, or existing TaskService."); + if (tsColl != null && tsColl.Length > 0) + { + TaskEventWatcher tsComp = Component as TaskEventWatcher; + TaskService ts = tsColl[0] as TaskService; + if (tsComp != null) + tsComp.TaskService = ts; + } + } + + protected virtual T GetService() => (T)Component?.Site?.GetService(typeof(T)); + } + } +#endif +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/TaskFolder.cs b/FlashPatcher/TaskService/TaskFolder.cs new file mode 100644 index 0000000..9bc60e0 --- /dev/null +++ b/FlashPatcher/TaskService/TaskFolder.cs @@ -0,0 +1,633 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.AccessControl; +using System.Text.RegularExpressions; +using JetBrains.Annotations; +using Microsoft.Win32.TaskScheduler.V1Interop; +using Microsoft.Win32.TaskScheduler.V2Interop; + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Provides the methods that are used to register (create) tasks in the folder, remove tasks from the folder, and create or remove subfolders from the folder. + /// + [PublicAPI] + public sealed class TaskFolder : IDisposable, IComparable + { + private ITaskScheduler v1List; + private readonly ITaskFolder v2Folder; + + internal const string rootString = @"\"; + + internal TaskFolder([NotNull] TaskService svc) + { + TaskService = svc; + v1List = svc.v1TaskScheduler; + } + + internal TaskFolder([NotNull] TaskService svc, [NotNull] ITaskFolder iFldr) + { + TaskService = svc; + v2Folder = iFldr; + } + + /// + /// Releases all resources used by this class. + /// + public void Dispose() + { + if (v2Folder != null) + Marshal.ReleaseComObject(v2Folder); + v1List = null; + } + + /// + /// Gets a which enumerates all the tasks in this and all subfolders. + /// + /// + /// A for all instances. + /// + [NotNull, ItemNotNull] + public IEnumerable AllTasks => EnumerateFolderTasks(this); + + /// + /// Gets the name that is used to identify the folder that contains a task. + /// + [NotNull] + public string Name => (v2Folder == null) ? rootString : v2Folder.Name; + + /// + /// Gets the parent folder of this folder. + /// + /// + /// The parent folder, or null if this folder is the root folder. + /// + public TaskFolder Parent + { + get + { + // V1 only has the root folder + if (v2Folder == null) + return null; + + string path = v2Folder.Path; + string parentPath = System.IO.Path.GetDirectoryName(path); + if (string.IsNullOrEmpty(parentPath)) + return null; + return TaskService.GetFolder(parentPath); + } + } + + /// + /// Gets the path to where the folder is stored. + /// + [NotNull] + public string Path => (v2Folder == null) ? rootString : v2Folder.Path; + + [NotNull] + internal TaskFolder GetFolder([NotNull] string path) + { + if (v2Folder != null) + return new TaskFolder(TaskService, v2Folder.GetFolder(path)); + throw new NotV1SupportedException(); + } + + /// + /// Gets or sets the security descriptor of the task. + /// + /// The security descriptor. + [Obsolete("This property will be removed in deference to the GetAccessControl, GetSecurityDescriptorSddlForm, SetAccessControl and SetSecurityDescriptorSddlForm methods.")] + public GenericSecurityDescriptor SecurityDescriptor + { +#pragma warning disable 0618 + get { return GetSecurityDescriptor(); } + set { SetSecurityDescriptor(value); } +#pragma warning restore 0618 + } + + /// + /// Gets all the subfolders in the folder. + /// + [NotNull, ItemNotNull] + public TaskFolderCollection SubFolders + { + get + { + try + { + if (v2Folder != null) + return new TaskFolderCollection(this, v2Folder.GetFolders(0)); + } catch { } + return new TaskFolderCollection(); + } + } + + /// + /// Gets a collection of all the tasks in the folder. + /// + [NotNull, ItemNotNull] + public TaskCollection Tasks => GetTasks(); + + /// + /// Gets or sets the that manages this task. + /// + /// The task service. + public TaskService TaskService { get; } + + /// + /// Compares the current object with another object of the same type. + /// + /// An object to compare with this object. + /// + /// A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the parameter.Zero This object is equal to . Greater than zero This object is greater than . + /// + int IComparable.CompareTo(TaskFolder other) => string.Compare(Path, other.Path, true); + + /// + /// Creates a folder for related tasks. Not available to Task Scheduler 1.0. + /// + /// The name used to identify the folder. If "FolderName\SubFolder1\SubFolder2" is specified, the entire folder tree will be created if the folders do not exist. This parameter can be a relative path to the current instance. The root task folder is specified with a backslash (\). An example of a task folder path, under the root task folder, is \MyTaskFolder. The '.' character cannot be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path. + /// The security descriptor associated with the folder. + /// A instance that represents the new subfolder. + [Obsolete("This method will be removed in deference to the CreateFolder(string, TaskSecurity) method.")] + public TaskFolder CreateFolder([NotNull] string subFolderName, GenericSecurityDescriptor sd) => CreateFolder(subFolderName, sd == null ? null : sd.GetSddlForm(Task.defaultAccessControlSections)); + + /// + /// Creates a folder for related tasks. Not available to Task Scheduler 1.0. + /// + /// The name used to identify the folder. If "FolderName\SubFolder1\SubFolder2" is specified, the entire folder tree will be created if the folders do not exist. This parameter can be a relative path to the current instance. The root task folder is specified with a backslash (\). An example of a task folder path, under the root task folder, is \MyTaskFolder. The '.' character cannot be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path. + /// The task security associated with the folder. + /// A instance that represents the new subfolder. + public TaskFolder CreateFolder([NotNull] string subFolderName, [NotNull] TaskSecurity folderSecurity) + { + if (folderSecurity == null) + throw new ArgumentNullException(nameof(folderSecurity)); + return CreateFolder(subFolderName, folderSecurity.GetSecurityDescriptorSddlForm(Task.defaultAccessControlSections)); + } + + /// + /// Creates a folder for related tasks. Not available to Task Scheduler 1.0. + /// + /// The name used to identify the folder. If "FolderName\SubFolder1\SubFolder2" is specified, the entire folder tree will be created if the folders do not exist. This parameter can be a relative path to the current instance. The root task folder is specified with a backslash (\). An example of a task folder path, under the root task folder, is \MyTaskFolder. The '.' character cannot be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path. + /// The security descriptor associated with the folder. + /// Set this value to false to avoid having an exception called if the folder already exists. + /// A instance that represents the new subfolder. + /// Security descriptor mismatch between specified credentials and credentials on existing folder by same name. + /// Invalid SDDL form. + /// Not supported under Task Scheduler 1.0. + public TaskFolder CreateFolder([NotNull] string subFolderName, string sddlForm = null, bool exceptionOnExists = true) + { + if (v2Folder == null) throw new NotV1SupportedException(); + ITaskFolder ifld = null; + try { ifld = v2Folder.CreateFolder(subFolderName, sddlForm); } + catch (COMException ce) + { + int serr = ce.ErrorCode & 0x0000FFFF; + if (serr == 0xb7) // ERROR_ALREADY_EXISTS + { + if (exceptionOnExists) throw; + try + { + ifld = v2Folder.GetFolder(subFolderName); + if (ifld != null && sddlForm != null && sddlForm.Trim().Length > 0) + { + string sd = ifld.GetSecurityDescriptor((int)Task.defaultSecurityInfosSections); + if (string.Compare(sddlForm, sd, StringComparison.OrdinalIgnoreCase) != 0) + throw new SecurityException("Security descriptor mismatch between specified credentials and credentials on existing folder by same name."); + } + } + catch + { + if (ifld != null) + Marshal.ReleaseComObject(ifld); + throw; + } + } + else if (serr == 0x534 || serr == 0x538 || serr == 0x539 || serr == 0x53A || serr == 0x519 || serr == 0x57) + throw new ArgumentException(@"Invalid SDDL form", nameof(sddlForm), ce); + else + throw; + } + return new TaskFolder(TaskService, ifld); + } + + /// + /// Deletes a subfolder from the parent folder. Not available to Task Scheduler 1.0. + /// + /// The name of the subfolder to be removed. The root task folder is specified with a backslash (\). This parameter can be a relative path to the folder you want to delete. An example of a task folder path, under the root task folder, is \MyTaskFolder. The '.' character cannot be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path. + /// Set this value to false to avoid having an exception called if the folder does not exist. + /// Not supported under Task Scheduler 1.0. + public void DeleteFolder([NotNull] string subFolderName, bool exceptionOnNotExists = true) + { + if (v2Folder != null) + { + try + { + v2Folder.DeleteFolder(subFolderName, 0); + } + catch (Exception e) + { + if (!(e is FileNotFoundException || e is DirectoryNotFoundException) || exceptionOnNotExists) + throw; + } + } + else + throw new NotV1SupportedException(); + } + + /// Deletes a task from the folder. + /// + /// The name of the task that is specified when the task was registered. The '.' character cannot be used to specify the current task folder and the '..' + /// characters cannot be used to specify the parent task folder in the path. + /// + /// Set this value to false to avoid having an exception called if the task does not exist. + public void DeleteTask([NotNull] string name, bool exceptionOnNotExists = true) + { + try + { + if (v2Folder != null) + v2Folder.DeleteTask(name, 0); + else + { + if (!name.EndsWith(".job", StringComparison.CurrentCultureIgnoreCase)) + name += ".job"; + v1List.Delete(name); + } + } + catch (FileNotFoundException) + { + if (exceptionOnNotExists) + throw; + } + } + + /// Returns an enumerable collection of folders that matches a specified filter and recursion option. + /// An optional predicate used to filter the returned instances. + /// An enumerable collection of folders that matches . + [NotNull, ItemNotNull] + public IEnumerable EnumerateFolders(Predicate filter = null) + { + foreach (var fld in SubFolders) + { + if (filter == null || filter(fld)) + yield return fld; + } + } + + /// Returns an enumerable collection of tasks that matches a specified filter and recursion option. + /// An optional predicate used to filter the returned instances. + /// Specifies whether the enumeration should include tasks in any subfolders. + /// An enumerable collection of directories that matches and . + [NotNull, ItemNotNull] + public IEnumerable EnumerateTasks(Predicate filter = null, bool recurse = false) => EnumerateFolderTasks(this, filter, recurse); + + /// Determines whether the specified , is equal to this instance. + /// The to compare with this instance. + /// true if the specified is equal to this instance; otherwise, false. + public override bool Equals(object obj) + { + var folder = obj as TaskFolder; + if (folder != null) + return Path == folder.Path && TaskService.TargetServer == folder.TaskService.TargetServer && GetSecurityDescriptorSddlForm() == folder.GetSecurityDescriptorSddlForm(); + return false; + } + + /// + /// Gets a object that encapsulates the specified type of access control list (ACL) entries for the task described by the + /// current object. + /// + /// A object that encapsulates the access control rules for the current folder. + [NotNull] + public TaskSecurity GetAccessControl() => GetAccessControl(Task.defaultAccessControlSections); + + /// + /// Gets a object that encapsulates the specified type of access control list (ACL) entries for the task folder described by + /// the current object. + /// + /// + /// One of the values that specifies which group of access control entries to retrieve. + /// + /// A object that encapsulates the access control rules for the current folder. + [NotNull] + public TaskSecurity GetAccessControl(AccessControlSections includeSections) => new TaskSecurity(this, includeSections); + + /// Returns a hash code for this instance. + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + public override int GetHashCode() => new { A = Path, B = TaskService.TargetServer, C = GetSecurityDescriptorSddlForm() }.GetHashCode(); + + /// Gets the security descriptor for the folder. Not available to Task Scheduler 1.0. + /// Section(s) of the security descriptor to return. + /// The security descriptor for the folder. + [Obsolete("This method will be removed in deference to the GetAccessControl and GetSecurityDescriptorSddlForm methods.")] + public GenericSecurityDescriptor GetSecurityDescriptor(SecurityInfos includeSections = Task.defaultSecurityInfosSections) => new RawSecurityDescriptor(GetSecurityDescriptorSddlForm(includeSections)); + + /// + /// Gets the security descriptor for the folder. Not available to Task Scheduler 1.0. + /// + /// Section(s) of the security descriptor to return. + /// The security descriptor for the folder. + /// Not supported under Task Scheduler 1.0. + public string GetSecurityDescriptorSddlForm(SecurityInfos includeSections = Task.defaultSecurityInfosSections) + { + if (v2Folder != null) + return v2Folder.GetSecurityDescriptor((int)includeSections); + throw new NotV1SupportedException(); + } + + /// + /// Gets a collection of all the tasks in the folder whose name matches the optional . + /// + /// The optional name filter expression. + /// Collection of all matching tasks. + [NotNull, ItemNotNull] + public TaskCollection GetTasks(Regex filter = null) + { + if (v2Folder != null) + return new TaskCollection(this, v2Folder.GetTasks(1), filter); + return new TaskCollection(TaskService, filter); + } + + /// Imports a from an XML file. + /// The task name. If this value is NULL, the task will be registered in the root task folder and the task name will be a GUID value that is created by the Task Scheduler service. A task name cannot begin or end with a space character. The '.' character cannot be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path. + /// The file containing the XML-formatted definition of the task. + /// If set to , overwrites any existing task with the same name. + /// A instance that represents the new task. + /// Importing from an XML file is only supported under Task Scheduler 2.0. + public Task ImportTask(string path, [NotNull] string xmlFile, bool overwriteExisting = true) => RegisterTask(path, File.ReadAllText(xmlFile), overwriteExisting ? TaskCreation.CreateOrUpdate : TaskCreation.Create); + + /// + /// Registers (creates) a new task in the folder using XML to define the task. + /// + /// The task name. If this value is NULL, the task will be registered in the root task folder and the task name will be a GUID value that is created by the Task Scheduler service. A task name cannot begin or end with a space character. The '.' character cannot be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path. + /// An XML-formatted definition of the task. + /// A union of flags. + /// The user credentials used to register the task. + /// The password for the userId used to register the task. + /// A value that defines what logon technique is used to run the registered task. + /// The security descriptor associated with the registered task. You can specify the access control list (ACL) in the security descriptor for a task in order to allow or deny certain users and groups access to a task. + /// A instance that represents the new task. + /// " + + /// "" + + /// " " + + /// " " + + /// " S-1-5-18" + + /// " " + + /// " " + + /// " " + + /// " " + + /// " 2017-09-04T14:04:03" + + /// " " + + /// " " + + /// " " + + /// " " + + /// " " + + /// " cmd" + + /// " " + + /// " " + + /// ""; + /// // Register the task in the root folder of the local machine using the SYSTEM account defined in XML + /// TaskService.Instance.RootFolder.RegisterTaskDefinition("Test", xml); + /// ]]> + public Task RegisterTask(string path, [NotNull] string xmlText, TaskCreation createType = TaskCreation.CreateOrUpdate, string userId = null, string password = null, TaskLogonType logonType = TaskLogonType.S4U, string sddl = null) + { + if (v2Folder != null) + return Task.CreateTask(TaskService, v2Folder.RegisterTask(path, xmlText, (int)createType, userId, password, logonType, sddl)); + + TaskDefinition td = TaskService.NewTask(); + XmlSerializationHelper.ReadObjectFromXmlText(xmlText, td); + return RegisterTaskDefinition(path, td, createType, userId ?? td.Principal.ToString(), + password, logonType == TaskLogonType.S4U ? td.Principal.LogonType : logonType, sddl); + } + + /// + /// Registers (creates) a task in a specified location using a instance to define a task. + /// + /// The task name. If this value is NULL, the task will be registered in the root task folder and the task name will be a GUID value that is created by the Task Scheduler service. A task name cannot begin or end with a space character. The '.' character cannot be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path. + /// The of the registered task. + /// A instance that represents the new task. + /// + /// + public Task RegisterTaskDefinition(string path, [NotNull] TaskDefinition definition) => RegisterTaskDefinition(path, definition, TaskCreation.CreateOrUpdate, + definition.Principal.ToString(), null, definition.Principal.LogonType); + + /// + /// Registers (creates) a task in a specified location using a instance to define a task. + /// + /// The task name. If this value is NULL, the task will be registered in the root task folder and the task name will be a GUID value that is created by the Task Scheduler service. A task name cannot begin or end with a space character. The '.' character cannot be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path. + /// The of the registered task. + /// A union of flags. + /// The user credentials used to register the task. + /// The password for the userId used to register the task. + /// A value that defines what logon technique is used to run the registered task. + /// The security descriptor associated with the registered task. You can specify the access control list (ACL) in the security descriptor for a task in order to allow or deny certain users and groups access to a task. + /// + /// A instance that represents the new task. This will return null if is set to ValidateOnly and there are no validation errors. + /// + /// + /// Task names may not include any characters which are invalid for file names. + /// or + /// Task names ending with a period followed by three or fewer characters cannot be retrieved due to a bug in the native library. + /// + /// This LogonType is not supported on Task Scheduler 1.0. + /// or + /// Security settings are not available on Task Scheduler 1.0. + /// or + /// Registration triggers are not available on Task Scheduler 1.0. + /// or + /// XML validation not available on Task Scheduler 1.0. + /// This method is effectively the "Save" method for tasks. It takes a modified TaskDefinition instance and registers it in the folder defined by this TaskFolder instance. Optionally, you can use this method to override the user, password and logon type defined in the definition and supply security against the task. + /// + /// This first example registers a simple task with a single trigger and action using the default security. + /// + /// This example registers that same task using the SYSTEM account. + /// + /// This example registers that same task using a specific username and password along with a security definition. + /// + public Task RegisterTaskDefinition([NotNull] string path, [NotNull] TaskDefinition definition, TaskCreation createType, string userId, string password = null, TaskLogonType logonType = TaskLogonType.S4U, string sddl = null) + { + if (definition.Actions.Count < 1 || definition.Actions.Count > 32) + throw new ArgumentOutOfRangeException(nameof(definition.Actions), @"A task must be registered with at least one action and no more than 32 actions."); + + userId ??= definition.Principal.Account; + if (userId == string.Empty) userId = null; + User user = new User(userId); + if (v2Folder != null) + { + definition.Actions.ConvertUnsupportedActions(); + if (logonType == TaskLogonType.ServiceAccount) + { + if (string.IsNullOrEmpty(userId) || !user.IsServiceAccount) + throw new ArgumentException(@"A valid system account name must be supplied for TaskLogonType.ServiceAccount. Valid entries are ""NT AUTHORITY\SYSTEM"", ""SYSTEM"", ""NT AUTHORITY\LOCALSERVICE"", or ""NT AUTHORITY\NETWORKSERVICE"".", nameof(userId)); + if (password != null) + throw new ArgumentException(@"A password cannot be supplied when specifying TaskLogonType.ServiceAccount.", nameof(password)); + } + /*else if ((LogonType == TaskLogonType.Password || LogonType == TaskLogonType.InteractiveTokenOrPassword || + (LogonType == TaskLogonType.S4U && UserId != null && !user.IsCurrent)) && password == null) + { + throw new ArgumentException("A password must be supplied when specifying TaskLogonType.Password or TaskLogonType.InteractiveTokenOrPassword or TaskLogonType.S4U from another account.", nameof(password)); + }*/ + else if (logonType == TaskLogonType.Group && password != null) + { + throw new ArgumentException(@"A password cannot be supplied when specifying TaskLogonType.Group.", nameof(password)); + } + // The following line compensates for an omission in the native library that never actually sets the registration date (thanks ixm7). + if (definition.RegistrationInfo.Date == DateTime.MinValue) definition.RegistrationInfo.Date = DateTime.Now; + var iRegTask = v2Folder.RegisterTaskDefinition(path, definition.v2Def, (int)createType, userId ?? user.Name, password, logonType, sddl); + if (createType == TaskCreation.ValidateOnly && iRegTask == null) + return null; + return Task.CreateTask(TaskService, iRegTask); + } + + // Check for V1 invalid task names + string invChars = Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars())); + if (Regex.IsMatch(path, @"[" + invChars + @"]")) + throw new ArgumentOutOfRangeException(nameof(path), @"Task names may not include any characters which are invalid for file names."); + if (Regex.IsMatch(path, @"\.[^" + invChars + @"]{0,3}\z")) + throw new ArgumentOutOfRangeException(nameof(path), @"Task names ending with a period followed by three or fewer characters cannot be retrieved due to a bug in the native library."); + + // Adds ability to set a password for a V1 task. Provided by Arcao. + TaskFlags flags = definition.v1Task.GetFlags(); + if (logonType == TaskLogonType.InteractiveTokenOrPassword && string.IsNullOrEmpty(password)) + logonType = TaskLogonType.InteractiveToken; + switch (logonType) + { + case TaskLogonType.Group: + case TaskLogonType.S4U: + case TaskLogonType.None: + throw new NotV1SupportedException("This LogonType is not supported on Task Scheduler 1.0."); + case TaskLogonType.InteractiveToken: + flags |= (TaskFlags.RunOnlyIfLoggedOn | TaskFlags.Interactive); + definition.v1Task.SetAccountInformation(user.Name, IntPtr.Zero); + break; + case TaskLogonType.ServiceAccount: + flags &= ~(TaskFlags.Interactive | TaskFlags.RunOnlyIfLoggedOn); + definition.v1Task.SetAccountInformation((String.IsNullOrEmpty(userId) || user.IsSystem) ? String.Empty : user.Name, IntPtr.Zero); + break; + case TaskLogonType.InteractiveTokenOrPassword: + flags |= TaskFlags.Interactive; + using (CoTaskMemString cpwd = new CoTaskMemString(password)) + definition.v1Task.SetAccountInformation(user.Name, cpwd.DangerousGetHandle()); + break; + case TaskLogonType.Password: + using (CoTaskMemString cpwd = new CoTaskMemString(password)) + definition.v1Task.SetAccountInformation(user.Name, cpwd.DangerousGetHandle()); + break; + default: + throw new ArgumentOutOfRangeException(nameof(logonType), logonType, null); + } + definition.v1Task.SetFlags(flags); + + switch (createType) + { + case TaskCreation.Create: + case TaskCreation.CreateOrUpdate: + case TaskCreation.Disable: + case TaskCreation.Update: + if (createType == TaskCreation.Disable) + definition.Settings.Enabled = false; + definition.V1Save(path); + break; + case TaskCreation.DontAddPrincipalAce: + throw new NotV1SupportedException("Security settings are not available on Task Scheduler 1.0."); + case TaskCreation.IgnoreRegistrationTriggers: + throw new NotV1SupportedException("Registration triggers are not available on Task Scheduler 1.0."); + case TaskCreation.ValidateOnly: + throw new NotV1SupportedException("XML validation not available on Task Scheduler 1.0."); + default: + throw new ArgumentOutOfRangeException(nameof(createType), createType, null); + } + return new Task(TaskService, definition.v1Task); + } + + /// + /// Applies access control list (ACL) entries described by a object to the file described by the current object. + /// + /// A object that describes an access control list (ACL) entry to apply to the current folder. + public void SetAccessControl([NotNull] TaskSecurity taskSecurity) { taskSecurity.Persist(this); } + + /// + /// Sets the security descriptor for the folder. Not available to Task Scheduler 1.0. + /// + /// The security descriptor for the folder. + /// Section(s) of the security descriptor to set. + [Obsolete("This method will be removed in deference to the SetAccessControl and SetSecurityDescriptorSddlForm methods.")] + public void SetSecurityDescriptor([NotNull] GenericSecurityDescriptor sd, SecurityInfos includeSections = Task.defaultSecurityInfosSections) { SetSecurityDescriptorSddlForm(sd.GetSddlForm((AccessControlSections)includeSections)); } + + /// + /// Sets the security descriptor for the folder. Not available to Task Scheduler 1.0. + /// + /// The security descriptor for the folder. + /// Flags that specify how to set the security descriptor. + /// Not supported under Task Scheduler 1.0. + public void SetSecurityDescriptorSddlForm([NotNull] string sddlForm, TaskSetSecurityOptions options = TaskSetSecurityOptions.None) + { + if (v2Folder != null) + v2Folder.SetSecurityDescriptor(sddlForm, (int)options); + else + throw new NotV1SupportedException(); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() => Path; + + /// + /// Enumerates the tasks in the specified folder and its child folders. + /// + /// The folder in which to start enumeration. + /// An optional filter to apply to the task list. + /// true if subfolders are to be queried recursively. + /// A that can be used to iterate through the tasks. + internal static IEnumerable EnumerateFolderTasks(TaskFolder folder, Predicate filter = null, bool recurse = true) + { + foreach (var task in folder.Tasks) + if (filter == null || filter(task)) + yield return task; + + if (!recurse) yield break; + + foreach (var sfld in folder.SubFolders) + foreach (var task in EnumerateFolderTasks(sfld, filter)) + yield return task; + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/TaskFolderCollection.cs b/FlashPatcher/TaskService/TaskFolderCollection.cs new file mode 100644 index 0000000..1d85fc7 --- /dev/null +++ b/FlashPatcher/TaskService/TaskFolderCollection.cs @@ -0,0 +1,233 @@ +using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace Microsoft.Win32.TaskScheduler +{ + /// Provides information and control for a collection of folders that contain tasks. + public sealed class TaskFolderCollection : ICollection, IDisposable, INotifyCollectionChanged, INotifyPropertyChanged + { + private const string IndexerName = "Item[]"; + private readonly TaskFolder parent; + private readonly TaskFolder[] v1FolderList; + private readonly V2Interop.ITaskFolderCollection v2FolderList; + + internal TaskFolderCollection() => v1FolderList = new TaskFolder[0]; + + internal TaskFolderCollection([NotNull] TaskFolder folder, [NotNull] V2Interop.ITaskFolderCollection iCollection) + { + parent = folder; + v2FolderList = iCollection; + } + + /// Occurs when a collection changes. + public event NotifyCollectionChangedEventHandler CollectionChanged; + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// Gets the number of items in the collection. + public int Count => v2FolderList?.Count ?? v1FolderList.Length; + + /// Gets a value indicating whether the is read-only. + bool ICollection.IsReadOnly => false; + + /// Gets the specified folder from the collection. + /// The index of the folder to be retrieved. + /// A TaskFolder instance that represents the requested folder. + public TaskFolder this[int index] + { + get + { + if (v2FolderList != null) + return new TaskFolder(parent.TaskService, v2FolderList[++index]); + return v1FolderList[index]; + } + } + + /// Gets the specified folder from the collection. + /// The path of the folder to be retrieved. + /// A TaskFolder instance that represents the requested folder. + public TaskFolder this[[NotNull] string path] + { + get + { + try + { + if (v2FolderList != null) + return parent.GetFolder(path); + if (v1FolderList != null && v1FolderList.Length > 0 && (path == string.Empty || path == "\\")) + return v1FolderList[0]; + } + catch { } + throw new ArgumentException(@"Path not found", nameof(path)); + } + } + + /// Adds an item to the . + /// The object to add to the . + /// + /// This action is technically unfeasible due to limitations of the underlying library. Use the instead. + /// + public void Add([NotNull] TaskFolder item) => throw new NotImplementedException(); + + /// Removes all items from the . + public void Clear() + { + if (v2FolderList != null) + { + for (var i = v2FolderList.Count; i > 0; i--) + parent.DeleteFolder(v2FolderList[i].Name, false); + OnNotifyPropertyChanged(nameof(Count)); + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + } + + /// Determines whether the contains a specific value. + /// The object to locate in the . + /// true if is found in the ; otherwise, false. + public bool Contains([NotNull] TaskFolder item) + { + if (v2FolderList != null) + { + for (var i = v2FolderList.Count; i > 0; i--) + if (string.Equals(item.Path, v2FolderList[i].Path, StringComparison.CurrentCultureIgnoreCase)) + return true; + } + else + return item.Path == "\\"; + return false; + } + + /// Copies the elements of the ICollection to an Array, starting at a particular Array index. + /// + /// The one-dimensional Array that is the destination of the elements copied from . The Array must have + /// zero-based indexing. + /// + /// The zero-based index in array at which copying begins. + public void CopyTo(TaskFolder[] array, int arrayIndex) + { + if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + if (array == null) throw new ArgumentNullException(nameof(array)); + if (v2FolderList != null) + { + if (arrayIndex + Count > array.Length) + throw new ArgumentException(); + foreach (var f in this) + array[arrayIndex++] = f; + } + else + { + if (arrayIndex + v1FolderList.Length > array.Length) + throw new ArgumentException(); + v1FolderList.CopyTo(array, arrayIndex); + } + } + + /// Releases all resources used by this class. + public void Dispose() + { + if (v1FolderList != null && v1FolderList.Length > 0) + { + v1FolderList[0].Dispose(); + v1FolderList[0] = null; + } + if (v2FolderList != null) + System.Runtime.InteropServices.Marshal.ReleaseComObject(v2FolderList); + } + + /// Determines whether the specified folder exists. + /// The path of the folder. + /// true if folder exists; otherwise, false. + public bool Exists([NotNull] string path) + { + try + { + parent.GetFolder(path); + return true; + } + catch { } + return false; + } + + /// Gets a list of items in a collection. + /// Enumerated list of items in the collection. + public IEnumerator GetEnumerator() + { + if (v2FolderList != null) + return new System.Runtime.InteropServices.ComEnumerator(() => v2FolderList.Count, (object o) => v2FolderList[o], o => new TaskFolder(parent.TaskService, o)); + return Array.AsReadOnly(v1FolderList).GetEnumerator(); + } + + /* + /// Returns the index of the TaskFolder within the collection. + /// TaskFolder to find. + /// Index of the TaskFolder; -1 if not found. + public int IndexOf(TaskFolder item) + { + return IndexOf(item.Path); + } + + /// Returns the index of the TaskFolder within the collection. + /// Path to find. + /// Index of the TaskFolder; -1 if not found. + public int IndexOf(string path) + { + if (v2FolderList != null) + { + for (int i = 0; i < v2FolderList.Count; i++) + { + if (v2FolderList[new System.Runtime.InteropServices.VariantWrapper(i)].Path == path) + return i; + } + return -1; + } + else + return (v1FolderList.Length > 0 && (path == string.Empty || path == "\\")) ? 0 : -1; + } + */ + + /// Removes the first occurrence of a specific object from the . + /// The object to remove from the . + /// + /// true if was successfully removed from the ; otherwise, false. This method + /// also returns false if is not found in the original . + /// + public bool Remove([NotNull] TaskFolder item) + { + if (v2FolderList != null) + { + for (var i = v2FolderList.Count; i > 0; i--) + { + if (string.Equals(item.Path, v2FolderList[i].Path, StringComparison.CurrentCultureIgnoreCase)) + { + try + { + parent.DeleteFolder(v2FolderList[i].Name); + OnNotifyPropertyChanged(nameof(Count)); + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, i)); + } + catch + { + return false; + } + return true; + } + } + } + return false; + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/TaskHandlerInterfaces.cs b/FlashPatcher/TaskService/TaskHandlerInterfaces.cs new file mode 100644 index 0000000..5966c36 --- /dev/null +++ b/FlashPatcher/TaskService/TaskHandlerInterfaces.cs @@ -0,0 +1,53 @@ +using System.Runtime.InteropServices; + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Defines the methods that are called by the Task Scheduler service to manage a COM handler. + /// + /// + /// This interface must be implemented for a task to perform a COM handler action. When the Task Scheduler performs a COM handler action, it creates and activates the handler and calls the methods of this interface as needed. For information on specifying a COM handler action, see the class. + /// + [ComImport, Guid("839D7762-5121-4009-9234-4F0D19394F04"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), System.Security.SuppressUnmanagedCodeSecurity] + public interface ITaskHandler + { + /// + /// Called to start the COM handler. This method must be implemented by the handler. + /// + /// An IUnkown interface that is used to communicate back with the Task Scheduler. + /// The arguments that are required by the handler. These arguments are defined in the property of the COM handler action. + void Start([In, MarshalAs(UnmanagedType.IUnknown)] object pHandlerServices, [In, MarshalAs(UnmanagedType.BStr)] string data); + /// + /// Called to stop the COM handler. This method must be implemented by the handler. + /// + /// The return code that the Task Schedule will raise as an event when the COM handler action is completed. + void Stop([MarshalAs(UnmanagedType.Error)] out int pRetCode); + /// + /// Called to pause the COM handler. This method is optional and should only be implemented to give the Task Scheduler the ability to pause and restart the handler. + /// + void Pause(); + /// + /// Called to resume the COM handler. This method is optional and should only be implemented to give the Task Scheduler the ability to resume the handler. + /// + void Resume(); + } + + /// + /// Provides the methods that are used by COM handlers to notify the Task Scheduler about the status of the handler. + /// + [ComImport, Guid("EAEC7A8F-27A0-4DDC-8675-14726A01A38A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), System.Security.SuppressUnmanagedCodeSecurity] + public interface ITaskHandlerStatus + { + /// + /// Tells the Task Scheduler about the percentage of completion of the COM handler. + /// + /// A value that indicates the percentage of completion for the COM handler. + /// The message that is displayed in the Task Scheduler UI. + void UpdateStatus([In] short percentComplete, [In, MarshalAs(UnmanagedType.BStr)] string statusMessage); + /// + /// Tells the Task Scheduler that the COM handler is completed. + /// + /// The error code that the Task Scheduler will raise as an event. + void TaskCompleted([In, MarshalAs(UnmanagedType.Error)] int taskErrCode); + } +} diff --git a/FlashPatcher/TaskService/TaskSecurity.cs b/FlashPatcher/TaskService/TaskSecurity.cs new file mode 100644 index 0000000..0b44433 --- /dev/null +++ b/FlashPatcher/TaskService/TaskSecurity.cs @@ -0,0 +1,466 @@ +using System; +using System.Runtime; +using System.Security; +using System.Security.AccessControl; +using System.Security.Principal; +using JetBrains.Annotations; + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Specifies the access control rights that can be applied to Task Scheduler tasks. + /// + [Flags] + public enum TaskRights + { + /// Specifies the right to exert full control over a task folder or task, and to modify access control and audit rules. This value represents the right to do anything with a task and is the combination of all rights in this enumeration. + FullControl = 0x1f01ff, + /// Specifies the right to create tasks and folders, and to add or remove data from tasks. This right includes the following rights: . + Write = 0x120116, + /// Specifies the right to open and copy folders or tasks as read-only. This right includes the following rights: . + Read = 0x120089, + /// Specifies the right run tasks. This right includes the following rights: . + Execute = 0x120089, + /// The right to wait on a task. + Synchronize = 0x100000, + /// The right to change the owner of a task. + TakeOwnership = 0x80000, + /// Specifies the right to change the security and audit rules associated with a task or folder. + ChangePermissions = 0x40000, + /// The right to open and copy the access rules and audit rules for a task. + ReadPermissions = 0x20000, + /// The right to delete a folder or task. + Delete = 0x10000, + /// Specifies the right to open and write file system attributes to a folder or file. This does not include the ability to write data, extended attributes, or access and audit rules. + WriteAttributes = 0x100, + /// Specifies the right to open and copy file system attributes from a folder or task. For example, this value specifies the right to view the file creation or modified date. This does not include the right to read data, extended file system attributes, or access and audit rules. + ReadAttributes = 0x80, + /// Specifies the right to delete a folder and any tasks contained within that folder. + DeleteChild = 0x40, + /// Specifies the right to run a task. + ExecuteFile = 0x20, + /// Specifies the right to open and write extended file system attributes to a folder or file. This does not include the ability to write data, attributes, or access and audit rules. + WriteExtendedAttributes = 0x10, + /// Specifies the right to open and copy extended system attributes from a folder or task. For example, this value specifies the right to view author and content information. This does not include the right to read data, system attributes, or access and audit rules. + ReadExtendedAttributes = 8, + /// Specifies the right to append data to the end of a file. + AppendData = 4, + /// Specifies the right to open and write to a file or folder. This does not include the right to open and write file system attributes, extended file system attributes, or access and audit rules. + WriteData = 2, + /// Specifies the right to open and copy a task or folder. This does not include the right to read file system attributes, extended file system attributes, or access and audit rules. + ReadData = 1, + } + + /// + /// Represents a set of access rights allowed or denied for a user or group. This class cannot be inherited. + /// + public sealed class TaskAccessRule : AccessRule + { + /// + /// Initializes a new instance of the class, specifying the user or group the rule applies to, the access rights, and whether the specified access rights are allowed or denied. + /// + /// The user or group the rule applies to. Must be of type or a type such as that can be converted to type . + /// A bitwise combination of values specifying the rights allowed or denied. + /// One of the values specifying whether the rights are allowed or denied. + public TaskAccessRule([NotNull] IdentityReference identity, TaskRights eventRights, AccessControlType type) + : this(identity, (int)eventRights, false, InheritanceFlags.None, PropagationFlags.None, type) + { + } + + /// + /// Initializes a new instance of the class, specifying the name of the user or group the rule applies to, the access rights, and whether the specified access rights are allowed or denied. + /// + /// The name of the user or group the rule applies to. + /// A bitwise combination of values specifying the rights allowed or denied. + /// One of the values specifying whether the rights are allowed or denied. + public TaskAccessRule([NotNull] string identity, TaskRights eventRights, AccessControlType type) + : this(new NTAccount(identity), (int)eventRights, false, InheritanceFlags.None, PropagationFlags.None, type) + { + } + + private TaskAccessRule([NotNull] IdentityReference identity, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type) + : base(identity, accessMask, isInherited, inheritanceFlags, propagationFlags, type) + { + } + + /// + /// Gets the rights allowed or denied by the access rule. + /// + /// + /// A bitwise combination of values indicating the rights allowed or denied by the access rule. + /// + public TaskRights TaskRights => (TaskRights)AccessMask; + } + + /// + /// Represents a set of access rights to be audited for a user or group. This class cannot be inherited. + /// + public sealed class TaskAuditRule : AuditRule + { + /// + /// Initializes a new instance of the class, specifying the user or group to audit, the rights to audit, and whether to audit success, failure, or both. + /// + /// The user or group the rule applies to. Must be of type or a type such as that can be converted to type . + /// A bitwise combination of values specifying the kinds of access to audit. + /// The audit flags. + public TaskAuditRule([NotNull] IdentityReference identity, TaskRights eventRights, AuditFlags flags) + : this(identity, (int)eventRights, false, InheritanceFlags.None, PropagationFlags.None, flags) + { + } + + internal TaskAuditRule([NotNull] IdentityReference identity, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags) + : base(identity, accessMask, isInherited, inheritanceFlags, propagationFlags, flags) + { + } + + /// + /// Gets the access rights affected by the audit rule. + /// + /// + /// A bitwise combination of values that indicates the rights affected by the audit rule. + /// + /// objects are immutable. You can create a new audit rule representing a different user, different rights, or a different combination of AuditFlags values, but you cannot modify an existing audit rule. + public TaskRights TaskRights => (TaskRights)AccessMask; + } + + /// + /// Represents the Windows access control security for a Task Scheduler task. This class cannot be inherited. + /// + /// + /// A TaskSecurity object specifies access rights for a Task Scheduler task, and also specifies how access attempts are audited. Access rights to the task are expressed as rules, with each access rule represented by a object. Each auditing rule is represented by a object. + /// This mirrors the underlying Windows security system, in which each securable object has at most one discretionary access control list (DACL) that controls access to the secured object, and at most one system access control list (SACL) that specifies which access attempts are audited. The DACL and SACL are ordered lists of access control entries (ACE) that specify access and auditing for users and groups. A or object might represent more than one ACE. + /// Note + /// A object can represent a local task or a Task Scheduler task. Windows access control security is meaningful only for Task Scheduler tasks. + /// The TaskSecurity, , and classes hide the implementation details of ACLs and ACEs. They allow you to ignore the seventeen different ACE types and the complexity of correctly maintaining inheritance and propagation of access rights. These objects are also designed to prevent the following common access control errors: + /// + /// Creating a security descriptor with a null DACL. A null reference to a DACL allows any user to add access rules to an object, potentially creating a denial-of-service attack. A new TaskSecurity object always starts with an empty DACL, which denies all access for all users. + /// Violating the canonical ordering of ACEs. If the ACE list in the DACL is not kept in the canonical order, users might inadvertently be given access to the secured object. For example, denied access rights must always appear before allowed access rights. TaskSecurity objects maintain the correct order internally. + /// Manipulating security descriptor flags, which should be under resource manager control only. + /// Creating invalid combinations of ACE flags. + /// Manipulating inherited ACEs. Inheritance and propagation are handled by the resource manager, in response to changes you make to access and audit rules. + /// Inserting meaningless ACEs into ACLs. + /// + /// The only capabilities not supported by the .NET security objects are dangerous activities that should be avoided by the majority of application developers, such as the following: + /// + /// Low-level tasks that are normally performed by the resource manager. + /// Adding or removing access control entries in ways that do not maintain the canonical ordering. + /// + /// To modify Windows access control security for a task, use the method to get the TaskSecurity object. Modify the security object by adding and removing rules, and then use the method to reattach it. + /// Important: Changes you make to a TaskSecurity object do not affect the access levels of the task until you call the method to assign the altered security object to the task. + /// To copy access control security from one task to another, use the method to get a TaskSecurity object representing the access and audit rules for the first task, then use the method, or a constructor that accepts a TaskSecurity object, to assign those rules to the second task. + /// Users with an investment in the security descriptor definition language (SDDL) can use the method to set access rules for a task, and the method to obtain a string that represents the access rules in SDDL format. This is not recommended for new development. + /// + public sealed class TaskSecurity : CommonObjectSecurity + { + /// + /// Initializes a new instance of the class with default values. + /// + public TaskSecurity() + : base(false) + { + } + + /// + /// Initializes a new instance of the class with the specified sections of the access control security rules from the specified task. + /// + /// The task. + /// The sections of the ACL to retrieve. + public TaskSecurity([NotNull] Task task, AccessControlSections sections = Task.defaultAccessControlSections) + : base(false) + { + SetSecurityDescriptorSddlForm(task.GetSecurityDescriptorSddlForm(Convert(sections)), sections); + this.CanonicalizeAccessRules(); + } + + /// + /// Initializes a new instance of the class with the specified sections of the access control security rules from the specified task. + /// + /// The folder. + /// The sections of the ACL to retrieve. + public TaskSecurity([NotNull] TaskFolder folder, AccessControlSections sections = Task.defaultAccessControlSections) + : base(false) + { + SetSecurityDescriptorSddlForm(folder.GetSecurityDescriptorSddlForm(Convert(sections)), sections); + this.CanonicalizeAccessRules(); + } + + /// + /// Gets the enumeration that the class uses to represent access rights. + /// + /// A object representing the enumeration. + public override Type AccessRightType => typeof(TaskRights); + + /// + /// Gets the type that the TaskSecurity class uses to represent access rules. + /// + /// A object representing the class. + public override Type AccessRuleType => typeof(TaskAccessRule); + + /// + /// Gets the type that the TaskSecurity class uses to represent audit rules. + /// + /// A object representing the class. + public override Type AuditRuleType => typeof(TaskAuditRule); + + /// + /// Gets a object that represent the default access rights. + /// + /// The default task security. + public static TaskSecurity DefaultTaskSecurity + { + get + { + var ret = new TaskSecurity(); + ret.AddAccessRule(new TaskAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null), TaskRights.FullControl, AccessControlType.Allow)); + ret.AddAccessRule(new TaskAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null), TaskRights.Read | TaskRights.Write | TaskRights.Execute, AccessControlType.Allow)); + ret.AddAccessRule(new TaskAccessRule(new SecurityIdentifier(WellKnownSidType.LocalServiceSid, null), TaskRights.Read, AccessControlType.Allow)); + ret.AddAccessRule(new TaskAccessRule(new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null), TaskRights.Read, AccessControlType.Allow)); + ret.AddAccessRule(new TaskAccessRule(new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null), TaskRights.Read, AccessControlType.Allow)); + return ret; + } + } + + /// + /// Creates a new access control rule for the specified user, with the specified access rights, access control, and flags. + /// + /// An that identifies the user or group the rule applies to. + /// A bitwise combination of values specifying the access rights to allow or deny, cast to an integer. + /// Meaningless for tasks, because they have no hierarchy. + /// Meaningless for tasks, because they have no hierarchy. + /// Meaningless for tasks, because they have no hierarchy. + /// One of the values specifying whether the rights are allowed or denied. + /// + /// The object that this method creates. + /// + public override AccessRule AccessRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type) => new TaskAccessRule(identityReference, (TaskRights)accessMask, type); + + /// + /// Searches for a matching rule with which the new rule can be merged. If none are found, adds the new rule. + /// + /// The access control rule to add. + public void AddAccessRule([NotNull] TaskAccessRule rule) + { + base.AddAccessRule(rule); + } + + /// + /// Searches for an audit rule with which the new rule can be merged. If none are found, adds the new rule. + /// + /// The audit rule to add. The user specified by this rule determines the search. + public void AddAuditRule([NotNull] TaskAuditRule rule) + { + base.AddAuditRule(rule); + } + + /// + /// Creates a new audit rule, specifying the user the rule applies to, the access rights to audit, and the outcome that triggers the audit rule. + /// + /// An that identifies the user or group the rule applies to. + /// A bitwise combination of values specifying the access rights to audit, cast to an integer. + /// Meaningless for tasks, because they have no hierarchy. + /// Meaningless for tasks, because they have no hierarchy. + /// Meaningless for tasks, because they have no hierarchy. + /// One of the values specifying whether to audit successful access, failed access, or both. + /// + /// A object representing the specified audit rule for the specified user. The return type of the method is the base class, , but the return value can be cast safely to the derived class. + /// + public override AuditRule AuditRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags) => new TaskAuditRule(identityReference, accessMask, isInherited, inheritanceFlags, propagationFlags, flags); + + /// + /// Searches for an access control rule with the same user and (allow or deny) as the specified rule, and with compatible inheritance and propagation flags; if such a rule is found, the rights contained in the specified access rule are removed from it. + /// + /// A that specifies the user and to search for, and a set of inheritance and propagation flags that a matching rule, if found, must be compatible with. Specifies the rights to remove from the compatible rule, if found. + /// true if a compatible rule is found; otherwise false. + public bool RemoveAccessRule([NotNull] TaskAccessRule rule) => base.RemoveAccessRule(rule); + + /// + /// Searches for all access control rules with the same user and (allow or deny) as the specified rule and, if found, removes them. + /// + /// A that specifies the user and to search for, and a set of inheritance and propagation flags that a matching rule, if found, must be compatible with. Any rights specified by this rule are ignored. + public void RemoveAccessRuleAll([NotNull] TaskAccessRule rule) + { + base.RemoveAccessRuleAll(rule); + } + + /// + /// Searches for an access control rule that exactly matches the specified rule and, if found, removes it. + /// + /// The to remove. + public void RemoveAccessRuleSpecific([NotNull] TaskAccessRule rule) + { + base.RemoveAccessRuleSpecific(rule); + } + + /// + /// Searches for an audit control rule with the same user as the specified rule, and with compatible inheritance and propagation flags; if a compatible rule is found, the rights contained in the specified rule are removed from it. + /// + /// A that specifies the user to search for, and a set of inheritance and propagation flags that a matching rule, if found, must be compatible with. Specifies the rights to remove from the compatible rule, if found. + /// true if a compatible rule is found; otherwise false. + public bool RemoveAuditRule([NotNull] TaskAuditRule rule) => base.RemoveAuditRule(rule); + + /// + /// Searches for all audit rules with the same user as the specified rule and, if found, removes them. + /// + /// A that specifies the user to search for. Any rights specified by this rule are ignored. + public void RemoveAuditRuleAll(TaskAuditRule rule) + { + base.RemoveAuditRuleAll(rule); + } + + /// + /// Searches for an audit rule that exactly matches the specified rule and, if found, removes it. + /// + /// The to remove. + public void RemoveAuditRuleSpecific([NotNull] TaskAuditRule rule) + { + base.RemoveAuditRuleSpecific(rule); + } + + /// + /// Removes all access control rules with the same user as the specified rule, regardless of , and then adds the specified rule. + /// + /// The to add. The user specified by this rule determines the rules to remove before this rule is added. + public void ResetAccessRule([NotNull] TaskAccessRule rule) + { + base.ResetAccessRule(rule); + } + + /// + /// Removes all access control rules with the same user and (allow or deny) as the specified rule, and then adds the specified rule. + /// + /// The to add. The user and of this rule determine the rules to remove before this rule is added. + public void SetAccessRule([NotNull] TaskAccessRule rule) + { + base.SetAccessRule(rule); + } + + /// + /// Removes all audit rules with the same user as the specified rule, regardless of the value, and then adds the specified rule. + /// + /// The to add. The user specified by this rule determines the rules to remove before this rule is added. + public void SetAuditRule([NotNull] TaskAuditRule rule) + { + base.SetAuditRule(rule); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() => GetSecurityDescriptorSddlForm(Task.defaultAccessControlSections); + + private static SecurityInfos Convert(AccessControlSections si) + { + SecurityInfos ret = 0; + if ((si & AccessControlSections.Audit) != 0) + ret |= SecurityInfos.SystemAcl; + if ((si & AccessControlSections.Access) != 0) + ret |= SecurityInfos.DiscretionaryAcl; + if ((si & AccessControlSections.Group) != 0) + ret |= SecurityInfos.Group; + if ((si & AccessControlSections.Owner) != 0) + ret |= SecurityInfos.Owner; + return ret; + } + + private static AccessControlSections Convert(SecurityInfos si) + { + AccessControlSections ret = AccessControlSections.None; + if ((si & SecurityInfos.SystemAcl) != 0) + ret |= AccessControlSections.Audit; + if ((si & SecurityInfos.DiscretionaryAcl) != 0) + ret |= AccessControlSections.Access; + if ((si & SecurityInfos.Group) != 0) + ret |= AccessControlSections.Group; + if ((si & SecurityInfos.Owner) != 0) + ret |= AccessControlSections.Owner; + return ret; + } + + private AccessControlSections GetAccessControlSectionsFromChanges() + { + AccessControlSections none = AccessControlSections.None; + if (AccessRulesModified) + { + none = AccessControlSections.Access; + } + if (AuditRulesModified) + { + none |= AccessControlSections.Audit; + } + if (OwnerModified) + { + none |= AccessControlSections.Owner; + } + if (GroupModified) + { + none |= AccessControlSections.Group; + } + return none; + } + + /// + /// Saves the specified sections of the security descriptor associated with this object to permanent storage. We recommend that the values of the parameters passed to the constructor and persist methods be identical. + /// + /// The task used to retrieve the persisted information. + /// One of the enumeration values that specifies the sections of the security descriptor (access rules, audit rules, owner, primary group) of the securable object to save. + [SecurityCritical] + internal void Persist([NotNull] Task task, AccessControlSections includeSections = Task.defaultAccessControlSections) + { + WriteLock(); + try + { + AccessControlSections accessControlSectionsFromChanges = GetAccessControlSectionsFromChanges(); + if (accessControlSectionsFromChanges != AccessControlSections.None) + { + task.SetSecurityDescriptorSddlForm(GetSecurityDescriptorSddlForm(accessControlSectionsFromChanges)); + OwnerModified = GroupModified = AccessRulesModified = AuditRulesModified = false; + } + } + finally + { + WriteUnlock(); + } + } + + /// + /// Saves the specified sections of the security descriptor associated with this object to permanent storage. We recommend that the values of the parameters passed to the constructor and persist methods be identical. + /// + /// The task folder used to retrieve the persisted information. + /// One of the enumeration values that specifies the sections of the security descriptor (access rules, audit rules, owner, primary group) of the securable object to save. + [SecurityCritical] + internal void Persist([NotNull] TaskFolder folder, AccessControlSections includeSections = Task.defaultAccessControlSections) + { + WriteLock(); + try + { + AccessControlSections accessControlSectionsFromChanges = GetAccessControlSectionsFromChanges(); + if (accessControlSectionsFromChanges != AccessControlSections.None) + { + folder.SetSecurityDescriptorSddlForm(GetSecurityDescriptorSddlForm(accessControlSectionsFromChanges)); + OwnerModified = GroupModified = AccessRulesModified = AuditRulesModified = false; + } + } + finally + { + WriteUnlock(); + } + } + + /// + /// Saves the specified sections of the security descriptor associated with this object to permanent storage. We recommend that the values of the parameters passed to the constructor and persist methods be identical. For more information, see Remarks. + /// + /// The name used to retrieve the persisted information. + /// One of the enumeration values that specifies the sections of the security descriptor (access rules, audit rules, owner, primary group) of the securable object to save. + protected override void Persist([NotNull] string name, AccessControlSections includeSections = Task.defaultAccessControlSections) + { + using (var ts = new TaskService()) + { + var task = ts.GetTask(name); + Persist(task, includeSections); + } + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/TaskService.bmp b/FlashPatcher/TaskService/TaskService.bmp new file mode 100644 index 0000000..def2e3d Binary files /dev/null and b/FlashPatcher/TaskService/TaskService.bmp differ diff --git a/FlashPatcher/TaskService/TaskService.cs b/FlashPatcher/TaskService/TaskService.cs new file mode 100644 index 0000000..76a55ac --- /dev/null +++ b/FlashPatcher/TaskService/TaskService.cs @@ -0,0 +1,1163 @@ +using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Runtime.InteropServices; + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Quick simple trigger types for the + /// method. + /// + public enum QuickTriggerType + { + /// At boot. + Boot, + + /// On system idle. + Idle, + + /// At logon of any user. + Logon, + + /// When the task is registered. + TaskRegistration, + + /// Hourly, starting now. + Hourly, + + /// Daily, starting now. + Daily, + + /// Weekly, starting now. + Weekly, + + /// Monthly, starting now. + Monthly + } + + /// + /// Known versions of the native Task Scheduler library. This can be used as a decoder for the + /// and values. + /// + public static class TaskServiceVersion + { + /// Task Scheduler 1.0 (Windows Server™ 2003, Windows® XP, or Windows® 2000). + [Description("Task Scheduler 1.0 (Windows Server™ 2003, Windows® XP, or Windows® 2000).")] + public static readonly Version V1_1 = new Version(1, 1); + + /// Task Scheduler 2.0 (Windows Vista™, Windows Server™ 2008). + [Description("Task Scheduler 2.0 (Windows Vista™, Windows Server™ 2008).")] + public static readonly Version V1_2 = new Version(1, 2); + + /// Task Scheduler 2.1 (Windows® 7, Windows Server™ 2008 R2). + [Description("Task Scheduler 2.1 (Windows® 7, Windows Server™ 2008 R2).")] + public static readonly Version V1_3 = new Version(1, 3); + + /// Task Scheduler 2.2 (Windows® 8.x, Windows Server™ 2012). + [Description("Task Scheduler 2.2 (Windows® 8.x, Windows Server™ 2012).")] + public static readonly Version V1_4 = new Version(1, 4); + + /// Task Scheduler 2.3 (Windows® 10, Windows Server™ 2016). + [Description("Task Scheduler 2.3 (Windows® 10, Windows Server™ 2016).")] + public static readonly Version V1_5 = new Version(1, 5); + + /// Task Scheduler 2.3 (Windows® 10, Windows Server™ 2016 post build 1703). + [Description("Task Scheduler 2.3 (Windows® 10, Windows Server™ 2016 post build 1703).")] + public static readonly Version V1_6 = new Version(1, 6); + } + + /// Provides access to the Task Scheduler service for managing registered tasks. + [Description("Provides access to the Task Scheduler service.")] + [ToolboxItem(true), Serializable] + public sealed partial class TaskService : Component, ISupportInitialize, System.Runtime.Serialization.ISerializable + { + internal static readonly bool LibraryIsV2 = Environment.OSVersion.Version.Major >= 6; + internal static readonly Guid PowerShellActionGuid = new Guid("dab4c1e3-cd12-46f1-96fc-3981143c9bab"); + private static Guid CLSID_Ctask = typeof(V1Interop.CTask).GUID; + private static Guid IID_ITask = typeof(V1Interop.ITask).GUID; + [ThreadStatic] + private static TaskService instance; + private static Version osLibVer; + + internal V1Interop.ITaskScheduler v1TaskScheduler; + internal V2Interop.ITaskService v2TaskService; + private bool connecting; + private bool forceV1; + private bool initializing; + private Version maxVer; + private bool maxVerSet; + private string targetServer; + private bool targetServerSet; + private string userDomain; + private bool userDomainSet; + private string userName; + private bool userNameSet; + private string userPassword; + private bool userPasswordSet; + private WindowsImpersonatedIdentity v1Impersonation; + + /// Creates a new instance of a TaskService connecting to the local machine as the current user. + public TaskService() + { + ResetHighestSupportedVersion(); + Connect(); + } + + /// Initializes a new instance of the class. + /// + /// The name of the computer that you want to connect to. If the this parameter is empty, then this will connect to the local computer. + /// + /// + /// The user name that is used during the connection to the computer. If the user is not specified, then the current token is used. + /// + /// The domain of the user specified in the parameter. + /// + /// The password that is used to connect to the computer. If the user name and password are not specified, then the current token is used. + /// + /// If set to true force Task Scheduler 1.0 compatibility. + public TaskService(string targetServer, string userName = null, string accountDomain = null, string password = null, bool forceV1 = false) + { + BeginInit(); + TargetServer = targetServer; + UserName = userName; + UserAccountDomain = accountDomain; + UserPassword = password; + this.forceV1 = forceV1; + ResetHighestSupportedVersion(); + EndInit(); + } + + private TaskService([NotNull] System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + BeginInit(); + TargetServer = (string)info.GetValue("TargetServer", typeof(string)); + UserName = (string)info.GetValue("UserName", typeof(string)); + UserAccountDomain = (string)info.GetValue("UserAccountDomain", typeof(string)); + UserPassword = (string)info.GetValue("UserPassword", typeof(string)); + forceV1 = (bool)info.GetValue("forceV1", typeof(bool)); + ResetHighestSupportedVersion(); + EndInit(); + } + + /// Delegate for methods that support update calls during COM handler execution. + /// The percentage of completion (0 to 100). + /// An optional message. + public delegate void ComHandlerUpdate(short percentage, string message); + + /// Occurs when the Task Scheduler is connected to the local or remote target. + public event EventHandler ServiceConnected; + + /// Occurs when the Task Scheduler is disconnected from the local or remote target. + public event EventHandler ServiceDisconnected; + + /// Gets a local instance of the using the current user's credentials. + /// Local user instance. + public static TaskService Instance + { + get + { + if (instance is null) + { + instance = new TaskService(); + instance.ServiceDisconnected += Instance_ServiceDisconnected; + } + return instance; + } + } + + /// + /// Gets the library version. This is the highest version supported by the local library. Tasks cannot be created using any + /// compatibility level higher than this version. + /// + /// The library version. + /// + /// The following table list the various versions and their host operating system: + /// + /// + /// Version + /// Operating System + /// + /// + /// 1.1 + /// Task Scheduler 1.0 (Windows Server™ 2003, Windows® XP, or Windows® 2000). + /// + /// + /// 1.2 + /// Task Scheduler 2.0 (Windows Vista™, Windows Server™ 2008). + /// + /// + /// 1.3 + /// Task Scheduler 2.1 (Windows® 7, Windows Server™ 2008 R2). + /// + /// + /// 1.4 + /// Task Scheduler 2.2 (Windows® 8.x, Windows Server™ 2012). + /// + /// + /// 1.5 + /// Task Scheduler 2.3 (Windows® 10, Windows Server™ 2016). + /// + /// + /// 1.6 + /// Task Scheduler 2.4 (Windows® 10 Version 1703, Windows Server™ 2016 Version 1703). + /// + /// + /// + [Browsable(false)] + public static Version LibraryVersion { get; } = Instance.HighestSupportedVersion; + + /// + /// Gets or sets a value indicating whether to allow tasks from later OS versions with new properties to be retrieved as read only tasks. + /// + /// true if allow read only tasks; otherwise, false. + [DefaultValue(false), Category("Behavior"), Description("Allow tasks from later OS versions with new properties to be retrieved as read only tasks.")] + public bool AllowReadOnlyTasks { get; set; } + + /// Gets the name of the domain to which the computer is connected. + [Browsable(false)] + [DefaultValue(null)] + [Obsolete("This property has been superseded by the UserAccountDomin property and may not be available in future releases.")] + public string ConnectedDomain + { + get + { + if (v2TaskService != null) + return v2TaskService.ConnectedDomain; + var parts = v1Impersonation.Name.Split('\\'); + if (parts.Length == 2) + return parts[0]; + return string.Empty; + } + } + + /// Gets the name of the user that is connected to the Task Scheduler service. + [Browsable(false)] + [DefaultValue(null)] + [Obsolete("This property has been superseded by the UserName property and may not be available in future releases.")] + public string ConnectedUser + { + get + { + if (v2TaskService != null) + return v2TaskService.ConnectedUser; + var parts = v1Impersonation.Name.Split('\\'); + if (parts.Length == 2) + return parts[1]; + return parts[0]; + } + } + + /// Gets the highest version of Task Scheduler that a computer supports. + /// + /// The following table list the various versions and their host operating system: + /// + /// + /// Version + /// Operating System + /// + /// + /// 1.1 + /// Task Scheduler 1.0 (Windows Server™ 2003, Windows® XP, or Windows® 2000). + /// + /// + /// 1.2 + /// Task Scheduler 2.0 (Windows Vista™, Windows Server™ 2008). + /// + /// + /// 1.3 + /// Task Scheduler 2.1 (Windows® 7, Windows Server™ 2008 R2). + /// + /// + /// 1.4 + /// Task Scheduler 2.2 (Windows® 8.x, Windows Server™ 2012). + /// + /// + /// 1.5 + /// Task Scheduler 2.3 (Windows® 10, Windows Server™ 2016). + /// + /// + /// 1.6 + /// Task Scheduler 2.4 (Windows® 10 Version 1703, Windows Server™ 2016 Version 1703). + /// + /// + /// + [Category("Data"), TypeConverter(typeof(VersionConverter)), Description("Highest version of library that should be used.")] + public Version HighestSupportedVersion + { + get => maxVer; + set + { + if (value > GetLibraryVersionFromLocalOS()) + throw new ArgumentOutOfRangeException(nameof(HighestSupportedVersion), @"The value of HighestSupportedVersion cannot exceed that of the underlying Windows version library."); + maxVer = value; + maxVerSet = true; + var localForceV1 = value <= TaskServiceVersion.V1_1; + if (localForceV1 == forceV1) return; + forceV1 = localForceV1; + Connect(); + } + } + + /// Gets the root ("\") folder. For Task Scheduler 1.0, this is the only folder. + [Browsable(false)] + public TaskFolder RootFolder => GetFolder(TaskFolder.rootString); + + /// Gets or sets the name of the computer that is running the Task Scheduler service that the user is connected to. + [Category("Data"), DefaultValue(null), Description("The name of the computer to connect to.")] + public string TargetServer + { + get => ShouldSerializeTargetServer() ? targetServer : null; + set + { + if (value == null || value.Trim() == string.Empty) value = null; + if (string.Compare(value, targetServer, StringComparison.OrdinalIgnoreCase) != 0) + { + targetServerSet = true; + targetServer = value; + Connect(); + } + } + } + + /// Gets or sets the user account domain to be used when connecting to the . + /// The user account domain. + [Category("Data"), DefaultValue(null), Description("The user account domain to be used when connecting.")] + public string UserAccountDomain + { + get => ShouldSerializeUserAccountDomain() ? userDomain : null; + set + { + if (value == null || value.Trim() == string.Empty) value = null; + if (string.Compare(value, userDomain, StringComparison.OrdinalIgnoreCase) != 0) + { + userDomainSet = true; + userDomain = value; + Connect(); + } + } + } + + /// Gets or sets the user name to be used when connecting to the . + /// The user name. + [Category("Data"), DefaultValue(null), Description("The user name to be used when connecting.")] + public string UserName + { + get => ShouldSerializeUserName() ? userName : null; + set + { + if (value == null || value.Trim() == string.Empty) value = null; + if (string.Compare(value, userName, StringComparison.OrdinalIgnoreCase) != 0) + { + userNameSet = true; + userName = value; + Connect(); + } + } + } + + /// Gets or sets the user password to be used when connecting to the . + /// The user password. + [Category("Data"), DefaultValue(null), Description("The user password to be used when connecting.")] + public string UserPassword + { + get => userPassword; + set + { + if (value == null || value.Trim() == string.Empty) value = null; + if (string.CompareOrdinal(value, userPassword) != 0) + { + userPasswordSet = true; + userPassword = value; + Connect(); + } + } + } + + /// Gets a which enumerates all the tasks in all folders. + /// A for all instances. + [Browsable(false)] + public System.Collections.Generic.IEnumerable AllTasks => RootFolder.AllTasks; + + /// Gets a Boolean value that indicates if you are connected to the Task Scheduler service. + [Browsable(false)] + public bool Connected => v2TaskService != null && v2TaskService.Connected || v1TaskScheduler != null; + + /// + /// Gets the connection token for this instance. This token is thread safe and can be used to create new + /// instances on other threads using the static method. + /// + /// The connection token. + public ConnectionToken Token => + ConnectionDataManager.TokenFromInstance(TargetServer, UserName, UserAccountDomain, UserPassword, forceV1); + + /// Gets a value indicating whether the component can raise an event. + protected override bool CanRaiseEvents { get; } = false; + + /// + /// Creates a new instance from a token. Given that a TaskService instance is thread specific, this is the + /// preferred method for multi-thread creation or asynchronous method parameters. + /// + /// The token. + /// A instance valid for the thread calling this method. + public static TaskService CreateFromToken(ConnectionToken token) => ConnectionDataManager.InstanceFromToken(token); + + /// Gets a formatted string that tells the Task Scheduler to retrieve a string from a resource .dll file. + /// The path to the .dll file that contains the resource. + /// The identifier for the resource text (typically a negative number). + /// A string in the format of $(@ [dllPath], [resourceId]). + /// + /// For example, the setting this property value to $(@ %SystemRoot%\System32\ResourceName.dll, -101) will set the property to the + /// value of the resource text with an identifier equal to -101 in the %SystemRoot%\System32\ResourceName.dll file. + /// + public static string GetDllResourceString([NotNull] string dllPath, int resourceId) => $"$(@ {dllPath}, {resourceId})"; + + /// + /// Runs an action that is defined via a COM handler. COM CLSID must be registered to an object that implements the + /// interface. + /// + /// The CLSID of the COM object. + /// An optional string passed to the COM object at startup. + /// The number of milliseconds to wait or -1 for indefinitely. + /// + /// An optional delegate that is called when the COM object calls the + /// method. + /// + /// The value set by the COM object via a call to the method. + public static int RunComHandlerAction(Guid clsid, string data = null, int millisecondsTimeout = -1, ComHandlerUpdate onUpdate = null) + { + var thread = new ComHandlerThread(clsid, data, millisecondsTimeout, onUpdate, null); + thread.Start().Join(); + return thread.ReturnCode; + } + + /// + /// Runs an action that is defined via a COM handler. COM CLSID must be registered to an object that implements the + /// interface. + /// + /// The CLSID of the COM object. + /// The action to run on thread completion. + /// An optional string passed to the COM object at startup. + /// The number of milliseconds to wait or -1 for indefinitely. + /// + /// An optional delegate that is called when the COM object calls the + /// method. + /// + public static void RunComHandlerActionAsync(Guid clsid, Action onComplete, string data = null, int millisecondsTimeout = -1, ComHandlerUpdate onUpdate = null) => new ComHandlerThread(clsid, data, millisecondsTimeout, onUpdate, onComplete).Start(); + + /// Adds or updates an Automatic Maintenance Task on the connected machine. + /// Name of the task with full path. + /// The amount of time the task needs once executed during regular Automatic maintenance. + /// + /// The amount of time after which the Task Scheduler attempts to run the task during emergency Automatic maintenance, if the task + /// failed to complete during regular Automatic Maintenance. + /// + /// The path to an executable file. + /// The arguments associated with the command-line operation. + /// + /// The directory that contains either the executable file or the files that are used by the executable file. + /// + /// A instance of the Automatic Maintenance Task. + /// + /// Automatic Maintenance tasks are only supported on Windows 8/Server 2012 and later. + /// + public Task AddAutomaticMaintenanceTask([NotNull] string taskPathAndName, TimeSpan period, TimeSpan deadline, string executablePath, string arguments = null, string workingDirectory = null) + { + if (HighestSupportedVersion.Minor < 4) + throw new InvalidOperationException("Automatic Maintenance tasks are only supported on Windows 8/Server 2012 and later."); + var td = NewTask(); + td.Settings.UseUnifiedSchedulingEngine = true; + td.Settings.MaintenanceSettings.Period = period; + td.Settings.MaintenanceSettings.Deadline = deadline; + td.Actions.Add(executablePath, arguments, workingDirectory); + // The task needs to grant explicit FRFX to LOCAL SERVICE (A;;FRFX;;;LS) + return RootFolder.RegisterTaskDefinition(taskPathAndName, td, TaskCreation.CreateOrUpdate, null, null, TaskLogonType.InteractiveToken, "D:P(A;;FA;;;BA)(A;;FA;;;SY)(A;;FRFX;;;LS)"); + } + + /// Creates a new task, registers the task, and returns the instance. + /// + /// The task name. If this value is NULL, the task will be registered in the root task folder and the task name will be a GUID value + /// that is created by the Task Scheduler service. A task name cannot begin or end with a space character. The '.' character cannot + /// be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path. + /// + /// The to determine when to run the task. + /// The to determine what happens when the task is triggered. + /// The user credentials used to register the task. + /// The password for the userId used to register the task. + /// + /// A value that defines what logon technique is used to run the registered task. + /// + /// The task description. + /// A instance of the registered task. + /// + /// This method is shorthand for creating a new TaskDescription, adding a trigger and action, and then registering it in the root folder. + /// + /// + /// + /// + /// + /// + public Task AddTask([NotNull] string path, [NotNull] Trigger trigger, [NotNull] Action action, string userId = null, string password = null, TaskLogonType logonType = TaskLogonType.InteractiveToken, string description = null) + { + var td = NewTask(); + if (!string.IsNullOrEmpty(description)) + td.RegistrationInfo.Description = description; + + // Create a trigger that will fire the task at a specific date and time + td.Triggers.Add(trigger); + + // Create an action that will launch Notepad whenever the trigger fires + td.Actions.Add(action); + + // Register the task in the root folder + return RootFolder.RegisterTaskDefinition(path, td, TaskCreation.CreateOrUpdate, userId, password, logonType); + } + + /// Creates a new task, registers the task, and returns the instance. + /// + /// The task name. If this value is NULL, the task will be registered in the root task folder and the task name will be a GUID value + /// that is created by the Task Scheduler service. A task name cannot begin or end with a space character. The '.' character cannot + /// be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path. + /// + /// The to determine when to run the task. + /// The executable path. + /// The arguments (optional). Value can be NULL. + /// The user credentials used to register the task. + /// The password for the userId used to register the task. + /// + /// A value that defines what logon technique is used to run the registered task. + /// + /// The task description. + /// A instance of the registered task. + /// + /// + /// + /// + /// + public Task AddTask([NotNull] string path, QuickTriggerType trigger, [NotNull] string exePath, string arguments = null, string userId = null, string password = null, TaskLogonType logonType = TaskLogonType.InteractiveToken, string description = null) + { + // Create a trigger based on quick trigger + Trigger newTrigger; + switch (trigger) + { + case QuickTriggerType.Boot: + newTrigger = new BootTrigger(); + break; + + case QuickTriggerType.Idle: + newTrigger = new IdleTrigger(); + break; + + case QuickTriggerType.Logon: + newTrigger = new LogonTrigger(); + break; + + case QuickTriggerType.TaskRegistration: + newTrigger = new RegistrationTrigger(); + break; + + case QuickTriggerType.Hourly: + newTrigger = new DailyTrigger { Repetition = new RepetitionPattern(TimeSpan.FromHours(1), TimeSpan.FromDays(1)) }; + break; + + case QuickTriggerType.Daily: + newTrigger = new DailyTrigger(); + break; + + case QuickTriggerType.Weekly: + newTrigger = new WeeklyTrigger(); + break; + + case QuickTriggerType.Monthly: + newTrigger = new MonthlyTrigger(); + break; + + default: + throw new ArgumentOutOfRangeException(nameof(trigger), trigger, null); + } + + return AddTask(path, newTrigger, new ExecAction(exePath, arguments), userId, password, logonType, description); + } + + /// Signals the object that initialization is starting. + public void BeginInit() => initializing = true; + + /// Signals the object that initialization is complete. + public void EndInit() + { + initializing = false; + Connect(); + } + + /// Determines whether the specified , is equal to this instance. + /// The to compare with this instance. + /// true if the specified is equal to this instance; otherwise, false. + public override bool Equals(object obj) + { + var tsobj = obj as TaskService; + if (tsobj != null) + return tsobj.TargetServer == TargetServer && tsobj.UserAccountDomain == UserAccountDomain && tsobj.UserName == UserName && tsobj.UserPassword == UserPassword && tsobj.forceV1 == forceV1; + return base.Equals(obj); + } + + /// Finds all tasks matching a name or standard wildcards. + /// Name of the task in regular expression form. + /// if set to true search all sub folders. + /// An array of containing all tasks matching . + public Task[] FindAllTasks(System.Text.RegularExpressions.Regex name, bool searchAllFolders = true) + { + var results = new System.Collections.Generic.List(); + FindTaskInFolder(RootFolder, name, ref results, searchAllFolders); + return results.ToArray(); + } + + /// Finds all tasks matching a name or standard wildcards. + /// The filter used to determine tasks to select. + /// if set to true search all sub folders. + /// An array of containing all tasks matching . + public Task[] FindAllTasks(Predicate filter, bool searchAllFolders = true) + { + if (filter == null) filter = t => true; + var results = new System.Collections.Generic.List(); + FindTaskInFolder(RootFolder, filter, ref results, searchAllFolders); + return results.ToArray(); + } + + /// Finds a task given a name and standard wildcards. + /// The task name. This can include the wildcards * or ?. + /// if set to true search all sub folders. + /// A if one matches , otherwise NULL. + public Task FindTask([NotNull] string name, bool searchAllFolders = true) + { + var results = FindAllTasks(new Wildcard(name), searchAllFolders); + if (results.Length > 0) + return results[0]; + return null; + } + + /// Gets the event log for this instance. + /// (Optional) The task path if only the events for a single task are desired. + /// A instance. + public TaskEventLog GetEventLog(string taskPath = null) => new TaskEventLog(TargetServer, taskPath, UserAccountDomain, UserName, UserPassword); + + /// Gets the path to a folder of registered tasks. + /// + /// The path to the folder to retrieve. Do not use a backslash following the last folder name in the path. The root task folder is + /// specified with a backslash (\). An example of a task folder path, under the root task folder, is \MyTaskFolder. The '.' character + /// cannot be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path. + /// + /// instance for the requested folder or null if was unrecognized. + /// + /// Folder other than the root (\) was requested on a system not supporting Task Scheduler 2.0. + /// + public TaskFolder GetFolder(string folderName) + { + TaskFolder f = null; + if (v2TaskService != null) + { + if (string.IsNullOrEmpty(folderName)) folderName = TaskFolder.rootString; + try + { + var ifld = v2TaskService.GetFolder(folderName); + if (ifld != null) + f = new TaskFolder(this, ifld); + } + catch (System.IO.DirectoryNotFoundException) { } + catch (System.IO.FileNotFoundException) { } + } + else if (folderName == TaskFolder.rootString || string.IsNullOrEmpty(folderName)) + f = new TaskFolder(this); + else + throw new NotV1SupportedException("Folder other than the root (\\) was requested on a system only supporting Task Scheduler 1.0."); + return f; + } + + /// Returns a hash code for this instance. + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + public override int GetHashCode() => new { A = TargetServer, B = UserAccountDomain, C = UserName, D = UserPassword, E = forceV1 }.GetHashCode(); + + /// Gets a collection of running tasks. + /// True to include hidden tasks. + /// instance with the list of running tasks. + public RunningTaskCollection GetRunningTasks(bool includeHidden = true) + { + if (v2TaskService != null) + try + { + return new RunningTaskCollection(this, v2TaskService.GetRunningTasks(includeHidden ? 1 : 0)); + } + catch { } + return new RunningTaskCollection(this); + } + + /// Gets the task with the specified path. + /// The task path. + /// + /// The instance matching the , if found. If not found, this method returns null. + /// + public Task GetTask([NotNull] string taskPath) + { + Task t = null; + if (v2TaskService != null) + { + var iTask = GetTask(v2TaskService, taskPath); + if (iTask != null) + t = Task.CreateTask(this, iTask); + } + else + { + taskPath = System.IO.Path.GetFileNameWithoutExtension(taskPath); + var iTask = GetTask(v1TaskScheduler, taskPath); + if (iTask != null) + t = new Task(this, iTask); + } + return t; + } + + /// + /// Returns an empty task definition object to be filled in with settings and properties and then registered using the + /// method. + /// + /// A instance for setting properties. + public TaskDefinition NewTask() + { + if (v2TaskService != null) + return new TaskDefinition(v2TaskService.NewTask(0)); + var v1Name = "Temp" + Guid.NewGuid().ToString("B"); + return new TaskDefinition(v1TaskScheduler.NewWorkItem(v1Name, CLSID_Ctask, IID_ITask), v1Name); + } + + /// Returns a populated with the properties defined in an XML file. + /// The XML file to use as input. + /// A instance. + /// Importing from an XML file is only supported under Task Scheduler 2.0. + public TaskDefinition NewTaskFromFile([NotNull] string xmlFile) + { + var td = NewTask(); + td.XmlText = System.IO.File.ReadAllText(xmlFile); + return td; + } + + /// Starts the Task Scheduler UI for the OS hosting the assembly if the session is running in interactive mode. + public void StartSystemTaskSchedulerManager() + { + if (Environment.UserInteractive) + System.Diagnostics.Process.Start("control.exe", "schedtasks"); + } + + [System.Security.SecurityCritical] + void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + info.AddValue("TargetServer", TargetServer, typeof(string)); + info.AddValue("UserName", UserName, typeof(string)); + info.AddValue("UserAccountDomain", UserAccountDomain, typeof(string)); + info.AddValue("UserPassword", UserPassword, typeof(string)); + info.AddValue("forceV1", forceV1, typeof(bool)); + } + + internal static V2Interop.IRegisteredTask GetTask([NotNull] V2Interop.ITaskService iSvc, [NotNull] string name) + { + V2Interop.ITaskFolder fld = null; + try + { + fld = iSvc.GetFolder("\\"); + return fld.GetTask(name); + } + catch + { + return null; + } + finally + { + if (fld != null) Marshal.ReleaseComObject(fld); + } + } + + internal static V1Interop.ITask GetTask([NotNull] V1Interop.ITaskScheduler iSvc, [NotNull] string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException(nameof(name)); + try + { + return iSvc.Activate(name, IID_ITask); + } + catch (UnauthorizedAccessException) + { + // TODO: Take ownership of the file and try again + throw; + } + catch (ArgumentException) + { + return iSvc.Activate(name + ".job", IID_ITask); + } + catch (FileNotFoundException) + { + return null; + } + } + + /// + /// Releases the unmanaged resources used by the and optionally releases the managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected override void Dispose(bool disposing) + { + if (v2TaskService != null) + { + try + { + Marshal.ReleaseComObject(v2TaskService); + } + catch { } + v2TaskService = null; + } + if (v1TaskScheduler != null) + { + try + { + Marshal.ReleaseComObject(v1TaskScheduler); + } + catch { } + v1TaskScheduler = null; + } + if (v1Impersonation != null) + { + v1Impersonation.Dispose(); + v1Impersonation = null; + } + if (!connecting) + ServiceDisconnected?.Invoke(this, EventArgs.Empty); + base.Dispose(disposing); + } + + private static Version GetLibraryVersionFromLocalOS() + { + if (osLibVer == null) + { + if (Environment.OSVersion.Version.Major < 6) + osLibVer = TaskServiceVersion.V1_1; + else + { + if (Environment.OSVersion.Version.Minor == 0) + osLibVer = TaskServiceVersion.V1_2; + else if (Environment.OSVersion.Version.Minor == 1) + osLibVer = TaskServiceVersion.V1_3; + else + { + try + { + var fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(Path.Combine(Environment.SystemDirectory, "taskschd.dll")); + if (fvi.FileBuildPart > 9600 && fvi.FileBuildPart <= 14393) + osLibVer = TaskServiceVersion.V1_5; + else if (fvi.FileBuildPart >= 15063) + osLibVer = TaskServiceVersion.V1_6; + else // fvi.FileBuildPart <= 9600 + osLibVer = TaskServiceVersion.V1_4; + } + catch { /* ignored */ }; + } + } + + if (osLibVer == null) + throw new NotSupportedException(@"The Task Scheduler library version for this system cannot be determined."); + } + return osLibVer; + } + + private static void Instance_ServiceDisconnected(object sender, EventArgs e) => instance?.Connect(); + + /// Connects this instance of the class to a running Task Scheduler. + private void Connect() + { + ResetUnsetProperties(); + + if (!initializing && !DesignMode) + { + if (!string.IsNullOrEmpty(userDomain) && !string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(userPassword) || string.IsNullOrEmpty(userDomain) && string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(userPassword)) + { + // Clear stuff if already connected + connecting = true; + Dispose(true); + + if (LibraryIsV2 && !forceV1) + { + v2TaskService = new V2Interop.ITaskService(); + if (!string.IsNullOrEmpty(targetServer)) + { + // Check to ensure character only server name. (Suggested by bigsan) + if (targetServer.StartsWith(@"\")) + targetServer = targetServer.TrimStart('\\'); + // Make sure null is provided for local machine to compensate for a native library oddity (Found by ctrollen) + if (targetServer.Equals(Environment.MachineName, StringComparison.CurrentCultureIgnoreCase)) + targetServer = null; + } + else + targetServer = null; + v2TaskService.Connect(targetServer, userName, userDomain, userPassword); + targetServer = v2TaskService.TargetServer; + userName = v2TaskService.ConnectedUser; + userDomain = v2TaskService.ConnectedDomain; + maxVer = GetV2Version(); + } + else + { + v1Impersonation = new WindowsImpersonatedIdentity(userName, userDomain, userPassword); + v1TaskScheduler = new V1Interop.ITaskScheduler(); + if (!string.IsNullOrEmpty(targetServer)) + { + // Check to ensure UNC format for server name. (Suggested by bigsan) + if (!targetServer.StartsWith(@"\\")) + targetServer = @"\\" + targetServer; + } + else + targetServer = null; + v1TaskScheduler.SetTargetComputer(targetServer); + targetServer = v1TaskScheduler.GetTargetComputer(); + maxVer = TaskServiceVersion.V1_1; + } + ServiceConnected?.Invoke(this, EventArgs.Empty); + connecting = false; + } + else + { + throw new ArgumentException("A username, password, and domain must be provided."); + } + } + } + + /// Finds the task in folder. + /// The folder. + /// The wildcard expression to compare task names with. + /// The results. + /// if set to true recurse folders. + /// True if any tasks are found, False if not. + private bool FindTaskInFolder([NotNull] TaskFolder fld, System.Text.RegularExpressions.Regex taskName, ref System.Collections.Generic.List results, bool recurse = true) + { + results.AddRange(fld.GetTasks(taskName)); + + if (recurse) + { + foreach (var f in fld.SubFolders) + { + if (FindTaskInFolder(f, taskName, ref results)) + return true; + } + } + return false; + } + + /// Finds the task in folder. + /// The folder. + /// The filter to use when looking for tasks. + /// The results. + /// if set to true recurse folders. + /// True if any tasks are found, False if not. + private bool FindTaskInFolder([NotNull] TaskFolder fld, Predicate filter, ref System.Collections.Generic.List results, bool recurse = true) + { + foreach (var t in fld.GetTasks()) + try + { + if (filter(t)) + results.Add(t); + } + catch + { + System.Diagnostics.Debug.WriteLine($"Unable to evaluate filter for task '{t.Path}'."); + } + + if (recurse) + { + foreach (var f in fld.SubFolders) + { + if (FindTaskInFolder(f, filter, ref results)) + return true; + } + } + return false; + } + + private Version GetV2Version() + { + var v = v2TaskService.HighestVersion; + return new Version((int)(v >> 16), (int)(v & 0x0000FFFF)); + } + + private void ResetHighestSupportedVersion() => maxVer = Connected ? (v2TaskService != null ? GetV2Version() : TaskServiceVersion.V1_1) : GetLibraryVersionFromLocalOS(); + + private void ResetUnsetProperties() + { + if (!maxVerSet) ResetHighestSupportedVersion(); + if (!targetServerSet) targetServer = null; + if (!userDomainSet) userDomain = null; + if (!userNameSet) userName = null; + if (!userPasswordSet) userPassword = null; + } + + private bool ShouldSerializeHighestSupportedVersion() => LibraryIsV2 && maxVer <= TaskServiceVersion.V1_1; + + private bool ShouldSerializeTargetServer() => targetServer != null && !targetServer.Trim('\\').Equals(Environment.MachineName.Trim('\\'), StringComparison.InvariantCultureIgnoreCase); + + private bool ShouldSerializeUserAccountDomain() => userDomain != null && !userDomain.Equals(Environment.UserDomainName, StringComparison.InvariantCultureIgnoreCase); + + private bool ShouldSerializeUserName() => userName != null && !userName.Equals(Environment.UserName, StringComparison.InvariantCultureIgnoreCase); + + /// + /// Represents a valid, connected session to a Task Scheduler instance. This token is thread-safe and should be the means of passing + /// information about a between threads. + /// + public struct ConnectionToken + { + internal int token; + + internal ConnectionToken(int value) => token = value; + } + + // Manages the list of tokens and associated data + private static class ConnectionDataManager + { + public static List connections = new List() { new ConnectionData(null) }; + + public static TaskService InstanceFromToken(ConnectionToken token) + { + ConnectionData data; + lock (connections) + { + data = connections[token.token < connections.Count ? token.token : 0]; + } + return new TaskService(data.TargetServer, data.UserName, data.UserAccountDomain, data.UserPassword, data.ForceV1); + } + + public static ConnectionToken TokenFromInstance(string targetServer, string userName = null, + string accountDomain = null, string password = null, bool forceV1 = false) + { + lock (connections) + { + var newData = new ConnectionData(targetServer, userName, accountDomain, password, forceV1); + for (var i = 0; i < connections.Count; i++) + { + if (connections[i].Equals(newData)) + return new ConnectionToken(i); + } + connections.Add(newData); + return new ConnectionToken(connections.Count - 1); + } + } + } + + private class ComHandlerThread + { + public int ReturnCode; + private readonly System.Threading.AutoResetEvent completed = new System.Threading.AutoResetEvent(false); + private readonly string Data; + private readonly Type objType; + private readonly TaskHandlerStatus status; + private readonly int Timeout; + + public ComHandlerThread(Guid clsid, string data, int millisecondsTimeout, ComHandlerUpdate onUpdate, Action onComplete) + { + objType = Type.GetTypeFromCLSID(clsid, true); + Data = data; + Timeout = millisecondsTimeout; + status = new TaskHandlerStatus(i => + { + completed.Set(); + onComplete?.Invoke(i); + }, onUpdate); + } + + public System.Threading.Thread Start() + { + var t = new System.Threading.Thread(ThreadProc); + t.Start(); + return t; + } + + private void ThreadProc() + { + completed.Reset(); + object obj = null; + try { obj = Activator.CreateInstance(objType); } catch { } + if (obj == null) return; + ITaskHandler taskHandler = null; + try { taskHandler = (ITaskHandler)obj; } catch { } + try + { + if (taskHandler != null) + { + taskHandler.Start(status, Data); + completed.WaitOne(Timeout); + taskHandler.Stop(out ReturnCode); + } + } + finally + { + if (taskHandler != null) + Marshal.ReleaseComObject(taskHandler); + Marshal.ReleaseComObject(obj); + } + } + + private class TaskHandlerStatus : ITaskHandlerStatus + { + private readonly Action OnCompleted; + private readonly ComHandlerUpdate OnUpdate; + + public TaskHandlerStatus(Action onCompleted, ComHandlerUpdate onUpdate) + { + OnCompleted = onCompleted; + OnUpdate = onUpdate; + } + + public void TaskCompleted([In, MarshalAs(UnmanagedType.Error)] int taskErrCode) => OnCompleted?.Invoke(taskErrCode); + + public void UpdateStatus([In] short percentComplete, [In, MarshalAs(UnmanagedType.BStr)] string statusMessage) => OnUpdate?.Invoke(percentComplete, statusMessage); + } + } + + // This private class holds information needed to create a new TaskService instance + private class ConnectionData : IEquatable + { + public bool ForceV1; + public string TargetServer, UserAccountDomain, UserName, UserPassword; + + public ConnectionData(string targetServer, string userName = null, string accountDomain = null, string password = null, bool forceV1 = false) + { + TargetServer = targetServer; + UserAccountDomain = accountDomain; + UserName = userName; + UserPassword = password; + ForceV1 = forceV1; + } + + public bool Equals(ConnectionData other) => string.Equals(TargetServer, other.TargetServer, StringComparison.InvariantCultureIgnoreCase) && + string.Equals(UserAccountDomain, other.UserAccountDomain, StringComparison.InvariantCultureIgnoreCase) && + string.Equals(UserName, other.UserName, StringComparison.InvariantCultureIgnoreCase) && + string.Equals(UserPassword, other.UserPassword, StringComparison.InvariantCultureIgnoreCase) && + ForceV1 == other.ForceV1; + } + + private class VersionConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + return true; + return base.CanConvertFrom(context, sourceType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + var s = value as string; + return s != null ? new Version(s) : base.ConvertFrom(context, culture, value); + } + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/TaskService.csproj b/FlashPatcher/TaskService/TaskService.csproj new file mode 100644 index 0000000..6a099ff --- /dev/null +++ b/FlashPatcher/TaskService/TaskService.csproj @@ -0,0 +1,54 @@ + + + net20;net35;net40;net452;netstandard2.0;netcoreapp2.0;netcoreapp2.1;netcoreapp3.0;netcoreapp3.1;net5.0-windows + + Microsoft.Win32.TaskScheduler + Microsoft.Win32.TaskScheduler + TaskScheduler + Task Scheduler Managed Wrapper (the original Microsoft.Win32.TaskScheduler) + Provides a single assembly wrapper for the 1.0 and 2.0 versions of Task Scheduler found in all Microsoft operating systems post Windows 98. It simplifies the coding, aggregates the multiple versions and allows for localization support. + task;interop;windows;taskscheduler;scheduler;.net;task scheduler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + \ No newline at end of file diff --git a/FlashPatcher/TaskService/TaskServiceCronExt.cs b/FlashPatcher/TaskService/TaskServiceCronExt.cs new file mode 100644 index 0000000..5b6c54d --- /dev/null +++ b/FlashPatcher/TaskService/TaskServiceCronExt.cs @@ -0,0 +1,443 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; + +namespace Microsoft.Win32.TaskScheduler +{ + public abstract partial class Trigger + { + /// Creates a trigger using a cron string. + /// String using cron defined syntax for specifying a time interval. See remarks for syntax. + /// Array of representing the specified cron string. + /// Unsupported cron string. + /// + /// This method does not support all combinations of cron strings. Please test extensively before use. Please post an issue with any + /// syntax that should work, but doesn't. + /// The following combinations are known not to work: + /// + /// Intervals on months (e.g. "* * * */5 *") + /// Intervals on DOW (e.g. "* * * * MON/3") + /// + /// + /// This section borrows liberally from the site http://www.nncron.ru/help/EN/working/cron-format.htm. The cron format consists of five fields separated + /// by white spaces: + /// + /// + /// <Minute> <Hour> <Day_of_the_Month> <Month_of_the_Year> <Day_of_the_Week> + /// + /// Each item has bounds as defined by the following: + /// + /// * * * * * + /// | | | | | + /// | | | | +---- Day of the Week (range: 1-7, 1 standing for Monday) + /// | | | +------ Month of the Year (range: 1-12) + /// | | +-------- Day of the Month (range: 1-31) + /// | +---------- Hour (range: 0-23) + /// +------------ Minute (range: 0-59) + /// + /// Any of these 5 fields may be an asterisk (*). This would mean the entire range of possible values, i.e. each minute, each hour, etc. + /// + /// Any of the first 4 fields can be a question mark ("?"). It stands for the current time, i.e. when a field is processed, the current time will be + /// substituted for the question mark: minutes for Minute field, hour for Hour field, day of the month for Day of month field and month for Month field. + /// + /// Any field may contain a list of values separated by commas, (e.g. 1,3,7) or a range of values (two integers separated by a hyphen, e.g. 1-5). + /// + /// After an asterisk (*) or a range of values, you can use character / to specify that values are repeated over and over with a certain interval between + /// them. For example, you can write "0-23/2" in Hour field to specify that some action should be performed every two hours (it will have the same effect + /// as "0,2,4,6,8,10,12,14,16,18,20,22"); value "*/4" in Minute field means that the action should be performed every 4 minutes, "1-30/3" means the same + /// as "1,4,7,10,13,16,19,22,25,28". + /// + /// + public static Trigger[] FromCronFormat([NotNull] string cronString) + { + var cron = CronExpression.Parse(cronString); + System.Diagnostics.Debug.WriteLine($"{cronString}=M:{cron.Minutes}; H:{cron.Hours}; D:{cron.Days}; M:{cron.Months}; W:{cron.DOW}"); + + var ret = new List(); + + // There isn't a clean mechanism to handle intervals on DOW or months, so punt + //if (cron.DOW.IsIncr) throw new NotSupportedException(); + //if (cron.Months.IsIncr) throw new NotSupportedException(); + + // WeeklyTrigger + if (cron.Days.FullRange && cron.Months.FullRange && !cron.DOW.IsEvery) + { + var tr = new WeeklyTrigger(cron.DOW.ToDOW()); + ret.AddRange(ProcessCronTimes(cron, tr)); + } + + // MonthlyDOWTrigger + if (!cron.DOW.FullRange && (!cron.Days.FullRange || !cron.Months.FullRange)) + { + var tr = new MonthlyDOWTrigger(cron.DOW.ToDOW(), cron.Months.ToMOY(), WhichWeek.AllWeeks); + ret.AddRange(ProcessCronTimes(cron, tr)); + } + + // MonthlyTrigger + if (!cron.Days.FullRange || !cron.Months.FullRange && cron.DOW.FullRange) + { + var tr = new MonthlyTrigger(1, cron.Months.ToMOY()) { DaysOfMonth = cron.Days.Values.ToArray() }; + ret.AddRange(ProcessCronTimes(cron, tr)); + } + + // DailyTrigger + if (cron.Days.FullRange && cron.Months.FullRange && cron.DOW.IsEvery) + { + var tr = new DailyTrigger((short)cron.Days.Increment); + ret.AddRange(ProcessCronTimes(cron, tr)); + } + + // Fail out + if (ret.Count == 0) + throw new NotSupportedException(); + + return ret.ToArray(); + } + + private static IEnumerable ProcessCronTimes(CronExpression cron, Trigger baseTrigger) + { + // Sequential hours, every minute + // "* * * * *" + // "* 2-6 * * *" + if (cron.Minutes.FullRange && (cron.Hours.IsEvery || cron.Hours.IsRange)) + { + System.Diagnostics.Debug.WriteLine("Minutes.FullRange && (Hours.IsEvery || Hours.IsRange)"); + yield return MakeTrigger( + new TimeSpan(cron.Hours.FirstValue, 0, 0), + TimeSpan.FromMinutes(cron.Minutes.Increment), + TimeSpan.FromHours(cron.Hours.Duration)); + } + // Non-sequential hours, every minute + // "* 3,5,6 * * *" + // "* 3-15/3 * * *" + else if (cron.Minutes.FullRange && (cron.Hours.IsList || cron.Hours.IsIncr)) + { + System.Diagnostics.Debug.WriteLine("Minutes.FullRange && (Hours.IsList || Hours.IsIncr)"); + foreach (var h in cron.Hours.Values) + { + yield return MakeTrigger( + new TimeSpan(h, 0, 0), + TimeSpan.FromMinutes(cron.Minutes.Increment), + TimeSpan.FromHours(1)); + } + } + // Non-repeating minutes, every hour + // "3,6 * * * *" Every hour starting at 12:03 and 12:06 + // "3-33 * * * *" + // "3-33/6 * * * *" + // "3,6 * 3-5 * *" + // "3-33 3-5 * * *" + // "3-33/6 3-5 * * *" + else if (!cron.Minutes.FullRange && (cron.Hours.IsEvery || cron.Hours.IsRange)) + { + System.Diagnostics.Debug.WriteLine("!Minutes.FullRange && (Hours.IsEvery || Hours.IsRange)"); + foreach (var m in cron.Minutes.Values) + { + yield return MakeTrigger( + new TimeSpan(cron.Hours.FirstValue, m, 0), + TimeSpan.FromHours(1), + TimeSpan.FromHours(cron.Hours.Duration)); + } + } + // Sequential or repeating minutes, and non-sequential hours + else if ((cron.Minutes.IsRange || cron.Minutes.IsIncr) && (cron.Hours.IsList || cron.Hours.IsIncr)) + { + System.Diagnostics.Debug.WriteLine("(Minutes.IsRange || Minutes.IsIncr) && (Hours.IsList || Hours.IsIncr)"); + foreach (var h in cron.Hours.Values) + { + yield return MakeTrigger( + new TimeSpan(h, cron.Minutes.FirstValue, 0), + TimeSpan.FromMinutes(cron.Minutes.Increment), + TimeSpan.FromMinutes(cron.Minutes.Duration)); + } + } + // Non-sequential, hours and minutes + // "3,6 3,6 * * *" Every day at 3:03, 3:06, 6:03 and 6:06 + // "3/6 3/6 * * *" Every day at 3:03, 3:06, 6:03 and 6:06 + else + { + System.Diagnostics.Debug.WriteLine("Minutes.IsList && (Hours.IsIncr || Hours.IsList)"); + foreach (var h in cron.Hours.Values) + foreach (var m in cron.Minutes.Values) + yield return MakeTrigger(new TimeSpan(h, m, 0)); + } + + Trigger MakeTrigger(TimeSpan start, TimeSpan interval = default, TimeSpan duration = default) + { + var newTr = (Trigger)baseTrigger.Clone(); + newTr.StartBoundary = newTr.StartBoundary.Date + start; + if (interval != default) + { + newTr.Repetition.Interval = interval; + newTr.Repetition.Duration = duration; + } + return newTr; + } + } + + internal class CronExpression + { + private FieldVal[] Fields = new FieldVal[5]; + + private CronExpression() { } + + public enum CronFieldType { Minutes, Hours, Days, Months, DaysOfWeek }; + + public FieldVal Days => Fields[2]; + + public FieldVal DOW => Fields[4]; + + public FieldVal Hours => Fields[1]; + + public FieldVal Minutes => Fields[0]; + + public FieldVal Months => Fields[3]; + + public static CronExpression Parse(string cronString) + { + var ret = new CronExpression(); + if (cronString == null) + throw new ArgumentNullException(nameof(cronString)); + + var tokens = cronString.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + if (tokens.Length != 5) + { + throw new ArgumentException($"'{cronString}' is not a valid crontab expression. It must contain at least 5 components of a schedule " + + "(in the sequence of minutes, hours, days, months, days of week)."); + } + + // min, hr, days, months, daysOfWeek + for (var i = 0; i < ret.Fields.Length; i++) + ret.Fields[i] = FieldVal.Parse(tokens[i], (CronFieldType)i); + + return ret; + } + + public struct FieldVal + { + private const string rangeRegEx = @"^(?:(?\*)|(?\d+)(?:-(?\d+))?)(?:\/(?\d+))?$"; + private readonly static Dictionary dow = new Dictionary(7) + { + { "SUN", "0" }, + { "MON", "1" }, + { "TUE", "2" }, + { "WED", "3" }, + { "THU", "4" }, + { "FRI", "5" }, + { "SAT", "6" }, + }; + private readonly static Dictionary mon = new Dictionary(12) + { + { "JAN", "1" }, + { "FEB", "2" }, + { "MAR", "3" }, + { "APR", "4" }, + { "MAY", "5" }, + { "JUN", "6" }, + { "JUL", "7" }, + { "AUG", "8" }, + { "SEP", "9" }, + { "OCT", "10" }, + { "NOV", "11" }, + { "DEC", "12" }, + }; + private readonly static Dictionary validRange = new Dictionary(5) + { + { CronFieldType.Days, new MinMax(1, 31) }, + { CronFieldType.DaysOfWeek, new MinMax(0, 6) }, + { CronFieldType.Hours, new MinMax(0, 23) }, + { CronFieldType.Minutes, new MinMax(0, 59) }, + { CronFieldType.Months, new MinMax(1, 12) }, + }; + private CronFieldType cft; + private FieldFlags flags; + private int incr; + private int[] vals; + public FieldVal(CronFieldType cft) { this.cft = cft; flags = 0; vals = new int[0]; incr = 1; FullRange = false; } + + enum FieldFlags { List, Every, Range, Increment }; + public int Duration => vals.Length == 1 ? 1 : vals[1] - vals[0] + 1; + public int Increment => incr; + public bool IsEvery { get => flags == FieldFlags.Every; private set => flags = FieldFlags.Every; } + public bool IsIncr { get => flags == FieldFlags.Increment; private set => flags = FieldFlags.Increment; } + public bool IsList { get => flags == 0; private set => flags = FieldFlags.List; } + public bool IsRange { get => flags == FieldFlags.Range; private set => flags = FieldFlags.Range; } + public bool FullRange { get; private set; } + public int FirstValue => vals[0]; + public IEnumerable Values + { + get + { + if (flags == 0) + { + foreach (var i in vals) + yield return i; + } + else + { + for (int i = vals[0]; i <= vals[1]; i += incr) + yield return i; + } + } + } + + public DaysOfTheWeek ToDOW() + { + if (IsEvery) return DaysOfTheWeek.AllDays; + DaysOfTheWeek ret = 0; + foreach (var i in Values) + ret |= (DaysOfTheWeek)(1 << i); + return ret; + } + + public MonthsOfTheYear ToMOY() + { + if (IsEvery) return MonthsOfTheYear.AllMonths; + MonthsOfTheYear ret = 0; + foreach (var i in Values) + ret |= (MonthsOfTheYear)(1 << (i - 1)); + return ret; + } + + public static FieldVal Parse(string str, CronFieldType cft) + { + var res = new FieldVal(cft); + if (string.IsNullOrEmpty(str)) + throw new ArgumentNullException(nameof(str), "A crontab field value cannot be empty."); + + // Do substitutions + str = DoSubs(str, cft); + + // Look first for a list of values (e.g. 1,2,3). + if (System.Text.RegularExpressions.Regex.IsMatch(str, @"^\d+(,\d+)*$")) + { + if (str.Contains("/")) throw new NotSupportedException(); + + res.vals = str.Split(',').Select(ParseInt).OrderBy(i => i).Distinct().ToArray(); + res.Validate(); + return res; + } + + // Look for *|nn[-nn][/n] pattern + var match = System.Text.RegularExpressions.Regex.Match(str, rangeRegEx); + if (match.Success) + { + bool hasAst = res.FullRange = match.Groups["A"].Success; + if (match.Groups["I"].Success) + { + res.incr = ParseInt(match.Groups["I"].Value); + res.IsIncr = true; + } + else + { + if (hasAst) + res.IsEvery = true; + else + res.IsRange = true; + } + var mm = validRange[cft]; + var start = hasAst ? mm.Min : ParseInt(match.Groups["D1"].Value); + var end = hasAst ? mm.Max : (match.Groups["D2"].Success ? ParseInt(match.Groups["D2"].Value) : (res.IsIncr ? mm.Max : start)); + if (end < start) throw new ArgumentOutOfRangeException(); + if (start == end && res.IsRange) + { + res.IsList = true; + res.vals = new[] { start }; + } + else + res.vals = new[] { start, end }; + res.Validate(); + return res; + } + + throw new FormatException(); + } + + public override string ToString() => $"Type:{flags}; Vals:{string.Join(",", vals.Select(i => i.ToString()).ToArray())}; Incr:{incr}"; + + private void Validate() + { + var l = validRange[cft]; + if (vals.Any(i => i < l.Min || i > l.Max)) throw new ArgumentOutOfRangeException(); + if (IsIncr && (incr < l.Min || incr > l.Max)) throw new ArgumentOutOfRangeException(); + } + + private static string DoSubs(string str, CronFieldType cft) + { + var sb = new System.Text.StringBuilder(str); + + // Handle SUN-SAT strings + if (cft == CronFieldType.DaysOfWeek) + { + foreach (var kv in dow) + sb.Replace(kv.Key, kv.Value); + } + + // Handle JAN–DEC strings + if (cft == CronFieldType.Months) + { + foreach (var kv in mon) + sb.Replace(kv.Key, kv.Value); + } + + // Check for "?" and substitute current time + if (sb.Length == 1 && sb.ToString() == "?") + { + var now = DateTime.Now; + var nval = 0; + switch (cft) + { + case CronFieldType.Minutes: + nval = now.Minute; + break; + case CronFieldType.Hours: + nval = now.Hour; + break; + case CronFieldType.Days: + nval = now.Day; + break; + case CronFieldType.Months: + nval = now.Month; + break; + case CronFieldType.DaysOfWeek: + nval = (int)now.DayOfWeek; + break; + default: + break; + } + sb.Remove(0, 1); + sb.Append(nval); + } + + // Expand or collapse ranges + var minMax = validRange[cft]; + foreach (System.Text.RegularExpressions.Match m in System.Text.RegularExpressions.Regex.Matches(sb.ToString(), @"(\d+)-(\d+)")) + { + var low = ParseInt(m.Groups[1].Value); + var high = ParseInt(m.Groups[2].Value); + if (low == minMax.Min && high == minMax.Max) + sb.Replace(m.Value, "*"); + else if (sb.ToString().Contains(',')) + { + var rsb = new System.Text.StringBuilder(low.ToString()); + for (int i = low; i < high; i++) + rsb.Append($",{i + 1}"); + sb.Replace(m.Value, rsb.ToString()); + } + } + + return sb.ToString(); + } + + private static int ParseInt(string str) => int.Parse(str.Trim()); + + private struct MinMax + { + public int Min, Max; + public MinMax(int min, int max) { Min = min; Max = max; } + } + } + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/TaskServiceFluentExt.cs b/FlashPatcher/TaskService/TaskServiceFluentExt.cs new file mode 100644 index 0000000..74a54e0 --- /dev/null +++ b/FlashPatcher/TaskService/TaskServiceFluentExt.cs @@ -0,0 +1,494 @@ +using JetBrains.Annotations; +using System; + +namespace Microsoft.Win32.TaskScheduler +{ + public sealed partial class TaskService + { + /// Initial call for a Fluent model of creating a task. + /// The path of the program to run. + /// An instance. + public Fluent.ActionBuilder Execute([NotNull] string path) => new Fluent.ActionBuilder(new Fluent.BuilderInfo(this), path); + } + + namespace Fluent + { + /// Fluent helper class. Not intended for use. + public class ActionBuilder : BaseBuilder + { + internal ActionBuilder(BuilderInfo taskBuilder, string path) + : base(taskBuilder) => TaskDef.Actions.Add(new ExecAction(path)); + + /// Adds a trigger that executes at logon of all users. + /// instance. + public TriggerBuilder AtLogon() => new TriggerBuilder(tb, TaskTriggerType.Logon); + + /// Adds a trigger that executes at logon of a specific user. + /// The user id. + /// instance. + public TriggerBuilder AtLogonOf(string userId) + { + var b = new TriggerBuilder(tb, TaskTriggerType.Logon); + ((LogonTrigger)b.trigger).UserId = userId; + return b; + } + + /// Adds a trigger that executes at task registration. + /// instance. + public TriggerBuilder AtTaskRegistration() => new TriggerBuilder(tb, TaskTriggerType.Registration); + + /// Adds a trigger that executes every day or week. + /// The interval of days or weeks. + /// instance. + public IntervalTriggerBuilder Every(short num) => new IntervalTriggerBuilder(tb, num); + + /// Adds a trigger that executes monthly on specific days. + /// The months of the year in which to run. + /// instance. + public MonthlyTriggerBuilder InTheMonthOf(MonthsOfTheYear moy) => new MonthlyTriggerBuilder(tb, moy); + + /// Adds a working directory to the . + /// The directory. + /// instance. + public ActionBuilder InWorkingDirectory([NotNull] string dir) + { + ((ExecAction)TaskDef.Actions[0]).WorkingDirectory = dir; + return this; + } + + /// Adds a trigger that executes monthly on certain days of the week. + /// The days of the week on which to run. + /// instance. + public MonthlyDOWTriggerBuilder OnAll(DaysOfTheWeek dow) => new MonthlyDOWTriggerBuilder(tb, dow); + + /// Adds a trigger that executes at system startup. + /// instance. + public TriggerBuilder OnBoot() => new TriggerBuilder(tb, TaskTriggerType.Boot); + + /// Adds a trigger that executes once at a specific time. + /// instance. + public TriggerBuilder Once() => new TriggerBuilder(tb, TaskTriggerType.Time); + + /// Adds a trigger that executes when system is idle. + /// instance. + public TriggerBuilder OnIdle() => new TriggerBuilder(tb, TaskTriggerType.Idle); + + /// Adds a trigger that executes once at specified state change. + /// Type of the change. + /// instance. + public TriggerBuilder OnStateChange(TaskSessionStateChangeType changeType) + { + var b = new TriggerBuilder(tb, TaskTriggerType.SessionStateChange); + ((SessionStateChangeTrigger)b.trigger).StateChange = changeType; + return b; + } + + /// Adds arguments to the . + /// The arguments. + /// instance. + public ActionBuilder WithArguments([NotNull] string args) + { + ((ExecAction)TaskDef.Actions[0]).Arguments = args; + return this; + } + } + + /// Fluent helper class. Not intended for use. + public abstract class BaseBuilder + { + internal BuilderInfo tb; + + internal BaseBuilder(BuilderInfo taskBuilder) => tb = taskBuilder; + + /// Transitions to settings syntax. + public SettingsBuilder When => new SettingsBuilder(tb); + + internal TaskDefinition TaskDef => tb.td; + + /// Assigns the name of the task and registers it. + /// The name. + /// A registered instance. + public Task AsTask([NotNull] string name) => tb.ts.RootFolder.RegisterTaskDefinition(name, TaskDef); + + /// Assigns the name of the task and registers it. + /// The name. + /// A union of flags. + /// The user credentials used to register the task. + /// The password for the userId used to register the task. + /// A value that defines what logon technique is used to run the registered task. + /// A registered instance. + public Task AsTask([NotNull] string name, TaskCreation createType, string userId, string password = null, TaskLogonType logonType = TaskLogonType.S4U) => tb.ts.RootFolder.RegisterTaskDefinition(name, TaskDef, createType, userId, password, logonType); + } + + /// Fluent helper class. Not intended for use. + public class IntervalTriggerBuilder : BaseBuilder + { + internal short interval = 0; + + internal IntervalTriggerBuilder(BuilderInfo taskBuilder, short interval) + : base(taskBuilder) => this.interval = interval; + + /// Specifies that an Every target uses days as the interval. + /// instance. + public TriggerBuilder Days() => new TriggerBuilder(tb) { trigger = TaskDef.Triggers.Add(new DailyTrigger(interval)) }; + + /// Specifies that an Every target uses weeks as the interval. + /// instance. + public WeeklyTriggerBuilder Weeks() => new WeeklyTriggerBuilder(tb, interval); + } + + /// Fluent helper class. Not intended for use. + public class MonthlyDOWTriggerBuilder : BaseBuilder + { + private TriggerBuilder trb; + + internal MonthlyDOWTriggerBuilder(BuilderInfo taskBuilder, DaysOfTheWeek dow) + : base(taskBuilder) => trb = new TriggerBuilder(taskBuilder, dow); + + /// Updates a monthly trigger to specify in which weeks of the month it will run. + /// The week. + /// instance. + public MonthlyDOWTriggerBuilder In(WhichWeek ww) + { + ((MonthlyDOWTrigger)trb.trigger).WeeksOfMonth = ww; + return this; + } + + /// Updates a monthly trigger to specify the months of the year in which it will run. + /// The month of the year. + /// instance. + public TriggerBuilder Of(MonthsOfTheYear moy) + { + ((MonthlyDOWTrigger)trb.trigger).MonthsOfYear = moy; + return trb; + } + } + + /// Fluent helper class. Not intended for use. + public class MonthlyTriggerBuilder : BaseBuilder + { + private TriggerBuilder trb; + + internal MonthlyTriggerBuilder(BuilderInfo taskBuilder, MonthsOfTheYear moy) + : base(taskBuilder) => trb = new TriggerBuilder(taskBuilder, moy); + + /// Updates a monthly trigger to specify the days of the month on which it will run. + /// The days. + /// instance. + public TriggerBuilder OnTheDays([NotNull] params int[] days) + { + ((MonthlyTrigger)trb.trigger).DaysOfMonth = days; + return trb; + } + } + + /// Fluent helper class. Not intended for use. + public class SettingsBuilder : BaseBuilder + { + internal SettingsBuilder(BuilderInfo taskBuilder) : base(taskBuilder) + { + } + + /// Indicates that the task will be started even if the computer is running on battery power. + /// instance. + public SettingsBuilder AllowingStartIfOnBatteries() + { + TaskDef.Settings.DisallowStartIfOnBatteries = false; + return this; + } + + /// + /// Indicates that the task will be started even if the task is triggered to run in a Remote Applications Integrated Locally + /// (RAIL) session. + /// + /// instance. + public SettingsBuilder AllowingStartOnRemoteAppSession() + { + TaskDef.Settings.DisallowStartOnRemoteAppSession = false; + return this; + } + + /// Sets the task data to a string. + /// instance. + public SettingsBuilder DataIs(string data) + { + TaskDef.Data = data; return this; + } + + /// Sets the amount of time that the Task Scheduler will wait before deleting the task after it expires. + /// instance. + public SettingsBuilder DeletingTaskAfter(TimeSpan duration) + { + TaskDef.Settings.DeleteExpiredTaskAfter = duration; + return this; + } + + /// Indicates that the task cannot be started with the Run command or the Context menu. + /// instance. + public SettingsBuilder DisallowingDemandStart() + { + TaskDef.Settings.AllowDemandStart = false; + return this; + } + + /// Indicates that the task may not be terminated by using TerminateProcess. + /// instance. + public SettingsBuilder DisallowingHardTerminate() + { + TaskDef.Settings.AllowHardTerminate = false; + return this; + } + + /// Sets the amount of time that is allowed to complete the task. + /// instance. + public SettingsBuilder ExecutingAtMost(TimeSpan duration) + { + TaskDef.Settings.ExecutionTimeLimit = duration; + return this; + } + + /// Sets the policy that defines how the Task Scheduler handles multiple instances of the task. + /// instance. + public SettingsBuilder InstancesAre(TaskInstancesPolicy policy) + { + TaskDef.Settings.MultipleInstances = policy; + return this; + } + + /// Indicates that the task will not be stopped if the computer switches to battery power. + /// instance. + public SettingsBuilder NotStoppingIfGoingOnBatteries() + { + TaskDef.Settings.StopIfGoingOnBatteries = true; + return this; + } + + /// Indicates that the Task Scheduler will run the task only if the computer is in an idle condition. + /// instance. + public SettingsBuilder OnlyIfIdle() + { + TaskDef.Settings.RunOnlyIfIdle = true; + return this; + } + + /// Indicates that the Task Scheduler will run the task only when a network is available. + /// instance. + public SettingsBuilder OnlyIfNetworkAvailable() + { + TaskDef.Settings.RunOnlyIfNetworkAvailable = true; + return this; + } + + /// Sets the priority level of the task. + /// instance. + public SettingsBuilder PriorityIs(System.Diagnostics.ProcessPriorityClass priority) + { + TaskDef.Settings.Priority = priority; + return this; + } + + /// Sets a value that specifies how long the Task Scheduler will attempt to restart the task. + /// instance. + public SettingsBuilder RestartingEvery(TimeSpan interval) + { + TaskDef.Settings.RestartInterval = interval; + return this; + } + + /// Indicates that the Task Scheduler can start the task at any time after its scheduled time has passed. + /// instance. + public SettingsBuilder StartingWhenAvailable() + { + TaskDef.Settings.StartWhenAvailable = true; + return this; + } + + /// Indicates that the Task Scheduler will wake the computer when it is time to run the task. + /// instance. + public SettingsBuilder WakingToRun() + { + TaskDef.Settings.WakeToRun = true; + return this; + } + } + + /// Fluent helper class. Not intended for use. + public class TriggerBuilder : BaseBuilder + { + internal Trigger trigger; + + internal TriggerBuilder(BuilderInfo taskBuilder) + : base(taskBuilder) + { + } + + internal TriggerBuilder(BuilderInfo taskBuilder, DaysOfTheWeek dow) + : this(taskBuilder) => TaskDef.Triggers.Add(trigger = new MonthlyDOWTrigger(dow)); + + internal TriggerBuilder(BuilderInfo taskBuilder, MonthsOfTheYear moy) + : this(taskBuilder) => TaskDef.Triggers.Add(trigger = new MonthlyTrigger() { MonthsOfYear = moy }); + + internal TriggerBuilder(BuilderInfo taskBuilder, TaskTriggerType taskTriggerType) + : this(taskBuilder) => TaskDef.Triggers.Add(trigger = Trigger.CreateTrigger(taskTriggerType)); + + /// Specifies a date on which a trigger will no longer run. + /// The year. + /// The month. + /// The day. + /// instance. + public TriggerBuilder Ending(int year, int month, int day) + { + trigger.EndBoundary = new DateTime(year, month, day, trigger.StartBoundary.Hour, trigger.StartBoundary.Minute, trigger.StartBoundary.Second); + return this; + } + + /// Specifies a date and time on which a trigger will no longer run. + /// The year. + /// The month. + /// The day. + /// The hour. + /// The min. + /// The sec. + /// instance. + public TriggerBuilder Ending(int year, int month, int day, int hour, int min, int sec) + { + trigger.EndBoundary = new DateTime(year, month, day, hour, min, sec); + return this; + } + + /// Specifies a date and time on which a trigger will no longer run. + /// A string representing a DateTime and parsable via . + /// instance. + public TriggerBuilder Ending([NotNull] string dt) + { + trigger.EndBoundary = DateTime.Parse(dt); + return this; + } + + /// Specifies a date and time on which a trigger will no longer run. + /// The DateTime value. + /// instance. + public TriggerBuilder Ending(DateTime dt) + { + trigger.EndBoundary = dt; + return this; + } + + /// Determines whether this trigger is disabled. + /// instance. + public TriggerBuilder IsDisabled() + { + trigger.Enabled = false; + return this; + } + + /// Specifies a repetition interval for the trigger. + /// The interval span. + /// instance. + public TriggerBuilder RepeatingEvery(TimeSpan span) + { + trigger.Repetition.Interval = span; + return this; + } + + /// Specifies a repetition interval for the trigger. + /// The interval span string. Must be parsable by . + /// instance. + public TriggerBuilder RepeatingEvery([NotNull] string span) + { + trigger.Repetition.Interval = TimeSpan.Parse(span); + return this; + } + + /// Specifies the maximum amount of time to repeat the execution of a trigger. + /// The duration span. + /// instance. + public TriggerBuilder RunningAtMostFor(TimeSpan span) + { + trigger.Repetition.Duration = span; + return this; + } + + /// Specifies the maximum amount of time to repeat the execution of a trigger. + /// The duration span string. Must be parsable by . + /// instance. + public TriggerBuilder RunningAtMostFor([NotNull] string span) + { + trigger.Repetition.Duration = TimeSpan.Parse(span); + return this; + } + + /// Specifies a date on which a trigger will start. + /// The year. + /// The month. + /// The day. + /// instance. + public TriggerBuilder Starting(int year, int month, int day) + { + trigger.StartBoundary = new DateTime(year, month, day, trigger.StartBoundary.Hour, trigger.StartBoundary.Minute, trigger.StartBoundary.Second); + return this; + } + + /// Specifies a date and time on which a trigger will start. + /// The year. + /// The month. + /// The day. + /// The hour. + /// The min. + /// The sec. + /// instance. + public TriggerBuilder Starting(int year, int month, int day, int hour, int min, int sec) + { + trigger.StartBoundary = new DateTime(year, month, day, hour, min, sec); + return this; + } + + /// Specifies a date and time on which a trigger will start. + /// A string representing a DateTime and parsable via . + /// instance. + public TriggerBuilder Starting([NotNull] string dt) + { + trigger.StartBoundary = DateTime.Parse(dt); + return this; + } + + /// Specifies a date and time on which a trigger will start. + /// The DateTime value. + /// instance. + public TriggerBuilder Starting(DateTime dt) + { + trigger.StartBoundary = dt; + return this; + } + } + + /// Fluent helper class. Not intended for use. + public class WeeklyTriggerBuilder : TriggerBuilder + { + internal WeeklyTriggerBuilder(BuilderInfo taskBuilder, short interval) + : base(taskBuilder) => TaskDef.Triggers.Add(trigger = new WeeklyTrigger() { WeeksInterval = interval }); + + /// Updates a weekly trigger to specify the days of the week on which it will run. + /// The days of the week. + /// instance. + public TriggerBuilder On(DaysOfTheWeek dow) + { + ((WeeklyTrigger)trigger).DaysOfWeek = dow; + return this as TriggerBuilder; + } + } + + /// Fluent helper class. Not intended for use. + internal sealed class BuilderInfo + { + public TaskDefinition td; + public TaskService ts; + + public BuilderInfo([NotNull] TaskService taskSvc) + { + ts = taskSvc; + td = ts.NewTask(); + } + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/Trigger.cs b/FlashPatcher/TaskService/Trigger.cs new file mode 100644 index 0000000..67cb44f --- /dev/null +++ b/FlashPatcher/TaskService/Trigger.cs @@ -0,0 +1,2779 @@ +using JetBrains.Annotations; +using Microsoft.Win32.TaskScheduler.V2Interop; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Xml.Serialization; + +namespace Microsoft.Win32.TaskScheduler +{ + /// Values for days of the week (Monday, Tuesday, etc.) + [Flags] + public enum DaysOfTheWeek : short + { + /// Sunday + Sunday = 0x1, + + /// Monday + Monday = 0x2, + + /// Tuesday + Tuesday = 0x4, + + /// Wednesday + Wednesday = 0x8, + + /// Thursday + Thursday = 0x10, + + /// Friday + Friday = 0x20, + + /// Saturday + Saturday = 0x40, + + /// All days + AllDays = 0x7F + } + + /// Values for months of the year (January, February, etc.) + [Flags] + public enum MonthsOfTheYear : short + { + /// January + January = 0x1, + + /// February + February = 0x2, + + /// March + March = 0x4, + + /// April + April = 0x8, + + /// May + May = 0x10, + + /// June + June = 0x20, + + /// July + July = 0x40, + + /// August + August = 0x80, + + /// September + September = 0x100, + + /// October + October = 0x200, + + /// November + November = 0x400, + + /// December + December = 0x800, + + /// All months + AllMonths = 0xFFF + } + + /// Defines the type of triggers that can be used by tasks. + [DefaultValue(Time)] + public enum TaskTriggerType + { + /// Triggers the task when a specific event occurs. Version 1.2 only. + Event = 0, + + /// Triggers the task at a specific time of day. + Time = 1, + + /// Triggers the task on a daily schedule. + Daily = 2, + + /// Triggers the task on a weekly schedule. + Weekly = 3, + + /// Triggers the task on a monthly schedule. + Monthly = 4, + + /// Triggers the task on a monthly day-of-week schedule. + MonthlyDOW = 5, + + /// Triggers the task when the computer goes into an idle state. + Idle = 6, + + /// Triggers the task when the task is registered. Version 1.2 only. + Registration = 7, + + /// Triggers the task when the computer boots. + Boot = 8, + + /// Triggers the task when a specific user logs on. + Logon = 9, + + /// Triggers the task when a specific user session state changes. Version 1.2 only. + SessionStateChange = 11, + + /// Triggers the custom trigger. Version 1.3 only. + Custom = 12 + } + + /// Values for week of month (first, second, ..., last) + [Flags] + public enum WhichWeek : short + { + /// First week of the month + FirstWeek = 1, + + /// Second week of the month + SecondWeek = 2, + + /// Third week of the month + ThirdWeek = 4, + + /// Fourth week of the month + FourthWeek = 8, + + /// Last week of the month + LastWeek = 0x10, + + /// Every week of the month + AllWeeks = 0x1F + } + + /// Interface that categorizes the trigger as a calendar trigger. + public interface ICalendarTrigger { } + + /// Interface for triggers that support a delay. + public interface ITriggerDelay + { + /// Gets or sets a value that indicates the amount of time before the task is started. + /// The delay duration. + TimeSpan Delay { get; set; } + } + + /// Interface for triggers that support a user identifier. + public interface ITriggerUserId + { + /// Gets or sets the user for the . + string UserId { get; set; } + } + + /// Represents a trigger that starts a task when the system is booted. + /// + /// A BootTrigger will fire when the system starts. It can only be delayed. All triggers that support a delay implement the + /// ITriggerDelay interface. + /// + /// + /// + /// + /// + /// + public sealed class BootTrigger : Trigger, ITriggerDelay + { + /// Creates an unbound instance of a . + public BootTrigger() : base(TaskTriggerType.Boot) { } + + internal BootTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.OnSystemStart) + { + } + + internal BootTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Gets or sets a value that indicates the amount of time between when the system is booted and when the task is started. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + [XmlIgnore] + public TimeSpan Delay + { + get => v2Trigger != null ? Task.StringToTimeSpan(((IBootTrigger)v2Trigger).Delay) : GetUnboundValueOrDefault(nameof(Delay), TimeSpan.Zero); + set + { + if (v2Trigger != null) + ((IBootTrigger)v2Trigger).Delay = Task.TimeSpanToString(value); + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(Delay)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() => Properties.Resources.TriggerBoot1; + } + + /// + /// Represents a custom trigger. This class is based on undocumented features and may change. This type of trigger is only + /// available for reading custom triggers. It cannot be used to create custom triggers. + /// + public sealed class CustomTrigger : Trigger, ITriggerDelay + { + private readonly NamedValueCollection nvc = new NamedValueCollection(); + private TimeSpan delay = TimeSpan.MinValue; + private string name = string.Empty; + + internal CustomTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Gets a value that indicates the amount of time between the trigger events and when the task is started. + /// This value cannot be set. + public TimeSpan Delay + { + get => delay; + set => throw new NotImplementedException(); + } + + /// Gets the name of the custom trigger type. + /// The name of the XML element representing this custom trigger. + public string Name => name; + + /// Gets the properties from the XML definition if possible. + [XmlArray, XmlArrayItem("Property")] + public NamedValueCollection Properties => nvc; + + /// Clones this instance. + /// This method will always throw an exception. + /// CustomTrigger cannot be cloned due to OS restrictions. + public override object Clone() => throw new InvalidOperationException("CustomTrigger cannot be cloned due to OS restrictions."); + + /// Updates custom properties from XML provided by definition. + /// The XML from the TaskDefinition. + internal void UpdateFromXml(string xml) + { + nvc.Clear(); + try + { + var xmlDoc = new System.Xml.XmlDocument(); + xmlDoc.LoadXml(xml); + var nsmgr = new System.Xml.XmlNamespaceManager(xmlDoc.NameTable); + nsmgr.AddNamespace("n", "http://schemas.microsoft.com/windows/2004/02/mit/task"); + var elem = xmlDoc.DocumentElement?.SelectSingleNode("n:Triggers/*[@id='" + Id + "']", nsmgr); + if (elem == null) + { + var nodes = xmlDoc.GetElementsByTagName("WnfStateChangeTrigger"); + if (nodes.Count == 1) + elem = nodes[0]; + } + + if (elem == null) return; + + name = elem.LocalName; + foreach (System.Xml.XmlNode node in elem.ChildNodes) + { + switch (node.LocalName) + { + case "Delay": + delay = Task.StringToTimeSpan(node.InnerText); + break; + + case "StartBoundary": + case "Enabled": + case "EndBoundary": + case "ExecutionTimeLimit": + break; + + default: + nvc.Add(node.LocalName, node.InnerText); + break; + } + } + } + catch { /* ignored */ } + } + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() => TaskScheduler.Properties.Resources.TriggerCustom1; + } + + /// + /// Represents a trigger that starts a task based on a daily schedule. For example, the task starts at a specific time every day, every + /// other day, every third day, and so on. + /// + /// A DailyTrigger will fire at a specified time every day or interval of days. + /// + /// + /// + /// + /// + [XmlRoot("CalendarTrigger", Namespace = TaskDefinition.tns, IsNullable = false)] + public sealed class DailyTrigger : Trigger, ICalendarTrigger, ITriggerDelay, IXmlSerializable + { + /// Creates an unbound instance of a . + /// Interval between the days in the schedule. + public DailyTrigger(short daysInterval = 1) : base(TaskTriggerType.Daily) => DaysInterval = daysInterval; + + internal DailyTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.RunDaily) + { + if (v1TriggerData.Data.daily.DaysInterval == 0) + v1TriggerData.Data.daily.DaysInterval = 1; + } + + internal DailyTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Sets or retrieves the interval between the days in the schedule. + [DefaultValue(1)] + public short DaysInterval + { + get + { + if (v2Trigger != null) + return ((IDailyTrigger)v2Trigger).DaysInterval; + return (short)v1TriggerData.Data.daily.DaysInterval; + } + set + { + if (v2Trigger != null) + ((IDailyTrigger)v2Trigger).DaysInterval = value; + else + { + v1TriggerData.Data.daily.DaysInterval = (ushort)value; + if (v1Trigger != null) + SetV1TriggerData(); + else + unboundValues[nameof(DaysInterval)] = value; + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a delay time that is randomly added to the start time of the trigger. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + [XmlIgnore] + public TimeSpan RandomDelay + { + get => v2Trigger != null ? Task.StringToTimeSpan(((IDailyTrigger)v2Trigger).RandomDelay) : GetUnboundValueOrDefault(nameof(RandomDelay), TimeSpan.Zero); + set + { + if (v2Trigger != null) + ((IDailyTrigger)v2Trigger).RandomDelay = Task.TimeSpanToString(value); + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(RandomDelay)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a value that indicates the amount of time before the task is started. + /// The delay duration. + TimeSpan ITriggerDelay.Delay + { + get => RandomDelay; + set => RandomDelay = value; + } + + /// + /// Copies the properties from another the current instance. This will not copy any properties associated with + /// any derived triggers except those supporting the interface. + /// + /// The source . + public override void CopyProperties(Trigger sourceTrigger) + { + base.CopyProperties(sourceTrigger); + if (sourceTrigger is DailyTrigger dt) + { + DaysInterval = dt.DaysInterval; + } + } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Trigger other) => other is DailyTrigger dt && base.Equals(dt) && DaysInterval == dt.DaysInterval; + + System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() => null; + + void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) => CalendarTrigger.ReadXml(reader, this, ReadMyXml); + + void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) => CalendarTrigger.WriteXml(writer, this, WriteMyXml); + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() => DaysInterval == 1 ? + string.Format(Properties.Resources.TriggerDaily1, AdjustToLocal(StartBoundary)) : + string.Format(Properties.Resources.TriggerDaily2, AdjustToLocal(StartBoundary), DaysInterval); + + private void ReadMyXml(System.Xml.XmlReader reader) + { + reader.ReadStartElement("ScheduleByDay"); + if (reader.MoveToContent() == System.Xml.XmlNodeType.Element && reader.LocalName == "DaysInterval") + // ReSharper disable once AssignNullToNotNullAttribute + DaysInterval = (short)reader.ReadElementContentAs(typeof(short), null); + reader.Read(); + reader.ReadEndElement(); + } + + private void WriteMyXml(System.Xml.XmlWriter writer) + { + writer.WriteStartElement("ScheduleByDay"); + writer.WriteElementString("DaysInterval", DaysInterval.ToString()); + writer.WriteEndElement(); + } + } + + /// + /// Represents a trigger that starts a task when a system event occurs. Only available for Task Scheduler 2.0 on Windows Vista or + /// Windows Server 2003 and later. + /// + /// The EventTrigger runs when a system event fires. + /// + /// + ///"; + /// eTrigger.ValueQueries.Add("Name", "Value"); + ///]]> + /// + /// + [XmlType(IncludeInSchema = false)] + public sealed class EventTrigger : Trigger, ITriggerDelay + { + private NamedValueCollection nvc; + + /// Creates an unbound instance of a . + public EventTrigger() : base(TaskTriggerType.Event) { } + + /// Initializes an unbound instance of the class and sets a basic event. + /// The event's log. + /// The event's source. Can be null. + /// The event's id. Can be null. + public EventTrigger(string log, string source, int? eventId) : this() => SetBasic(log, source, eventId); + + internal EventTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Gets or sets a value that indicates the amount of time between when the system is booted and when the task is started. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + public TimeSpan Delay + { + get => v2Trigger != null ? Task.StringToTimeSpan(((IEventTrigger)v2Trigger).Delay) : GetUnboundValueOrDefault(nameof(Delay), TimeSpan.Zero); + set + { + if (v2Trigger != null) + ((IEventTrigger)v2Trigger).Delay = Task.TimeSpanToString(value); + else + unboundValues[nameof(Delay)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the XPath query string that identifies the event that fires the trigger. + [DefaultValue(null)] + public string Subscription + { + get => v2Trigger != null ? ((IEventTrigger)v2Trigger).Subscription : GetUnboundValueOrDefault(nameof(Subscription)); + set + { + if (v2Trigger != null) + ((IEventTrigger)v2Trigger).Subscription = value; + else + unboundValues[nameof(Subscription)] = value; + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets a collection of named XPath queries. Each query in the collection is applied to the last matching event XML returned from + /// the subscription query specified in the Subscription property. The name of the query can be used as a variable in the message of + /// a action. + /// + [XmlArray] + [XmlArrayItem("Value", typeof(NameValuePair))] + public NamedValueCollection ValueQueries => nvc ??= v2Trigger == null ? new NamedValueCollection() : new NamedValueCollection(((IEventTrigger)v2Trigger).ValueQueries); + + /// Builds an event log XML query string based on the input parameters. + /// The event's log. + /// The event's source. Can be null. + /// The event's id. Can be null. + /// XML query string. + /// log + public static string BuildQuery(string log, string source, int? eventId) + { + var sb = new StringBuilder(); + if (string.IsNullOrEmpty(log)) + throw new ArgumentNullException(nameof(log)); + sb.AppendFormat(""); + return sb.ToString(); + } + + /// + /// Copies the properties from another the current instance. This will not copy any properties associated with + /// any derived triggers except those supporting the interface. + /// + /// The source . + public override void CopyProperties(Trigger sourceTrigger) + { + base.CopyProperties(sourceTrigger); + if (sourceTrigger is EventTrigger et) + { + Subscription = et.Subscription; + et.ValueQueries.CopyTo(ValueQueries); + } + } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Trigger other) => other is EventTrigger et && base.Equals(et) && Subscription == et.Subscription; + + /// Gets basic event information. + /// The event's log. + /// The event's source. Can be null. + /// The event's id. Can be null. + /// true if subscription represents a basic event, false if not. + public bool GetBasic(out string log, out string source, out int? eventId) + { + log = source = null; + eventId = null; + if (!string.IsNullOrEmpty(Subscription)) + { + using var str = new System.IO.MemoryStream(Encoding.UTF8.GetBytes(Subscription)); + using var rdr = new System.Xml.XmlTextReader(str) + { + WhitespaceHandling = System.Xml.WhitespaceHandling.None + }; + try + { + rdr.MoveToContent(); + rdr.ReadStartElement("QueryList"); + if (rdr.Name == "Query" && rdr.MoveToAttribute("Path")) + { + var path = rdr.Value; + if (rdr.MoveToElement() && rdr.ReadToDescendant("Select") && path.Equals(rdr["Path"], StringComparison.InvariantCultureIgnoreCase)) + { + var content = rdr.ReadString(); + var m = System.Text.RegularExpressions.Regex.Match(content, + @"\*(?:\[System\[(?:Provider\[\@Name='(?[^']+)'\])?(?:\s+and\s+)?(?:EventID=(?\d+))?\]\])", + System.Text.RegularExpressions.RegexOptions.IgnoreCase | + System.Text.RegularExpressions.RegexOptions.Compiled | + System.Text.RegularExpressions.RegexOptions.Singleline | + System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace); + if (m.Success) + { + log = path; + if (m.Groups["s"].Success) + source = m.Groups["s"].Value; + if (m.Groups["e"].Success) + eventId = Convert.ToInt32(m.Groups["e"].Value); + return true; + } + } + } + } + catch { /* ignored */ } + } + return false; + } + + /// + /// Sets the subscription for a basic event. This will replace the contents of the property and clear all + /// entries in the property. + /// + /// The event's log. + /// The event's source. Can be null. + /// The event's id. Can be null. + public void SetBasic([NotNull] string log, string source, int? eventId) + { + ValueQueries.Clear(); + Subscription = BuildQuery(log, source, eventId); + } + + internal override void Bind(ITaskDefinition iTaskDef) + { + base.Bind(iTaskDef); + nvc?.Bind(((IEventTrigger)v2Trigger).ValueQueries); + } + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() + { + if (!GetBasic(out var log, out var source, out var id)) + return Properties.Resources.TriggerEvent1; + var sb = new StringBuilder(); + sb.AppendFormat(Properties.Resources.TriggerEventBasic1, log); + if (!string.IsNullOrEmpty(source)) + sb.AppendFormat(Properties.Resources.TriggerEventBasic2, source); + if (id.HasValue) + sb.AppendFormat(Properties.Resources.TriggerEventBasic3, id.Value); + return sb.ToString(); + } + } + + /// + /// Represents a trigger that starts a task when the computer goes into an idle state. For information about idle conditions, see Task + /// Idle Conditions. + /// + /// + /// An IdleTrigger will fire when the system becomes idle. It is generally a good practice to set a limit on how long it can run using + /// the ExecutionTimeLimit property. + /// + /// + /// + /// + /// + /// + public sealed class IdleTrigger : Trigger + { + /// Creates an unbound instance of a . + public IdleTrigger() : base(TaskTriggerType.Idle) { } + + internal IdleTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.OnIdle) + { + } + + internal IdleTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() => Properties.Resources.TriggerIdle1; + } + + /// + /// Represents a trigger that starts a task when a user logs on. When the Task Scheduler service starts, all logged-on users are + /// enumerated and any tasks registered with logon triggers that match the logged on user are run. Not available on Task Scheduler 1.0. + /// + /// + /// A LogonTrigger will fire after a user logs on. It can only be delayed. Under V2, you can specify which user it applies to. + /// + /// + /// + /// + /// + /// + public sealed class LogonTrigger : Trigger, ITriggerDelay, ITriggerUserId + { + /// Creates an unbound instance of a . + public LogonTrigger() : base(TaskTriggerType.Logon) { } + + internal LogonTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.OnLogon) + { + } + + internal LogonTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Gets or sets a value that indicates the amount of time between when the system is booted and when the task is started. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + [XmlIgnore] + public TimeSpan Delay + { + get => v2Trigger != null ? Task.StringToTimeSpan(((ILogonTrigger)v2Trigger).Delay) : GetUnboundValueOrDefault(nameof(Delay), TimeSpan.Zero); + set + { + if (v2Trigger != null) + ((ILogonTrigger)v2Trigger).Delay = Task.TimeSpanToString(value); + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(Delay)] = value; + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets The identifier of the user. For example, "MyDomain\MyName" or for a local account, "Administrator". + /// This property can be in one of the following formats: + /// • User name or SID: The task is started when the user logs on to the computer. + /// • NULL: The task is started when any user logs on to the computer. + /// + /// + /// If you want a task to be triggered when any member of a group logs on to the computer rather than when a specific user logs on, + /// then do not assign a value to the LogonTrigger.UserId property. Instead, create a logon trigger with an empty + /// LogonTrigger.UserId property and assign a value to the principal for the task using the Principal.GroupId property. + /// + /// Not supported under Task Scheduler 1.0. + [DefaultValue(null)] + [XmlIgnore] + public string UserId + { + get => v2Trigger != null ? ((ILogonTrigger)v2Trigger).UserId : GetUnboundValueOrDefault(nameof(UserId)); + set + { + if (v2Trigger != null) + ((ILogonTrigger)v2Trigger).UserId = value; + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(UserId)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() + { + var user = string.IsNullOrEmpty(UserId) ? Properties.Resources.TriggerAnyUser : UserId; + return string.Format(Properties.Resources.TriggerLogon1, user); + } + } + + /// + /// Represents a trigger that starts a task on a monthly day-of-week schedule. For example, the task starts on every first Thursday, May + /// through October. + /// + [XmlRoot("CalendarTrigger", Namespace = TaskDefinition.tns, IsNullable = false)] + public sealed class MonthlyDOWTrigger : Trigger, ICalendarTrigger, ITriggerDelay, IXmlSerializable + { + /// Creates an unbound instance of a . + /// The days of the week. + /// The months of the year. + /// The weeks of the month. + public MonthlyDOWTrigger(DaysOfTheWeek daysOfWeek = DaysOfTheWeek.Sunday, MonthsOfTheYear monthsOfYear = MonthsOfTheYear.AllMonths, WhichWeek weeksOfMonth = WhichWeek.FirstWeek) : base(TaskTriggerType.MonthlyDOW) + { + DaysOfWeek = daysOfWeek; + MonthsOfYear = monthsOfYear; + WeeksOfMonth = weeksOfMonth; + } + + internal MonthlyDOWTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.RunMonthlyDOW) + { + if (v1TriggerData.Data.monthlyDOW.Months == 0) + v1TriggerData.Data.monthlyDOW.Months = MonthsOfTheYear.AllMonths; + if (v1TriggerData.Data.monthlyDOW.DaysOfTheWeek == 0) + v1TriggerData.Data.monthlyDOW.DaysOfTheWeek = DaysOfTheWeek.Sunday; + } + + internal MonthlyDOWTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Gets or sets the days of the week during which the task runs. + [DefaultValue(0)] + public DaysOfTheWeek DaysOfWeek + { + get => v2Trigger != null + ? (DaysOfTheWeek)((IMonthlyDOWTrigger)v2Trigger).DaysOfWeek + : v1TriggerData.Data.monthlyDOW.DaysOfTheWeek; + set + { + if (v2Trigger != null) + ((IMonthlyDOWTrigger)v2Trigger).DaysOfWeek = (short)value; + else + { + v1TriggerData.Data.monthlyDOW.DaysOfTheWeek = value; + if (v1Trigger != null) + SetV1TriggerData(); + else + unboundValues[nameof(DaysOfWeek)] = (short)value; + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the months of the year during which the task runs. + [DefaultValue(0)] + public MonthsOfTheYear MonthsOfYear + { + get => v2Trigger != null + ? (MonthsOfTheYear)((IMonthlyDOWTrigger)v2Trigger).MonthsOfYear + : v1TriggerData.Data.monthlyDOW.Months; + set + { + if (v2Trigger != null) + ((IMonthlyDOWTrigger)v2Trigger).MonthsOfYear = (short)value; + else + { + v1TriggerData.Data.monthlyDOW.Months = value; + if (v1Trigger != null) + SetV1TriggerData(); + else + unboundValues[nameof(MonthsOfYear)] = (short)value; + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a delay time that is randomly added to the start time of the trigger. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + [XmlIgnore] + public TimeSpan RandomDelay + { + get => v2Trigger != null ? Task.StringToTimeSpan(((IMonthlyDOWTrigger)v2Trigger).RandomDelay) : GetUnboundValueOrDefault(nameof(RandomDelay), TimeSpan.Zero); + set + { + if (v2Trigger != null) + ((IMonthlyDOWTrigger)v2Trigger).RandomDelay = Task.TimeSpanToString(value); + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(RandomDelay)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a Boolean value that indicates that the task runs on the last week of the month. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(false)] + [XmlIgnore] + public bool RunOnLastWeekOfMonth + { + get => ((IMonthlyDOWTrigger)v2Trigger)?.RunOnLastWeekOfMonth ?? GetUnboundValueOrDefault(nameof(RunOnLastWeekOfMonth), false); + set + { + if (v2Trigger != null) + ((IMonthlyDOWTrigger)v2Trigger).RunOnLastWeekOfMonth = value; + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(RunOnLastWeekOfMonth)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the weeks of the month during which the task runs. + [DefaultValue(0)] + public WhichWeek WeeksOfMonth + { + get + { + if (v2Trigger == null) + return v1Trigger != null + ? v1TriggerData.Data.monthlyDOW.V2WhichWeek + : GetUnboundValueOrDefault(nameof(WeeksOfMonth), WhichWeek.FirstWeek); + var ww = (WhichWeek)((IMonthlyDOWTrigger)v2Trigger).WeeksOfMonth; + // Following addition give accurate results for confusing RunOnLastWeekOfMonth property (thanks kbergeron) + if (((IMonthlyDOWTrigger)v2Trigger).RunOnLastWeekOfMonth) + ww |= WhichWeek.LastWeek; + return ww; + } + set + { + // In Windows 10, the native library no longer acknowledges the LastWeek value and requires the RunOnLastWeekOfMonth to be + // expressly set. I think this is wrong so I am correcting their changed functionality. (thanks @SebastiaanPolfliet) + if (value.IsFlagSet(WhichWeek.LastWeek)) + RunOnLastWeekOfMonth = true; + if (v2Trigger != null) + { + ((IMonthlyDOWTrigger)v2Trigger).WeeksOfMonth = (short)value; + } + else + { + try + { + v1TriggerData.Data.monthlyDOW.V2WhichWeek = value; + } + catch (NotV1SupportedException) + { + if (v1Trigger != null) throw; + } + if (v1Trigger != null) + SetV1TriggerData(); + else + unboundValues[nameof(WeeksOfMonth)] = (short)value; + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a value that indicates the amount of time before the task is started. + /// The delay duration. + TimeSpan ITriggerDelay.Delay + { + get => RandomDelay; + set => RandomDelay = value; + } + + /// + /// Copies the properties from another the current instance. This will not copy any properties associated with + /// any derived triggers except those supporting the interface. + /// + /// The source . + public override void CopyProperties(Trigger sourceTrigger) + { + base.CopyProperties(sourceTrigger); + if (sourceTrigger is MonthlyDOWTrigger mt) + { + DaysOfWeek = mt.DaysOfWeek; + MonthsOfYear = mt.MonthsOfYear; + try { RunOnLastWeekOfMonth = mt.RunOnLastWeekOfMonth; } catch { /* ignored */ } + WeeksOfMonth = mt.WeeksOfMonth; + } + if (sourceTrigger is MonthlyTrigger m) + MonthsOfYear = m.MonthsOfYear; + } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Trigger other) => other is MonthlyDOWTrigger mt && base.Equals(other) && DaysOfWeek == mt.DaysOfWeek && + MonthsOfYear == mt.MonthsOfYear && WeeksOfMonth == mt.WeeksOfMonth && v1Trigger == null && RunOnLastWeekOfMonth == mt.RunOnLastWeekOfMonth; + + System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() => null; + + void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) => CalendarTrigger.ReadXml(reader, this, ReadMyXml); + + void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) => CalendarTrigger.WriteXml(writer, this, WriteMyXml); + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() + { + var ww = TaskEnumGlobalizer.GetString(WeeksOfMonth); + var days = TaskEnumGlobalizer.GetString(DaysOfWeek); + var months = TaskEnumGlobalizer.GetString(MonthsOfYear); + return string.Format(Properties.Resources.TriggerMonthlyDOW1, AdjustToLocal(StartBoundary), ww, days, months); + } + + /// Reads the subclass XML for V1 streams. + /// The reader. + private void ReadMyXml([NotNull] System.Xml.XmlReader reader) + { + reader.ReadStartElement("ScheduleByMonthDayOfWeek"); + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + switch (reader.LocalName) + { + case "Weeks": + reader.Read(); + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + if (reader.LocalName == "Week") + { + var wk = reader.ReadElementContentAsString(); + if (wk == "Last") + WeeksOfMonth = WhichWeek.LastWeek; + else + { + WeeksOfMonth = (int.Parse(wk)) switch + { + 1 => WhichWeek.FirstWeek, + 2 => WhichWeek.SecondWeek, + 3 => WhichWeek.ThirdWeek, + 4 => WhichWeek.FourthWeek, + _ => throw new System.Xml.XmlException("Week element must contain a 1-4 or Last as content."), + }; + } + } + } + reader.ReadEndElement(); + break; + + case "DaysOfWeek": + reader.Read(); + DaysOfWeek = 0; + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + try + { + DaysOfWeek |= (DaysOfTheWeek)Enum.Parse(typeof(DaysOfTheWeek), reader.LocalName); + } + catch + { + throw new System.Xml.XmlException("Invalid days of the week element."); + } + reader.Read(); + } + reader.ReadEndElement(); + break; + + case "Months": + reader.Read(); + MonthsOfYear = 0; + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + try + { + MonthsOfYear |= (MonthsOfTheYear)Enum.Parse(typeof(MonthsOfTheYear), reader.LocalName); + } + catch + { + throw new System.Xml.XmlException("Invalid months of the year element."); + } + reader.Read(); + } + reader.ReadEndElement(); + break; + + default: + reader.Skip(); + break; + } + } + reader.ReadEndElement(); + } + + /// Writes the subclass XML for V1 streams. + /// The writer. + private void WriteMyXml([NotNull] System.Xml.XmlWriter writer) + { + writer.WriteStartElement("ScheduleByMonthDayOfWeek"); + + writer.WriteStartElement("Weeks"); + if ((WeeksOfMonth & WhichWeek.FirstWeek) == WhichWeek.FirstWeek) + writer.WriteElementString("Week", "1"); + if ((WeeksOfMonth & WhichWeek.SecondWeek) == WhichWeek.SecondWeek) + writer.WriteElementString("Week", "2"); + if ((WeeksOfMonth & WhichWeek.ThirdWeek) == WhichWeek.ThirdWeek) + writer.WriteElementString("Week", "3"); + if ((WeeksOfMonth & WhichWeek.FourthWeek) == WhichWeek.FourthWeek) + writer.WriteElementString("Week", "4"); + if ((WeeksOfMonth & WhichWeek.LastWeek) == WhichWeek.LastWeek) + writer.WriteElementString("Week", "Last"); + writer.WriteEndElement(); + + writer.WriteStartElement("DaysOfWeek"); + foreach (DaysOfTheWeek e in Enum.GetValues(typeof(DaysOfTheWeek))) + if (e != DaysOfTheWeek.AllDays && (DaysOfWeek & e) == e) + writer.WriteElementString(e.ToString(), null); + writer.WriteEndElement(); + + writer.WriteStartElement("Months"); + foreach (MonthsOfTheYear e in Enum.GetValues(typeof(MonthsOfTheYear))) + if (e != MonthsOfTheYear.AllMonths && (MonthsOfYear & e) == e) + writer.WriteElementString(e.ToString(), null); + writer.WriteEndElement(); + + writer.WriteEndElement(); + } + } + + /// + /// Represents a trigger that starts a job based on a monthly schedule. For example, the task starts on specific days of specific months. + /// + [XmlRoot("CalendarTrigger", Namespace = TaskDefinition.tns, IsNullable = false)] + public sealed class MonthlyTrigger : Trigger, ICalendarTrigger, ITriggerDelay, IXmlSerializable + { + /// Creates an unbound instance of a . + /// + /// The day of the month. This must be a value between 1 and 32. If this value is set to 32, then the value will be set and no days will be added regardless of the month. + /// + /// The months of the year. + public MonthlyTrigger(int dayOfMonth = 1, MonthsOfTheYear monthsOfYear = MonthsOfTheYear.AllMonths) : base(TaskTriggerType.Monthly) + { + if (dayOfMonth < 1 || dayOfMonth > 32) throw new ArgumentOutOfRangeException(nameof(dayOfMonth)); + if (!monthsOfYear.IsValidFlagValue()) throw new ArgumentOutOfRangeException(nameof(monthsOfYear)); + if (dayOfMonth == 32) + { + DaysOfMonth = new int[0]; + RunOnLastDayOfMonth = true; + } + else + DaysOfMonth = new[] { dayOfMonth }; + MonthsOfYear = monthsOfYear; + } + + internal MonthlyTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.RunMonthly) + { + if (v1TriggerData.Data.monthlyDate.Months == 0) + v1TriggerData.Data.monthlyDate.Months = MonthsOfTheYear.AllMonths; + if (v1TriggerData.Data.monthlyDate.Days == 0) + v1TriggerData.Data.monthlyDate.Days = 1; + } + + internal MonthlyTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Gets or sets the days of the month during which the task runs. + public int[] DaysOfMonth + { + get => v2Trigger != null ? MaskToIndices(((IMonthlyTrigger)v2Trigger).DaysOfMonth) : MaskToIndices((int)v1TriggerData.Data.monthlyDate.Days); + set + { + var mask = IndicesToMask(value); + if (v2Trigger != null) + ((IMonthlyTrigger)v2Trigger).DaysOfMonth = mask; + else + { + v1TriggerData.Data.monthlyDate.Days = (uint)mask; + if (v1Trigger != null) + SetV1TriggerData(); + else + unboundValues[nameof(DaysOfMonth)] = mask; + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the months of the year during which the task runs. + [DefaultValue(0)] + public MonthsOfTheYear MonthsOfYear + { + get => v2Trigger != null + ? (MonthsOfTheYear)((IMonthlyTrigger)v2Trigger).MonthsOfYear + : v1TriggerData.Data.monthlyDOW.Months; + set + { + if (v2Trigger != null) + ((IMonthlyTrigger)v2Trigger).MonthsOfYear = (short)value; + else + { + v1TriggerData.Data.monthlyDOW.Months = value; + if (v1Trigger != null) + SetV1TriggerData(); + else + unboundValues[nameof(MonthsOfYear)] = (short)value; + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a delay time that is randomly added to the start time of the trigger. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + [XmlIgnore] + public TimeSpan RandomDelay + { + get => v2Trigger != null ? Task.StringToTimeSpan(((IMonthlyTrigger)v2Trigger).RandomDelay) : GetUnboundValueOrDefault(nameof(RandomDelay), TimeSpan.Zero); + set + { + if (v2Trigger != null) + ((IMonthlyTrigger)v2Trigger).RandomDelay = Task.TimeSpanToString(value); + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(RandomDelay)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a Boolean value that indicates that the task runs on the last day of the month. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(false)] + [XmlIgnore] + public bool RunOnLastDayOfMonth + { + get => ((IMonthlyTrigger)v2Trigger)?.RunOnLastDayOfMonth ?? GetUnboundValueOrDefault(nameof(RunOnLastDayOfMonth), false); + set + { + if (v2Trigger != null) + ((IMonthlyTrigger)v2Trigger).RunOnLastDayOfMonth = value; + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(RunOnLastDayOfMonth)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a value that indicates the amount of time before the task is started. + /// The delay duration. + TimeSpan ITriggerDelay.Delay + { + get => RandomDelay; + set => RandomDelay = value; + } + + /// + /// Copies the properties from another the current instance. This will not copy any properties associated with + /// any derived triggers except those supporting the interface. + /// + /// The source . + public override void CopyProperties(Trigger sourceTrigger) + { + base.CopyProperties(sourceTrigger); + if (sourceTrigger is MonthlyTrigger mt) + { + DaysOfMonth = mt.DaysOfMonth; + MonthsOfYear = mt.MonthsOfYear; + try { RunOnLastDayOfMonth = mt.RunOnLastDayOfMonth; } catch { /* ignored */ } + } + if (sourceTrigger is MonthlyDOWTrigger mdt) + MonthsOfYear = mdt.MonthsOfYear; + } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Trigger other) => other is MonthlyTrigger mt && base.Equals(mt) && ListsEqual(DaysOfMonth, mt.DaysOfMonth) && + MonthsOfYear == mt.MonthsOfYear && v1Trigger == null && RunOnLastDayOfMonth == mt.RunOnLastDayOfMonth; + + System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() => null; + + void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) => CalendarTrigger.ReadXml(reader, this, ReadMyXml); + + void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) => CalendarTrigger.WriteXml(writer, this, WriteMyXml); + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() + { + var days = string.Join(Properties.Resources.ListSeparator, Array.ConvertAll(DaysOfMonth, i => i.ToString())); + if (RunOnLastDayOfMonth) + days += (days.Length == 0 ? "" : Properties.Resources.ListSeparator) + Properties.Resources.WWLastWeek; + var months = TaskEnumGlobalizer.GetString(MonthsOfYear); + return string.Format(Properties.Resources.TriggerMonthly1, AdjustToLocal(StartBoundary), days, months); + } + + /// + /// Converts an array of bit indices into a mask with bits turned ON at every index contained in the array. Indices must be from 1 + /// to 32 and bits are numbered the same. + /// + /// An array with an element for each bit of the mask which is ON. + /// An integer to be interpreted as a mask. + private static int IndicesToMask(int[] indices) + { + if (indices is null || indices.Length == 0) return 0; + var mask = 0; + foreach (var index in indices) + { + if (index < 1 || index > 31) throw new ArgumentException("Days must be in the range 1..31"); + mask |= 1 << (index - 1); + } + return mask; + } + + /// Compares two collections. + /// Item type of collections. + /// The first collection. + /// The second collection + /// true if the collections values are equal; false otherwise. + private static bool ListsEqual(ICollection left, ICollection right) where T : IComparable + { + if (left == null && right == null) return true; + if (left == null || right == null) return false; + if (left.Count != right.Count) return false; + List l1 = new List(left), l2 = new List(right); + l1.Sort(); l2.Sort(); + for (var i = 0; i < l1.Count; i++) + if (l1[i].CompareTo(l2[i]) != 0) return false; + return true; + } + + /// + /// Convert an integer representing a mask to an array where each element contains the index of a bit that is ON in the mask. Bits + /// are considered to number from 1 to 32. + /// + /// An integer to be interpreted as a mask. + /// An array with an element for each bit of the mask which is ON. + private static int[] MaskToIndices(int mask) + { + //count bits in mask + var cnt = 0; + for (var i = 0; mask >> i > 0; i++) + cnt += (1 & (mask >> i)); + //allocate return array with one entry for each bit + var indices = new int[cnt]; + //fill array with bit indices + cnt = 0; + for (var i = 0; mask >> i > 0; i++) + if ((1 & (mask >> i)) == 1) + indices[cnt++] = i + 1; + return indices; + } + + /// Reads the subclass XML for V1 streams. + /// The reader. + private void ReadMyXml([NotNull] System.Xml.XmlReader reader) + { + reader.ReadStartElement("ScheduleByMonth"); + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + switch (reader.LocalName) + { + case "DaysOfMonth": + reader.Read(); + var days = new List(); + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + if (reader.LocalName != "Day") continue; + var sday = reader.ReadElementContentAsString(); + if (sday.Equals("Last", StringComparison.InvariantCultureIgnoreCase)) continue; + var day = int.Parse(sday); + if (day >= 1 && day <= 31) + days.Add(day); + } + DaysOfMonth = days.ToArray(); + reader.ReadEndElement(); + break; + + case "Months": + reader.Read(); + MonthsOfYear = 0; + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + try + { + MonthsOfYear |= (MonthsOfTheYear)Enum.Parse(typeof(MonthsOfTheYear), reader.LocalName); + } + catch + { + throw new System.Xml.XmlException("Invalid months of the year element."); + } + reader.Read(); + } + reader.ReadEndElement(); + break; + + default: + reader.Skip(); + break; + } + } + reader.ReadEndElement(); + } + + private void WriteMyXml([NotNull] System.Xml.XmlWriter writer) + { + writer.WriteStartElement("ScheduleByMonth"); + + writer.WriteStartElement("DaysOfMonth"); + foreach (var day in DaysOfMonth) + writer.WriteElementString("Day", day.ToString()); + writer.WriteEndElement(); + + writer.WriteStartElement("Months"); + foreach (MonthsOfTheYear e in Enum.GetValues(typeof(MonthsOfTheYear))) + if (e != MonthsOfTheYear.AllMonths && (MonthsOfYear & e) == e) + writer.WriteElementString(e.ToString(), null); + writer.WriteEndElement(); + + writer.WriteEndElement(); + } + } + + /// + /// Represents a trigger that starts a task when the task is registered or updated. Not available on Task Scheduler 1.0. Only + /// available for Task Scheduler 2.0 on Windows Vista or Windows Server 2003 and later. + /// + /// The RegistrationTrigger will fire after the task is registered (saved). It is advisable to put in a delay. + /// + /// + /// + /// + /// + [XmlType(IncludeInSchema = false)] + public sealed class RegistrationTrigger : Trigger, ITriggerDelay + { + /// Creates an unbound instance of a . + public RegistrationTrigger() : base(TaskTriggerType.Registration) { } + + internal RegistrationTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Gets or sets a value that indicates the amount of time between when the system is booted and when the task is started. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + [XmlIgnore] + public TimeSpan Delay + { + get => v2Trigger != null ? Task.StringToTimeSpan(((IRegistrationTrigger)v2Trigger).Delay) : GetUnboundValueOrDefault(nameof(Delay), TimeSpan.Zero); + set + { + if (v2Trigger != null) + ((IRegistrationTrigger)v2Trigger).Delay = Task.TimeSpanToString(value); + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(Delay)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() => Properties.Resources.TriggerRegistration1; + } + + /// Defines how often the task is run and how long the repetition pattern is repeated after the task is started. + /// This can be used directly or by assignment for a . + /// + /// + /// + /// + /// + [XmlRoot("Repetition", Namespace = TaskDefinition.tns, IsNullable = true)] + [TypeConverter(typeof(RepetitionPatternConverter))] + public sealed class RepetitionPattern : IDisposable, IXmlSerializable, IEquatable, INotifyPropertyChanged + { + private readonly Trigger pTrigger; + private readonly IRepetitionPattern v2Pattern; + private TimeSpan unboundInterval = TimeSpan.Zero, unboundDuration = TimeSpan.Zero; + private bool unboundStopAtDurationEnd; + + /// Initializes a new instance of the class. + /// + /// The amount of time between each restart of the task. The maximum time allowed is 31 days, and the minimum time allowed is 1 minute. + /// + /// + /// The duration of how long the pattern is repeated. The minimum time allowed is one minute. If TimeSpan.Zero is specified, + /// the pattern is repeated indefinitely. + /// + /// + /// If set to true the running instance of the task is stopped at the end of repetition pattern duration. + /// + public RepetitionPattern(TimeSpan interval, TimeSpan duration, bool stopAtDurationEnd = false) + { + Interval = interval; + Duration = duration; + StopAtDurationEnd = stopAtDurationEnd; + } + + internal RepetitionPattern([NotNull] Trigger parent) + { + pTrigger = parent; + if (pTrigger?.v2Trigger != null) + v2Pattern = pTrigger.v2Trigger.Repetition; + } + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// Gets or sets how long the pattern is repeated. + /// + /// The duration that the pattern is repeated. The minimum time allowed is one minute. If TimeSpan.Zero is specified, the + /// pattern is repeated indefinitely. + /// + /// If you specify a repetition duration for a task, you must also specify the repetition interval. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + public TimeSpan Duration + { + get => v2Pattern != null + ? Task.StringToTimeSpan(v2Pattern.Duration) + : (pTrigger != null ? TimeSpan.FromMinutes(pTrigger.v1TriggerData.MinutesDuration) : unboundDuration); + set + { + if (value.Ticks < 0 || value != TimeSpan.Zero && value < TimeSpan.FromMinutes(1)) + throw new ArgumentOutOfRangeException(nameof(Duration)); + if (v2Pattern != null) + { + v2Pattern.Duration = Task.TimeSpanToString(value); + } + else if (pTrigger != null) + { + pTrigger.v1TriggerData.MinutesDuration = (uint)value.TotalMinutes; + Bind(); + } + else + unboundDuration = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the amount of time between each restart of the task. + /// + /// The amount of time between each restart of the task. The maximum time allowed is 31 days, and the minimum time allowed is 1 minute. + /// + /// If you specify a repetition duration for a task, you must also specify the repetition interval. + /// + /// The maximum time allowed is 31 days, and the minimum time allowed is 1 minute. + /// + [DefaultValue(typeof(TimeSpan), "00:00:00")] + public TimeSpan Interval + { + get => v2Pattern != null + ? Task.StringToTimeSpan(v2Pattern.Interval) + : (pTrigger != null ? TimeSpan.FromMinutes(pTrigger.v1TriggerData.MinutesInterval) : unboundInterval); + set + { + if (value.Ticks < 0 || (v2Pattern != null || pTrigger == null) && value != TimeSpan.Zero && (value < TimeSpan.FromMinutes(1) || value > TimeSpan.FromDays(31))) + throw new ArgumentOutOfRangeException(nameof(Interval)); + if (v2Pattern != null) + { + v2Pattern.Interval = Task.TimeSpanToString(value); + } + else if (pTrigger != null) + { + if (value != TimeSpan.Zero && value < TimeSpan.FromMinutes(1)) + throw new ArgumentOutOfRangeException(nameof(Interval)); + pTrigger.v1TriggerData.MinutesInterval = (uint)value.TotalMinutes; + Bind(); + } + else + unboundInterval = value; + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets a Boolean value that indicates if a running instance of the task is stopped at the end of repetition pattern duration. + /// + [DefaultValue(false)] + public bool StopAtDurationEnd + { + get + { + if (v2Pattern != null) + return v2Pattern.StopAtDurationEnd; + if (pTrigger != null) + return (pTrigger.v1TriggerData.Flags & V1Interop.TaskTriggerFlags.KillAtDurationEnd) == V1Interop.TaskTriggerFlags.KillAtDurationEnd; + return unboundStopAtDurationEnd; + } + set + { + if (v2Pattern != null) + v2Pattern.StopAtDurationEnd = value; + else if (pTrigger != null) + { + if (value) + pTrigger.v1TriggerData.Flags |= V1Interop.TaskTriggerFlags.KillAtDurationEnd; + else + pTrigger.v1TriggerData.Flags &= ~V1Interop.TaskTriggerFlags.KillAtDurationEnd; + Bind(); + } + else + unboundStopAtDurationEnd = value; + OnNotifyPropertyChanged(); + } + } + + /// Releases all resources used by this class. + public void Dispose() + { + if (v2Pattern != null) Marshal.ReleaseComObject(v2Pattern); + } + + /// Determines whether the specified , is equal to this instance. + /// The to compare with this instance. + /// true if the specified is equal to this instance; otherwise, false. + // ReSharper disable once BaseObjectEqualsIsObjectEquals + public override bool Equals(object obj) => obj is RepetitionPattern pattern ? Equals(pattern) : base.Equals(obj); + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public bool Equals(RepetitionPattern other) => other != null && Duration == other.Duration && Interval == other.Interval && StopAtDurationEnd == other.StopAtDurationEnd; + + /// Returns a hash code for this instance. + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + public override int GetHashCode() => new { A = Duration, B = Interval, C = StopAtDurationEnd }.GetHashCode(); + + /// Determines whether any properties for this have been set. + /// true if properties have been set; otherwise, false. + public bool IsSet() + { + if (v2Pattern != null) + return v2Pattern.StopAtDurationEnd || !string.IsNullOrEmpty(v2Pattern.Duration) || !string.IsNullOrEmpty(v2Pattern.Interval); + if (pTrigger != null) + return (pTrigger.v1TriggerData.Flags & V1Interop.TaskTriggerFlags.KillAtDurationEnd) == V1Interop.TaskTriggerFlags.KillAtDurationEnd || pTrigger.v1TriggerData.MinutesDuration > 0 || pTrigger.v1TriggerData.MinutesInterval > 0; + return false; + } + + System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() => null; + + void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) + { + if (!reader.IsEmptyElement) + { + reader.ReadStartElement(XmlSerializationHelper.GetElementName(this), TaskDefinition.tns); + XmlSerializationHelper.ReadObjectProperties(reader, this, ReadXmlConverter); + reader.ReadEndElement(); + } + else + reader.Skip(); + } + + void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) => XmlSerializationHelper.WriteObjectProperties(writer, this); + + internal void Bind() + { + if (pTrigger.v1Trigger != null) + pTrigger.SetV1TriggerData(); + else if (pTrigger.v2Trigger != null) + { + if (pTrigger.v1TriggerData.MinutesInterval != 0) + v2Pattern.Interval = $"PT{pTrigger.v1TriggerData.MinutesInterval}M"; + if (pTrigger.v1TriggerData.MinutesDuration != 0) + v2Pattern.Duration = $"PT{pTrigger.v1TriggerData.MinutesDuration}M"; + v2Pattern.StopAtDurationEnd = (pTrigger.v1TriggerData.Flags & V1Interop.TaskTriggerFlags.KillAtDurationEnd) == V1Interop.TaskTriggerFlags.KillAtDurationEnd; + } + } + + internal void Set([NotNull] RepetitionPattern value) + { + Duration = value.Duration; + Interval = value.Interval; + StopAtDurationEnd = value.StopAtDurationEnd; + } + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + + private bool ReadXmlConverter(System.Reflection.PropertyInfo pi, object obj, ref object value) + { + if (pi.Name != "Interval" || !(value is TimeSpan span) || span.Equals(TimeSpan.Zero) || Duration > span) + return false; + Duration = span.Add(TimeSpan.FromMinutes(1)); + return true; + } + } + + /// + /// Triggers tasks for console connect or disconnect, remote connect or disconnect, or workstation lock or unlock notifications. + /// Only available for Task Scheduler 2.0 on Windows Vista or Windows Server 2003 and later. + /// + /// + /// The SessionStateChangeTrigger will fire after six different system events: connecting or disconnecting locally or remotely, or + /// locking or unlocking the session. + /// + /// + /// + /// + /// + /// + [XmlType(IncludeInSchema = false)] + public sealed class SessionStateChangeTrigger : Trigger, ITriggerDelay, ITriggerUserId + { + /// Creates an unbound instance of a . + public SessionStateChangeTrigger() : base(TaskTriggerType.SessionStateChange) { } + + /// Initializes a new instance of the class. + /// The state change. + /// The user identifier. + public SessionStateChangeTrigger(TaskSessionStateChangeType stateChange, string userId = null) : this() { StateChange = stateChange; UserId = userId; } + + internal SessionStateChangeTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Gets or sets a value that indicates the amount of time between when the system is booted and when the task is started. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + public TimeSpan Delay + { + get => v2Trigger != null ? Task.StringToTimeSpan(((ISessionStateChangeTrigger)v2Trigger).Delay) : GetUnboundValueOrDefault(nameof(Delay), TimeSpan.Zero); + set + { + if (v2Trigger != null) + ((ISessionStateChangeTrigger)v2Trigger).Delay = Task.TimeSpanToString(value); + else + unboundValues[nameof(Delay)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the kind of Terminal Server session change that would trigger a task launch. + [DefaultValue(1)] + public TaskSessionStateChangeType StateChange + { + get => ((ISessionStateChangeTrigger)v2Trigger)?.StateChange ?? GetUnboundValueOrDefault(nameof(StateChange), TaskSessionStateChangeType.ConsoleConnect); + set + { + if (v2Trigger != null) + ((ISessionStateChangeTrigger)v2Trigger).StateChange = value; + else + unboundValues[nameof(StateChange)] = value; + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets the user for the Terminal Server session. When a session state change is detected for this user, a task is started. + /// + [DefaultValue(null)] + public string UserId + { + get => v2Trigger != null ? ((ISessionStateChangeTrigger)v2Trigger).UserId : GetUnboundValueOrDefault(nameof(UserId)); + set + { + if (v2Trigger != null) + ((ISessionStateChangeTrigger)v2Trigger).UserId = value; + else + unboundValues[nameof(UserId)] = value; + OnNotifyPropertyChanged(); + } + } + + /// + /// Copies the properties from another the current instance. This will not copy any properties associated with + /// any derived triggers except those supporting the interface. + /// + /// The source . + public override void CopyProperties(Trigger sourceTrigger) + { + base.CopyProperties(sourceTrigger); + if (sourceTrigger is SessionStateChangeTrigger st && !StateChangeIsSet()) + StateChange = st.StateChange; + } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Trigger other) => other is SessionStateChangeTrigger st && base.Equals(st) && StateChange == st.StateChange; + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() + { + var str = Properties.Resources.ResourceManager.GetString("TriggerSession" + StateChange.ToString()); + var user = string.IsNullOrEmpty(UserId) ? Properties.Resources.TriggerAnyUser : UserId; + if (StateChange != TaskSessionStateChangeType.SessionLock && StateChange != TaskSessionStateChangeType.SessionUnlock) + user = string.Format(Properties.Resources.TriggerSessionUserSession, user); + return string.Format(str, user); + } + + /// Returns a value indicating if the StateChange property has been set. + /// StateChange property has been set. + private bool StateChangeIsSet() => v2Trigger != null || (unboundValues?.ContainsKey("StateChange") ?? false); + } + + /// Represents a trigger that starts a task at a specific date and time. + /// A TimeTrigger runs at a specified date and time. + /// + /// + /// + /// + /// + public sealed class TimeTrigger : Trigger, ITriggerDelay, ICalendarTrigger + { + /// Creates an unbound instance of a . + public TimeTrigger() : base(TaskTriggerType.Time) { } + + /// Creates an unbound instance of a and assigns the execution time. + /// Date and time for the trigger to fire. + public TimeTrigger(DateTime startBoundary) : base(TaskTriggerType.Time) => StartBoundary = startBoundary; + + internal TimeTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.RunOnce) + { + } + + internal TimeTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Gets or sets a delay time that is randomly added to the start time of the trigger. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + [XmlIgnore] + public TimeSpan RandomDelay + { + get => v2Trigger != null ? Task.StringToTimeSpan(((ITimeTrigger)v2Trigger).RandomDelay) : GetUnboundValueOrDefault(nameof(RandomDelay), TimeSpan.Zero); + set + { + if (v2Trigger != null) + ((ITimeTrigger)v2Trigger).RandomDelay = Task.TimeSpanToString(value); + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(RandomDelay)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a value that indicates the amount of time before the task is started. + /// The delay duration. + TimeSpan ITriggerDelay.Delay + { + get => RandomDelay; + set => RandomDelay = value; + } + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() => string.Format(Properties.Resources.TriggerTime1, AdjustToLocal(StartBoundary)); + } + + /// + /// Abstract base class which provides the common properties that are inherited by all trigger classes. A trigger can be created using + /// the or the method. + /// + public abstract partial class Trigger : IDisposable, ICloneable, IEquatable, IComparable, IComparable, INotifyPropertyChanged + { + internal const string V2BoundaryDateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFK"; + internal static readonly CultureInfo DefaultDateCulture = CultureInfo.CreateSpecificCulture("en-US"); + + internal V1Interop.ITaskTrigger v1Trigger; + internal V1Interop.TaskTrigger v1TriggerData; + internal ITrigger v2Trigger; + + /// In testing and may change. Do not use until officially introduced into library. + protected Dictionary unboundValues = new Dictionary(); + + private static bool? foundTimeSpan2; + private static Type timeSpan2Type; + private readonly TaskTriggerType ttype; + private RepetitionPattern repititionPattern; + + internal Trigger([NotNull] V1Interop.ITaskTrigger trigger, V1Interop.TaskTriggerType type) + { + v1Trigger = trigger; + v1TriggerData = trigger.GetTrigger(); + v1TriggerData.Type = type; + ttype = ConvertFromV1TriggerType(type); + } + + internal Trigger([NotNull] ITrigger iTrigger) + { + v2Trigger = iTrigger; + ttype = iTrigger.Type; + if (string.IsNullOrEmpty(v2Trigger.StartBoundary) && this is ICalendarTrigger) + StartBoundary = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Unspecified); + } + + internal Trigger(TaskTriggerType triggerType) + { + ttype = triggerType; + + v1TriggerData.TriggerSize = (ushort)Marshal.SizeOf(typeof(V1Interop.TaskTrigger)); + if (ttype != TaskTriggerType.Registration && ttype != TaskTriggerType.Event && ttype != TaskTriggerType.SessionStateChange) + v1TriggerData.Type = ConvertToV1TriggerType(ttype); + + if (this is ICalendarTrigger) + StartBoundary = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Unspecified); + } + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// Gets or sets a Boolean value that indicates whether the trigger is enabled. + public bool Enabled + { + get => v2Trigger?.Enabled ?? GetUnboundValueOrDefault(nameof(Enabled), !v1TriggerData.Flags.IsFlagSet(V1Interop.TaskTriggerFlags.Disabled)); + set + { + if (v2Trigger != null) + v2Trigger.Enabled = value; + else + { + v1TriggerData.Flags = v1TriggerData.Flags.SetFlags(V1Interop.TaskTriggerFlags.Disabled, !value); + if (v1Trigger != null) + SetV1TriggerData(); + else + unboundValues[nameof(Enabled)] = value; + } + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets the date and time when the trigger is deactivated. The trigger cannot start the task after it is deactivated. + /// While the maximum value for this property is , the Windows Task Scheduler management + /// application that is part of the OS will fail if this value is greater than December 31, 9998. + /// + /// + /// + /// Version 1 (1.1 on all systems prior to Vista) of the native library only allows for the Day, Month and Year values of the structure. + /// + /// + /// Version 2 (1.2 or higher) of the native library only allows for both date and time and all values. + /// However, the user interface and methods will always show the time translated to local time. The + /// library makes every attempt to maintain the Kind value. When using the UI elements provided in the TaskSchedulerEditor library, + /// the "Synchronize across time zones" checkbox will be checked if the Kind is Local or Utc. If the Kind is Unspecified and the + /// user selects the checkbox, the Kind will be changed to Utc and the time adjusted from the value displayed as the local time. + /// + /// + [DefaultValue(typeof(DateTime), "9999-12-31T23:59:59.9999999")] + public DateTime EndBoundary + { + get + { + if (v2Trigger != null) + return string.IsNullOrEmpty(v2Trigger.EndBoundary) ? DateTime.MaxValue : DateTime.Parse(v2Trigger.EndBoundary, DefaultDateCulture); + return GetUnboundValueOrDefault(nameof(EndBoundary), v1TriggerData.EndDate.GetValueOrDefault(DateTime.MaxValue)); + } + set + { + if (v2Trigger != null) + { + if (value <= StartBoundary) + throw new ArgumentException(Properties.Resources.Error_TriggerEndBeforeStart); + v2Trigger.EndBoundary = value == DateTime.MaxValue ? null : value.ToString(V2BoundaryDateFormat, DefaultDateCulture); + } + else + { + v1TriggerData.EndDate = value == DateTime.MaxValue ? (DateTime?)null : value; + if (v1Trigger != null) + SetV1TriggerData(); + else + unboundValues[nameof(EndBoundary)] = value; + } + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets or sets the maximum amount of time that the task launched by this trigger is allowed to run. Not available with Task + /// Scheduler 1.0. + /// + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + [XmlIgnore] + public TimeSpan ExecutionTimeLimit + { + get => v2Trigger != null ? Task.StringToTimeSpan(v2Trigger.ExecutionTimeLimit) : GetUnboundValueOrDefault(nameof(ExecutionTimeLimit), TimeSpan.Zero); + set + { + if (v2Trigger != null) + v2Trigger.ExecutionTimeLimit = Task.TimeSpanToString(value); + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(ExecutionTimeLimit)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the identifier for the trigger. Cannot set with Task Scheduler 1.0. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(null)] + [XmlIgnore] + public string Id + { + get => v2Trigger != null ? v2Trigger.Id : GetUnboundValueOrDefault(nameof(Id)); + set + { + if (v2Trigger != null) + v2Trigger.Id = value; + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(Id)] = value; + OnNotifyPropertyChanged(); + } + } + + /// + /// Gets a instance that indicates how often the task is run and how long the repetition pattern is + /// repeated after the task is started. + /// + public RepetitionPattern Repetition + { + get => repititionPattern ??= new RepetitionPattern(this); + set + { + Repetition.Set(value); + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the date and time when the trigger is activated. + /// + /// + /// Version 1 (1.1 on all systems prior to Vista) of the native library only allows for values where the is unspecified. If the DateTime value Kind is then it will be used as + /// is. If the DateTime value Kind is then it will be converted to the local time and then used. + /// + /// + /// Version 2 (1.2 or higher) of the native library only allows for all values. However, the user + /// interface and methods will always show the time translated to local time. The library makes + /// every attempt to maintain the Kind value. When using the UI elements provided in the TaskSchedulerEditor library, the + /// "Synchronize across time zones" checkbox will be checked if the Kind is Local or Utc. If the Kind is Unspecified and the user + /// selects the checkbox, the Kind will be changed to Utc and the time adjusted from the value displayed as the local time. + /// + /// + /// Under Version 2, when converting the string used in the native library for this value (ITrigger.Startboundary) this library will + /// behave as follows: + /// + /// + /// YYYY-MM-DDTHH:MM:SS format uses DateTimeKind.Unspecified and the time specified. + /// + /// + /// YYYY-MM-DDTHH:MM:SSZ format uses DateTimeKind.Utc and the time specified as the GMT time. + /// + /// + /// YYYY-MM-DDTHH:MM:SS±HH:MM format uses DateTimeKind.Local and the time specified in that time zone. + /// + /// + /// + /// + public DateTime StartBoundary + { + get + { + if (v2Trigger == null) return GetUnboundValueOrDefault(nameof(StartBoundary), v1TriggerData.BeginDate); + if (string.IsNullOrEmpty(v2Trigger.StartBoundary)) + return DateTime.MinValue; + var ret = DateTime.Parse(v2Trigger.StartBoundary, DefaultDateCulture); + if (v2Trigger.StartBoundary.EndsWith("Z")) + ret = ret.ToUniversalTime(); + return ret; + } + set + { + if (v2Trigger != null) + { + if (value > EndBoundary) + throw new ArgumentException(Properties.Resources.Error_TriggerEndBeforeStart); + v2Trigger.StartBoundary = value == DateTime.MinValue ? null : value.ToString(V2BoundaryDateFormat, DefaultDateCulture); + } + else + { + v1TriggerData.BeginDate = value; + if (v1Trigger != null) + SetV1TriggerData(); + else + unboundValues[nameof(StartBoundary)] = value; + } + OnNotifyPropertyChanged(); + } + } + + /// Gets the type of the trigger. + /// The of the trigger. + [XmlIgnore] + public TaskTriggerType TriggerType => ttype; + + /// Creates the specified trigger. + /// Type of the trigger to instantiate. + /// of specified type. + public static Trigger CreateTrigger(TaskTriggerType triggerType) + { + switch (triggerType) + { + case TaskTriggerType.Boot: + return new BootTrigger(); + + case TaskTriggerType.Daily: + return new DailyTrigger(); + + case TaskTriggerType.Event: + return new EventTrigger(); + + case TaskTriggerType.Idle: + return new IdleTrigger(); + + case TaskTriggerType.Logon: + return new LogonTrigger(); + + case TaskTriggerType.Monthly: + return new MonthlyTrigger(); + + case TaskTriggerType.MonthlyDOW: + return new MonthlyDOWTrigger(); + + case TaskTriggerType.Registration: + return new RegistrationTrigger(); + + case TaskTriggerType.SessionStateChange: + return new SessionStateChangeTrigger(); + + case TaskTriggerType.Time: + return new TimeTrigger(); + + case TaskTriggerType.Weekly: + return new WeeklyTrigger(); + + case TaskTriggerType.Custom: + break; + + default: + throw new ArgumentOutOfRangeException(nameof(triggerType), triggerType, null); + } + return null; + } + + /// Creates a new that is an unbound copy of this instance. + /// A new that is an unbound copy of this instance. + public virtual object Clone() + { + var ret = CreateTrigger(TriggerType); + ret.CopyProperties(this); + return ret; + } + + /// + /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current + /// instance precedes, follows, or occurs in the same position in the sort order as the other object. + /// + /// An object to compare with this instance. + /// A value that indicates the relative order of the objects being compared. + public int CompareTo(Trigger other) => string.Compare(Id, other?.Id, StringComparison.InvariantCulture); + + /// + /// Copies the properties from another the current instance. This will not copy any properties associated with + /// any derived triggers except those supporting the interface. + /// + /// The source . + public virtual void CopyProperties(Trigger sourceTrigger) + { + if (sourceTrigger == null) + return; + Enabled = sourceTrigger.Enabled; + EndBoundary = sourceTrigger.EndBoundary; + try { ExecutionTimeLimit = sourceTrigger.ExecutionTimeLimit; } + catch { /* ignored */ } + Id = sourceTrigger.Id; + Repetition.Duration = sourceTrigger.Repetition.Duration; + Repetition.Interval = sourceTrigger.Repetition.Interval; + Repetition.StopAtDurationEnd = sourceTrigger.Repetition.StopAtDurationEnd; + StartBoundary = sourceTrigger.StartBoundary; + if (sourceTrigger is ITriggerDelay delay && this is ITriggerDelay) + try { ((ITriggerDelay)this).Delay = delay.Delay; } + catch { /* ignored */ } + if (sourceTrigger is ITriggerUserId id && this is ITriggerUserId) + try { ((ITriggerUserId)this).UserId = id.UserId; } + catch { /* ignored */ } + } + + /// Releases all resources used by this class. + public virtual void Dispose() + { + if (v2Trigger != null) + Marshal.ReleaseComObject(v2Trigger); + if (v1Trigger != null) + Marshal.ReleaseComObject(v1Trigger); + } + + /// Determines whether the specified , is equal to this instance. + /// The to compare with this instance. + /// true if the specified is equal to this instance; otherwise, false. + // ReSharper disable once BaseObjectEqualsIsObjectEquals + public override bool Equals(object obj) => obj is Trigger trigger ? Equals(trigger) : base.Equals(obj); + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public virtual bool Equals(Trigger other) + { + if (other == null) return false; + var ret = TriggerType == other.TriggerType && Enabled == other.Enabled && EndBoundary == other.EndBoundary && + ExecutionTimeLimit == other.ExecutionTimeLimit && Id == other.Id && Repetition.Equals(other.Repetition) && + StartBoundary == other.StartBoundary; + if (other is ITriggerDelay delay && this is ITriggerDelay) + try { ret = ret && ((ITriggerDelay)this).Delay == delay.Delay; } + catch { /* ignored */ } + if (other is ITriggerUserId id && this is ITriggerUserId) + try { ret = ret && ((ITriggerUserId)this).UserId == id.UserId; } + catch { /* ignored */ } + return ret; + } + + /// Returns a hash code for this instance. + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + public override int GetHashCode() => new + { + A = TriggerType, + B = Enabled, + C = EndBoundary, + D = ExecutionTimeLimit, + E = Id, + F = Repetition, + G = StartBoundary, + H = (this as ITriggerDelay)?.Delay ?? TimeSpan.Zero, + I = (this as ITriggerUserId)?.UserId + }.GetHashCode(); + + /// Sets the repetition. + /// + /// The amount of time between each restart of the task. The maximum time allowed is 31 days, and the minimum time allowed is 1 minute. + /// + /// + /// The duration of how long the pattern is repeated. The minimum time allowed is one minute. If TimeSpan.Zero is specified, + /// the pattern is repeated indefinitely. + /// + /// + /// if set to true the running instance of the task is stopped at the end of repetition pattern duration. + /// + [Obsolete("Set the Repetition property directly with a new instance of RepetitionPattern.", false)] + public void SetRepetition(TimeSpan interval, TimeSpan duration, bool stopAtDurationEnd = true) + { + Repetition.Duration = duration; + Repetition.Interval = interval; + Repetition.StopAtDurationEnd = stopAtDurationEnd; + } + + /// Returns a string representing this trigger. + /// String value of trigger. + public override string ToString() => v1Trigger != null ? v1Trigger.GetTriggerString() : V2GetTriggerString() + V2BaseTriggerString(); + + /// Returns a that represents this trigger in a specific language. + /// The language of the resulting string. + /// String value of trigger. + public virtual string ToString([NotNull] CultureInfo culture) + { + using (new CultureSwitcher(culture)) + return ToString(); + } + + int IComparable.CompareTo(object obj) => CompareTo(obj as Trigger); + + internal static DateTime AdjustToLocal(DateTime dt) => dt.Kind == DateTimeKind.Utc ? dt.ToLocalTime() : dt; + + internal static V1Interop.TaskTriggerType ConvertToV1TriggerType(TaskTriggerType type) + { + if (type == TaskTriggerType.Registration || type == TaskTriggerType.Event || type == TaskTriggerType.SessionStateChange) + throw new NotV1SupportedException(); + var tv1 = (int)type - 1; + if (tv1 >= 7) tv1--; + return (V1Interop.TaskTriggerType)tv1; + } + + internal static Trigger CreateTrigger([NotNull] V1Interop.ITaskTrigger trigger) => CreateTrigger(trigger, trigger.GetTrigger().Type); + + internal static Trigger CreateTrigger([NotNull] V1Interop.ITaskTrigger trigger, V1Interop.TaskTriggerType triggerType) + { + Trigger t = triggerType switch + { + V1Interop.TaskTriggerType.RunOnce => new TimeTrigger(trigger), + V1Interop.TaskTriggerType.RunDaily => new DailyTrigger(trigger), + V1Interop.TaskTriggerType.RunWeekly => new WeeklyTrigger(trigger), + V1Interop.TaskTriggerType.RunMonthly => new MonthlyTrigger(trigger), + V1Interop.TaskTriggerType.RunMonthlyDOW => new MonthlyDOWTrigger(trigger), + V1Interop.TaskTriggerType.OnIdle => new IdleTrigger(trigger), + V1Interop.TaskTriggerType.OnSystemStart => new BootTrigger(trigger), + V1Interop.TaskTriggerType.OnLogon => new LogonTrigger(trigger), + _ => throw new ArgumentOutOfRangeException(nameof(triggerType), triggerType, null), + }; + return t; + } + + internal static Trigger CreateTrigger([NotNull] ITrigger iTrigger, ITaskDefinition iDef = null) + { + switch (iTrigger.Type) + { + case TaskTriggerType.Boot: + return new BootTrigger((IBootTrigger)iTrigger); + + case TaskTriggerType.Daily: + return new DailyTrigger((IDailyTrigger)iTrigger); + + case TaskTriggerType.Event: + return new EventTrigger((IEventTrigger)iTrigger); + + case TaskTriggerType.Idle: + return new IdleTrigger((IIdleTrigger)iTrigger); + + case TaskTriggerType.Logon: + return new LogonTrigger((ILogonTrigger)iTrigger); + + case TaskTriggerType.Monthly: + return new MonthlyTrigger((IMonthlyTrigger)iTrigger); + + case TaskTriggerType.MonthlyDOW: + return new MonthlyDOWTrigger((IMonthlyDOWTrigger)iTrigger); + + case TaskTriggerType.Registration: + return new RegistrationTrigger((IRegistrationTrigger)iTrigger); + + case TaskTriggerType.SessionStateChange: + return new SessionStateChangeTrigger((ISessionStateChangeTrigger)iTrigger); + + case TaskTriggerType.Time: + return new TimeTrigger((ITimeTrigger)iTrigger); + + case TaskTriggerType.Weekly: + return new WeeklyTrigger((IWeeklyTrigger)iTrigger); + + case TaskTriggerType.Custom: + var ct = new CustomTrigger(iTrigger); + if (iDef != null) + try { ct.UpdateFromXml(iDef.XmlText); } catch { /* ignored */ } + return ct; + + default: + throw new ArgumentOutOfRangeException(); + } + } + + /// Gets the best time span string. + /// The to display. + /// Either the full string representation created by TimeSpan2 or the default TimeSpan representation. + internal static string GetBestTimeSpanString(TimeSpan span) + { + // See if the TimeSpan2 assembly is accessible + if (!foundTimeSpan2.HasValue) + { + try + { + foundTimeSpan2 = false; + timeSpan2Type = System.Reflection.ReflectionHelper.LoadType("System.TimeSpan2", "TimeSpan2.dll"); + if (timeSpan2Type != null) + foundTimeSpan2 = true; + } + catch { /* ignored */ } + } + + // If the TimeSpan2 assembly is available, try to call the ToString("f") method and return the result. + if (foundTimeSpan2 == true && timeSpan2Type != null) + { + try + { + return System.Reflection.ReflectionHelper.InvokeMethod(timeSpan2Type, new object[] { span }, "ToString", "f"); + } + catch { /* ignored */ } + } + + return span.ToString(); + } + + internal virtual void Bind([NotNull] V1Interop.ITask iTask) + { + if (v1Trigger == null) + { + v1Trigger = iTask.CreateTrigger(out var _); + } + SetV1TriggerData(); + } + + internal virtual void Bind([NotNull] ITaskDefinition iTaskDef) + { + var iTriggers = iTaskDef.Triggers; + v2Trigger = iTriggers.Create(ttype); + Marshal.ReleaseComObject(iTriggers); + if ((unboundValues.TryGetValue("StartBoundary", out var dt) ? (DateTime)dt : StartBoundary) > (unboundValues.TryGetValue("EndBoundary", out dt) ? (DateTime)dt : EndBoundary)) + throw new ArgumentException(Properties.Resources.Error_TriggerEndBeforeStart); + foreach (var key in unboundValues.Keys) + { + try + { + var o = unboundValues[key]; + CheckBindValue(key, ref o); + v2Trigger.GetType().InvokeMember(key, System.Reflection.BindingFlags.SetProperty, null, v2Trigger, new[] { o }); + } + catch (System.Reflection.TargetInvocationException tie) when (tie.InnerException != null) { throw tie.InnerException; } + catch { /* ignored */ } + } + unboundValues.Clear(); + unboundValues = null; + + repititionPattern = new RepetitionPattern(this); + repititionPattern.Bind(); + } + + /// Assigns the unbound TriggerData structure to the V1 trigger instance. + internal void SetV1TriggerData() + { + if (v1TriggerData.MinutesInterval != 0 && v1TriggerData.MinutesInterval >= v1TriggerData.MinutesDuration) + throw new ArgumentException("Trigger.Repetition.Interval must be less than Trigger.Repetition.Duration under Task Scheduler 1.0."); + if (v1TriggerData.EndDate <= v1TriggerData.BeginDate) + throw new ArgumentException(Properties.Resources.Error_TriggerEndBeforeStart); + if (v1TriggerData.BeginDate == DateTime.MinValue) + v1TriggerData.BeginDate = DateTime.Now; + v1Trigger?.SetTrigger(ref v1TriggerData); + System.Diagnostics.Debug.WriteLine(v1TriggerData); + } + + /// Checks the bind value for any conversion. + /// The key (property) name. + /// The value. + protected virtual void CheckBindValue(string key, ref object o) + { + if (o is TimeSpan ts) + o = Task.TimeSpanToString(ts); + if (o is DateTime dt) + { + if (key == "EndBoundary" && dt == DateTime.MaxValue || key == "StartBoundary" && dt == DateTime.MinValue) + o = null; + else + o = dt.ToString(V2BoundaryDateFormat, DefaultDateCulture); + } + } + + /// Gets the unbound value or a default. + /// Return type. + /// The property name. + /// The default value if not found in unbound value list. + /// The unbound value, if set, or the default value. + protected T GetUnboundValueOrDefault(string prop, T def = default) => unboundValues.TryGetValue(prop, out var val) ? (T)val : def; + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + protected void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected virtual string V2GetTriggerString() => string.Empty; + + private static TaskTriggerType ConvertFromV1TriggerType(V1Interop.TaskTriggerType v1Type) + { + var tv2 = (int)v1Type + 1; + if (tv2 > 6) tv2++; + return (TaskTriggerType)tv2; + } + + private string V2BaseTriggerString() + { + var ret = new StringBuilder(); + if (Repetition.Interval != TimeSpan.Zero) + { + var sduration = Repetition.Duration == TimeSpan.Zero ? Properties.Resources.TriggerDuration0 : string.Format(Properties.Resources.TriggerDurationNot0, GetBestTimeSpanString(Repetition.Duration)); + ret.AppendFormat(Properties.Resources.TriggerRepetition, GetBestTimeSpanString(Repetition.Interval), sduration); + } + if (EndBoundary != DateTime.MaxValue) + ret.AppendFormat(Properties.Resources.TriggerEndBoundary, AdjustToLocal(EndBoundary)); + if (ret.Length > 0) + ret.Insert(0, Properties.Resources.HyphenSeparator); + return ret.ToString(); + } + } + + /// + /// Represents a trigger that starts a task based on a weekly schedule. For example, the task starts at 8:00 A.M. on a specific day of + /// the week every week or every other week. + /// + /// A WeeklyTrigger runs at a specified time on specified days of the week every week or interval of weeks. + /// + /// + /// + /// + /// + [XmlRoot("CalendarTrigger", Namespace = TaskDefinition.tns, IsNullable = false)] + public sealed class WeeklyTrigger : Trigger, ICalendarTrigger, ITriggerDelay, IXmlSerializable + { + /// Creates an unbound instance of a . + /// The days of the week. + /// The interval between the weeks in the schedule. + public WeeklyTrigger(DaysOfTheWeek daysOfWeek = DaysOfTheWeek.Sunday, short weeksInterval = 1) : base(TaskTriggerType.Weekly) + { + DaysOfWeek = daysOfWeek; + WeeksInterval = weeksInterval; + } + + internal WeeklyTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.RunWeekly) + { + if (v1TriggerData.Data.weekly.DaysOfTheWeek == 0) + v1TriggerData.Data.weekly.DaysOfTheWeek = DaysOfTheWeek.Sunday; + if (v1TriggerData.Data.weekly.WeeksInterval == 0) + v1TriggerData.Data.weekly.WeeksInterval = 1; + } + + internal WeeklyTrigger([NotNull] ITrigger iTrigger) : base(iTrigger) + { + } + + /// Gets or sets the days of the week on which the task runs. + [DefaultValue(0)] + public DaysOfTheWeek DaysOfWeek + { + get => v2Trigger != null + ? (DaysOfTheWeek)((IWeeklyTrigger)v2Trigger).DaysOfWeek + : v1TriggerData.Data.weekly.DaysOfTheWeek; + set + { + if (v2Trigger != null) + ((IWeeklyTrigger)v2Trigger).DaysOfWeek = (short)value; + else + { + v1TriggerData.Data.weekly.DaysOfTheWeek = value; + if (v1Trigger != null) + SetV1TriggerData(); + else + unboundValues[nameof(DaysOfWeek)] = (short)value; + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a delay time that is randomly added to the start time of the trigger. + /// Not supported under Task Scheduler 1.0. + [DefaultValue(typeof(TimeSpan), "00:00:00")] + [XmlIgnore] + public TimeSpan RandomDelay + { + get => v2Trigger != null ? Task.StringToTimeSpan(((IWeeklyTrigger)v2Trigger).RandomDelay) : GetUnboundValueOrDefault(nameof(RandomDelay), TimeSpan.Zero); + set + { + if (v2Trigger != null) + ((IWeeklyTrigger)v2Trigger).RandomDelay = Task.TimeSpanToString(value); + else if (v1Trigger != null) + throw new NotV1SupportedException(); + else + unboundValues[nameof(RandomDelay)] = value; + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets the interval between the weeks in the schedule. + [DefaultValue(1)] + public short WeeksInterval + { + get => ((IWeeklyTrigger)v2Trigger)?.WeeksInterval ?? (short)v1TriggerData.Data.weekly.WeeksInterval; + set + { + if (v2Trigger != null) + ((IWeeklyTrigger)v2Trigger).WeeksInterval = value; + else + { + v1TriggerData.Data.weekly.WeeksInterval = (ushort)value; + if (v1Trigger != null) + SetV1TriggerData(); + else + unboundValues[nameof(WeeksInterval)] = value; + } + OnNotifyPropertyChanged(); + } + } + + /// Gets or sets a value that indicates the amount of time before the task is started. + /// The delay duration. + TimeSpan ITriggerDelay.Delay + { + get => RandomDelay; + set => RandomDelay = value; + } + + /// + /// Copies the properties from another the current instance. This will not copy any properties associated with + /// any derived triggers except those supporting the interface. + /// + /// The source . + public override void CopyProperties(Trigger sourceTrigger) + { + base.CopyProperties(sourceTrigger); + if (sourceTrigger is WeeklyTrigger wt) + { + DaysOfWeek = wt.DaysOfWeek; + WeeksInterval = wt.WeeksInterval; + } + } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Trigger other) => other is WeeklyTrigger wt && base.Equals(wt) && DaysOfWeek == wt.DaysOfWeek && WeeksInterval == wt.WeeksInterval; + + System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() => null; + + void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) => CalendarTrigger.ReadXml(reader, this, ReadMyXml); + + void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) => CalendarTrigger.WriteXml(writer, this, WriteMyXml); + + /// Gets the non-localized trigger string for V2 triggers. + /// String describing the trigger. + protected override string V2GetTriggerString() + { + var days = TaskEnumGlobalizer.GetString(DaysOfWeek); + return string.Format(WeeksInterval == 1 ? Properties.Resources.TriggerWeekly1Week : Properties.Resources.TriggerWeeklyMultWeeks, AdjustToLocal(StartBoundary), days, WeeksInterval); + } + + /// Reads the subclass XML for V1 streams. + /// The reader. + private void ReadMyXml(System.Xml.XmlReader reader) + { + reader.ReadStartElement("ScheduleByWeek"); + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + switch (reader.LocalName) + { + case "WeeksInterval": + WeeksInterval = (short)reader.ReadElementContentAsInt(); + break; + + case "DaysOfWeek": + reader.Read(); + DaysOfWeek = 0; + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + try + { + DaysOfWeek |= (DaysOfTheWeek)Enum.Parse(typeof(DaysOfTheWeek), reader.LocalName); + } + catch + { + throw new System.Xml.XmlException("Invalid days of the week element."); + } + reader.Read(); + } + reader.ReadEndElement(); + break; + + default: + reader.Skip(); + break; + } + } + reader.ReadEndElement(); + } + + /// Writes the subclass XML for V1 streams. + /// The writer. + private void WriteMyXml(System.Xml.XmlWriter writer) + { + writer.WriteStartElement("ScheduleByWeek"); + + if (WeeksInterval != 1) + writer.WriteElementString("WeeksInterval", WeeksInterval.ToString()); + + writer.WriteStartElement("DaysOfWeek"); + foreach (DaysOfTheWeek e in Enum.GetValues(typeof(DaysOfTheWeek))) + if (e != DaysOfTheWeek.AllDays && (DaysOfWeek & e) == e) + writer.WriteElementString(e.ToString(), null); + writer.WriteEndElement(); + + writer.WriteEndElement(); + } + } + + internal static class CalendarTrigger + { + internal delegate void CalendarXmlReader(System.Xml.XmlReader reader); + + internal delegate void CalendarXmlWriter(System.Xml.XmlWriter writer); + + public static void WriteXml([NotNull] System.Xml.XmlWriter writer, [NotNull] Trigger t, [NotNull] CalendarXmlWriter calWriterProc) + { + if (!t.Enabled) + writer.WriteElementString("Enabled", System.Xml.XmlConvert.ToString(t.Enabled)); + if (t.EndBoundary != DateTime.MaxValue) + writer.WriteElementString("EndBoundary", System.Xml.XmlConvert.ToString(t.EndBoundary, System.Xml.XmlDateTimeSerializationMode.RoundtripKind)); + XmlSerializationHelper.WriteObject(writer, t.Repetition); + writer.WriteElementString("StartBoundary", System.Xml.XmlConvert.ToString(t.StartBoundary, System.Xml.XmlDateTimeSerializationMode.RoundtripKind)); + calWriterProc(writer); + } + + internal static Trigger GetTriggerFromXml([NotNull] System.Xml.XmlReader reader) + { + Trigger t = null; + var xml = reader.ReadOuterXml(); + var match = System.Text.RegularExpressions.Regex.Match(xml, @"\<(?ScheduleBy.+)\>"); + if (match.Success && match.Groups.Count == 2) + { + switch (match.Groups[1].Value) + { + case "ScheduleByDay": + t = new DailyTrigger(); + break; + + case "ScheduleByWeek": + t = new WeeklyTrigger(); + break; + + case "ScheduleByMonth": + t = new MonthlyTrigger(); + break; + + case "ScheduleByMonthDayOfWeek": + t = new MonthlyDOWTrigger(); + break; + } + + if (t != null) + { + using var ms = new System.IO.StringReader(xml); + using var iReader = System.Xml.XmlReader.Create(ms); + ((IXmlSerializable)t).ReadXml(iReader); + } + } + return t; + } + + internal static void ReadXml([NotNull] System.Xml.XmlReader reader, [NotNull] Trigger t, [NotNull] CalendarXmlReader calReaderProc) + { + reader.ReadStartElement("CalendarTrigger", TaskDefinition.tns); + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + switch (reader.LocalName) + { + case "Enabled": + t.Enabled = reader.ReadElementContentAsBoolean(); + break; + + case "EndBoundary": + t.EndBoundary = reader.ReadElementContentAsDateTime(); + break; + + case "RandomDelay": + ((ITriggerDelay)t).Delay = Task.StringToTimeSpan(reader.ReadElementContentAsString()); + break; + + case "StartBoundary": + t.StartBoundary = reader.ReadElementContentAsDateTime(); + break; + + case "Repetition": + XmlSerializationHelper.ReadObject(reader, t.Repetition); + break; + + case "ScheduleByDay": + case "ScheduleByWeek": + case "ScheduleByMonth": + case "ScheduleByMonthDayOfWeek": + calReaderProc(reader); + break; + + default: + reader.Skip(); + break; + } + } + reader.ReadEndElement(); + } + } + + internal sealed class RepetitionPatternConverter : TypeConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) => destinationType == typeof(string) || base.CanConvertTo(context, destinationType); + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + var rp = (RepetitionPattern)value; + if (destinationType != typeof(string)) return base.ConvertTo(context, culture, value, destinationType); + if (rp.Interval == TimeSpan.Zero) return ""; + var sduration = rp.Duration == TimeSpan.Zero ? Properties.Resources.TriggerDuration0 : string.Format(Properties.Resources.TriggerDurationNot0Short, Trigger.GetBestTimeSpanString(rp.Duration)); + return string.Format(Properties.Resources.TriggerRepetitionShort, Trigger.GetBestTimeSpanString(rp.Interval), sduration); + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/TriggerCollection.cs b/FlashPatcher/TaskService/TriggerCollection.cs new file mode 100644 index 0000000..3ae41c5 --- /dev/null +++ b/FlashPatcher/TaskService/TriggerCollection.cs @@ -0,0 +1,534 @@ +using JetBrains.Annotations; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Xml.Serialization; + +namespace Microsoft.Win32.TaskScheduler +{ + /// Provides the methods that are used to add to, remove from, and get the triggers of a task. + [XmlRoot("Triggers", Namespace = TaskDefinition.tns, IsNullable = false)] + public sealed class TriggerCollection : IList, IDisposable, IXmlSerializable, IList, INotifyCollectionChanged, INotifyPropertyChanged + { + private const string IndexerName = "Item[]"; + private readonly V2Interop.ITriggerCollection v2Coll; + private bool inV2set; + private V1Interop.ITask v1Task; + private V2Interop.ITaskDefinition v2Def; + + internal TriggerCollection([NotNull] V1Interop.ITask iTask) => v1Task = iTask; + + internal TriggerCollection([NotNull] V2Interop.ITaskDefinition iTaskDef) + { + v2Def = iTaskDef; + v2Coll = v2Def.Triggers; + } + + /// Occurs when a collection changes. + public event NotifyCollectionChangedEventHandler CollectionChanged; + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// Gets the number of triggers in the collection. + public int Count => v2Coll?.Count ?? v1Task.GetTriggerCount(); + + bool IList.IsFixedSize => false; + + bool ICollection.IsReadOnly => false; + + bool IList.IsReadOnly => false; + + bool ICollection.IsSynchronized => false; + + object ICollection.SyncRoot => this; + + /// Gets or sets a specified trigger from the collection. + /// The . + /// The id ( ) of the trigger to be retrieved. + /// Specialized instance. + /// + /// + /// + /// Mismatching Id for trigger and lookup. + public Trigger this[[NotNull] string triggerId] + { + get + { + if (string.IsNullOrEmpty(triggerId)) + throw new ArgumentNullException(nameof(triggerId)); + foreach (var t in this) + if (string.Equals(t.Id, triggerId)) + return t; + throw new ArgumentOutOfRangeException(nameof(triggerId)); + } + set + { + if (value == null) + throw new NullReferenceException(); + if (string.IsNullOrEmpty(triggerId)) + throw new ArgumentNullException(nameof(triggerId)); + if (triggerId != value.Id) + throw new InvalidOperationException("Mismatching Id for trigger and lookup."); + var index = IndexOf(triggerId); + if (index >= 0) + { + var orig = this[index].Clone(); + inV2set = true; + try + { + RemoveAt(index); + Insert(index, value); + } + finally + { + inV2set = true; + } + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, orig, index)); + } + else + Add(value); + } + } + + /// Gets a specified trigger from the collection. + /// The index of the trigger to be retrieved. + /// Specialized instance. + public Trigger this[int index] + { + get + { + if (v2Coll != null) + return Trigger.CreateTrigger(v2Coll[++index], v2Def); + return Trigger.CreateTrigger(v1Task.GetTrigger((ushort)index)); + } + set + { + if (index < 0 || Count <= index) + throw new ArgumentOutOfRangeException(nameof(index), index, @"Index is not a valid index in the TriggerCollection"); + var orig = this[index].Clone(); + inV2set = true; + try + { + Insert(index, value); + RemoveAt(index + 1); + } + finally + { + inV2set = false; + } + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, orig, index)); + } + } + + object IList.this[int index] + { + get => this[index]; + set => this[index] = (Trigger)value; + } + + /*/// + /// Add an unbound to the task. derivative to + /// add to the task. Bound trigger. unboundTrigger + /// is null. + public Trigger Add([NotNull] Trigger unboundTrigger) + { + if (unboundTrigger == null) + throw new ArgumentNullException(nameof(unboundTrigger)); + if (v2Def != null) + unboundTrigger.Bind(v2Def); + else + unboundTrigger.Bind(v1Task); + return unboundTrigger; + }*/ + + /// Add an unbound to the task. + /// A type derived from . + /// derivative to add to the task. + /// Bound trigger. + /// unboundTrigger is null. + public TTrigger Add([NotNull] TTrigger unboundTrigger) where TTrigger : Trigger + { + if (unboundTrigger == null) + throw new ArgumentNullException(nameof(unboundTrigger)); + if (v2Def != null) + unboundTrigger.Bind(v2Def); + else + unboundTrigger.Bind(v1Task); + OnNotifyPropertyChanged(nameof(Count)); + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, unboundTrigger)); + return unboundTrigger; + } + + /// Add a new trigger to the collections of triggers for the task. + /// The type of trigger to create. + /// A instance of the specified type. + public Trigger AddNew(TaskTriggerType taskTriggerType) + { + if (v1Task != null) + return Trigger.CreateTrigger(v1Task.CreateTrigger(out _), Trigger.ConvertToV1TriggerType(taskTriggerType)); + + return Trigger.CreateTrigger(v2Coll.Create(taskTriggerType), v2Def); + } + + /// Adds a collection of unbound triggers to the end of the . + /// + /// The triggers to be added to the end of the . The collection itself cannot be null and + /// cannot contain null elements. + /// + /// is null. + public void AddRange([NotNull] IEnumerable triggers) + { + if (triggers == null) + throw new ArgumentNullException(nameof(triggers)); + foreach (var item in triggers) + Add(item); + } + + /// Clears all triggers from the task. + public void Clear() + { + if (v2Coll != null) + v2Coll.Clear(); + else + { + inV2set = true; + try + { + for (var i = Count - 1; i >= 0; i--) + RemoveAt(i); + } + finally + { + inV2set = false; + } + } + OnNotifyPropertyChanged(nameof(Count)); + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + + /// Determines whether the contains a specific value. + /// The object to locate in the . + /// true if is found in the ; otherwise, false. + public bool Contains([NotNull] Trigger item) => Find(a => a.Equals(item)) != null; + + /// Determines whether the specified trigger type is contained in this collection. + /// Type of the trigger. + /// true if the specified trigger type is contained in this collection; otherwise, false. + public bool ContainsType(Type triggerType) => Find(a => a.GetType() == triggerType) != null; + + /// + /// Copies the elements of the to an , starting at a particular index. + /// + /// + /// The one-dimensional that is the destination of the elements copied from . The + /// must have zero-based indexing. + /// + /// The zero-based index in at which copying begins. + public void CopyTo(Trigger[] array, int arrayIndex) => CopyTo(0, array, arrayIndex, Count); + + /// + /// Copies the elements of the to a array, starting at a particular array index. + /// + /// The zero-based index in the source at which copying begins. + /// + /// The array that is the destination of the elements copied from . The array must have zero-based indexing. + /// + /// The zero-based index in array at which copying begins. + /// The number of elements to copy. + /// is null. + /// is less than 0. + /// + /// The number of elements in the source is greater than the available space from to the end of the destination . + /// + public void CopyTo(int index, Trigger[] array, int arrayIndex, int count) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException(nameof(index)); + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + if (count < 0 || count > (Count - index)) + throw new ArgumentOutOfRangeException(nameof(count)); + if ((Count - index) > (array.Length - arrayIndex)) + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + for (var i = 0; i < count; i++) + array[arrayIndex + i] = (Trigger)this[index + i].Clone(); + } + + /// Releases all resources used by this class. + public void Dispose() + { + if (v2Coll != null) Marshal.ReleaseComObject(v2Coll); + v2Def = null; + v1Task = null; + } + + /// + /// Searches for an that matches the conditions defined by the specified predicate, and returns the first + /// occurrence within the entire collection. + /// + /// + /// The delegate that defines the conditions of the to search for. + /// + /// + /// The first that matches the conditions defined by the specified predicate, if found; otherwise, null. + /// + public Trigger Find([NotNull] Predicate match) + { + if (match == null) + throw new ArgumentNullException(nameof(match)); + foreach (var item in this) + if (match(item)) return item; + return null; + } + + /// + /// Searches for an that matches the conditions defined by the specified predicate, and returns the zero-based + /// index of the first occurrence within the collection that starts at the specified index and contains the specified number of elements. + /// + /// The zero-based starting index of the search. + /// The number of elements in the collection to search. + /// The delegate that defines the conditions of the element to search for. + /// + /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1. + /// + public int FindIndexOf(int startIndex, int count, [NotNull] Predicate match) + { + if (startIndex < 0 || startIndex >= Count) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + if (startIndex + count > Count) + throw new ArgumentOutOfRangeException(nameof(count)); + if (match == null) + throw new ArgumentNullException(nameof(match)); + for (var i = startIndex; i < startIndex + count; i++) + if (match(this[i])) return i; + return -1; + } + + /// + /// Searches for an that matches the conditions defined by the specified predicate, and returns the zero-based + /// index of the first occurrence within the collection. + /// + /// The delegate that defines the conditions of the element to search for. + /// + /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1. + /// + public int FindIndexOf([NotNull] Predicate match) => FindIndexOf(0, Count, match); + + /// Gets the collection enumerator for this collection. + /// The for this collection. + public IEnumerator GetEnumerator() + { + if (v1Task != null) + return new V1TriggerEnumerator(v1Task); + return new ComEnumerator(() => v2Coll.Count, i => v2Coll[i], o => Trigger.CreateTrigger(o, v2Def)); + } + + /// Determines the index of a specific item in the . + /// The object to locate in the . + /// The index of if found in the list; otherwise, -1. + public int IndexOf([NotNull] Trigger item) => FindIndexOf(a => a.Equals(item)); + + /// Determines the index of a specific item in the . + /// The id ( ) of the trigger to be retrieved. + /// The index of if found in the list; otherwise, -1. + public int IndexOf([NotNull] string triggerId) + { + if (string.IsNullOrEmpty(triggerId)) + throw new ArgumentNullException(triggerId); + return FindIndexOf(a => string.Equals(a.Id, triggerId)); + } + + /// Inserts an trigger at the specified index. + /// The zero-based index at which trigger should be inserted. + /// The trigger to insert into the list. + public void Insert(int index, [NotNull] Trigger trigger) + { + if (trigger == null) + throw new ArgumentNullException(nameof(trigger)); + if (index >= Count) + throw new ArgumentOutOfRangeException(nameof(index)); + + var pushItems = new Trigger[Count - index]; + CopyTo(index, pushItems, 0, Count - index); + for (var j = Count - 1; j >= index; j--) + RemoveAt(j); + Add(trigger); + foreach (var t in pushItems) + Add(t); + } + + /// Removes the first occurrence of a specific object from the . + /// The object to remove from the . + /// + /// true if was successfully removed from the ; otherwise, false. This method + /// also returns false if is not found in the original . + /// + public bool Remove([NotNull] Trigger item) + { + var idx = IndexOf(item); + if (idx != -1) + { + try + { + RemoveAt(idx); + return true; + } + catch { } + } + return false; + } + + /// Removes the trigger at a specified index. + /// Index of trigger to remove. + /// Index out of range. + public void RemoveAt(int index) + { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException(nameof(index), index, @"Failed to remove Trigger. Index out of range."); + var item = this[index].Clone(); + if (v2Coll != null) + v2Coll.Remove(++index); + else + v1Task.DeleteTrigger((ushort)index); //Remove the trigger from the Task Scheduler + if (!inV2set) + { + OnNotifyPropertyChanged(nameof(Count)); + OnNotifyPropertyChanged(IndexerName); + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); + } + } + + /// Copies the elements of the to a new array. + /// An array containing copies of the elements of the . + public Trigger[] ToArray() + { + var ret = new Trigger[Count]; + CopyTo(ret, 0); + return ret; + } + + /// Returns a that represents the triggers in this collection. + /// A that represents the triggers in this collection. + public override string ToString() + { + if (Count == 1) + return this[0].ToString(); + if (Count > 1) + return Properties.Resources.MultipleTriggers; + return string.Empty; + } + + void ICollection.Add(Trigger item) => Add(item); + + int IList.Add(object value) + { + Add((Trigger)value); + return Count - 1; + } + + bool IList.Contains(object value) => Contains((Trigger)value); + + void ICollection.CopyTo(Array array, int index) + { + if (array != null && array.Rank != 1) + throw new RankException("Multi-dimensional arrays are not supported."); + var src = new Trigger[Count]; + CopyTo(src, 0); + Array.Copy(src, 0, array, index, Count); + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() => null; + + int IList.IndexOf(object value) => IndexOf((Trigger)value); + + void IList.Insert(int index, object value) => Insert(index, (Trigger)value); + + void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) + { + reader.ReadStartElement(XmlSerializationHelper.GetElementName(this), TaskDefinition.tns); + while (reader.MoveToContent() == System.Xml.XmlNodeType.Element) + { + switch (reader.LocalName) + { + case "BootTrigger": + XmlSerializationHelper.ReadObject(reader, AddNew(TaskTriggerType.Boot)); + break; + + case "IdleTrigger": + XmlSerializationHelper.ReadObject(reader, AddNew(TaskTriggerType.Idle)); + break; + + case "TimeTrigger": + XmlSerializationHelper.ReadObject(reader, AddNew(TaskTriggerType.Time)); + break; + + case "LogonTrigger": + XmlSerializationHelper.ReadObject(reader, AddNew(TaskTriggerType.Logon)); + break; + + case "CalendarTrigger": + Add(CalendarTrigger.GetTriggerFromXml(reader)); + break; + + default: + reader.Skip(); + break; + } + } + reader.ReadEndElement(); + } + + void IList.Remove(object value) => Remove((Trigger)value); + + void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) + { + foreach (var t in this) + XmlSerializationHelper.WriteObject(writer, t); + } + + internal void Bind() + { + foreach (var t in this) + t.SetV1TriggerData(); + } + + /// Called when a property has changed to notify any attached elements. + /// Name of the property. + private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + + private sealed class V1TriggerEnumerator : IEnumerator + { + private short curItem = -1; + private V1Interop.ITask iTask; + + internal V1TriggerEnumerator(V1Interop.ITask task) => iTask = task; + + public Trigger Current => Trigger.CreateTrigger(iTask.GetTrigger((ushort)curItem)); + + object IEnumerator.Current => Current; + + /// Releases all resources used by this class. + public void Dispose() => iTask = null; + + public bool MoveNext() => (++curItem < iTask.GetTriggerCount()); + + public void Reset() => curItem = -1; + } + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/User.cs b/FlashPatcher/TaskService/User.cs new file mode 100644 index 0000000..8db1a1f --- /dev/null +++ b/FlashPatcher/TaskService/User.cs @@ -0,0 +1,146 @@ +using System; +using System.Security.Principal; + +namespace Microsoft.Win32.TaskScheduler +{ + /// Represents a system account. + internal class User : IEquatable, IDisposable + { + private static readonly WindowsIdentity cur = WindowsIdentity.GetCurrent(); + private SecurityIdentifier sid; + + /// Initializes a new instance of the class. + /// + /// Name of the user. This can be in the format DOMAIN\username or username@domain.com or username or + /// null (for current user). + /// + public User(string userName = null) + { + if (string.IsNullOrEmpty(userName)) userName = null; + // 2018-03-02: Hopefully not a breaking change, but by adding in the comparison of an account name without a domain and the + // current user, there is a chance that current implementations will break given the condition that a local account with the same + // name as a domain account exists and the intention was to prefer the local account. In such a case, the developer should + // prepend the user name in TaskDefinition.Principal.UserId with the machine name of the local machine. + if (userName == null || cur.Name.Equals(userName, StringComparison.InvariantCultureIgnoreCase) || GetUser(cur.Name).Equals(userName, StringComparison.InvariantCultureIgnoreCase)) + { + Identity = cur; + sid = Identity.User; + } + else if (userName.Contains("\\") && !userName.StartsWith(@"NT AUTHORITY\")) + { + try + { + using (var ds = new NativeMethods.DomainService()) + { + Identity = new WindowsIdentity(ds.CrackName(userName)); + sid = Identity.User; + } + } + catch { } + } + + if (Identity == null) + { + if (userName != null && userName.Contains("@")) + { + Identity = new WindowsIdentity(userName); + sid = Identity.User; + } + + if (Identity == null && userName != null) + { + var ntacct = new NTAccount(userName); + try { sid = (SecurityIdentifier)ntacct.Translate(typeof(SecurityIdentifier)); } catch { } + } + } + + string GetUser(string domUser) + { + var split = domUser.Split('\\'); + return split.Length == 2 ? split[1] : domUser; + } + } + + /// Initializes a new instance of the class. + /// The . + internal User(WindowsIdentity wid) { Identity = wid; sid = wid.User; } + + /// Gets the current user. + /// The current user. + public static User Current => new User(cur); + + /// Gets the identity. + /// The identity. + public WindowsIdentity Identity { get; private set; } + + /// Gets a value indicating whether this instance is in an administrator role. + /// true if this instance is an admin; otherwise, false. + public bool IsAdmin => Identity != null ? new WindowsPrincipal(Identity).IsInRole(WindowsBuiltInRole.Administrator) : false; + + /// Gets a value indicating whether this instance is the interactive user. + /// true if this instance is the current user; otherwise, false. + public bool IsCurrent => Identity?.User.Equals(cur.User) ?? false; + + /// Gets a value indicating whether this instance is a service account. + /// true if this instance is a service account; otherwise, false. + public bool IsServiceAccount + { + get + { + try + { + return (sid != null && (sid.IsWellKnown(WellKnownSidType.LocalSystemSid) || sid.IsWellKnown(WellKnownSidType.NetworkServiceSid) || sid.IsWellKnown(WellKnownSidType.LocalServiceSid))); + } + catch { } + return false; + } + } + + /// Gets a value indicating whether this instance is the SYSTEM account. + /// true if this instance is the SYSTEM account; otherwise, false. + public bool IsSystem => sid != null && sid.IsWellKnown(WellKnownSidType.LocalSystemSid); + + /// Gets the SID string. + /// The SID string. + public string SidString => sid?.ToString(); + + /// Gets the NT name (DOMAIN\username). + /// The name of the user. + public string Name => Identity?.Name ?? ((NTAccount)sid?.Translate(typeof(NTAccount)))?.Value; + + /// Create a instance from a SID string. + /// The SID string. + /// A instance. + public static User FromSidString(string sid) => new User(((NTAccount)new SecurityIdentifier(sid).Translate(typeof(NTAccount))).Value); + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public void Dispose() => Identity?.Dispose(); + + /// Determines whether the specified , is equal to this instance. + /// The to compare with this instance. + /// true if the specified is equal to this instance; otherwise, false. + public override bool Equals(object obj) + { + if (obj is User user) + return Equals(user); + if (obj is WindowsIdentity wid && sid != null) + return sid.Equals(wid.User); + try + { + if (obj is string un) + return Equals(new User(un)); + } + catch { } + return base.Equals(obj); + } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public bool Equals(User other) => (other != null && sid != null) ? sid.Equals(other.sid) : false; + + /// Returns a hash code for this instance. + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + public override int GetHashCode() => sid?.GetHashCode() ?? 0; + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/V1/TaskSchedulerV1Interop.cs b/FlashPatcher/TaskService/V1/TaskSchedulerV1Interop.cs new file mode 100644 index 0000000..303dc29 --- /dev/null +++ b/FlashPatcher/TaskService/V1/TaskSchedulerV1Interop.cs @@ -0,0 +1,472 @@ +using System; +using System.Runtime.InteropServices; +using JetBrains.Annotations; +// ReSharper disable InconsistentNaming +// ReSharper disable FieldCanBeMadeReadOnly.Global + +namespace Microsoft.Win32.TaskScheduler.V1Interop +{ +#pragma warning disable CS0618 // Type or member is obsolete + + #region class HRESULT -- Values peculiar to the task scheduler. + internal class HResult + { + // The task is ready to run at its next scheduled time. + public const int SCHED_S_TASK_READY = 0x00041300; + // The task is currently running. + public const int SCHED_S_TASK_RUNNING = 0x00041301; + // The task will not run at the scheduled times because it has been disabled. + public const int SCHED_S_TASK_DISABLED = 0x00041302; + // The task has not yet run. + public const int SCHED_S_TASK_HAS_NOT_RUN = 0x00041303; + // There are no more runs scheduled for this task. + public const int SCHED_S_TASK_NO_MORE_RUNS = 0x00041304; + // One or more of the properties that are needed to run this task on a schedule have not been set. + public const int SCHED_S_TASK_NOT_SCHEDULED = 0x00041305; + // The last run of the task was terminated by the user. + public const int SCHED_S_TASK_TERMINATED = 0x00041306; + // Either the task has no triggers or the existing triggers are disabled or not set. + public const int SCHED_S_TASK_NO_VALID_TRIGGERS = 0x00041307; + // Event triggers don't have set run times. + public const int SCHED_S_EVENT_TRIGGER = 0x00041308; + // Trigger not found. + public const int SCHED_E_TRIGGER_NOT_FOUND = unchecked((int)0x80041309); + // One or more of the properties that are needed to run this task have not been set. + public const int SCHED_E_TASK_NOT_READY = unchecked((int)0x8004130A); + // There is no running instance of the task to terminate. + public const int SCHED_E_TASK_NOT_RUNNING = unchecked((int)0x8004130B); + // The Task Scheduler Service is not installed on this computer. + public const int SCHED_E_SERVICE_NOT_INSTALLED = unchecked((int)0x8004130C); + // The task object could not be opened. + public const int SCHED_E_CANNOT_OPEN_TASK = unchecked((int)0x8004130D); + // The object is either an invalid task object or is not a task object. + public const int SCHED_E_INVALID_TASK = unchecked((int)0x8004130E); + // No account information could be found in the Task Scheduler security database for the task indicated. + public const int SCHED_E_ACCOUNT_INFORMATION_NOT_SET = unchecked((int)0x8004130F); + // Unable to establish existence of the account specified. + public const int SCHED_E_ACCOUNT_NAME_NOT_FOUND = unchecked((int)0x80041310); + // Corruption was detected in the Task Scheduler security database; the database has been reset. + public const int SCHED_E_ACCOUNT_DBASE_CORRUPT = unchecked((int)0x80041311); + // Task Scheduler security services are available only on Windows NT. + public const int SCHED_E_NO_SECURITY_SERVICES = unchecked((int)0x80041312); + // The task object version is either unsupported or invalid. + public const int SCHED_E_UNKNOWN_OBJECT_VERSION = unchecked((int)0x80041313); + // The task has been configured with an unsupported combination of account settings and run time options. + public const int SCHED_E_UNSUPPORTED_ACCOUNT_OPTION = unchecked((int)0x80041314); + // The Task Scheduler Service is not running. + public const int SCHED_E_SERVICE_NOT_RUNNING = unchecked((int)0x80041315); + // The Task Scheduler service must be configured to run in the System account to function properly. Individual tasks may be configured to run in other accounts. + public const int SCHED_E_SERVICE_NOT_LOCALSYSTEM = unchecked((int)0x80041316); + } + #endregion + + #region Enums + + /// + /// Options for a task, used for the Flags property of a Task. Uses the + /// "Flags" attribute, so these values are combined with |. + /// Some flags are documented as Windows 95 only, but they have a + /// user interface in Windows XP so that may not be true. + /// + [Flags] + internal enum TaskFlags + { + /// + /// The interactive flag is set if the task is intended to be displayed to the user. + /// If the flag is not set, no user interface associated with the task is presented + /// to the user when the task is executed. + /// + Interactive = 0x1, + /// + /// The task will be deleted when there are no more scheduled run times. + /// + DeleteWhenDone = 0x2, + /// + /// The task is disabled. This is useful to temporarily prevent a task from running + /// at the scheduled time(s). + /// + Disabled = 0x4, + /// + /// The task begins only if the computer is not in use at the scheduled start time. Windows 95 only. + /// + StartOnlyIfIdle = 0x10, + /// + /// The task terminates if the computer makes an idle to non-idle transition while the task is running. + /// The computer is not considered idle until the IdleWait triggers' time elapses with no user input. + /// Windows 95 only. For information regarding idle triggers, see . + /// + KillOnIdleEnd = 0x20, + /// + /// The task does not start if its target computer is running on battery power. Windows 95 only. + /// + DontStartIfOnBatteries = 0x40, + /// + /// The task ends, and the associated application quits if the task's target computer switches + /// to battery power. Windows 95 only. + /// + KillIfGoingOnBatteries = 0x80, + /// + /// The task runs only if the system is docked. Windows 95 only. + /// + RunOnlyIfDocked = 0x100, + /// + /// The work item created will be hidden. + /// + Hidden = 0x200, + /// + /// The task runs only if there is currently a valid Internet connection. + /// This feature is currently not implemented. + /// + RunIfConnectedToInternet = 0x400, + /// + /// The task starts again if the computer makes a non-idle to idle transition before all the + /// task's task_triggers elapse. (Use this flag in conjunction with KillOnIdleEnd.) Windows 95 only. + /// + RestartOnIdleResume = 0x800, + /// + /// The task runs only if the SYSTEM account is available. + /// + SystemRequired = 0x1000, + /// + /// The task runs only if the user specified in SetAccountInformation is logged on interactively. + /// This flag has no effect on work items set to run in the local account. + /// + RunOnlyIfLoggedOn = 0x2000 + } + + /// + /// Status values returned for a task. Some values have been determined to occur although + /// they do no appear in the Task Scheduler system documentation. + /// + internal enum TaskStatus + { + /// The task is ready to run at its next scheduled time. + Ready = HResult.SCHED_S_TASK_READY, + /// The task is currently running. + Running = HResult.SCHED_S_TASK_RUNNING, + /// One or more of the properties that are needed to run this task on a schedule have not been set. + NotScheduled = HResult.SCHED_S_TASK_NOT_SCHEDULED, + /// The task has not yet run. + NeverRun = HResult.SCHED_S_TASK_HAS_NOT_RUN, + /// The task will not run at the scheduled times because it has been disabled. + Disabled = HResult.SCHED_S_TASK_DISABLED, + /// There are no more runs scheduled for this task. + NoMoreRuns = HResult.SCHED_S_TASK_NO_MORE_RUNS, + /// The last run of the task was terminated by the user. + Terminated = HResult.SCHED_S_TASK_TERMINATED, + /// Either the task has no triggers or the existing triggers are disabled or not set. + NoTriggers = HResult.SCHED_S_TASK_NO_VALID_TRIGGERS, + /// Event triggers don't have set run times. + NoTriggerTime = HResult.SCHED_S_EVENT_TRIGGER + } + + /// Valid types of triggers + internal enum TaskTriggerType + { + /// Trigger is set to run the task a single time. + RunOnce = 0, + /// Trigger is set to run the task on a daily interval. + RunDaily = 1, + /// Trigger is set to run the work item on specific days of a specific week of a specific month. + RunWeekly = 2, + /// Trigger is set to run the task on a specific day(s) of the month. + RunMonthly = 3, + /// Trigger is set to run the task on specific days, weeks, and months. + RunMonthlyDOW = 4, + /// Trigger is set to run the task if the system remains idle for the amount of time specified by the idle wait time of the task. + OnIdle = 5, + /// Trigger is set to run the task at system startup. + OnSystemStart = 6, + /// Trigger is set to run the task when a user logs on. + OnLogon = 7 + } + + [Flags] + internal enum TaskTriggerFlags : uint + { + HasEndDate = 0x1, + KillAtDurationEnd = 0x2, + Disabled = 0x4 + } + + #endregion + + #region Structs + + [StructLayout(LayoutKind.Sequential)] + internal struct Daily + { + public ushort DaysInterval; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct Weekly + { + public ushort WeeksInterval; + public DaysOfTheWeek DaysOfTheWeek; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MonthlyDate + { + public uint Days; + public MonthsOfTheYear Months; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MonthlyDOW + { + public ushort WhichWeek; + public DaysOfTheWeek DaysOfTheWeek; + public MonthsOfTheYear Months; + + public WhichWeek V2WhichWeek + { + get + { + return (WhichWeek)(1 << ((short)WhichWeek - 1)); + } + set + { + int idx = Array.IndexOf(new short[] { 0x1, 0x2, 0x4, 0x8, 0x10 }, (short)value); + if (idx >= 0) + WhichWeek = (ushort)(idx + 1); + else + throw new NotV1SupportedException("Only a single week can be set with Task Scheduler 1.0."); + } + } + } + + [StructLayout(LayoutKind.Explicit)] + internal struct TriggerTypeData + { + [FieldOffset(0)] + public Daily daily; + [FieldOffset(0)] + public Weekly weekly; + [FieldOffset(0)] + public MonthlyDate monthlyDate; + [FieldOffset(0)] + public MonthlyDOW monthlyDOW; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TaskTrigger + { + public ushort TriggerSize; // Structure size. + public ushort Reserved1; // Reserved. Must be zero. + public ushort BeginYear; // Trigger beginning date year. + public ushort BeginMonth; // Trigger beginning date month. + public ushort BeginDay; // Trigger beginning date day. + public ushort EndYear; // Optional trigger ending date year. + public ushort EndMonth; // Optional trigger ending date month. + public ushort EndDay; // Optional trigger ending date day. + public ushort StartHour; // Run bracket start time hour. + public ushort StartMinute; // Run bracket start time minute. + public uint MinutesDuration; // Duration of run bracket. + public uint MinutesInterval; // Run bracket repetition interval. + public TaskTriggerFlags Flags; // Trigger flags. + public TaskTriggerType Type; // Trigger type. + public TriggerTypeData Data; // Trigger data peculiar to this type (union). + public ushort Reserved2; // Reserved. Must be zero. + public ushort RandomMinutesInterval; // Maximum number of random minutes after start time. + + public DateTime BeginDate + { + get { try { return BeginYear == 0 ? DateTime.MinValue : new DateTime(BeginYear, BeginMonth, BeginDay, StartHour, StartMinute, 0, DateTimeKind.Unspecified); } catch { return DateTime.MinValue; } } + set + { + if (value != DateTime.MinValue) + { + DateTime local = value.Kind == DateTimeKind.Utc ? value.ToLocalTime() : value; + BeginYear = (ushort)local.Year; + BeginMonth = (ushort)local.Month; + BeginDay = (ushort)local.Day; + StartHour = (ushort)local.Hour; + StartMinute = (ushort)local.Minute; + } + else + BeginYear = BeginMonth = BeginDay = StartHour = StartMinute = 0; + } + } + + public DateTime? EndDate + { + get { try { return EndYear == 0 ? (DateTime?)null : new DateTime(EndYear, EndMonth, EndDay); } catch { return DateTime.MaxValue; } } + set + { + if (value.HasValue) + { + EndYear = (ushort)value.Value.Year; + EndMonth = (ushort)value.Value.Month; + EndDay = (ushort)value.Value.Day; + Flags |= TaskTriggerFlags.HasEndDate; + } + else + { + EndYear = EndMonth = EndDay = 0; + Flags &= ~TaskTriggerFlags.HasEndDate; + } + } + } + + public override string ToString() => $"Trigger Type: {Type};\n> Start: {BeginDate}; End: {(EndYear == 0 ? "null" : EndDate?.ToString())};\n> DurMin: {MinutesDuration}; DurItv: {MinutesInterval};\n>"; + } + + #endregion + + [ComImport, Guid("148BD527-A2AB-11CE-B11F-00AA00530503"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), System.Security.SuppressUnmanagedCodeSecurity, CoClass(typeof(CTaskScheduler))] + internal interface ITaskScheduler + { + void SetTargetComputer([In, MarshalAs(UnmanagedType.LPWStr)] string Computer); + CoTaskMemString GetTargetComputer(); + [return: MarshalAs(UnmanagedType.Interface)] + IEnumWorkItems Enum(); + [return: MarshalAs(UnmanagedType.Interface)] + ITask Activate([In, MarshalAs(UnmanagedType.LPWStr)][NotNull] string Name, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid); + void Delete([In, MarshalAs(UnmanagedType.LPWStr)][NotNull] string Name); + [return: MarshalAs(UnmanagedType.Interface)] + ITask NewWorkItem([In, MarshalAs(UnmanagedType.LPWStr)][NotNull] string TaskName, [In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid); + void AddWorkItem([In, MarshalAs(UnmanagedType.LPWStr)][NotNull] string TaskName, [In, MarshalAs(UnmanagedType.Interface)] ITask WorkItem); + void IsOfType([In, MarshalAs(UnmanagedType.LPWStr)][NotNull] string TaskName, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid); + } + + [Guid("148BD528-A2AB-11CE-B11F-00AA00530503"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IEnumWorkItems + { + [PreserveSig()] + //int Next([In] uint celt, [Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 0)] out string[] rgpwszNames, [Out] out uint pceltFetched); + int Next([In] uint RequestCount, [Out] out IntPtr Names, [Out] out uint Fetched); + void Skip([In] uint Count); + void Reset(); + [return: MarshalAs(UnmanagedType.Interface)] + IEnumWorkItems Clone(); + } + +#if WorkItem + // The IScheduledWorkItem interface is actually never used because ITask inherits all of its + // methods. As ITask is the only kind of WorkItem (in 2002) it is the only interface we need. + [Guid("a6b952f0-a4b1-11d0-997d-00aa006887ec"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IScheduledWorkItem + { + void CreateTrigger([Out] out ushort NewTriggerIndex, [Out, MarshalAs(UnmanagedType.Interface)] out ITaskTrigger Trigger); + void DeleteTrigger([In] ushort TriggerIndex); + void GetTriggerCount([Out] out ushort Count); + void GetTrigger([In] ushort TriggerIndex, [Out, MarshalAs(UnmanagedType.Interface)] out ITaskTrigger Trigger); + void GetTriggerString([In] ushort TriggerIndex, out System.IntPtr TriggerString); + void GetRunTimes([In, MarshalAs(UnmanagedType.Struct)] SystemTime Begin, [In, MarshalAs(UnmanagedType.Struct)] SystemTime End, ref ushort Count, [Out] out System.IntPtr TaskTimes); + void GetNextRunTime([In, Out, MarshalAs(UnmanagedType.Struct)] ref SystemTime NextRun); + void SetIdleWait([In] ushort IdleMinutes, [In] ushort DeadlineMinutes); + void GetIdleWait([Out] out ushort IdleMinutes, [Out] out ushort DeadlineMinutes); + void Run(); + void Terminate(); + void EditWorkItem([In] uint hParent, [In] uint dwReserved); + void GetMostRecentRunTime([In, Out, MarshalAs(UnmanagedType.Struct)] ref SystemTime LastRun); + void GetStatus([Out, MarshalAs(UnmanagedType.Error)] out int Status); + void GetExitCode([Out] out uint ExitCode); + void SetComment([In, MarshalAs(UnmanagedType.LPWStr)] string Comment); + void GetComment(out System.IntPtr Comment); + void SetCreator([In, MarshalAs(UnmanagedType.LPWStr)] string Creator); + void GetCreator(out System.IntPtr Creator); + void SetWorkItemData([In] ushort DataLen, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0, ArraySubType=UnmanagedType.U1)] byte[] Data); + void GetWorkItemData([Out] out ushort DataLen, [Out] out System.IntPtr Data); + void SetErrorRetryCount([In] ushort RetryCount); + void GetErrorRetryCount([Out] out ushort RetryCount); + void SetErrorRetryInterval([In] ushort RetryInterval); + void GetErrorRetryInterval([Out] out ushort RetryInterval); + void SetFlags([In] uint Flags); + void GetFlags([Out] out uint Flags); + void SetAccountInformation([In, MarshalAs(UnmanagedType.LPWStr)] string AccountName, [In, MarshalAs(UnmanagedType.LPWStr)] string Password); + void GetAccountInformation(out System.IntPtr AccountName); + } +#endif + + [ComImport, Guid("148BD524-A2AB-11CE-B11F-00AA00530503"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), System.Security.SuppressUnmanagedCodeSecurity, CoClass(typeof(CTask))] + internal interface ITask + { + [return: MarshalAs(UnmanagedType.Interface)] + ITaskTrigger CreateTrigger([Out] out ushort NewTriggerIndex); + void DeleteTrigger([In] ushort TriggerIndex); + [return: MarshalAs(UnmanagedType.U2)] + ushort GetTriggerCount(); + [return: MarshalAs(UnmanagedType.Interface)] + ITaskTrigger GetTrigger([In] ushort TriggerIndex); + CoTaskMemString GetTriggerString([In] ushort TriggerIndex); + void GetRunTimes([In, MarshalAs(UnmanagedType.Struct)] ref NativeMethods.SYSTEMTIME Begin, [In, MarshalAs(UnmanagedType.Struct)] ref NativeMethods.SYSTEMTIME End, ref ushort Count, [In, Out] ref IntPtr TaskTimes); + [return: MarshalAs(UnmanagedType.Struct)] + NativeMethods.SYSTEMTIME GetNextRunTime(); + void SetIdleWait([In] ushort IdleMinutes, [In] ushort DeadlineMinutes); + void GetIdleWait([Out] out ushort IdleMinutes, [Out] out ushort DeadlineMinutes); + void Run(); + void Terminate(); + void EditWorkItem([In] IntPtr hParent, [In] uint dwReserved); + [return: MarshalAs(UnmanagedType.Struct)] + NativeMethods.SYSTEMTIME GetMostRecentRunTime(); + TaskStatus GetStatus(); + uint GetExitCode(); + void SetComment([In, MarshalAs(UnmanagedType.LPWStr)] string Comment); + CoTaskMemString GetComment(); + void SetCreator([In, MarshalAs(UnmanagedType.LPWStr)] string Creator); + CoTaskMemString GetCreator(); + void SetWorkItemData([In] ushort DataLen, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0, ArraySubType = UnmanagedType.U1)] byte[] Data); + void GetWorkItemData(out ushort DataLen, [Out] out IntPtr Data); + void SetErrorRetryCount([In] ushort RetryCount); + ushort GetErrorRetryCount(); + void SetErrorRetryInterval([In] ushort RetryInterval); + ushort GetErrorRetryInterval(); + void SetFlags([In] TaskFlags Flags); + TaskFlags GetFlags(); + void SetAccountInformation([In, MarshalAs(UnmanagedType.LPWStr)] string AccountName, [In] IntPtr Password); + CoTaskMemString GetAccountInformation(); + void SetApplicationName([In, MarshalAs(UnmanagedType.LPWStr)] string ApplicationName); + CoTaskMemString GetApplicationName(); + void SetParameters([In, MarshalAs(UnmanagedType.LPWStr)] string Parameters); + CoTaskMemString GetParameters(); + void SetWorkingDirectory([In, MarshalAs(UnmanagedType.LPWStr)] string WorkingDirectory); + CoTaskMemString GetWorkingDirectory(); + void SetPriority([In] uint Priority); + uint GetPriority(); + void SetTaskFlags([In] uint Flags); + uint GetTaskFlags(); + void SetMaxRunTime([In] uint MaxRunTimeMS); + uint GetMaxRunTime(); + } + + [Guid("148BD52B-A2AB-11CE-B11F-00AA00530503"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ITaskTrigger + { + void SetTrigger([In, Out, MarshalAs(UnmanagedType.Struct)] ref TaskTrigger Trigger); + [return: MarshalAs(UnmanagedType.Struct)] + TaskTrigger GetTrigger(); + CoTaskMemString GetTriggerString(); + } + + [ComImport, Guid("148BD52A-A2AB-11CE-B11F-00AA00530503"), System.Security.SuppressUnmanagedCodeSecurity, ClassInterface(ClassInterfaceType.None)] + internal class CTaskScheduler + { + } + + [ComImport, Guid("148BD520-A2AB-11CE-B11F-00AA00530503"), System.Security.SuppressUnmanagedCodeSecurity, ClassInterface(ClassInterfaceType.None)] + internal class CTask + { + } + + internal sealed class CoTaskMemString : SafeHandle + { + public CoTaskMemString() : base(IntPtr.Zero, true) { } + public CoTaskMemString(IntPtr handle) : this() { SetHandle(handle); } + public CoTaskMemString(string text) : this() { SetHandle(Marshal.StringToCoTaskMemUni(text)); } + + public static implicit operator string (CoTaskMemString cmem) => cmem.ToString(); + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() + { + Marshal.FreeCoTaskMem(handle); + return true; + } + + public override string ToString() => Marshal.PtrToStringUni(handle); + } +} \ No newline at end of file diff --git a/FlashPatcher/TaskService/V1/TaskSchedulerV1Schema.xsd b/FlashPatcher/TaskService/V1/TaskSchedulerV1Schema.xsd new file mode 100644 index 0000000..8758076 --- /dev/null +++ b/FlashPatcher/TaskService/V1/TaskSchedulerV1Schema.xsd @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlashPatcher/TaskService/V2/TaskSchedulerV2Interop.cs b/FlashPatcher/TaskService/V2/TaskSchedulerV2Interop.cs new file mode 100644 index 0000000..aab5320 --- /dev/null +++ b/FlashPatcher/TaskService/V2/TaskSchedulerV2Interop.cs @@ -0,0 +1,577 @@ +using System; +using System.Collections; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using JetBrains.Annotations; + +namespace Microsoft.Win32.TaskScheduler.V2Interop +{ + internal enum TaskEnumFlags + { + Hidden = 1 + } + +#pragma warning disable CS0618 // Type or member is obsolete + [ComImport, Guid("BAE54997-48B1-4CBE-9965-D6BE263EBEA4"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IAction + { + string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + TaskActionType Type { get; } + } + + [ComImport, Guid("02820E19-7B98-4ED2-B2E8-FDCCCEFF619B"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IActionCollection + { + int Count { get; } + IAction this[int index] { [return: MarshalAs(UnmanagedType.Interface)] get; } + [return: MarshalAs(UnmanagedType.Interface)] + IEnumerator GetEnumerator(); + string XmlText { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + [return: MarshalAs(UnmanagedType.Interface)] + IAction Create([In] TaskActionType Type); + void Remove([In, MarshalAs(UnmanagedType.Struct)][NotNull] object index); + void Clear(); + string Context { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("2A9C35DA-D357-41F4-BBC1-207AC1B1F3CB"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IBootTrigger : ITrigger + { + new TaskTriggerType Type { get; } + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + + string Delay { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("6D2FD252-75C5-4F66-90BA-2A7D8CC3039F"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IComHandlerAction : IAction + { + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new TaskActionType Type { get; } + string ClassId { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Data { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsDual), Guid("126C5CD8-B288-41D5-8DBF-E491446ADC5C"), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IDailyTrigger : ITrigger + { + new TaskTriggerType Type { get; } + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + + short DaysInterval { get; [param: In] set; } + string RandomDelay { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("10F62C64-7E16-4314-A0C2-0C3683F99D40"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IEmailAction : IAction + { + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new TaskActionType Type { get; } + + string Server { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Subject { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string To { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Cc { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Bcc { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string ReplyTo { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string From { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + ITaskNamedValueCollection HeaderFields { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + string Body { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + object[] Attachments { [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] get; [param: In, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] set; } + } + + [ComImport, Guid("D45B0167-9653-4EEF-B94F-0732CA7AF251"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IEventTrigger : ITrigger + { + new TaskTriggerType Type { get; } + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + + string Subscription { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Delay { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + ITaskNamedValueCollection ValueQueries { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + } + + [ComImport, Guid("4C3D624D-FD6B-49A3-B9B7-09CB3CD3F047"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IExecAction : IAction + { + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new TaskActionType Type { get; } + + string Path { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Arguments { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string WorkingDirectory { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("84594461-0053-4342-A8FD-088FABF11F32"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IIdleSettings + { + string IdleDuration { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string WaitTimeout { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + bool StopOnIdleEnd { get; [param: In] set; } + bool RestartOnIdle { get; [param: In] set; } + } + + [ComImport, Guid("D537D2B0-9FB3-4D34-9739-1FF5CE7B1EF3"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IIdleTrigger : ITrigger + { + new TaskTriggerType Type { get; } + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + } + + [ComImport, Guid("72DADE38-FAE4-4B3E-BAF4-5D009AF02B1C"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ILogonTrigger : ITrigger + { + new TaskTriggerType Type { get; } + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + + string Delay { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string UserId { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("77D025A3-90FA-43AA-B52E-CDA5499B946A"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IMonthlyDOWTrigger : ITrigger + { + new TaskTriggerType Type { get; } + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + + short DaysOfWeek { get; [param: In] set; } + short WeeksOfMonth { get; [param: In] set; } + short MonthsOfYear { get; [param: In] set; } + bool RunOnLastWeekOfMonth { get; [param: In] set; } + string RandomDelay { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("97C45EF1-6B02-4A1A-9C0E-1EBFBA1500AC"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IMonthlyTrigger : ITrigger + { + new TaskTriggerType Type { get; } + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + + int DaysOfMonth { get; [param: In] set; } + short MonthsOfYear { get; [param: In] set; } + bool RunOnLastDayOfMonth { get; [param: In] set; } + string RandomDelay { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("9F7DEA84-C30B-4245-80B6-00E9F646F1B4"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface INetworkSettings + { + string Name { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("D98D51E5-C9B4-496A-A9C1-18980261CF0F"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IPrincipal + { + string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string DisplayName { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string UserId { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + TaskLogonType LogonType { get; set; } + string GroupId { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + TaskRunLevel RunLevel { get; set; } + } + + [ComImport, Guid("248919AE-E345-4A6D-8AEB-E0D3165C904E"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IPrincipal2 + { + TaskProcessTokenSidType ProcessTokenSidType { get; [param: In] set; } + int RequiredPrivilegeCount { get; } + string this[int index] { [return: MarshalAs(UnmanagedType.BStr)] get; } + void AddRequiredPrivilege([In, MarshalAs(UnmanagedType.BStr)] string privilege); + } + + [ComImport, Guid("9C86F320-DEE3-4DD1-B972-A303F26B061E"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity, DefaultMember("Path")] + internal interface IRegisteredTask + { + string Name { [return: MarshalAs(UnmanagedType.BStr)] get; } + string Path { [return: MarshalAs(UnmanagedType.BStr)] get; } + TaskState State { get; } + bool Enabled { get; set; } + [return: MarshalAs(UnmanagedType.Interface)] + IRunningTask Run([In, MarshalAs(UnmanagedType.Struct)] object parameters); + [return: MarshalAs(UnmanagedType.Interface)] + IRunningTask RunEx([In, MarshalAs(UnmanagedType.Struct)] object parameters, [In] int flags, [In] int sessionID, [In, MarshalAs(UnmanagedType.BStr)] string user); + [return: MarshalAs(UnmanagedType.Interface)] + IRunningTaskCollection GetInstances(int flags); + DateTime LastRunTime { get; } + int LastTaskResult { get; } + int NumberOfMissedRuns { get; } + DateTime NextRunTime { get; } + ITaskDefinition Definition { [return: MarshalAs(UnmanagedType.Interface)] get; } + string Xml { [return: MarshalAs(UnmanagedType.BStr)] get; } + [return: MarshalAs(UnmanagedType.BStr)] + string GetSecurityDescriptor(int securityInformation); + void SetSecurityDescriptor([In, MarshalAs(UnmanagedType.BStr)] string sddl, [In] int flags); + void Stop(int flags); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x60020011)] + void GetRunTimes([In] ref Microsoft.Win32.NativeMethods.SYSTEMTIME pstStart, [In] ref Microsoft.Win32.NativeMethods.SYSTEMTIME pstEnd, [In, Out] ref uint pCount, [In, Out] ref IntPtr pRunTimes); + } + + [ComImport, Guid("86627EB4-42A7-41E4-A4D9-AC33A72F2D52"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IRegisteredTaskCollection + { + int Count { get; } + IRegisteredTask this[object index] { [return: MarshalAs(UnmanagedType.Interface)] get; } + [return: MarshalAs(UnmanagedType.Interface)] + IEnumerator GetEnumerator(); + } + + [ComImport, Guid("416D8B73-CB41-4EA1-805C-9BE9A5AC4A74"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IRegistrationInfo + { + string Description { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Author { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Version { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Date { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Documentation { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string XmlText { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string URI { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + object SecurityDescriptor { [return: MarshalAs(UnmanagedType.Struct)] get; [param: In, MarshalAs(UnmanagedType.Struct)] set; } + string Source { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("4C8FEC3A-C218-4E0C-B23D-629024DB91A2"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IRegistrationTrigger : ITrigger + { + new TaskTriggerType Type { get; } + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + + string Delay { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("7FB9ACF1-26BE-400E-85B5-294B9C75DFD6"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IRepetitionPattern + { + string Interval { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Duration { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + bool StopAtDurationEnd { get; [param: In] set; } + } + + [ComImport, Guid("653758FB-7B9A-4F1E-A471-BEEB8E9B834E"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity, DefaultMember("InstanceGuid")] + internal interface IRunningTask + { + string Name { [return: MarshalAs(UnmanagedType.BStr)] get; } + string InstanceGuid { [return: MarshalAs(UnmanagedType.BStr)] get; } + string Path { [return: MarshalAs(UnmanagedType.BStr)] get; } + TaskState State { get; } + string CurrentAction { [return: MarshalAs(UnmanagedType.BStr)] get; } + void Stop(); + void Refresh(); + uint EnginePID { get; } + } + + [ComImport, Guid("6A67614B-6828-4FEC-AA54-6D52E8F1F2DB"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IRunningTaskCollection + { + int Count { get; } + IRunningTask this[object index] { [return: MarshalAs(UnmanagedType.Interface)] get; } + [return: MarshalAs(UnmanagedType.Interface)] + IEnumerator GetEnumerator(); + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsDual), Guid("754DA71B-4385-4475-9DD9-598294FA3641"), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ISessionStateChangeTrigger : ITrigger + { + new TaskTriggerType Type { get; } + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + + string Delay { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string UserId { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + TaskSessionStateChangeType StateChange { get; [param: In] set; } + } + + [ComImport, Guid("505E9E68-AF89-46B8-A30F-56162A83D537"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IShowMessageAction : IAction + { + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new TaskActionType Type { get; } + + string Title { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string MessageBody { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("F5BC8FC5-536D-4F77-B852-FBC1356FDEB6"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ITaskDefinition + { + IRegistrationInfo RegistrationInfo { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + ITriggerCollection Triggers { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + ITaskSettings Settings { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + string Data { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + IPrincipal Principal { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + IActionCollection Actions { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + string XmlText { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("8CFAC062-A080-4C15-9A88-AA7C2AF80DFC"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity, DefaultMember("Path")] + internal interface ITaskFolder + { + string Name { [return: MarshalAs(UnmanagedType.BStr)] get; } + string Path { [return: MarshalAs(UnmanagedType.BStr)] get; } + [return: MarshalAs(UnmanagedType.Interface)] + ITaskFolder GetFolder([MarshalAs(UnmanagedType.BStr)] string Path); + [return: MarshalAs(UnmanagedType.Interface)] + ITaskFolderCollection GetFolders(int flags); + [return: MarshalAs(UnmanagedType.Interface)] + ITaskFolder CreateFolder([In, MarshalAs(UnmanagedType.BStr)] string subFolderName, [In, Optional, MarshalAs(UnmanagedType.Struct)] object sddl); + void DeleteFolder([MarshalAs(UnmanagedType.BStr)] string subFolderName, [In] int flags); + [return: MarshalAs(UnmanagedType.Interface)] + IRegisteredTask GetTask([MarshalAs(UnmanagedType.BStr)][NotNull] string Path); + [return: MarshalAs(UnmanagedType.Interface)] + IRegisteredTaskCollection GetTasks(int flags); + void DeleteTask([In, MarshalAs(UnmanagedType.BStr)][NotNull] string Name, [In] int flags); + [return: MarshalAs(UnmanagedType.Interface)] + IRegisteredTask RegisterTask([In, MarshalAs(UnmanagedType.BStr)][NotNull] string Path, [In, MarshalAs(UnmanagedType.BStr)][NotNull] string XmlText, [In] int flags, [In, MarshalAs(UnmanagedType.Struct)] object UserId, [In, MarshalAs(UnmanagedType.Struct)] object password, [In] TaskLogonType LogonType, [In, Optional, MarshalAs(UnmanagedType.Struct)] object sddl); + [return: MarshalAs(UnmanagedType.Interface)] + IRegisteredTask RegisterTaskDefinition([In, MarshalAs(UnmanagedType.BStr)][NotNull] string Path, [In, MarshalAs(UnmanagedType.Interface)][NotNull] ITaskDefinition pDefinition, [In] int flags, [In, MarshalAs(UnmanagedType.Struct)] object UserId, [In, MarshalAs(UnmanagedType.Struct)] object password, [In] TaskLogonType LogonType, [In, Optional, MarshalAs(UnmanagedType.Struct)] object sddl); + [return: MarshalAs(UnmanagedType.BStr)] + string GetSecurityDescriptor(int securityInformation); + void SetSecurityDescriptor([In, MarshalAs(UnmanagedType.BStr)] string sddl, [In] int flags); + } + + [ComImport, Guid("79184A66-8664-423F-97F1-637356A5D812"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ITaskFolderCollection + { + int Count { get; } + ITaskFolder this[object index] { [return: MarshalAs(UnmanagedType.Interface)] get; } + [return: MarshalAs(UnmanagedType.Interface)] + IEnumerator GetEnumerator(); + } + + [ComImport, Guid("B4EF826B-63C3-46E4-A504-EF69E4F7EA4D"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ITaskNamedValueCollection + { + int Count { get; } + ITaskNamedValuePair this[int index] { [return: MarshalAs(UnmanagedType.Interface)] get; } + [return: MarshalAs(UnmanagedType.Interface)] + IEnumerator GetEnumerator(); + [return: MarshalAs(UnmanagedType.Interface)] + ITaskNamedValuePair Create([In, MarshalAs(UnmanagedType.BStr)][NotNull] string Name, [In, MarshalAs(UnmanagedType.BStr)] string Value); + void Remove([In] int index); + void Clear(); + } + + [ComImport, Guid("39038068-2B46-4AFD-8662-7BB6F868D221"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity, DefaultMember("Name")] + internal interface ITaskNamedValuePair + { + string Name { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string Value { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, DefaultMember("TargetServer"), Guid("2FABA4C7-4DA9-4013-9697-20CC3FD40F85"), System.Security.SuppressUnmanagedCodeSecurity, CoClass(typeof(TaskSchedulerClass))] + internal interface ITaskService + { + [return: MarshalAs(UnmanagedType.Interface)] + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(1)] + ITaskFolder GetFolder([In, MarshalAs(UnmanagedType.BStr)][NotNull] string Path); + [return: MarshalAs(UnmanagedType.Interface)] + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(2)] + IRunningTaskCollection GetRunningTasks(int flags); + [return: MarshalAs(UnmanagedType.Interface)] + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(3)] + ITaskDefinition NewTask([In] uint flags); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(4)] + void Connect([In, Optional, MarshalAs(UnmanagedType.Struct)] object serverName, [In, Optional, MarshalAs(UnmanagedType.Struct)] object user, [In, Optional, MarshalAs(UnmanagedType.Struct)] object domain, [In, Optional, MarshalAs(UnmanagedType.Struct)] object password); + [DispId(5)] + bool Connected { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(5)] get; } + [DispId(0)] + string TargetServer { [return: MarshalAs(UnmanagedType.BStr)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0)] get; } + [DispId(6)] + string ConnectedUser { [return: MarshalAs(UnmanagedType.BStr)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(6)] get; } + [DispId(7)] + string ConnectedDomain { [return: MarshalAs(UnmanagedType.BStr)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(7)] get; } + [DispId(8)] + uint HighestVersion { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(8)] get; } + } + + [ComImport, DefaultMember("TargetServer"), Guid("0F87369F-A4E5-4CFC-BD3E-73E6154572DD"), ClassInterface((short)0), System.Security.SuppressUnmanagedCodeSecurity] + internal class TaskSchedulerClass + { + } + + [ComImport, Guid("8FD4711D-2D02-4C8C-87E3-EFF699DE127E"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ITaskSettings + { + bool AllowDemandStart { get; [param: In] set; } + string RestartInterval { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + int RestartCount { get; [param: In] set; } + TaskInstancesPolicy MultipleInstances { get; [param: In] set; } + bool StopIfGoingOnBatteries { get; [param: In] set; } + bool DisallowStartIfOnBatteries { get; [param: In] set; } + bool AllowHardTerminate { get; [param: In] set; } + bool StartWhenAvailable { get; [param: In] set; } + string XmlText { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + bool RunOnlyIfNetworkAvailable { get; [param: In] set; } + string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + bool Enabled { get; [param: In] set; } + string DeleteExpiredTaskAfter { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + int Priority { get; [param: In] set; } + TaskCompatibility Compatibility { get; [param: In] set; } + bool Hidden { get; [param: In] set; } + IIdleSettings IdleSettings { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + bool RunOnlyIfIdle { get; [param: In] set; } + bool WakeToRun { get; [param: In] set; } + INetworkSettings NetworkSettings { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + } + + [ComImport, Guid("2C05C3F0-6EED-4c05-A15F-ED7D7A98A369"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ITaskSettings2 + { + bool DisallowStartOnRemoteAppSession { get; [param: In] set; } + bool UseUnifiedSchedulingEngine { get; [param: In] set; } + } + + [ComImport, Guid("0AD9D0D7-0C7F-4EBB-9A5F-D1C648DCA528"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ITaskSettings3 : ITaskSettings + { + new bool AllowDemandStart { get; [param: In] set; } + new string RestartInterval { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new int RestartCount { get; [param: In] set; } + new TaskInstancesPolicy MultipleInstances { get; [param: In] set; } + new bool StopIfGoingOnBatteries { get; [param: In] set; } + new bool DisallowStartIfOnBatteries { get; [param: In] set; } + new bool AllowHardTerminate { get; [param: In] set; } + new bool StartWhenAvailable { get; [param: In] set; } + new string XmlText { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool RunOnlyIfNetworkAvailable { get; [param: In] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + new string DeleteExpiredTaskAfter { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new int Priority { get; [param: In] set; } + new TaskCompatibility Compatibility { get; [param: In] set; } + new bool Hidden { get; [param: In] set; } + new IIdleSettings IdleSettings { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new bool RunOnlyIfIdle { get; [param: In] set; } + new bool WakeToRun { get; [param: In] set; } + new INetworkSettings NetworkSettings { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + + bool DisallowStartOnRemoteAppSession { get; [param: In] set; } + bool UseUnifiedSchedulingEngine { get; [param: In] set; } + IMaintenanceSettings MaintenanceSettings { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + [return: MarshalAs(UnmanagedType.Interface)] + IMaintenanceSettings CreateMaintenanceSettings(); + bool Volatile { get; [param: In] set; } + } + + [ComImport, Guid("A6024FA8-9652-4ADB-A6BF-5CFCD877A7BA"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IMaintenanceSettings + { + string Period { [param: In, MarshalAs(UnmanagedType.BStr)] set; [return: MarshalAs(UnmanagedType.BStr)] get; } + string Deadline { [param: In, MarshalAs(UnmanagedType.BStr)] set; [return: MarshalAs(UnmanagedType.BStr)] get; } + bool Exclusive { [param: In] set; get; } + } + + [ComImport, Guid("3E4C9351-D966-4B8B-BB87-CEBA68BB0107"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ITaskVariables + { + [return: MarshalAs(UnmanagedType.BStr)] + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + string GetInput(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetOutput([In, MarshalAs(UnmanagedType.BStr)] string input); + [return: MarshalAs(UnmanagedType.BStr)] + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + string GetContext(); + } + + [ComImport, Guid("B45747E0-EBA7-4276-9F29-85C5BB300006"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ITimeTrigger : ITrigger + { + new TaskTriggerType Type { get; } + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + + string RandomDelay { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } + + [ComImport, Guid("09941815-EA89-4B5B-89E0-2A773801FAC3"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ITrigger + { + TaskTriggerType Type { get; } + string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + bool Enabled { get; [param: In] set; } + } + + [ComImport, Guid("85DF5081-1B24-4F32-878A-D9D14DF4CB77"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface ITriggerCollection + { + int Count { get; } + ITrigger this[int index] { [return: MarshalAs(UnmanagedType.Interface)] get; } + [return: MarshalAs(UnmanagedType.Interface)] + IEnumerator GetEnumerator(); + [return: MarshalAs(UnmanagedType.Interface)] + ITrigger Create([In] TaskTriggerType Type); + void Remove([In, MarshalAs(UnmanagedType.Struct)] object index); + void Clear(); + } + + [ComImport, Guid("5038FC98-82FF-436D-8728-A512A57C9DC1"), InterfaceType(ComInterfaceType.InterfaceIsDual), System.Security.SuppressUnmanagedCodeSecurity] + internal interface IWeeklyTrigger : ITrigger + { + new TaskTriggerType Type { get; } + new string Id { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new IRepetitionPattern Repetition { [return: MarshalAs(UnmanagedType.Interface)] get; [param: In, MarshalAs(UnmanagedType.Interface)] set; } + new string ExecutionTimeLimit { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string StartBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new string EndBoundary { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + new bool Enabled { get; [param: In] set; } + + short DaysOfWeek { get; [param: In] set; } + short WeeksInterval { get; [param: In] set; } + string RandomDelay { [return: MarshalAs(UnmanagedType.BStr)] get; [param: In, MarshalAs(UnmanagedType.BStr)] set; } + } +} + diff --git a/FlashPatcher/TaskService/V2/TaskSchedulerV2Schema.xsd b/FlashPatcher/TaskService/V2/TaskSchedulerV2Schema.xsd new file mode 100644 index 0000000..624324b --- /dev/null +++ b/FlashPatcher/TaskService/V2/TaskSchedulerV2Schema.xsd @@ -0,0 +1,691 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlashPatcher/TaskService/Wildcard.cs b/FlashPatcher/TaskService/Wildcard.cs new file mode 100644 index 0000000..f349cbf --- /dev/null +++ b/FlashPatcher/TaskService/Wildcard.cs @@ -0,0 +1,37 @@ +using System.Text.RegularExpressions; +using JetBrains.Annotations; + +namespace Microsoft.Win32.TaskScheduler +{ + /// + /// Represents a wildcard running on the + /// engine. + /// + public class Wildcard : Regex + { + /// + /// Initializes a wildcard with the given search pattern and options. + /// + /// The wildcard pattern to match. + /// A combination of one or more . + public Wildcard([NotNull] string pattern, RegexOptions options = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace) + : base(WildcardToRegex(pattern), options) + { + } + + /// + /// Converts a wildcard to a regular expression. + /// + /// The wildcard pattern to convert. + /// A regular expression equivalent of the given wildcard. + public static string WildcardToRegex([NotNull] string pattern) + { + string s = Regex.Escape(pattern); + s = Regex.Replace(s, @"(? 0) + { + var defaultAttr = (DefaultValueAttribute)attributes[0]; + return defaultAttr.Value; + } + + // Attribute not found, fall back to default value for the type + if (prop.PropertyType.IsValueType) + return Activator.CreateInstance(prop.PropertyType); + return null; + } + + private static bool GetPropertyValue(object obj, [NotNull] string property, ref object outVal) + { + PropertyInfo pi = obj?.GetType().GetProperty(property); + if (pi != null) + { + outVal = pi.GetValue(obj, null); + return true; + } + return false; + } + + private static bool GetAttributeValue(Type objType, Type attrType, string property, bool inherit, ref object outVal) + { + object[] attrs = objType.GetCustomAttributes(attrType, inherit); + if (attrs.Length > 0) + return GetPropertyValue(attrs[0], property, ref outVal); + return false; + } + + private static bool GetAttributeValue([NotNull] PropertyInfo propInfo, Type attrType, string property, bool inherit, ref object outVal) + { + Attribute attr = Attribute.GetCustomAttribute(propInfo, attrType, inherit); + return GetPropertyValue(attr, property, ref outVal); + } + + private static bool IsStandardType(Type type) => type.IsPrimitive || type == typeof(DateTime) || type == typeof(DateTimeOffset) || type == typeof(Decimal) || type == typeof(Guid) || type == typeof(TimeSpan) || type == typeof(string) || type.IsEnum; + + private static bool HasMembers([NotNull] object obj) + { + if (obj is IXmlSerializable) + { + using (System.IO.MemoryStream mem = new System.IO.MemoryStream()) + { + using (XmlTextWriter tw = new XmlTextWriter(mem, Encoding.UTF8)) + { + ((IXmlSerializable)obj).WriteXml(tw); + tw.Flush(); + return mem.Length > 3; + } + } + } + + // Enumerate each public property + PropertyInfo[] props = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); + foreach (var pi in props) + { + if (!Attribute.IsDefined(pi, typeof(XmlIgnoreAttribute), false)) + { + object value = pi.GetValue(obj, null); + if (!Equals(value, GetDefaultValue(pi))) + { + if (!IsStandardType(pi.PropertyType)) + { + if (HasMembers(value)) + return true; + } + else + return true; + } + } + } + return false; + } + + public static string GetPropertyAttributeName([NotNull] PropertyInfo pi) + { + object oVal = null; + string eName = pi.Name; + if (GetAttributeValue(pi, typeof(XmlAttributeAttribute), "AttributeName", false, ref oVal)) + eName = oVal.ToString(); + return eName; + } + + public static string GetPropertyElementName([NotNull] PropertyInfo pi) + { + object oVal = null; + string eName = pi.Name; + if (GetAttributeValue(pi, typeof(XmlElementAttribute), "ElementName", false, ref oVal)) + eName = oVal.ToString(); + else if (GetAttributeValue(pi.PropertyType, typeof(XmlRootAttribute), "ElementName", true, ref oVal)) + eName = oVal.ToString(); + return eName; + } + + public delegate bool PropertyConversionHandler([NotNull] PropertyInfo pi, Object obj, ref Object value); + + public static bool WriteProperty([NotNull] XmlWriter writer, [NotNull] PropertyInfo pi, [NotNull] Object obj, PropertyConversionHandler handler = null) + { + if (Attribute.IsDefined(pi, typeof(XmlIgnoreAttribute), false) || Attribute.IsDefined(pi, typeof(XmlAttributeAttribute), false)) + return false; + + object value = pi.GetValue(obj, null); + object defValue = GetDefaultValue(pi); + if ((value == null && defValue == null) || (value != null && value.Equals(defValue))) + return false; + + Type propType = pi.PropertyType; + if (handler != null && handler(pi, obj, ref value)) + propType = value.GetType(); + + bool isStdType = IsStandardType(propType); + bool rw = pi.CanRead && pi.CanWrite; + bool ro = pi.CanRead && !pi.CanWrite; + string eName = GetPropertyElementName(pi); + if (isStdType && rw) + { + string output = GetXmlValue(value, propType); + if (output != null) + writer.WriteElementString(eName, output); + } + else if (!isStdType) + { + object outVal = null; + if (propType.GetInterface("IXmlSerializable") == null && GetAttributeValue(pi, typeof(XmlArrayAttribute), "ElementName", true, ref outVal) && propType.GetInterface("IEnumerable") != null) + { + if (string.IsNullOrEmpty(outVal.ToString())) outVal = eName; + writer.WriteStartElement(outVal.ToString()); + var attributes = Attribute.GetCustomAttributes(pi, typeof(XmlArrayItemAttribute), true); + var dict = new Dictionary(attributes.Length); + foreach (XmlArrayItemAttribute a in attributes) + dict.Add(a.Type, a.ElementName); + foreach (object item in ((System.Collections.IEnumerable)value)) + { + string aeName; + Type itemType = item.GetType(); + if (dict.TryGetValue(itemType, out aeName)) + { + if (IsStandardType(itemType)) + writer.WriteElementString(aeName, GetXmlValue(item, itemType)); + else + WriteObject(writer, item, null, false, aeName); + } + } + writer.WriteEndElement(); + } + else + WriteObject(writer, value); + } + return false; + } + + private static string GetXmlValue([NotNull] object value, Type propType) + { + string output = null; + if (propType.IsEnum) + { + if (Attribute.IsDefined(propType, typeof(FlagsAttribute), false)) + output = Convert.ChangeType(value, Enum.GetUnderlyingType(propType)).ToString(); + else + output = value.ToString(); + } + else + { + switch (propType.FullName) + { + case "System.Boolean": + output = XmlConvert.ToString((System.Boolean)value); + break; + case "System.Byte": + output = XmlConvert.ToString((System.Byte)value); + break; + case "System.Char": + output = XmlConvert.ToString((System.Char)value); + break; + case "System.DateTime": + output = XmlConvert.ToString((System.DateTime)value, XmlDateTimeSerializationMode.RoundtripKind); + break; + case "System.DateTimeOffset": + output = XmlConvert.ToString((System.DateTimeOffset)value); + break; + case "System.Decimal": + output = XmlConvert.ToString((System.Decimal)value); + break; + case "System.Double": + output = XmlConvert.ToString((System.Double)value); + break; + case "System.Single": + output = XmlConvert.ToString((System.Single)value); + break; + case "System.Guid": + output = XmlConvert.ToString((System.Guid)value); + break; + case "System.Int16": + output = XmlConvert.ToString((System.Int16)value); + break; + case "System.Int32": + output = XmlConvert.ToString((System.Int32)value); + break; + case "System.Int64": + output = XmlConvert.ToString((System.Int64)value); + break; + case "System.SByte": + output = XmlConvert.ToString((System.SByte)value); + break; + case "System.TimeSpan": + output = XmlConvert.ToString((System.TimeSpan)value); + break; + case "System.UInt16": + output = XmlConvert.ToString((System.UInt16)value); + break; + case "System.UInt32": + output = XmlConvert.ToString((System.UInt32)value); + break; + case "System.UInt64": + output = XmlConvert.ToString((System.UInt64)value); + break; + default: + output = value == null ? string.Empty : value.ToString(); + break; + } + } + + return output; + } + + public static void WriteObjectAttributes([NotNull] XmlWriter writer, [NotNull] object obj, PropertyConversionHandler handler = null) + { + // Enumerate each property + foreach (var pi in obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) + if (Attribute.IsDefined(pi, typeof(XmlAttributeAttribute), false)) + WriteObjectAttribute(writer, pi, obj, handler); + } + + public static void WriteObjectAttribute([NotNull] XmlWriter writer, [NotNull] PropertyInfo pi, [NotNull] object obj, PropertyConversionHandler handler = null) + { + object value = pi.GetValue(obj, null); + object defValue = GetDefaultValue(pi); + if ((value == null && defValue == null) || (value != null && value.Equals(defValue))) + return; + + Type propType = pi.PropertyType; + if (handler != null && handler(pi, obj, ref value)) + propType = value.GetType(); + + writer.WriteAttributeString(GetPropertyAttributeName(pi), GetXmlValue(value, propType)); + } + + public static void WriteObjectProperties([NotNull] XmlWriter writer, [NotNull] object obj, PropertyConversionHandler handler = null) + { + // Enumerate each public property + foreach (var pi in obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) + WriteProperty(writer, pi, obj, handler); + } + + public static void WriteObject([NotNull] XmlWriter writer, [NotNull] object obj, PropertyConversionHandler handler = null, bool includeNS = false, string elemName = null) + { + if (obj == null) + return; + + // Get name of top level element + string oName = elemName ?? GetElementName(obj); + + if (!HasMembers(obj)) + return; + + if (includeNS) + writer.WriteStartElement(oName, GetTopLevelNamespace(obj)); + else + writer.WriteStartElement(oName); + + if (obj is IXmlSerializable) + { + ((IXmlSerializable)obj).WriteXml(writer); + } + else + { + WriteObjectAttributes(writer, obj, handler); + WriteObjectProperties(writer, obj, handler); + } + + writer.WriteEndElement(); + } + + public static string GetElementName([NotNull] object obj) + { + object oVal = null; + return GetAttributeValue(obj.GetType(), typeof(XmlRootAttribute), "ElementName", true, ref oVal) ? oVal.ToString() : obj.GetType().Name; + } + + public static string GetTopLevelNamespace([NotNull] object obj) + { + object oVal = null; + return GetAttributeValue(obj.GetType(), typeof(XmlRootAttribute), "Namespace", true, ref oVal) ? oVal.ToString() : null; + } + + public static void ReadObjectProperties([NotNull] XmlReader reader, [NotNull] object obj, PropertyConversionHandler handler = null) + { + // Build property lookup table + PropertyInfo[] props = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); + Dictionary attrHash = new Dictionary(props.Length); + Dictionary propHash = new Dictionary(props.Length); + foreach (var pi in props) + { + if (!Attribute.IsDefined(pi, typeof(XmlIgnoreAttribute), false)) + { + if (Attribute.IsDefined(pi, typeof(XmlAttributeAttribute), false)) + attrHash.Add(GetPropertyAttributeName(pi), pi); + else + propHash.Add(GetPropertyElementName(pi), pi); + } + } + + if (reader.HasAttributes) + { + for (int i = 0; i < reader.AttributeCount; i++) + { + PropertyInfo pi; + reader.MoveToAttribute(i); + if (attrHash.TryGetValue(reader.LocalName, out pi)) + { + if (IsStandardType(pi.PropertyType)) + { + object value = null; + if (pi.PropertyType.IsEnum) + value = Enum.Parse(pi.PropertyType, reader.Value); + else + value = Convert.ChangeType(reader.Value, pi.PropertyType); + + if (handler != null) + handler(pi, obj, ref value); + + pi.SetValue(obj, value, null); + } + } + } + } + + while (reader.MoveToContent() == XmlNodeType.Element) + { + PropertyInfo pi; + object outVal = null; + if (propHash.TryGetValue(reader.LocalName, out pi)) + { + var tc = TypeDescriptor.GetConverter(pi.PropertyType); + if (IsStandardType(pi.PropertyType)) + { + object value = null; + if (pi.PropertyType.IsEnum) + value = Enum.Parse(pi.PropertyType, reader.ReadElementContentAsString()); + else if (pi.PropertyType == typeof(Guid)) + value = new GuidConverter().ConvertFromString(reader.ReadElementContentAsString()); + else + value = reader.ReadElementContentAs(pi.PropertyType, null); + + if (handler != null) + handler(pi, obj, ref value); + + pi.SetValue(obj, value, null); + } + else if (pi.PropertyType == typeof(Version)) + { + Version v = new Version(reader.ReadElementContentAsString()); + pi.SetValue(obj, v, null); + } + else if (pi.PropertyType.GetInterface("IEnumerable") != null && pi.PropertyType.GetInterface("IXmlSerializable") == null && GetAttributeValue(pi, typeof(XmlArrayAttribute), "ElementName", true, ref outVal)) + { + string elem = string.IsNullOrEmpty(outVal?.ToString()) ? pi.Name : outVal.ToString(); + reader.ReadStartElement(elem); + var attributes = Attribute.GetCustomAttributes(pi, typeof(XmlArrayItemAttribute), true); + var dict = new Dictionary(attributes.Length); + foreach (XmlArrayItemAttribute a in attributes) + dict.Add(a.ElementName, a.Type); + List output = new List(); + while (reader.MoveToContent() == XmlNodeType.Element) + { + Type itemType; + if (dict.TryGetValue(reader.LocalName, out itemType)) + { + object o; + if (IsStandardType(itemType)) + o = reader.ReadElementContentAs(itemType, null); + else + { + o = Activator.CreateInstance(itemType); + ReadObject(reader, o, handler); + } + if (o != null) + output.Add(o); + } + } + reader.ReadEndElement(); + if (output.Count > 0) + { + System.Collections.IEnumerable par = output; + Type et = typeof(object); + if (dict.Count == 1) + { + foreach (var v in dict.Values) { et = v; break; } + } + /*else + { + Type t1 = output[0].GetType(); + bool same = true; + foreach (var item in output) + if (item.GetType() != t1) { same = false; break; } + if (same) + et = t1; + } + if (et != typeof(object)) + { + Array ao = Array.CreateInstance(et, output.Count); + for (int i = 0; i < output.Count; i++) + ao.SetValue(output[i], i); + par = ao; + } + else + par = output.ToArray();*/ + bool done = false; + if (pi.PropertyType == par.GetType() || (pi.PropertyType.IsArray && (pi.PropertyType.GetElementType() == typeof(object) || pi.PropertyType.GetElementType() == et))) + try { pi.SetValue(obj, par, null); done = true; } catch { } + if (!done) + { + var mi = pi.PropertyType.GetMethod("AddRange", new Type[] { typeof(System.Collections.IEnumerable) }); + if (mi != null) + try { mi.Invoke(pi.GetValue(obj, null), new object[] { par }); done = true; } catch { } + } + if (!done) + { + var mi = pi.PropertyType.GetMethod("Add", new Type[] { typeof(object) }); + if (mi != null) + try { foreach (var i in par) mi.Invoke(pi.GetValue(obj, null), new object[] { i }); done = true; } catch { } + } + if (!done && et != typeof(Object)) + { + var mi = pi.PropertyType.GetMethod("Add", new Type[] { et }); + if (mi != null) + try { foreach (var i in par) mi.Invoke(pi.GetValue(obj, null), new object[] { i }); done = true; } catch { } + } + // Throw error if not done + } + } + else + { + object inst = pi.GetValue(obj, null) ?? Activator.CreateInstance(pi.PropertyType); + if (inst == null) + throw new InvalidOperationException($"Can't get instance of {pi.PropertyType.Name}."); + ReadObject(reader, inst, handler); + } + } + else + { + reader.Skip(); + reader.MoveToContent(); + } + } + } + + public static void ReadObject([NotNull] XmlReader reader, [NotNull] object obj, PropertyConversionHandler handler = null) + { + if (obj == null) + throw new ArgumentNullException(nameof(obj)); + + reader.MoveToContent(); + + if (obj is IXmlSerializable) + { + ((IXmlSerializable)obj).ReadXml(reader); + } + else + { + object oVal = null; + string oName = GetAttributeValue(obj.GetType(), typeof(XmlRootAttribute), "ElementName", true, ref oVal) ? oVal.ToString() : obj.GetType().Name; + if (reader.LocalName != oName) + throw new XmlException("XML element name does not match object."); + + if (!reader.IsEmptyElement) + { + reader.ReadStartElement(); + reader.MoveToContent(); + ReadObjectProperties(reader, obj, handler); + reader.ReadEndElement(); + } + else + reader.Skip(); + } + } + + public static void ReadObjectFromXmlText([NotNull] string xml, [NotNull] object obj, PropertyConversionHandler handler = null) + { + using (System.IO.StringReader sr = new System.IO.StringReader(xml)) + { + using (XmlReader reader = XmlReader.Create(sr)) + { + reader.MoveToContent(); + ReadObject(reader, obj, handler); + } + } + } + + public static string WriteObjectToXmlText([NotNull] object obj, PropertyConversionHandler handler = null) + { + StringBuilder sb = new StringBuilder(); + using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { Indent = true })) + WriteObject(writer, obj, handler, true); + return sb.ToString(); + } + } +} diff --git a/FlashPatcher/bin/Release/Flash Patcher.exe b/FlashPatcher/bin/Release/Flash Patcher.exe deleted file mode 100644 index 6218554..0000000 Binary files a/FlashPatcher/bin/Release/Flash Patcher.exe and /dev/null differ diff --git a/FlashPatcher/bin/Release/Flash Patcher.exe.config b/FlashPatcher/bin/Release/Flash Patcher.exe.config deleted file mode 100644 index 92c094c..0000000 --- a/FlashPatcher/bin/Release/Flash Patcher.exe.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/FlashPatcher/bin/Release/Flash Patcher.pdb b/FlashPatcher/bin/Release/Flash Patcher.pdb deleted file mode 100644 index a49b037..0000000 Binary files a/FlashPatcher/bin/Release/Flash Patcher.pdb and /dev/null differ diff --git a/FlashPatcher/obj/Debug/.NETFramework,Version=v4.8.AssemblyAttributes.cs b/FlashPatcher/obj/Debug/.NETFramework,Version=v4.8.AssemblyAttributes.cs deleted file mode 100644 index 15efebf..0000000 --- a/FlashPatcher/obj/Debug/.NETFramework,Version=v4.8.AssemblyAttributes.cs +++ /dev/null @@ -1,4 +0,0 @@ -// -using System; -using System.Reflection; -[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] diff --git a/FlashPatcher/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/FlashPatcher/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache deleted file mode 100644 index a754cbc..0000000 Binary files a/FlashPatcher/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache and /dev/null differ diff --git a/FlashPatcher/obj/Debug/FlashPatcher.csprojAssemblyReference.cache b/FlashPatcher/obj/Debug/FlashPatcher.csprojAssemblyReference.cache deleted file mode 100644 index ce3216a..0000000 Binary files a/FlashPatcher/obj/Debug/FlashPatcher.csprojAssemblyReference.cache and /dev/null differ diff --git a/FlashPatcher/obj/Release/.NETFramework,Version=v4.8.AssemblyAttributes.cs b/FlashPatcher/obj/Release/.NETFramework,Version=v4.8.AssemblyAttributes.cs deleted file mode 100644 index 15efebf..0000000 --- a/FlashPatcher/obj/Release/.NETFramework,Version=v4.8.AssemblyAttributes.cs +++ /dev/null @@ -1,4 +0,0 @@ -// -using System; -using System.Reflection; -[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] diff --git a/FlashPatcher/obj/Release/DesignTimeResolveAssemblyReferences.cache b/FlashPatcher/obj/Release/DesignTimeResolveAssemblyReferences.cache deleted file mode 100644 index 4bec350..0000000 Binary files a/FlashPatcher/obj/Release/DesignTimeResolveAssemblyReferences.cache and /dev/null differ diff --git a/FlashPatcher/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache b/FlashPatcher/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache deleted file mode 100644 index a3b4399..0000000 Binary files a/FlashPatcher/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache and /dev/null differ diff --git a/FlashPatcher/obj/Release/Flash Patcher.exe b/FlashPatcher/obj/Release/Flash Patcher.exe deleted file mode 100644 index 6218554..0000000 Binary files a/FlashPatcher/obj/Release/Flash Patcher.exe and /dev/null differ diff --git a/FlashPatcher/obj/Release/Flash Patcher.pdb b/FlashPatcher/obj/Release/Flash Patcher.pdb deleted file mode 100644 index a49b037..0000000 Binary files a/FlashPatcher/obj/Release/Flash Patcher.pdb and /dev/null differ diff --git a/FlashPatcher/obj/Release/FlashPatcher.FlashPatcherForm.resources b/FlashPatcher/obj/Release/FlashPatcher.FlashPatcherForm.resources deleted file mode 100644 index f7849ec..0000000 Binary files a/FlashPatcher/obj/Release/FlashPatcher.FlashPatcherForm.resources and /dev/null differ diff --git a/FlashPatcher/obj/Release/FlashPatcher.Properties.Resources.resources b/FlashPatcher/obj/Release/FlashPatcher.Properties.Resources.resources deleted file mode 100644 index 6c05a97..0000000 Binary files a/FlashPatcher/obj/Release/FlashPatcher.Properties.Resources.resources and /dev/null differ diff --git a/FlashPatcher/obj/Release/FlashPatcher.csproj.CoreCompileInputs.cache b/FlashPatcher/obj/Release/FlashPatcher.csproj.CoreCompileInputs.cache deleted file mode 100644 index df3e7b7..0000000 --- a/FlashPatcher/obj/Release/FlashPatcher.csproj.CoreCompileInputs.cache +++ /dev/null @@ -1 +0,0 @@ -26d71f5f180327a37d2c65ba8cf4401c2e6c1582 diff --git a/FlashPatcher/obj/Release/FlashPatcher.csproj.FileListAbsolute.txt b/FlashPatcher/obj/Release/FlashPatcher.csproj.FileListAbsolute.txt deleted file mode 100644 index 5332e56..0000000 --- a/FlashPatcher/obj/Release/FlashPatcher.csproj.FileListAbsolute.txt +++ /dev/null @@ -1,9 +0,0 @@ -C:\Users\User\Documents\FlashPatcher-1.6\FlashPatcher\obj\Release\FlashPatcher.FlashPatcherForm.resources -C:\Users\User\Documents\FlashPatcher-1.6\FlashPatcher\obj\Release\FlashPatcher.Properties.Resources.resources -C:\Users\User\Documents\FlashPatcher-1.6\FlashPatcher\obj\Release\FlashPatcher.csproj.GenerateResource.cache -C:\Users\User\Documents\FlashPatcher-1.6\FlashPatcher\obj\Release\FlashPatcher.csproj.CoreCompileInputs.cache -C:\Users\User\Documents\FlashPatcher-1.6\FlashPatcher\obj\Release\Flash Patcher.exe -C:\Users\User\Documents\FlashPatcher-1.6\FlashPatcher\obj\Release\Flash Patcher.pdb -C:\Users\User\Documents\FlashPatcher-1.6\FlashPatcher\bin\Release\Flash Patcher.exe.config -C:\Users\User\Documents\FlashPatcher-1.6\FlashPatcher\bin\Release\Flash Patcher.exe -C:\Users\User\Documents\FlashPatcher-1.6\FlashPatcher\bin\Release\Flash Patcher.pdb diff --git a/FlashPatcher/obj/Release/FlashPatcher.csproj.GenerateResource.cache b/FlashPatcher/obj/Release/FlashPatcher.csproj.GenerateResource.cache deleted file mode 100644 index b9d808e..0000000 Binary files a/FlashPatcher/obj/Release/FlashPatcher.csproj.GenerateResource.cache and /dev/null differ diff --git a/FlashPatcher/obj/Release/TempPE/Properties.Resources.Designer.cs.dll b/FlashPatcher/obj/Release/TempPE/Properties.Resources.Designer.cs.dll deleted file mode 100644 index e6919ab..0000000 Binary files a/FlashPatcher/obj/Release/TempPE/Properties.Resources.Designer.cs.dll and /dev/null differ