diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..a7ce38b --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-warp": { + "version": "1.1.0", + "commands": [ + "dotnet-warp" + ] + } + } +} \ No newline at end of file diff --git a/.github/workflows/release-action.yml b/.github/workflows/release-action.yml new file mode 100644 index 0000000..fcf8f55 --- /dev/null +++ b/.github/workflows/release-action.yml @@ -0,0 +1,79 @@ +name: Release PresentationObsSceneSwitcher + +on: + push: + tags: + - 'v*' + +jobs: + + build: + runs-on: windows-latest # For a list of available runner types, refer to + # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on + + env: + Solution_Name: PresentationObsSceneSwitcherConsole + ProjectDirectory: PresentationObsSceneSwitcherConsole + FileName: PresentationObsSceneSwitcher + ProjectPath: PresentationObsSceneSwitcherConsole\PresentationObsSceneSwitcherConsole.csproj + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + # Install the .NET Core workload + - name: Install .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 3.1.101 + + # Restore tools + - name: Restore tools + run: dotnet tool restore + + # Restore the application to populate the obj folder with RuntimeIdentifiers + - name: Restore the application + run: dotnet restore $env:ProjectPath + + # Decode the base 64 encoded pfx and save the Signing_Certificate + - name: Build + run: | + mkdir ${{ env.ProjectDirectory }}\publish + dotnet warp $env:ProjectPath -o ${{ env.ProjectDirectory }}\publish\${{ env.FileName }}.exe + + # Publish + - name: Upload build artifacts + uses: actions/upload-artifact@v2 + with: + name: Exe + path: ${{ env.ProjectDirectory }}\publish + + # Zip + - name: Zip + run: | + cd ${{ env.ProjectDirectory }}\publish + Compress-Archive -DestinationPath ${{ env.FileName }} -Path .\* + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: false + prerelease: false + + - name: Upload Release Asset + id: upload-release-asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ${{ env.ProjectDirectory }}\publish\PresentationObsSceneSwitcher.zip + asset_name: PresentationObsSceneSwitcher.zip + asset_content_type: application/zip \ No newline at end of file diff --git a/OBS.cs b/OBS.cs index e82d390..ee968bc 100644 --- a/OBS.cs +++ b/OBS.cs @@ -25,6 +25,20 @@ public bool ChangeScene(string scene) return true; } + public bool StartRecording() + { + try { _OBS.Api.StartRecording(); } + catch { /* Recording already started */ } + return true; + } + + public bool StopRecording() + { + try { _OBS.Api.StopRecording(); } + catch { /* Recording already stopped */ } + return true; + } + protected virtual void Dispose(bool disposing) { if (!_DisposedValue) diff --git a/PowerPointInterop/PowerPoint.cs b/PowerPointInterop/PowerPoint.cs new file mode 100644 index 0000000..25dd196 --- /dev/null +++ b/PowerPointInterop/PowerPoint.cs @@ -0,0 +1,27 @@ +using Microsoft.Office.Interop.PowerPoint; +using System; +using System.Threading.Tasks; + +namespace PowerPointInterop +{ + /// + /// This projects allows you to compile a .dll with an embed COM Reference. + /// Used to add compilation support using dotnet cli as it doesn't allow you to use COMReference. + /// + public static class PowerPoint + { + private static Application powerPoint = new Application(); + + public static void SubscribeSlideShowNextSlide(Func subscription) + { + powerPoint.SlideShowNextSlide += async (SlideShowWindow Wn) => + { + var command = String.Empty; + try { command = Wn.View.Slide.NotesPage.Shapes[2].TextFrame.TextRange.Text; } + catch { /*no notes*/ } + + await subscription(command); + }; + } + } +} diff --git a/PowerPointInterop/PowerPointInterop.csproj b/PowerPointInterop/PowerPointInterop.csproj new file mode 100644 index 0000000..bb76c8f --- /dev/null +++ b/PowerPointInterop/PowerPointInterop.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.0 + + + + + {91493440-5a91-11cf-8700-00aa0060263b} + 2 + 12 + primary + 0 + false + True + + + + diff --git a/PowerPointInterop/README.md b/PowerPointInterop/README.md new file mode 100644 index 0000000..0d0b855 --- /dev/null +++ b/PowerPointInterop/README.md @@ -0,0 +1 @@ +This projects allows you to compile a .dll with an embed COM Reference. Used to add compilation support using dotnet cli as it doesn't allow you to use COMReference. diff --git a/PowerPointToOBSSceneSwitcher.csproj b/PowerPointToOBSSceneSwitcher.csproj index 75b9f85..e51fe00 100644 --- a/PowerPointToOBSSceneSwitcher.csproj +++ b/PowerPointToOBSSceneSwitcher.csproj @@ -1,24 +1,36 @@ - - - - Exe - netcoreapp3.1 - - - - - {91493440-5a91-11cf-8700-00aa0060263b} - 2 - 12 - primary - 0 - false - True - - - - - - - - + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + + + + + + + + + + {91493440-5a91-11cf-8700-00aa0060263b} + 2 + 12 + primary + 0 + false + True + + + + diff --git a/PowerPointToOBSSceneSwitcher.sln b/PowerPointToOBSSceneSwitcher.sln index e2cad97..472cb50 100644 --- a/PowerPointToOBSSceneSwitcher.sln +++ b/PowerPointToOBSSceneSwitcher.sln @@ -1,25 +1,49 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30428.66 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerPointToOBSSceneSwitcher", "PowerPointToOBSSceneSwitcher.csproj", "{8A844363-5A92-403B-90CD-BFCB30ED5054}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8A844363-5A92-403B-90CD-BFCB30ED5054}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8A844363-5A92-403B-90CD-BFCB30ED5054}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8A844363-5A92-403B-90CD-BFCB30ED5054}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8A844363-5A92-403B-90CD-BFCB30ED5054}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {515C02C0-0CF2-4890-A1FB-4D6A5F115CD6} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30428.66 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerPointToOBSSceneSwitcher", "PowerPointToOBSSceneSwitcher.csproj", "{8A844363-5A92-403B-90CD-BFCB30ED5054}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PresentationObsSceneSwitcher", "PresentationObsSceneSwitcher\PresentationObsSceneSwitcher.csproj", "{5B07EF15-11D6-4646-8322-965BD7D4ADEE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{76FD753E-6BFA-477C-BA87-23D96C053DC5}" + ProjectSection(SolutionItems) = preProject + .config\dotnet-tools.json = .config\dotnet-tools.json + .github\workflows\release-action.yml = .github\workflows\release-action.yml + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerPointInterop", "PowerPointInterop\PowerPointInterop.csproj", "{6D327EF6-B794-4441-8893-3EFD05DA682F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PresentationObsSceneSwitcherConsole", "PresentationObsSceneSwitcherConsole\PresentationObsSceneSwitcherConsole.csproj", "{557DE28E-D0A2-4DFB-82F7-D7A32EB96C0C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8A844363-5A92-403B-90CD-BFCB30ED5054}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A844363-5A92-403B-90CD-BFCB30ED5054}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A844363-5A92-403B-90CD-BFCB30ED5054}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A844363-5A92-403B-90CD-BFCB30ED5054}.Release|Any CPU.Build.0 = Release|Any CPU + {5B07EF15-11D6-4646-8322-965BD7D4ADEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B07EF15-11D6-4646-8322-965BD7D4ADEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B07EF15-11D6-4646-8322-965BD7D4ADEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B07EF15-11D6-4646-8322-965BD7D4ADEE}.Release|Any CPU.Build.0 = Release|Any CPU + {6D327EF6-B794-4441-8893-3EFD05DA682F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6D327EF6-B794-4441-8893-3EFD05DA682F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6D327EF6-B794-4441-8893-3EFD05DA682F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6D327EF6-B794-4441-8893-3EFD05DA682F}.Release|Any CPU.Build.0 = Release|Any CPU + {557DE28E-D0A2-4DFB-82F7-D7A32EB96C0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {557DE28E-D0A2-4DFB-82F7-D7A32EB96C0C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {557DE28E-D0A2-4DFB-82F7-D7A32EB96C0C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {557DE28E-D0A2-4DFB-82F7-D7A32EB96C0C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {515C02C0-0CF2-4890-A1FB-4D6A5F115CD6} + EndGlobalSection +EndGlobal diff --git a/PresentationObsSceneSwitcher/ConfigurationForm.Designer.cs b/PresentationObsSceneSwitcher/ConfigurationForm.Designer.cs new file mode 100644 index 0000000..11f4f41 --- /dev/null +++ b/PresentationObsSceneSwitcher/ConfigurationForm.Designer.cs @@ -0,0 +1,222 @@ + +namespace PresentationObsSceneSwitcher +{ + partial class ConfigurationForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ConfigurationForm)); + this.panel1 = new System.Windows.Forms.Panel(); + this.tbPassword = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.buttonStart = new System.Windows.Forms.Button(); + this.tbPort = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tbIpAddress = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.menuStrip = new System.Windows.Forms.MenuStrip(); + this.menuItemClose = new System.Windows.Forms.ToolStripMenuItem(); + this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); + this.panel1.SuspendLayout(); + this.menuStrip.SuspendLayout(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.BackColor = System.Drawing.Color.WhiteSmoke; + this.panel1.Controls.Add(this.tbPassword); + this.panel1.Controls.Add(this.label4); + this.panel1.Controls.Add(this.buttonStart); + this.panel1.Controls.Add(this.tbPort); + this.panel1.Controls.Add(this.label3); + this.panel1.Controls.Add(this.tbIpAddress); + this.panel1.Controls.Add(this.label2); + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 25); + this.panel1.Margin = new System.Windows.Forms.Padding(10); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(329, 150); + this.panel1.TabIndex = 0; + // + // tbPassword + // + this.tbPassword.Location = new System.Drawing.Point(93, 72); + this.tbPassword.Margin = new System.Windows.Forms.Padding(5, 10, 10, 0); + this.tbPassword.Name = "tbPassword"; + this.tbPassword.Size = new System.Drawing.Size(224, 25); + this.tbPassword.TabIndex = 7; + this.tbPassword.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(9, 75); + this.label4.Margin = new System.Windows.Forms.Padding(0, 10, 0, 0); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(67, 17); + this.label4.TabIndex = 6; + this.label4.Text = "Password:"; + // + // buttonStart + // + this.buttonStart.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(85)))), ((int)(((byte)(85)))), ((int)(((byte)(85))))); + this.buttonStart.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonStart.ForeColor = System.Drawing.Color.WhiteSmoke; + this.buttonStart.Location = new System.Drawing.Point(9, 107); + this.buttonStart.Margin = new System.Windows.Forms.Padding(0, 10, 0, 0); + this.buttonStart.Name = "buttonStart"; + this.buttonStart.Size = new System.Drawing.Size(308, 30); + this.buttonStart.TabIndex = 5; + this.buttonStart.Text = "Start / Restart"; + this.buttonStart.UseVisualStyleBackColor = false; + this.buttonStart.Click += new System.EventHandler(this.buttonStart_Click); + // + // tbPort + // + this.tbPort.Location = new System.Drawing.Point(269, 37); + this.tbPort.Margin = new System.Windows.Forms.Padding(5, 10, 0, 0); + this.tbPort.Name = "tbPort"; + this.tbPort.Size = new System.Drawing.Size(48, 25); + this.tbPort.TabIndex = 4; + this.tbPort.Text = "4444"; + this.tbPort.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(185, 40); + this.label3.Margin = new System.Windows.Forms.Padding(0, 10, 0, 0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(79, 17); + this.label3.TabIndex = 3; + this.label3.Text = "Ip Address*:"; + // + // tbIpAddress + // + this.tbIpAddress.Location = new System.Drawing.Point(93, 37); + this.tbIpAddress.Margin = new System.Windows.Forms.Padding(5, 10, 10, 0); + this.tbIpAddress.Name = "tbIpAddress"; + this.tbIpAddress.Size = new System.Drawing.Size(82, 25); + this.tbIpAddress.TabIndex = 2; + this.tbIpAddress.Text = "127.0.0.1"; + this.tbIpAddress.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(9, 40); + this.label2.Margin = new System.Windows.Forms.Padding(0, 10, 0, 0); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(79, 17); + this.label2.TabIndex = 1; + this.label2.Text = "Ip Address*:"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point); + this.label1.Location = new System.Drawing.Point(9, 10); + this.label1.Margin = new System.Windows.Forms.Padding(0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(152, 17); + this.label1.TabIndex = 0; + this.label1.Text = "OBS Websocket Server:"; + // + // menuStrip + // + this.menuStrip.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(85)))), ((int)(((byte)(85)))), ((int)(((byte)(85))))); + this.menuStrip.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.menuItemClose}); + this.menuStrip.Location = new System.Drawing.Point(0, 0); + this.menuStrip.Name = "menuStrip"; + this.menuStrip.Size = new System.Drawing.Size(329, 25); + this.menuStrip.TabIndex = 0; + this.menuStrip.Text = "Menu Strip"; + // + // menuItemClose + // + this.menuItemClose.ForeColor = System.Drawing.Color.WhiteSmoke; + this.menuItemClose.Name = "menuItemClose"; + this.menuItemClose.Size = new System.Drawing.Size(52, 21); + this.menuItemClose.Text = "Close"; + this.menuItemClose.ToolTipText = "Closes the application"; + this.menuItemClose.Click += new System.EventHandler(this.menuItemClose_Click); + // + // notifyIcon + // + this.notifyIcon.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info; + this.notifyIcon.BalloonTipText = "Hidden!"; + this.notifyIcon.BalloonTipTitle = "Presentation Obs Scene Switcher"; + this.notifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon.Icon"))); + this.notifyIcon.Text = "notifyIcon"; + this.notifyIcon.Visible = true; + this.notifyIcon.DoubleClick += new System.EventHandler(this.notifyIcon_DoubleClick); + // + // ConfigurationForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(329, 175); + this.Controls.Add(this.panel1); + this.Controls.Add(this.menuStrip); + this.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MainMenuStrip = this.menuStrip; + this.Name = "ConfigurationForm"; + this.Text = "ConfigurationForm"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ConfigurationForm_FormClosing); + this.Resize += new System.EventHandler(this.ConfigurationForm_Resize); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.menuStrip.ResumeLayout(false); + this.menuStrip.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.MenuStrip menuStrip; + private System.Windows.Forms.ToolStripMenuItem menuItemClose; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox tbIpAddress; + private System.Windows.Forms.TextBox tbPort; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.NotifyIcon notifyIcon; + private System.Windows.Forms.Button buttonStart; + private System.Windows.Forms.TextBox tbPassword; + private System.Windows.Forms.Label label4; + } +} + diff --git a/PresentationObsSceneSwitcher/ConfigurationForm.cs b/PresentationObsSceneSwitcher/ConfigurationForm.cs new file mode 100644 index 0000000..6e618db --- /dev/null +++ b/PresentationObsSceneSwitcher/ConfigurationForm.cs @@ -0,0 +1,72 @@ +using PowerPointToOBSSceneSwitcher.Obs; +using System; +using System.Windows.Forms; + +namespace PresentationObsSceneSwitcher +{ + public partial class ConfigurationForm : Form + { + #region GUI Behavior fields + + private bool manualClosing; + private bool showDisplay; + + #endregion + + private readonly ObsWebSocketClientSettings settings; + private ObsWebSocketClient client; + + // TODO: Refactor this Injection + public ConfigurationForm(ObsWebSocketClientSettings settings, ObsWebSocketClient client) + { + InitializeComponent(); + this.settings = settings ?? new ObsWebSocketClientSettings(); + this.client = client; + } + + #region GUI Behavior events + + protected override void SetVisibleCore(bool value) => base.SetVisibleCore(showDisplay && value); + + private void menuItemClose_Click(object sender, EventArgs e) + { + this.manualClosing = true; + this.notifyIcon.Dispose(); + this.Close(); + } + + private void notifyIcon_DoubleClick(object sender, EventArgs e) + { + this.showDisplay = true; + this.Visible = !this.Visible; + this.WindowState = FormWindowState.Normal; + } + + private void ConfigurationForm_Resize(object sender, EventArgs e) + { + if (this.WindowState == FormWindowState.Minimized) this.Hide(); + } + + private void ConfigurationForm_FormClosing(object sender, FormClosingEventArgs e) + { + if (!manualClosing) + { + e.Cancel = true; + this.Hide(); + } + } + + + #endregion + + private async void buttonStart_Click(object sender, EventArgs e) + { + // TODO: Handle the parse better when bindingsource support come. + settings.IpAddress = tbIpAddress.Text; + settings.Port = int.Parse(tbPort.Text); + settings.Password = tbPassword.Text; + + await client.ConnectAsync(settings); + } + } +} diff --git a/PresentationObsSceneSwitcher/ConfigurationForm.resx b/PresentationObsSceneSwitcher/ConfigurationForm.resx new file mode 100644 index 0000000..5456d88 --- /dev/null +++ b/PresentationObsSceneSwitcher/ConfigurationForm.resx @@ -0,0 +1,635 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAEAAAOkOAADpDgAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEXi8AhF4wA4NeNQaDXjUGg141BoNe + NQaDXjUGg141BoNeNQaDXjUGg141BoNeNQaCXTMEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgl0zBINeNQaDXjUGg141BoNeNQaDXjUGg141BoNe + NQaDXjUGg141BoNeNQaEXjADhF4vAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg14wA4Ne + MSiDXjRYg140WINeNFiDXjRYg140WINeNFiDXjRYg140WINeNFiDXjRUgl0zNQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIJdMzWDXjRUg140WINe + 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 + Gv8yJhr/MiYa/zMkGis5HBwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg10yAINd + MgqEXTIShF0zFIRdMxSAWjIVTjcjOzgqHP84Khz/OCoc/zkrHOVCMB9nhF0zFIRdMxSEXTMUhF0zFIRd + MxSEXTMUhF0zFIRdMxSEXTMUhF0zFIRdMxSEXTMUhF0zFIRdMxSEXTMUhF0zFIRdMxSEXTMUhF0zFIRd + MxSEXTMUkGxBFrOXaCPIsH9JyrSEjsq1hNbLtYT5y7WE/8u1hP/LtYT/y7WE/8u1hP/LtYT/y7WE/su1 + hOPLtYSliXZVmEw9K+s7LR7/OCoc/zgqHP9ONyM7gFoyFYRdMxSEXTMUhF0yEoNdMgqDXTIAAAAAAAAA + AACCXDEAglwxDYNdMzWDXTNfg10zeYRdM3+EXTN/g10zf3dVMJRaQSb/WkEm/1pBJv9dQyfxbk4srIRd + M3+EXTN/hF0zf4RdM3+EXTN/hF0zf4RdM3+EXTN/hF0zf4RdM3+EXTN/hF0zf4RdM3+EXTN/hF0zf4Rd + M3+EXTN/hF0zf4RdM3+EXTN/i2Y8f6KDVYe8oXKxyLCA6cu1hP7LtYT/y7WE/8u1hP/LtYT/y7WE/8u1 + hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8iygvuijGT+dV9A/2BILP9bQif/d1UwlINdM3+EXTN/hF0zf4Nd + M3mDXTNfg10zNIVeMg2FXjIAg18zC4NdMmWDXTPcg10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/iGQ5/519Uf+8o3P/yrSD/8u1hP/LtYT/y7WE/8u1 + hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8Wtff+khln/jGg9/4Re + NP+DXTP/g10z/4NdM/+DXTP/g10z/4NdM9yEXTNkgVo1CoNeM0mDXTP0g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/iWU7/6KDVv/Ap3f/y7WE/8u1 + hP/LtYT/y7WE/8y2hf/PuIj/0rqM/9S8j//VvpD/1b2Q/9S9j//Tu43/0LmK/8y2hv/LtYT/y7WE/8u1 + hP/LtYT/ybOC/6yPYf+NaT7/hF40/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z84JbNEiDXTO6g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/iGM4/6OE + V//Cqnr/y7WE/8u1hP/LtYT/zLaF/9C5iv/Xv5L/4MWc/+jMpv/t0Kz/79Ov//DTsP/u0a3/6s6o/+LH + n//ZwJX/0rqM/8y2hf/LtYT/y7WE/8u1hP/LtIP/q45g/4pmO/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXDS5g10z8oNdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/hmA2/5x7T/++pXX/y7WE/8u1hP/LtYT/zbaG/9W8j//hx5//7dCs//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/79Ku/+XKo//Xv5P/zreI/8u1hP/LtYT/y7WE/8mzgv+jhVf/hmE3/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z8XJRLv9yUS7/clEu/3JRLv9yUS7/clEu/3JRLv9yUS7/clEu/3JR + Lv9yUS7/clEu/3JRLv9yUS7/clEu/3JRLv90Ui7/fFgx/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/5FvQ/+2m2z/y7WE/8u1hP/LtYT/zbeH/9e/k//nzKb/79Kv//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/68+r/9zDmP/OuIj/y7WE/8u1 + hP/LtYT/xK19/5RyRv+EXjT/g10z/4NdM/+DXTP/g10z/4NdM/9EMh//RDIf/0QyH/9EMh//RDIf/0Qy + H/9EMh//RDIf/0QyH/9EMh//RDIf/0QyH/9EMh//RDIf/0QyH/9EMh//STUh/2NHKf+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4diOP+lhln/xq9+/8u1hP/LtYT/zLaF/9e/ + k//ozaf/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/t0a3/28KX/823h//LtYT/y7WE/8u1hP+xlWf/iGQ5/4NdM/+DXTP/g10z/4NdM/+DXTP/Py8e/z8v + Hv8/Lx7/Py8e/z8vHv8/Lx7/Py8e/z8vHv8/Lx7/Py8e/z8vHv8/Lx7/Py8e/z8vHv8/Lx7/Py8e/0My + H/9dQyf/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+TcUb/uJ5v/8u1 + hP/LtYT/y7WE/9O8jf/my6P/8NOv//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw/+zPq//WvpD/zLaF/8u1hP/LtYT/yLGB/5Z1SP+EXjT/g10z/4Nd + M/+DXTP/g10z/2hKK/9oSiv/aEor/2hKK/9oSiv/aEor/2hKK/9oSiv/aEor/2hKK/9oSiv/aEor/2hK + K/9oSiv/aEor/2hKK/9sTSz/elcw/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+FXzX/ooNW/8avf//LtYT/y7WE/863h//exZv/7tGt//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/5Mmi/8+4if/LtYT/y7WE/8u1 + hP+vk2T/hmE3/4NdM/+DXTP/g10z/4NdM/99WTH/fVkx/31ZMf99WTH/fVkx/31ZMf99WTH/fVkx/31Z + Mf99WTH/fVkx/31ZMf99WTH/fVkx/31ZMf99WTH/flox/4JcM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/i2c8/66SY//LtYT/y7WE/8u1hP/UvI//58yl//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw/+7R + rv/WvZH/zLaF/8u1hP/LtYT/wqp7/4plO/+DXTP/g10z/4NdM/+DXTP/WUAm/1lAJv9ZQCb/WUAm/1lA + Jv9ZQCb/WUAm/1lAJv9ZQCb/WUAm/1lAJv9ZQCb/WUAm/1lAJv9ZQCb/WUAm/11DJ/9vUC3/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/5NxRf+4nm7/y7WE/8u1hP/LtYX/28KX/+3Q + rP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsf/w07H/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/4Mad/863h//LtYT/y7WE/8q1g/+TcET/hF40/4NdM/+DXTP/g10z/zIm + Gv8yJhr/MiYa/zImGv8yJhr/MiYa/zImGv8yJhr/MiYa/zImGv8yJhr/MiYa/zImGv8yJhr/MiYa/zIm + Gv84Khz/WEAl/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+ZeEz/v6Z2/8u1 + hP/LtYT/zbeH/+DGnf/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//Lavf/1483/9uTQ//Pc + wP/w1LP/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw/+jNpv/PuIn/y7WE/8u1hP/LtYT/nn5R/4Rf + Nf+DXTP/g10z/4NdM/9VPiX/VT4l/1U+Jf9VPiX/VT4l/1U+Jf9VPiX/VT4l/1U+Jf9VPiX/VT4l/1U+ + Jf9VPiX/VT4l/1U+Jf9VPiX/WUAm/21OLP+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/nXxQ/8Ore//LtYT/y7WE/9C5iv/jyKD/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//HW + tv/469v//vv5///+/P/68eX/8tq8//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/t0a3/0LmK/8u1 + hP/LtYT/y7WE/6aIWv+FXzX/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/55+Uf/FrX3/y7WE/8u1hP/Ruov/5Mmi//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/z3L//+/Xs//////////////38//Tfxf/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/79Ow/9C5iv/LtYT/y7WE/8u1hP+oi17/hWA1/4NdM/+DXTP/g10z/2hLK/9oSyv/aEsr/2hL + K/9oSyv/aEsr/2hLK/9oSyv/aEsr/2hLK/9oSyv/aEsr/2hLK/9oSyv/aEsr/2hLK/9rTSz/eFYw/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+efVH/xKx8/8u1hP/LtYT/0bmK/+TJ + of/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8tm7//rx5v///v3///////348v/z3cL/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw/+7Rrv/QuYr/y7WE/8u1hP/LtYT/p4lc/4VgNf+DXTP/g10z/4Nd + M/8+Lh7/Pi4e/z4uHv8+Lh7/Pi4e/z4uHv8+Lh7/Pi4e/z4uHv8+Lh7/Pi4e/z4uHv8+Lh7/Pi4e/z4u + Hv89Lh7/QjEf/19EKP+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/m3pO/8Go + ef/LtYT/y7WE/864iP/ix5//8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DUsf/14cn/+e7g//rv + 4//25M//8da2//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/rzqn/z7iJ/8u1hP/LtYT/y7WE/6KC + Vv+FXzX/g10z/4NdM/+DXTP/RTIg/0UyIP9FMiD/RTIg/0UyIP9FMiD/RTIg/0UyIP9FMiD/RTIg/0Uy + IP9FMiD/RTIg/0UyIP9FMiD/RTIg/0o2If9jRyn/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/5Z0SP+7oXL/y7WE/8u1hP/MtoX/3sSa/+/Srv/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NSx//LYuv/y2bv/8dSz//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/5Mmh/864 + iP/LtYT/y7WE/8u1hP+Yd0r/hF40/4NdM/+DXTP/g10z/25OLf9uTi3/bk4t/25OLf9uTi3/bk4t/25O + Lf9uTi3/bk4t/25OLf9uTi3/bk4t/25OLf9uTi3/bk4t/25OLf9xUS7/fVgx/4NdM/+DXTP/g10z/4Ff + Nv96ZkT/dmlK/39hOv+DXTP/g10z/4NdM/+Pa0H/spdp/8u1hP/LtYT/y7WE/9i/k//qzqn/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw/9rBlv/Ntob/y7WE/8u1hP/HsID/jWk+/4NdM/+DXTP/g10z/4NdM/93VS//d1Uv/3dV + L/93VS//d1Uv/3dVL/93VS//d1Uv/3dVL/93VS//d1Uv/3dVL/93VS//d1Uv/3dVL/94VS//elcx/4Fb + M/+DXTP/g10z/39hOv9oeGP/RZqi/0Ceqv9Zhn7/e2VC/4NdM/+DXTP/h2I3/6eJXP/Js4L/y7WE/8u1 + hP/QuYr/4sig/+/Sr//w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw/+rOqf/Suoz/y7WE/8u1hP/LtYT/uJ5v/4diN/+DXTP/g10z/4Nd + M/+DXTP/TTgi/004Iv9NOCL/TTgi/004Iv9NOCL/TTgi/004Iv9NOCL/TTgi/004Iv9NOCL/TTgi/004 + Iv9NOCL/TTki/1I8JP9oSyv/g10z/4NdM/90bE7/QZ2o/xrD7f8aw+//L6/J/2R7a/+DXTP/g10z/4Nd + M/+aeU3/v6Z3/8u1hP/LtYT/y7WE/9e/k//qzqn/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw/+/Srv/cwpj/zbeG/8u1hP/LtYT/y7SE/6CA + VP+FXzX/g10z/4NdM/+DXTP/g10z/zImGv8yJhr/MiYa/zImGv8yJhr/MiYa/zImGv8yJhr/MiYa/zIm + Gv8yJhr/MiYa/zImGv8yJhr/MiYa/zImGv85Khz/WkEn/4NdM/+DXTP/b3FX/zWovv8ZxPD/GcTw/ye3 + 2P9Zhn7/g10z/4NdM/+DXTP/i2c8/62RY//Js4L/y7WE/8u1hP/OuIj/3cSa/+zQq//w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/iyKD/0LmK/8u1 + hP/LtYT/y7WE/72jdP+NaT7/g10z/4NdM/+DXTP/g10z/4NdM/9gRSj/YEUo/2BFKP9gRSj/YEUo/2BF + KP9gRSj/YEUo/2BFKP9gRSj/YEUo/2BFKP9gRSj/YEUo/2BFKP9gRSj/ZEgp/3NSLv+DXTP/g10z/3ln + Rf9OkJL/IL3j/x3A6f86pLb/bXNb/4NdM/+DXTP/g10z/4ReNP+aeUz/vqV1/8u1hP/LtYT/y7WE/9C5 + iv/fxZz/7NCs//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw/+/S + r//kyaL/0ruN/8y2hf/LtYT/y7WE/8qzgv+gf1L/hWA1/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z+YNd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+CXjb/dGxO/1uEe/9XiIL/anVf/4BgOf+DXTP/g10z/4NdM/+DXTP/iWU6/6eJ + W//FrX3/y7WE/8u1hP/LtYT/0LmK/9zDmP/pzqj/79Kv//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw/+zQrP/gxp3/0ruN/8y2hf/LtYT/y7WE/8u1hP+zmGn/i2Y7/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z+YNdM9eDXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+CXjX/gV82/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+Oaj//r5Jk/8ixgP/LtYT/y7WE/8u1hP/OuIj/1r6R/+DGnf/pzaf/79Ku//DT + sP/w07D/8NOw//DTsP/w07D/686q/+PIoP/ZwJT/z7mJ/8u1hf/LtYT/y7WE/8u1hP+5oHD/k3FF/4Re + NP+DXTP/g10z/4NdM/+DXTP/g10z/4NdMtWCXTN6g10z/oNdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/hF40/5JvRP+yl2j/yLGA/8u1hP/LtYT/y7WE/8u1 + hP/PuIn/1b2P/9rBlv/exJr/4Mad/+DGnf/exZv/28KX/9a+kf/Ruov/zLaF/8u1hP/LtYT/y7WE/8u1 + hP+7onP/mHZK/4VfNf+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/6DXTJ4gV40HYNdM6WDXTP8g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+FXzX/kW9D/66R + Y//FrX3/y7WE/8u1hP/LtYT/y7WE/8u1hP/MtoX/zreH/8+4if/PuIn/zriH/8y2hf/LtYT/y7WE/8u1 + hP/LtYT/y7WE/8u0g/+3nG3/mHZK/4VgNv+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/uDXTOkg1wyHYNe + MwGDXjMpglwzcYNdM6iEXTO7hF00vYRdNL2EXTS9hF00vYRdNL2EXTS9hF00vYRdNL2EXTS9hF00vYRd + NL2EXTS9hF00vYRdNL2EXTS9hF00vYRdNL2EXTS9hF00vYRdNL2EXTS9hF00vYRdNL2EXTS9hF00vYRd + NL2EXTS9hF00vYVeNb2RbkS9rI9hzMKqeuvKtIP8y7WE/8u1hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8u1 + hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8WuffOzmGnSmXdLv4ZgNr2EXTS9hF00vYRdNL2EXTS9hF0zu4Nd + M6iDXTRwg10yKINdMgEAAAAAgFo1AIFaNQ2EXTQphFwzM4RdNDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRd + NDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRd + NDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRdNDSEXTQ0hF42NJt7Tzy+pHRQy7SDiMu1hNHLtYT4y7WE/8u1 + hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8u1hP/LtYT/y7WE4cu1hJrDq3paooJWP4hiOTWEXTQ0hF00NIRd + NDSEXTQ0hF00NIRcMzOEXTQpg102DINdNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1b+AAs22 + hBnMtIU9y7WEaMu1hJXLtYS4y7WE0su1hN7LtYTey7WE1su1hMDLtYSfy7WFc8u1hEnKtoQhyraEBQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADV1VUC5uBWG+jiViDq6lUEAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA/4CAAMuzhAvKtYUey7aELsq1hDrLtYQ/y7WFP8u1hDzLtYUyzLWFI8q2 + hg/Ht4cCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAObgVxnm4lgj5uJYAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5+BYJefg + V4vn4Fez5+FXWOTkWwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAObgWDLn4Fet5+BXwebe + ViLm3VUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAObhWCLn4Fec5+BX9ufgV9Dn4Vdp6N9XEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAefh + WErn4Fe+5+BX+OfgV+Hl31ge495aAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD//4AB5uZeCeTkWwzm4lgH5+BWPOfgV67n4Ff25+BX3+fgV5Dm4Vcu399gAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA6uNVFubfVnnn4FfQ5+BX+ufgWNfm4FhR5OBaB9/fYAbr4FwS6+BcAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6OBWK+fgV5Ln4Feg5t9WPeniWQjm31Yy5+BXmefg + V+3n4Ffu5+BXwufgV3Tm3lci1dVVAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADj41UQ5+BXWufgV7Xn4Ffo5+BX/OfgV7jm4FhD5OBZCePjVRPn4FeX5+BXw+fe + VS7n3lUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOfhVzTn4Fe25+BX9Ofg + V7nn4VdJ4t5aCOfgWB/n4Fds5+BXz+fgV/jn4Ffn5+BWxOfgVonn4FdF6uJVEv//QAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA399QCebgVjTn4Fd25+BXuefgV9/n4Ff55+BX6efgV4Tn4Fcs5eBaBefh + VR3n4Fen5+BX8OfgV/no4Vc16OFWAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADo4lUL5+BXUefgV8bn4Ff35+BXzefgV2no4lcS6OBXD+jhVzjn4VeG5+BX2+fgV/rn4Ffu5+BX2+fg + V8fn4Vem5uBXhebhWG/n4Vhh5uBXYOfgVmnn31h+5+BXnOfgV8Hn4FfW5+BX6efgV/rn4Ffu5+BXoObg + V0Tn4FgV5+BYAufhV0Ln4Fe85+BX9efgV/bn31dz6OFXDejiVwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA//8AAOffVwvo4FdK5+BXvOfgV/nn4Ffj5+BXl+ffVzLh3VYG5+FXFObh + Vzbn4FZz5+BXvefgV/Dn4Ff+5+BX9ufgV+7n4Ffo5+BX5efgV+Tn4Ffn5+BX7OfgV/Tn4Ff85+BX++ff + V83n31eI5t9XQObgVhzl4FkF599YFujgV37n4FfW5+BX+ufgV+bo31he5t5XEebeVwAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6OFXCefhVzPn4FeZ5+BX8Ofg + V/Ln31fM5uBXfejgWCbu2lwF5+BWD+fgVyDo4Fc35+BXYefgWIro4Fiq599XwOfgV8zn4FfL5+BWxOjh + V7Hn4FeV599WbObgWD/n31cl6N9XFOTdVwTr4FwR5+BXYufgV8Hn4Ffs5+BX/effWL/o31c/6d5YC+ne + WQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADn4lcE6OJXG+fgV2Tn4FfL5+BX+efgV+7n4FfP5+BXj+ffWEHm31kO6t9VAufhWArn4FgT6OBYGeff + Vx7n4Fch5+BXIOfgVh/o4Vcb5+BWFebfVg3k3lkD/PxDA+bfWTHn4Fd55+BXxefgV+fn4Ff75+BX6Ofg + V33n31gk695WBe7dVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAOrqVQHn4FcL5t9WLufgV33n4FfX5+BX++fgV/Ln4Ffk5+BXx+jg + WJfo4Fdl5+FVP+jgVR/o4lEM5uZNAwAAAADf31AK6OJUGufgVzbn4FZZ5uFXiefgV77n4Ffe5+BX7ufg + V/zn4Fbt5+FXmefhVjfm4FYQ5uBWAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOXeVQPn4FcO5t9XKufg + WGvn4Fe/5+BX8ufgV/zn4Ff05+BX7OfgV+bn4Ffh5+BX3ufgV9zn4Ffc5+BX3efgV+Dn4Ffk5+BX6ufg + V/Ln4Ff75+BX/OfgV8/n31iD5t9VMubhVxPn41QD5uZNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAOXcWALo31gK5+BXFufgVjfn4FZt599XpefgV9Tn4Ff05+BX/ufgV//n4Ff/5+BX/+fg + V//n4Ff/5+BX+ufgV9/m4Fez5uFYfejgV0Dn4Fcc599YDuTeVAPb20kAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADm4VUD5+BWCuffVxDn4FcW5d9VHujh + VjLn4VZE5+BXUejgWFHm4FZJ5eFWOefhVSLn4FYY5uBXEubhWAvo4FYE6t9VAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANvbSQDp4lQC5+JVBOfgVwbo4FgG5t9WBePhVQPm5k0B//8AAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA//////////////////////////////////////////////////////gAf////gAf8AB////+ + AA/wAH////4AD/AAf////gAP8AB////+AA/4AH////4AH/wA/////wA//gP///8AQH/+A///+AAAf+AA + AAAAAAAHgAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAP/////8AAP//// + //D+AD+P////8H///wf////wP//8B////4AP//gB////gAP/4AD///+AAH8AAP///4AAAAAB////wAAA + AAP////gAAAAB/////AAAAAP////+AAIAB/////+AAAAf/////+AAAH///////AAD////////4D///// + //////////////////////////////////////////////////8= + + + + + AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAEAAAOkOAADpDgAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + MxSEXTMUhF0zFIRdMxSEXTMUhF0zFIRdMxSEXTMUhF0zFIRdMxSEXTMUhF0zFIRdMxSEXTMUhF0zFIRd + MxSEXTMUkGxBFrOXaCPIsH9JyrSEjsq1hNbLtYT5y7WE/8u1hP/LtYT/y7WE/8u1hP/LtYT/y7WE/su1 + hOPLtYSliXZVmEw9K+s7LR7/OCoc/zgqHP9ONyM7gFoyFYRdMxSEXTMUhF0yEoNdMgqDXTIAAAAAAAAA + AACCXDEAglwxDYNdMzWDXTNfg10zeYRdM3+EXTN/g10zf3dVMJRaQSb/WkEm/1pBJv9dQyfxbk4srIRd + M3+EXTN/hF0zf4RdM3+EXTN/hF0zf4RdM3+EXTN/hF0zf4RdM3+EXTN/hF0zf4RdM3+EXTN/hF0zf4Rd + M3+EXTN/hF0zf4RdM3+EXTN/i2Y8f6KDVYe8oXKxyLCA6cu1hP7LtYT/y7WE/8u1hP/LtYT/y7WE/8u1 + hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8iygvuijGT+dV9A/2BILP9bQif/d1UwlINdM3+EXTN/hF0zf4Nd + M3mDXTNfg10zNIVeMg2FXjIAg18zC4NdMmWDXTPcg10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/iGQ5/519Uf+8o3P/yrSD/8u1hP/LtYT/y7WE/8u1 + hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8Wtff+khln/jGg9/4Re + NP+DXTP/g10z/4NdM/+DXTP/g10z/4NdM9yEXTNkgVo1CoNeM0mDXTP0g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/iWU7/6KDVv/Ap3f/y7WE/8u1 + hP/LtYT/y7WE/8y2hf/PuIj/0rqM/9S8j//VvpD/1b2Q/9S9j//Tu43/0LmK/8y2hv/LtYT/y7WE/8u1 + hP/LtYT/ybOC/6yPYf+NaT7/hF40/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z84JbNEiDXTO6g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/iGM4/6OE + V//Cqnr/y7WE/8u1hP/LtYT/zLaF/9C5iv/Xv5L/4MWc/+jMpv/t0Kz/79Ov//DTsP/u0a3/6s6o/+LH + n//ZwJX/0rqM/8y2hf/LtYT/y7WE/8u1hP/LtIP/q45g/4pmO/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXDS5g10z8oNdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/hmA2/5x7T/++pXX/y7WE/8u1hP/LtYT/zbaG/9W8j//hx5//7dCs//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/79Ku/+XKo//Xv5P/zreI/8u1hP/LtYT/y7WE/8mzgv+jhVf/hmE3/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z8XJRLv9yUS7/clEu/3JRLv9yUS7/clEu/3JRLv9yUS7/clEu/3JR + Lv9yUS7/clEu/3JRLv9yUS7/clEu/3JRLv90Ui7/fFgx/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/5FvQ/+2m2z/y7WE/8u1hP/LtYT/zbeH/9e/k//nzKb/79Kv//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/68+r/9zDmP/OuIj/y7WE/8u1 + hP/LtYT/xK19/5RyRv+EXjT/g10z/4NdM/+DXTP/g10z/4NdM/9EMh//RDIf/0QyH/9EMh//RDIf/0Qy + H/9EMh//RDIf/0QyH/9EMh//RDIf/0QyH/9EMh//RDIf/0QyH/9EMh//STUh/2NHKf+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4diOP+lhln/xq9+/8u1hP/LtYT/zLaF/9e/ + k//ozaf/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/t0a3/28KX/823h//LtYT/y7WE/8u1hP+xlWf/iGQ5/4NdM/+DXTP/g10z/4NdM/+DXTP/Py8e/z8v + Hv8/Lx7/Py8e/z8vHv8/Lx7/Py8e/z8vHv8/Lx7/Py8e/z8vHv8/Lx7/Py8e/z8vHv8/Lx7/Py8e/0My + H/9dQyf/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+TcUb/uJ5v/8u1 + hP/LtYT/y7WE/9O8jf/my6P/8NOv//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw/+zPq//WvpD/zLaF/8u1hP/LtYT/yLGB/5Z1SP+EXjT/g10z/4Nd + M/+DXTP/g10z/2hKK/9oSiv/aEor/2hKK/9oSiv/aEor/2hKK/9oSiv/aEor/2hKK/9oSiv/aEor/2hK + K/9oSiv/aEor/2hKK/9sTSz/elcw/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+FXzX/ooNW/8avf//LtYT/y7WE/863h//exZv/7tGt//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/5Mmi/8+4if/LtYT/y7WE/8u1 + hP+vk2T/hmE3/4NdM/+DXTP/g10z/4NdM/99WTH/fVkx/31ZMf99WTH/fVkx/31ZMf99WTH/fVkx/31Z + Mf99WTH/fVkx/31ZMf99WTH/fVkx/31ZMf99WTH/flox/4JcM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/i2c8/66SY//LtYT/y7WE/8u1hP/UvI//58yl//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw/+7R + rv/WvZH/zLaF/8u1hP/LtYT/wqp7/4plO/+DXTP/g10z/4NdM/+DXTP/WUAm/1lAJv9ZQCb/WUAm/1lA + Jv9ZQCb/WUAm/1lAJv9ZQCb/WUAm/1lAJv9ZQCb/WUAm/1lAJv9ZQCb/WUAm/11DJ/9vUC3/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/5NxRf+4nm7/y7WE/8u1hP/LtYX/28KX/+3Q + rP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsf/w07H/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/4Mad/863h//LtYT/y7WE/8q1g/+TcET/hF40/4NdM/+DXTP/g10z/zIm + Gv8yJhr/MiYa/zImGv8yJhr/MiYa/zImGv8yJhr/MiYa/zImGv8yJhr/MiYa/zImGv8yJhr/MiYa/zIm + Gv84Khz/WEAl/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+ZeEz/v6Z2/8u1 + hP/LtYT/zbeH/+DGnf/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//Lavf/1483/9uTQ//Pc + wP/w1LP/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw/+jNpv/PuIn/y7WE/8u1hP/LtYT/nn5R/4Rf + Nf+DXTP/g10z/4NdM/9VPiX/VT4l/1U+Jf9VPiX/VT4l/1U+Jf9VPiX/VT4l/1U+Jf9VPiX/VT4l/1U+ + Jf9VPiX/VT4l/1U+Jf9VPiX/WUAm/21OLP+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/nXxQ/8Ore//LtYT/y7WE/9C5iv/jyKD/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//HW + tv/469v//vv5///+/P/68eX/8tq8//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/t0a3/0LmK/8u1 + hP/LtYT/y7WE/6aIWv+FXzX/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/55+Uf/FrX3/y7WE/8u1hP/Ruov/5Mmi//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/z3L//+/Xs//////////////38//Tfxf/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/79Ow/9C5iv/LtYT/y7WE/8u1hP+oi17/hWA1/4NdM/+DXTP/g10z/2hLK/9oSyv/aEsr/2hL + K/9oSyv/aEsr/2hLK/9oSyv/aEsr/2hLK/9oSyv/aEsr/2hLK/9oSyv/aEsr/2hLK/9rTSz/eFYw/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+efVH/xKx8/8u1hP/LtYT/0bmK/+TJ + of/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8tm7//rx5v///v3///////348v/z3cL/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw/+7Rrv/QuYr/y7WE/8u1hP/LtYT/p4lc/4VgNf+DXTP/g10z/4Nd + M/8+Lh7/Pi4e/z4uHv8+Lh7/Pi4e/z4uHv8+Lh7/Pi4e/z4uHv8+Lh7/Pi4e/z4uHv8+Lh7/Pi4e/z4u + Hv89Lh7/QjEf/19EKP+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/m3pO/8Go + ef/LtYT/y7WE/864iP/ix5//8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DUsf/14cn/+e7g//rv + 4//25M//8da2//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/rzqn/z7iJ/8u1hP/LtYT/y7WE/6KC + Vv+FXzX/g10z/4NdM/+DXTP/RTIg/0UyIP9FMiD/RTIg/0UyIP9FMiD/RTIg/0UyIP9FMiD/RTIg/0Uy + IP9FMiD/RTIg/0UyIP9FMiD/RTIg/0o2If9jRyn/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/5Z0SP+7oXL/y7WE/8u1hP/MtoX/3sSa/+/Srv/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NSx//LYuv/y2bv/8dSz//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/5Mmh/864 + iP/LtYT/y7WE/8u1hP+Yd0r/hF40/4NdM/+DXTP/g10z/25OLf9uTi3/bk4t/25OLf9uTi3/bk4t/25O + Lf9uTi3/bk4t/25OLf9uTi3/bk4t/25OLf9uTi3/bk4t/25OLf9xUS7/fVgx/4NdM/+DXTP/g10z/4Ff + Nv96ZkT/dmlK/39hOv+DXTP/g10z/4NdM/+Pa0H/spdp/8u1hP/LtYT/y7WE/9i/k//qzqn/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw/9rBlv/Ntob/y7WE/8u1hP/HsID/jWk+/4NdM/+DXTP/g10z/4NdM/93VS//d1Uv/3dV + L/93VS//d1Uv/3dVL/93VS//d1Uv/3dVL/93VS//d1Uv/3dVL/93VS//d1Uv/3dVL/94VS//elcx/4Fb + M/+DXTP/g10z/39hOv9oeGP/RZqi/0Ceqv9Zhn7/e2VC/4NdM/+DXTP/h2I3/6eJXP/Js4L/y7WE/8u1 + hP/QuYr/4sig/+/Sr//w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw/+rOqf/Suoz/y7WE/8u1hP/LtYT/uJ5v/4diN/+DXTP/g10z/4Nd + M/+DXTP/TTgi/004Iv9NOCL/TTgi/004Iv9NOCL/TTgi/004Iv9NOCL/TTgi/004Iv9NOCL/TTgi/004 + Iv9NOCL/TTki/1I8JP9oSyv/g10z/4NdM/90bE7/QZ2o/xrD7f8aw+//L6/J/2R7a/+DXTP/g10z/4Nd + M/+aeU3/v6Z3/8u1hP/LtYT/y7WE/9e/k//qzqn/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw/+/Srv/cwpj/zbeG/8u1hP/LtYT/y7SE/6CA + VP+FXzX/g10z/4NdM/+DXTP/g10z/zImGv8yJhr/MiYa/zImGv8yJhr/MiYa/zImGv8yJhr/MiYa/zIm + Gv8yJhr/MiYa/zImGv8yJhr/MiYa/zImGv85Khz/WkEn/4NdM/+DXTP/b3FX/zWovv8ZxPD/GcTw/ye3 + 2P9Zhn7/g10z/4NdM/+DXTP/i2c8/62RY//Js4L/y7WE/8u1hP/OuIj/3cSa/+zQq//w07D/8NOw//DT + sP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/iyKD/0LmK/8u1 + hP/LtYT/y7WE/72jdP+NaT7/g10z/4NdM/+DXTP/g10z/4NdM/9gRSj/YEUo/2BFKP9gRSj/YEUo/2BF + KP9gRSj/YEUo/2BFKP9gRSj/YEUo/2BFKP9gRSj/YEUo/2BFKP9gRSj/ZEgp/3NSLv+DXTP/g10z/3ln + Rf9OkJL/IL3j/x3A6f86pLb/bXNb/4NdM/+DXTP/g10z/4ReNP+aeUz/vqV1/8u1hP/LtYT/y7WE/9C5 + iv/fxZz/7NCs//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DTsP/w07D/8NOw/+/S + r//kyaL/0ruN/8y2hf/LtYT/y7WE/8qzgv+gf1L/hWA1/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z+YNd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+CXjb/dGxO/1uEe/9XiIL/anVf/4BgOf+DXTP/g10z/4NdM/+DXTP/iWU6/6eJ + W//FrX3/y7WE/8u1hP/LtYT/0LmK/9zDmP/pzqj/79Kv//DTsP/w07D/8NOw//DTsP/w07D/8NOw//DT + sP/w07D/8NOw/+zQrP/gxp3/0ruN/8y2hf/LtYT/y7WE/8u1hP+zmGn/i2Y7/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z+YNdM9eDXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+CXjX/gV82/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+Oaj//r5Jk/8ixgP/LtYT/y7WE/8u1hP/OuIj/1r6R/+DGnf/pzaf/79Ku//DT + sP/w07D/8NOw//DTsP/w07D/686q/+PIoP/ZwJT/z7mJ/8u1hf/LtYT/y7WE/8u1hP+5oHD/k3FF/4Re + NP+DXTP/g10z/4NdM/+DXTP/g10z/4NdMtWCXTN6g10z/oNdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/hF40/5JvRP+yl2j/yLGA/8u1hP/LtYT/y7WE/8u1 + hP/PuIn/1b2P/9rBlv/exJr/4Mad/+DGnf/exZv/28KX/9a+kf/Ruov/zLaF/8u1hP/LtYT/y7WE/8u1 + hP+7onP/mHZK/4VfNf+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/6DXTJ4gV40HYNdM6WDXTP8g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4Nd + M/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/+FXzX/kW9D/66R + Y//FrX3/y7WE/8u1hP/LtYT/y7WE/8u1hP/MtoX/zreH/8+4if/PuIn/zriH/8y2hf/LtYT/y7WE/8u1 + hP/LtYT/y7WE/8u0g/+3nG3/mHZK/4VgNv+DXTP/g10z/4NdM/+DXTP/g10z/4NdM/uDXTOkg1wyHYNe + MwGDXjMpglwzcYNdM6iEXTO7hF00vYRdNL2EXTS9hF00vYRdNL2EXTS9hF00vYRdNL2EXTS9hF00vYRd + NL2EXTS9hF00vYRdNL2EXTS9hF00vYRdNL2EXTS9hF00vYRdNL2EXTS9hF00vYRdNL2EXTS9hF00vYRd + NL2EXTS9hF00vYVeNb2RbkS9rI9hzMKqeuvKtIP8y7WE/8u1hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8u1 + hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8WuffOzmGnSmXdLv4ZgNr2EXTS9hF00vYRdNL2EXTS9hF0zu4Nd + M6iDXTRwg10yKINdMgEAAAAAgFo1AIFaNQ2EXTQphFwzM4RdNDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRd + NDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRd + NDSEXTQ0hF00NIRdNDSEXTQ0hF00NIRdNDSEXTQ0hF42NJt7Tzy+pHRQy7SDiMu1hNHLtYT4y7WE/8u1 + hP/LtYT/y7WE/8u1hP/LtYT/y7WE/8u1hP/LtYT/y7WE4cu1hJrDq3paooJWP4hiOTWEXTQ0hF00NIRd + NDSEXTQ0hF00NIRcMzOEXTQpg102DINdNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1b+AAs22 + hBnMtIU9y7WEaMu1hJXLtYS4y7WE0su1hN7LtYTey7WE1su1hMDLtYSfy7WFc8u1hEnKtoQhyraEBQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADV1VUC5uBWG+jiViDq6lUEAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA/4CAAMuzhAvKtYUey7aELsq1hDrLtYQ/y7WFP8u1hDzLtYUyzLWFI8q2 + hg/Ht4cCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAObgVxnm4lgj5uJYAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5+BYJefg + V4vn4Fez5+FXWOTkWwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAObgWDLn4Fet5+BXwebe + ViLm3VUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAObhWCLn4Fec5+BX9ufgV9Dn4Vdp6N9XEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAefh + WErn4Fe+5+BX+OfgV+Hl31ge495aAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD//4AB5uZeCeTkWwzm4lgH5+BWPOfgV67n4Ff25+BX3+fgV5Dm4Vcu399gAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA6uNVFubfVnnn4FfQ5+BX+ufgWNfm4FhR5OBaB9/fYAbr4FwS6+BcAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6OBWK+fgV5Ln4Feg5t9WPeniWQjm31Yy5+BXmefg + V+3n4Ffu5+BXwufgV3Tm3lci1dVVAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADj41UQ5+BXWufgV7Xn4Ffo5+BX/OfgV7jm4FhD5OBZCePjVRPn4FeX5+BXw+fe + VS7n3lUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOfhVzTn4Fe25+BX9Ofg + V7nn4VdJ4t5aCOfgWB/n4Fds5+BXz+fgV/jn4Ffn5+BWxOfgVonn4FdF6uJVEv//QAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA399QCebgVjTn4Fd25+BXuefgV9/n4Ff55+BX6efgV4Tn4Fcs5eBaBefh + VR3n4Fen5+BX8OfgV/no4Vc16OFWAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADo4lUL5+BXUefgV8bn4Ff35+BXzefgV2no4lcS6OBXD+jhVzjn4VeG5+BX2+fgV/rn4Ffu5+BX2+fg + V8fn4Vem5uBXhebhWG/n4Vhh5uBXYOfgVmnn31h+5+BXnOfgV8Hn4FfW5+BX6efgV/rn4Ffu5+BXoObg + V0Tn4FgV5+BYAufhV0Ln4Fe85+BX9efgV/bn31dz6OFXDejiVwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA//8AAOffVwvo4FdK5+BXvOfgV/nn4Ffj5+BXl+ffVzLh3VYG5+FXFObh + Vzbn4FZz5+BXvefgV/Dn4Ff+5+BX9ufgV+7n4Ffo5+BX5efgV+Tn4Ffn5+BX7OfgV/Tn4Ff85+BX++ff + V83n31eI5t9XQObgVhzl4FkF599YFujgV37n4FfW5+BX+ufgV+bo31he5t5XEebeVwAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6OFXCefhVzPn4FeZ5+BX8Ofg + V/Ln31fM5uBXfejgWCbu2lwF5+BWD+fgVyDo4Fc35+BXYefgWIro4Fiq599XwOfgV8zn4FfL5+BWxOjh + V7Hn4FeV599WbObgWD/n31cl6N9XFOTdVwTr4FwR5+BXYufgV8Hn4Ffs5+BX/effWL/o31c/6d5YC+ne + WQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADn4lcE6OJXG+fgV2Tn4FfL5+BX+efgV+7n4FfP5+BXj+ffWEHm31kO6t9VAufhWArn4FgT6OBYGeff + Vx7n4Fch5+BXIOfgVh/o4Vcb5+BWFebfVg3k3lkD/PxDA+bfWTHn4Fd55+BXxefgV+fn4Ff75+BX6Ofg + V33n31gk695WBe7dVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAOrqVQHn4FcL5t9WLufgV33n4FfX5+BX++fgV/Ln4Ffk5+BXx+jg + WJfo4Fdl5+FVP+jgVR/o4lEM5uZNAwAAAADf31AK6OJUGufgVzbn4FZZ5uFXiefgV77n4Ffe5+BX7ufg + V/zn4Fbt5+FXmefhVjfm4FYQ5uBWAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOXeVQPn4FcO5t9XKufg + WGvn4Fe/5+BX8ufgV/zn4Ff05+BX7OfgV+bn4Ffh5+BX3ufgV9zn4Ffc5+BX3efgV+Dn4Ffk5+BX6ufg + V/Ln4Ff75+BX/OfgV8/n31iD5t9VMubhVxPn41QD5uZNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAOXcWALo31gK5+BXFufgVjfn4FZt599XpefgV9Tn4Ff05+BX/ufgV//n4Ff/5+BX/+fg + V//n4Ff/5+BX+ufgV9/m4Fez5uFYfejgV0Dn4Fcc599YDuTeVAPb20kAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADm4VUD5+BWCuffVxDn4FcW5d9VHujh + VjLn4VZE5+BXUejgWFHm4FZJ5eFWOefhVSLn4FYY5uBXEubhWAvo4FYE6t9VAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANvbSQDp4lQC5+JVBOfgVwbo4FgG5t9WBePhVQPm5k0B//8AAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA//////////////////////////////////////////////////////gAf////gAf8AB////+ + AA/wAH////4AD/AAf////gAP8AB////+AA/4AH////4AH/wA/////wA//gP///8AQH/+A///+AAAf+AA + AAAAAAAHgAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAP/////8AAP//// + //D+AD+P////8H///wf////wP//8B////4AP//gB////gAP/4AD///+AAH8AAP///4AAAAAB////wAAA + AAP////gAAAAB/////AAAAAP////+AAIAB/////+AAAAf/////+AAAH///////AAD////////4D///// + //////////////////////////////////////////////////8= + + + \ No newline at end of file diff --git a/PresentationObsSceneSwitcher/IPresentationSubscriber.cs b/PresentationObsSceneSwitcher/IPresentationSubscriber.cs new file mode 100644 index 0000000..7cf38e8 --- /dev/null +++ b/PresentationObsSceneSwitcher/IPresentationSubscriber.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; + +namespace PresentationObsSceneSwitcher +{ + /// + /// Receives the name of the OBS scene. + /// + /// + public delegate Task PresentationSuscription(string scene); + + /// + /// Manages the suscriptions to a Presetation + /// + public interface IPresentationSubscriber + { + bool Subscribe(string appName, PresentationSuscription suscription); + } +} diff --git a/PresentationObsSceneSwitcher/JsonSettingsRepository.cs b/PresentationObsSceneSwitcher/JsonSettingsRepository.cs new file mode 100644 index 0000000..cf045a0 --- /dev/null +++ b/PresentationObsSceneSwitcher/JsonSettingsRepository.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; +using PowerPointToOBSSceneSwitcher.Obs; +using System.IO; +using System.Threading.Tasks; + +namespace PresentationObsSceneSwitcher +{ + public class JsonSettingsRepository + { + public async Task SaveAsync(ObsWebSocketClientSettings settings) + { + string json = JsonConvert.SerializeObject(settings); + await File.WriteAllTextAsync(@".\settings.json", json).ConfigureAwait(false); // Maybe AppData is a better location, but... + } + + public async Task LoadAsync() + { + try + { + string json = await File.ReadAllTextAsync(@".\settings.json").ConfigureAwait(false); + + return JsonConvert.DeserializeObject(json); + } + catch (FileNotFoundException ex) + { + return null; + } + } + } +} diff --git a/PresentationObsSceneSwitcher/Obs/ObsWebSocketClient.cs b/PresentationObsSceneSwitcher/Obs/ObsWebSocketClient.cs new file mode 100644 index 0000000..059f7a4 --- /dev/null +++ b/PresentationObsSceneSwitcher/Obs/ObsWebSocketClient.cs @@ -0,0 +1,168 @@ +using OBS.WebSocket.NET; +using System; +using System.ComponentModel.DataAnnotations; +using System.Net; +using System.Threading.Tasks; + +namespace PowerPointToOBSSceneSwitcher.Obs +{ + /// + /// Defines all the settings a ObsWebSocketClient needs + /// + /// Configuring the ObsWebSocketClient with a Settings object allows to use it with DI + public class ObsWebSocketClientSettings + { + private string ipAddress = "127.0.0.1"; + + /// + /// Ip address of the obs websocket server + /// + public string IpAddress + { + get => ipAddress; + set => this.ipAddress = IPAddress.TryParse(value, out _) ? value + : throw new ValidationException($"The field {nameof(IpAddress)} should be a valid IP"); + } + + /// + /// Port of the OBS WebSocket server + /// + public int Port { get; set; } = 4444; + + /// + /// Optional Password of the OBS WebSocket server + /// + public string Password { get; set; } = ""; + } + + /// + /// Connects to OBS WebSocket server + /// + public class ObsWebSocketClient : IDisposable + { + private bool disposedValue; + private ObsWebSocket obsWebSocket; + + public bool IsConnected => obsWebSocket.IsConnected; + + /// + /// Constructor + /// + /// Settings to connect + public ObsWebSocketClient() + { + this.obsWebSocket = new ObsWebSocket(); // Always not null + } + + /// + /// Connects to the OBS WebSocket server + /// + /// + public void Connect(ObsWebSocketClientSettings settings) + { + if (obsWebSocket.IsConnected) + obsWebSocket.Disconnect(); + + obsWebSocket.Connect($"ws://{settings.IpAddress}:{settings.Port}", settings.Password ?? ""); + } + + /// + /// Connects to the OBS WebSocket server + /// + /// + public async Task ConnectAsync(ObsWebSocketClientSettings settings) + { + // At least this won't block the main thread if using from GUI + await Task.WhenAny(Task.Run(() => obsWebSocket.Connect($"ws://{settings.IpAddress}:{settings.Port}", "")), Task.Delay(3000)); + } + + /// + /// Changes OBS current scene + /// + /// The Scene name in OBS + /// Always true + public bool ChangeScene(string scene) + { + obsWebSocket.Api.SetCurrentScene(scene); + return true; + } + + /// + /// Changes OBS current scene + /// + /// The Scene name in OBS + /// Always true + public async Task ChangeSceneAsync(string scene) + { + await Task.Run(() => obsWebSocket.Api.SetCurrentScene(scene)); + return true; + } + + /// + /// Starts recording OBS + /// + /// Always true + public bool StartRecording() + { + obsWebSocket.Api.StartRecording(); + return true; + } + + /// + /// Starts recording OBS + /// + /// Always true + public async Task StartRecordingAsync() + { + await Task.Run(() => obsWebSocket.Api.StartRecording()); + return true; + } + + /// + /// Starts recording OBS + /// + /// Always true + public bool StopRecording() + { + obsWebSocket.Api.StopRecording(); + return true; + } + + /// + /// Starts recording OBS + /// + /// Always true + public async Task StopRecordingAsync() + { + await Task.Run(() => obsWebSocket.Api.StopRecording()); + return true; + } + + #region Dispose + + ~ObsWebSocketClient() => Dispose(disposing: false); + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: dispose managed state (managed objects) + } + + obsWebSocket.Disconnect(); + obsWebSocket = null; + disposedValue = true; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/PresentationObsSceneSwitcher/PowerPoint/PowerPointPresentationSuscriber.cs b/PresentationObsSceneSwitcher/PowerPoint/PowerPointPresentationSuscriber.cs new file mode 100644 index 0000000..f819ba6 --- /dev/null +++ b/PresentationObsSceneSwitcher/PowerPoint/PowerPointPresentationSuscriber.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace PresentationObsSceneSwitcher.PowerPoint +{ + /// + /// Subscribes to a PowerPoint presentation. + /// + public class PowerPointPresentationSubscriber : IPresentationSubscriber + { + /// + /// \( --> Literal + /// ((?[^\)]+)\) --> Avoid backtracking searching until a ) is found. No wildcard in regex please. + /// \) --> Literal + /// : --> Literal + /// \[ + /// (?[^\]]+) --> Avoid backtracking searching until a ] is found. No wildcard in regex please. + /// \] + /// + /// Making it static and RegexOptions.Compiled is the best for Regex performance. + /// + private static readonly Regex extractInfoFromNotesRegex = new Regex(@"\((?[^\)]+)\):\[(?[^\]]+)\]", RegexOptions.Compiled | RegexOptions.CultureInvariant); + + //private static Application powerPoint = new Application(); + + private readonly Dictionary suscriptions = new Dictionary(); + + /// + /// Constructor + /// + public PowerPointPresentationSubscriber() + { + PowerPointInterop.PowerPoint.SubscribeSlideShowNextSlide(async (string note) => + { + foreach (Match match in extractInfoFromNotesRegex.Matches(note)) + { + string appName = match.Groups["AppName"].Value; + string info = match.Groups["Info"].Value; + + if (suscriptions.TryGetValue(appName, out PresentationSuscription suscription)) + { + await suscription(info).ConfigureAwait(false); + } + } + }); + } + + /// + /// Subscribes an app to powerpoint slide changes + /// + /// The app subscribing + /// The handler of the slide change + /// + public bool Subscribe(string appName, PresentationSuscription suscription) => suscriptions.TryAdd(appName, suscription); + } +} diff --git a/PresentationObsSceneSwitcher/PresentationObsSceneSwitcher.csproj b/PresentationObsSceneSwitcher/PresentationObsSceneSwitcher.csproj new file mode 100644 index 0000000..f61c57e --- /dev/null +++ b/PresentationObsSceneSwitcher/PresentationObsSceneSwitcher.csproj @@ -0,0 +1,34 @@ + + + + Library + netcoreapp3.1 + true + + + + + + + + + + + + + + + .\lib\Debug\PowerPointInterop.dll + + + + + + + .\lib\Release\PowerPointInterop.dll + + + + + + \ No newline at end of file diff --git a/PresentationObsSceneSwitcher/lib/Debug/PowerPointInterop.dll b/PresentationObsSceneSwitcher/lib/Debug/PowerPointInterop.dll new file mode 100644 index 0000000..e52e660 Binary files /dev/null and b/PresentationObsSceneSwitcher/lib/Debug/PowerPointInterop.dll differ diff --git a/PresentationObsSceneSwitcher/lib/Debug/PowerPointInterop.pdb b/PresentationObsSceneSwitcher/lib/Debug/PowerPointInterop.pdb new file mode 100644 index 0000000..bb97872 Binary files /dev/null and b/PresentationObsSceneSwitcher/lib/Debug/PowerPointInterop.pdb differ diff --git a/PresentationObsSceneSwitcher/lib/Release/PowerPointInterop.dll b/PresentationObsSceneSwitcher/lib/Release/PowerPointInterop.dll new file mode 100644 index 0000000..36c7c95 Binary files /dev/null and b/PresentationObsSceneSwitcher/lib/Release/PowerPointInterop.dll differ diff --git a/PresentationObsSceneSwitcher/lib/Release/PowerPointInterop.pdb b/PresentationObsSceneSwitcher/lib/Release/PowerPointInterop.pdb new file mode 100644 index 0000000..f556791 Binary files /dev/null and b/PresentationObsSceneSwitcher/lib/Release/PowerPointInterop.pdb differ diff --git a/PresentationObsSceneSwitcher/proyector.ico b/PresentationObsSceneSwitcher/proyector.ico new file mode 100644 index 0000000..4ec97ec Binary files /dev/null and b/PresentationObsSceneSwitcher/proyector.ico differ diff --git a/PresentationObsSceneSwitcher/settings.json b/PresentationObsSceneSwitcher/settings.json new file mode 100644 index 0000000..9756740 --- /dev/null +++ b/PresentationObsSceneSwitcher/settings.json @@ -0,0 +1 @@ +{"IpAddress":"127.0.0.1","Port":4444,"Password":""} \ No newline at end of file diff --git a/PresentationObsSceneSwitcherConsole/CommandLineApp.cs b/PresentationObsSceneSwitcherConsole/CommandLineApp.cs new file mode 100644 index 0000000..a822137 --- /dev/null +++ b/PresentationObsSceneSwitcherConsole/CommandLineApp.cs @@ -0,0 +1,114 @@ +using McMaster.Extensions.CommandLineUtils; +using Microsoft.Extensions.Logging; +using PowerPointToOBSSceneSwitcher.Obs; +using PresentationObsSceneSwitcherConsole; +using System; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace PresentationObsSceneSwitcher +{ + public class CommandLineApp + { + [Option(Description = "Run as console app", ShortName = "cmd")] + public bool NoGui { get; } = false; + + [Option(Description = "IpAddress", ShortName = "ip")] + public string IpAddress { get; } + + [Option(Description = "Port", ShortName = "p")] + public int? Port { get; } + + [Option(Description = "Optional Password", ShortName = "pass")] + public string Password { get; } + + private readonly Func formFactory; + private readonly JsonSettingsRepository settingsRepository; + private readonly ObsWebSocketClient client; + private readonly IPresentationSubscriber subscriber; + private readonly ILogger logger; + + public CommandLineApp(Func formFactory, + JsonSettingsRepository settingsRepository, ObsWebSocketClient client, + IPresentationSubscriber subscriber, ILogger logger) + { + this.formFactory = formFactory; + this.settingsRepository = settingsRepository; + this.client = client; + this.subscriber = subscriber; + this.logger = logger; + } + + public async Task OnExecuteAsync() + { + ObsWebSocketClientSettings settings = await ReadSettings().ConfigureAwait(false); + + logger.LogInformation("Try to connect using Address: {IpAddress}:{Port}", settings.IpAddress, settings.Port); + + try + { + await client.ConnectAsync(settings).ConfigureAwait(false); + logger.LogInformation("Connected"); + } + catch (Exception ex) + { + logger.LogError("Cannot connect: {Message}", ex.Message); + } + + /* Suscribe the client. */ + subscriber.Subscribe("OBS", async command => + { + logger.LogTrace("Received command: {Command}", command); + + if (command == "**START") + await client.StartRecordingAsync(); + else if (command == "**STOP") + await client.StopRecordingAsync(); + else if (string.IsNullOrEmpty(command)) + await client.ChangeSceneAsync(command); + }); + + + if (!NoGui) + { + logger.LogInformation("Runnig with GUI"); + ConsoleWindowController.Hide(); + RunGui(settings); + + /* Save if running GUI. */ + await settingsRepository.SaveAsync(settings); + } + else + { + logger.LogInformation("Runnig without GUI"); + Console.ReadKey(); + } + } + + private async Task ReadSettings() + { + ObsWebSocketClientSettings settings = (await settingsRepository.LoadAsync().ConfigureAwait(false)) + ?? new ObsWebSocketClientSettings(); + + if (!string.IsNullOrEmpty(IpAddress)) + settings.IpAddress = IpAddress; + + if (Port.HasValue) + settings.Port = Port.Value; + + if (!string.IsNullOrEmpty(Password)) + settings.Password = Password; + + return settings; + } + + private void RunGui(ObsWebSocketClientSettings settings) + { + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + Application.Run(formFactory(settings)); + } + } +} diff --git a/PresentationObsSceneSwitcherConsole/ConsoleWindowController.cs b/PresentationObsSceneSwitcherConsole/ConsoleWindowController.cs new file mode 100644 index 0000000..85d761d --- /dev/null +++ b/PresentationObsSceneSwitcherConsole/ConsoleWindowController.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.InteropServices; + +namespace PresentationObsSceneSwitcherConsole +{ + public class ConsoleWindowController + { + const int SW_HIDE = 0; + const int SW_SHOW = 5; + + [DllImport("kernel32.dll")] + static extern IntPtr GetConsoleWindow(); + + [DllImport("user32.dll")] + static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + + public static void Show() + { + ShowWindow(GetConsoleWindow(), SW_SHOW); + } + + public static void Hide() + { + ShowWindow(GetConsoleWindow(), SW_HIDE); + } + } +} diff --git a/PresentationObsSceneSwitcherConsole/PresentationObsSceneSwitcherConsole.csproj b/PresentationObsSceneSwitcherConsole/PresentationObsSceneSwitcherConsole.csproj new file mode 100644 index 0000000..b3ad9e1 --- /dev/null +++ b/PresentationObsSceneSwitcherConsole/PresentationObsSceneSwitcherConsole.csproj @@ -0,0 +1,22 @@ + + + + Exe + netcoreapp3.1 + true + true + win-x64 + + + + + + + + + + + + + + diff --git a/PresentationObsSceneSwitcherConsole/Program.cs b/PresentationObsSceneSwitcherConsole/Program.cs new file mode 100644 index 0000000..d253093 --- /dev/null +++ b/PresentationObsSceneSwitcherConsole/Program.cs @@ -0,0 +1,30 @@ +using McMaster.Extensions.CommandLineUtils; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using PowerPointToOBSSceneSwitcher.Obs; +using PresentationObsSceneSwitcher; +using PresentationObsSceneSwitcher.PowerPoint; +using System; +using System.Threading.Tasks; + +namespace PresentationObsSceneSwitcherConsole +{ + internal static class Program + { + private static async Task Main(string[] args) + { + ServiceProvider services = new ServiceCollection().AddLogging(builder => builder.AddConsole().AddDebug()) + .AddScoped() + .AddSingleton() + .AddScoped() + .AddScoped>(ctx => + settings => new ConfigurationForm(settings, ctx.GetRequiredService())) + .BuildServiceProvider(); + + CommandLineApplication app = new CommandLineApplication(); + app.Conventions.UseDefaultConventions().UseConstructorInjection(services); + + return await app.ExecuteAsync(args); + } + } +} diff --git a/Program.cs b/Program.cs index 29ef558..800a973 100644 --- a/Program.cs +++ b/Program.cs @@ -40,13 +40,31 @@ async static void App_SlideShowNextSlide(SlideShowWindow Wn) { if (line.StartsWith("OBS:")) { line = line.Substring(4).Trim(); - Console.WriteLine($" Switching to OBS Scene named \"{line}\""); - try { OBS.ChangeScene(line); } - catch { Console.WriteLine($" ERROR: {ex.Message.ToString()}"); } - break; + await HandleCommand(line); } } } } + + static async Task HandleCommand(string command) + { + switch (command) + { + case "": + break; + case "**START": + OBS.StartRecording(); + break; + case "**STOP": + OBS.StopRecording(); + break; + + default: + Console.WriteLine($" Switching to OBS Scene named \"{command}\""); + try { OBS.ChangeScene(command); } + catch (Exception ex) { Console.WriteLine($" ERROR: {ex.Message.ToString()}"); } + break; + } + } } } \ No newline at end of file