From 7b056c9dea848dad69738446668295162cd96c4c Mon Sep 17 00:00:00 2001 From: Vincent Maas Date: Sat, 22 Aug 2020 12:45:14 +0200 Subject: [PATCH] init commit --- .gitignore | 340 +++ ColorControl.sln | 31 + ColorControl/App.config | 17 + ColorControl/ColorControl.csproj | 238 ++ ColorControl/ColorDataConverter.cs | 54 + ColorControl/Config.cs | 14 + ColorControl/ExceptionExtensions.cs | 65 + ColorControl/LgPreset.cs | 70 + ColorControl/LgPresets.json | 1 + ColorControl/LgService.cs | 182 ++ ColorControl/MainForm.Designer.cs | 971 +++++++++ ColorControl/MainForm.cs | 1604 ++++++++++++++ ColorControl/MainForm.resx | 1906 +++++++++++++++++ ColorControl/NvPreset.cs | 186 ++ ColorControl/NvService.cs | 221 ++ ColorControl/PnpDev.cs | 22 + ColorControl/PresetBase.cs | 49 + ColorControl/Program.cs | 43 + ColorControl/Properties/AssemblyInfo.cs | 36 + ColorControl/Properties/Resources.Designer.cs | 71 + ColorControl/Properties/Resources.resx | 117 + ColorControl/Properties/Settings.Designer.cs | 30 + ColorControl/Properties/Settings.settings | 7 + ColorControl/Properties/app.manifest | 59 + ColorControl/RestartDetector.cs | 90 + ColorControl/ScreenInterrogatory.cs | 313 +++ ColorControl/TreeNodeBuilder.cs | 99 + ColorControl/Utils.cs | 231 ++ ColorControl/lgtv/App.cs | 11 + ColorControl/lgtv/Channel.cs | 10 + ColorControl/lgtv/ClientKeyStore.cs | 28 + ColorControl/lgtv/ExternalInput.cs | 15 + ColorControl/lgtv/IsConnectedDelegate.cs | 4 + ColorControl/lgtv/LgApp.cs | 19 + ColorControl/lgtv/LgTvApi.cs | 371 ++++ ColorControl/lgtv/LgTvConnection.cs | 167 ++ ColorControl/lgtv/LgWebOsMouseService.cs | 82 + ColorControl/lgtv/MessageType.cs | 4 + ColorControl/lgtv/README.md | 30 + ColorControl/lgtv/RawRequestMessage.cs | 18 + ColorControl/lgtv/RequestMessage.cs | 23 + ColorControl/packages.config | 10 + ColorControl/pngbarn.ico | Bin 0 -> 106479 bytes 43 files changed, 7859 insertions(+) create mode 100644 .gitignore create mode 100644 ColorControl.sln create mode 100644 ColorControl/App.config create mode 100644 ColorControl/ColorControl.csproj create mode 100644 ColorControl/ColorDataConverter.cs create mode 100644 ColorControl/Config.cs create mode 100644 ColorControl/ExceptionExtensions.cs create mode 100644 ColorControl/LgPreset.cs create mode 100644 ColorControl/LgPresets.json create mode 100644 ColorControl/LgService.cs create mode 100644 ColorControl/MainForm.Designer.cs create mode 100644 ColorControl/MainForm.cs create mode 100644 ColorControl/MainForm.resx create mode 100644 ColorControl/NvPreset.cs create mode 100644 ColorControl/NvService.cs create mode 100644 ColorControl/PnpDev.cs create mode 100644 ColorControl/PresetBase.cs create mode 100644 ColorControl/Program.cs create mode 100644 ColorControl/Properties/AssemblyInfo.cs create mode 100644 ColorControl/Properties/Resources.Designer.cs create mode 100644 ColorControl/Properties/Resources.resx create mode 100644 ColorControl/Properties/Settings.Designer.cs create mode 100644 ColorControl/Properties/Settings.settings create mode 100644 ColorControl/Properties/app.manifest create mode 100644 ColorControl/RestartDetector.cs create mode 100644 ColorControl/ScreenInterrogatory.cs create mode 100644 ColorControl/TreeNodeBuilder.cs create mode 100644 ColorControl/Utils.cs create mode 100644 ColorControl/lgtv/App.cs create mode 100644 ColorControl/lgtv/Channel.cs create mode 100644 ColorControl/lgtv/ClientKeyStore.cs create mode 100644 ColorControl/lgtv/ExternalInput.cs create mode 100644 ColorControl/lgtv/IsConnectedDelegate.cs create mode 100644 ColorControl/lgtv/LgApp.cs create mode 100644 ColorControl/lgtv/LgTvApi.cs create mode 100644 ColorControl/lgtv/LgTvConnection.cs create mode 100644 ColorControl/lgtv/LgWebOsMouseService.cs create mode 100644 ColorControl/lgtv/MessageType.cs create mode 100644 ColorControl/lgtv/README.md create mode 100644 ColorControl/lgtv/RawRequestMessage.cs create mode 100644 ColorControl/lgtv/RequestMessage.cs create mode 100644 ColorControl/packages.config create mode 100644 ColorControl/pngbarn.ico diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ce6fdd --- /dev/null +++ b/.gitignore @@ -0,0 +1,340 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- Backup*.rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb \ No newline at end of file diff --git a/ColorControl.sln b/ColorControl.sln new file mode 100644 index 0000000..c62f64f --- /dev/null +++ b/ColorControl.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30128.74 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorControl", "ColorControl\ColorControl.csproj", "{A6005D08-70F0-44CB-A384-9219EBA84F21}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A6005D08-70F0-44CB-A384-9219EBA84F21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A6005D08-70F0-44CB-A384-9219EBA84F21}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6005D08-70F0-44CB-A384-9219EBA84F21}.Debug|x64.ActiveCfg = Debug|x64 + {A6005D08-70F0-44CB-A384-9219EBA84F21}.Debug|x64.Build.0 = Debug|x64 + {A6005D08-70F0-44CB-A384-9219EBA84F21}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A6005D08-70F0-44CB-A384-9219EBA84F21}.Release|Any CPU.Build.0 = Release|Any CPU + {A6005D08-70F0-44CB-A384-9219EBA84F21}.Release|x64.ActiveCfg = Release|x64 + {A6005D08-70F0-44CB-A384-9219EBA84F21}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {34BA158F-AE57-4A7B-A372-11FEFBBC1F98} + EndGlobalSection +EndGlobal diff --git a/ColorControl/App.config b/ColorControl/App.config new file mode 100644 index 0000000..7d67223 --- /dev/null +++ b/ColorControl/App.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ColorControl/ColorControl.csproj b/ColorControl/ColorControl.csproj new file mode 100644 index 0000000..cbecb74 --- /dev/null +++ b/ColorControl/ColorControl.csproj @@ -0,0 +1,238 @@ + + + + + Debug + AnyCPU + {A6005D08-70F0-44CB-A384-9219EBA84F21} + WinExe + ColorControl + ColorControl + v4.7.2 + 512 + true + true + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + false + https://www.maassoft.com/downloads/ColorControl/ + ColorControl + Maassoft + 1 + 1.0.3.%2a + false + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + MinimumRecommendedRules.ruleset + true + + + 482C987E8C69872608C9D44751E004C5784E8540 + + + ColorControl_TemporaryKey.pfx + + + true + + + LocalIntranet + + + Properties\app.manifest + + + true + + + false + + + ColorControl_TemporaryKey.pfx + + + pngbarn.ico + + + + ..\packages\TaskScheduler.2.8.20\lib\net452\Microsoft.Win32.TaskScheduler.dll + + + ..\packages\Native.0.1.0\lib\net35\Native.dll + + + ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll + + + ..\packages\NLog.4.7.2\lib\net45\NLog.dll + + + ..\packages\NStandard.0.4.3\lib\net46\NStandard.dll + + + ..\packages\NvAPIWrapper.Net.0.8.0.98\lib\net45\NvAPIWrapper.dll + + + ..\packages\NWin32.1.0.6\lib\net46\NWin32.dll + + + + + + + + + False + ..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll + + + + + + + + + + + + + + + + + ..\..\..\..\..\..\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + MainForm.cs + + + + + MainForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + + PreserveNewest + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + False + Microsoft .NET Framework 4.7.2 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + + + \ No newline at end of file diff --git a/ColorControl/ColorDataConverter.cs b/ColorControl/ColorDataConverter.cs new file mode 100644 index 0000000..7928308 --- /dev/null +++ b/ColorControl/ColorDataConverter.cs @@ -0,0 +1,54 @@ +using NvAPIWrapper.Display; +using NvAPIWrapper.Native.Display; +using System; +using System.Collections.Generic; +using System.Web.Script.Serialization; + +namespace ColorControl +{ + public class ColorDataConverter : JavaScriptConverter + { + public override IEnumerable SupportedTypes + { + get { return new List() { typeof(ColorData) }; } + } + + public override IDictionary Serialize(object obj, JavaScriptSerializer serializer) + { + Dictionary result = new Dictionary(); + if (obj == null) return result; + return result; + } + + public override object Deserialize(IDictionary dictionary, Type type, JavaScriptSerializer serializer) + { + var format = ColorDataFormat.RGB; + var dynamicRange = ColorDataDynamicRange.VESA; + var colorDepth = ColorDataDepth.BPC8; + var colorimetry = ColorDataColorimetry.Auto; + var selectionPolicy = ColorDataSelectionPolicy.User; + object value; + if (dictionary.TryGetValue("ColorFormat", out value)) + { + format = (ColorDataFormat)Enum.ToObject(typeof(ColorDataFormat), value); + } + if (dictionary.TryGetValue("ColorDepth", out value)) + { + colorDepth = (ColorDataDepth)Enum.ToObject(typeof(ColorDataDepth), value); + } + if (dictionary.TryGetValue("Colorimetry", out value)) + { + colorimetry = (ColorDataColorimetry)Enum.ToObject(typeof(ColorDataColorimetry), value); + } + if (dictionary.TryGetValue("DynamicRange", out value)) + { + dynamicRange = (ColorDataDynamicRange)Enum.ToObject(typeof(ColorDataDynamicRange), value); + } + if (dictionary.TryGetValue("SelectionPolicy", out value)) + { + selectionPolicy = (ColorDataSelectionPolicy)Enum.ToObject(typeof(ColorDataSelectionPolicy), value); + } + return new ColorData(format, dynamicRange: dynamicRange, colorimetry: colorimetry, colorDepth: colorDepth, colorSelectionPolicy: selectionPolicy); + } + } +} diff --git a/ColorControl/Config.cs b/ColorControl/Config.cs new file mode 100644 index 0000000..12c055d --- /dev/null +++ b/ColorControl/Config.cs @@ -0,0 +1,14 @@ +namespace ColorControl +{ + class Config + { + public bool StartMinimized { get; set; } + + public int DisplaySettingsDelay { get; set; } + + public Config() + { + DisplaySettingsDelay = 1000; + } + } +} diff --git a/ColorControl/ExceptionExtensions.cs b/ColorControl/ExceptionExtensions.cs new file mode 100644 index 0000000..8feafdb --- /dev/null +++ b/ColorControl/ExceptionExtensions.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace ColorControl +{ + + /// + /// Extension methods for Exception class. + /// + static class ExceptionExtensions + { + /// + /// Provides full stack trace for the exception that occurred. + /// + /// Exception object. + /// Environment stack trace, for pulling additional stack frames. + public static string ToLogString(this Exception exception, string environmentStackTrace) + { + List environmentStackTraceLines = ExceptionExtensions.GetUserStackTraceLines(environmentStackTrace); + environmentStackTraceLines.RemoveAt(0); + + List stackTraceLines = ExceptionExtensions.GetStackTraceLines(exception.StackTrace); + stackTraceLines.AddRange(environmentStackTraceLines); + + string fullStackTrace = String.Join(Environment.NewLine, stackTraceLines); + + string logMessage = exception.Message + Environment.NewLine + fullStackTrace; + return logMessage; + } + + /// + /// Gets a list of stack frame lines, as strings. + /// + /// Stack trace string. + private static List GetStackTraceLines(string stackTrace) + { + return stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList(); + } + + /// + /// Gets a list of stack frame lines, as strings, only including those for which line number is known. + /// + /// Full stack trace, including external code. + private static List GetUserStackTraceLines(string fullStackTrace) + { + List outputList = new List(); + Regex regex = new Regex(@"([^\)]*\)) in (.*):line (\d)*$"); + + List stackTraceLines = ExceptionExtensions.GetStackTraceLines(fullStackTrace); + foreach (string stackTraceLine in stackTraceLines) + { + if (!regex.IsMatch(stackTraceLine)) + { + continue; + } + + outputList.Add(stackTraceLine); + } + + return outputList; + } + } +} diff --git a/ColorControl/LgPreset.cs b/ColorControl/LgPreset.cs new file mode 100644 index 0000000..e7f59a4 --- /dev/null +++ b/ColorControl/LgPreset.cs @@ -0,0 +1,70 @@ +using LgTv; +using System.Collections.Generic; +using System.Linq; + +namespace ColorControl +{ + class LgPreset : PresetBase + { + public string name { get; set; } + public string appId { get; set; } + public List steps { get; set; } + + public static List LgApps { get; set; } + + public LgPreset() + { + steps = new List(); + } + + public LgPreset(LgPreset preset) : this() + { + id = GetNewId(); + name = preset.name + " (copy)"; + appId = preset.appId; + + foreach (var step in preset.steps) + { + steps.Add(step); + } + } + + public LgPreset Clone() + { + var preset = new LgPreset(this); + + return preset; + } + + public static List GetColumnNames() + { + return new List() { "Name", "App|200", "Steps|400", "Shortcut" }; + } + + public List GetDisplayValues() + { + var values = new List(); + + values.Add(name); + var app = appId; + if (LgApps != null) + { + var item = LgApps.FirstOrDefault(x => x.appId.Equals(appId)); + if (item != null) + { + app = item.title + " (" + appId + ")"; + } + } + values.Add(app); + values.Add(GetStepsDisplay()); + values.Add(shortcut); + + return values; + } + + public string GetStepsDisplay() + { + return steps.Aggregate("", (a, b) => (string.IsNullOrEmpty(a) ? "" : a + ", ") + b); + } + } +} diff --git a/ColorControl/LgPresets.json b/ColorControl/LgPresets.json new file mode 100644 index 0000000..2ded776 --- /dev/null +++ b/ColorControl/LgPresets.json @@ -0,0 +1 @@ +[{"name":"mode1","appId":"com.palm.app.settings","steps":["RIGHT:500","ENTER:1000","ENTER","DOWN","DOWN","DOWN","DOWN","DOWN","DOWN","DOWN","ENTER","EXIT"],"shortcut":"","id":33675143},{"name":"mode2","appId":"com.palm.app.settings","steps":["RIGHT:500","ENTER:1000","ENTER","DOWN","DOWN","DOWN","DOWN","DOWN","DOWN","DOWN","DOWN","ENTER","EXIT"],"shortcut":"","id":34640832},{"name":"oledDown","appId":"com.palm.app.settings","steps":["RIGHT:500","ENTER:1000","DOWN","ENTER","ENTER","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","EXIT"],"shortcut":"","id":43332040},{"name":"oledUp","appId":"com.palm.app.settings","steps":["RIGHT:500","ENTER:1000","DOWN","ENTER","ENTER","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","EXIT"],"shortcut":"","id":54444047},{"name":"screenOff","appId":"com.palm.app.settings","steps":["RIGHT:500","DOWN","DOWN","ENTER","DOWN","DOWN","DOWN","DOWN","DOWN","ENTER"],"shortcut":"","id":20234383},{"name":"hdrCinemaHome","appId":"com.palm.app.settings","steps":["RIGHT:500","ENTER:1000","ENTER","DOWN","DOWN","ENTER","EXIT"],"shortcut":"","id":47891719},{"name":"hdrCinema","appId":"com.palm.app.settings","steps":["RIGHT:500","ENTER:1000","ENTER","DOWN","DOWN","DOWN","ENTER","EXIT"],"shortcut":"","id":28372289},{"name":"inputPC","appId":"com.webos.app.homeconnect","steps":["UP","ENTER:1000","DOWN","ENTER:1000","DOWN","DOWN","DOWN","DOWN","DOWN","DOWN","DOWN","DOWN","DOWN","ENTER","UP","RIGHT","ENTER:1000","EXIT"],"shortcut":null,"id":54024015},{"name":"inputGameConsole","appId":"com.webos.app.homeconnect","steps":["UP","ENTER:1000","DOWN","ENTER:1000","DOWN","DOWN","DOWN","DOWN","DOWN","DOWN","ENTER","UP","RIGHT","ENTER:1000","EXIT"],"shortcut":null,"id":16454088},{"name":"oledDown (20)","appId":"com.palm.app.settings","steps":["RIGHT:500","ENTER:1000","DOWN","ENTER","ENTER","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","LEFT","EXIT"],"shortcut":"","id":-1681896321},{"name":"oledUp (20)","appId":"com.palm.app.settings","steps":["RIGHT:500","ENTER:1000","DOWN","ENTER","ENTER","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","RIGHT","EXIT"],"shortcut":"","id":-694559408},{"name":"HDMI1","appId":"com.webos.app.hdmi1","steps":[],"shortcut":"","id":40041277}] \ No newline at end of file diff --git a/ColorControl/LgService.cs b/ColorControl/LgService.cs new file mode 100644 index 0000000..eab0044 --- /dev/null +++ b/ColorControl/LgService.cs @@ -0,0 +1,182 @@ +using LgTv; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using Windows.Data.Json; + +namespace ColorControl +{ + class LgService + { + public static string LgControllerExe = "LgController.exe"; + public static string LgListAppsJson = "listApps.json"; + + private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + public string FriendlyScreenName { get; private set; } + + public List Devices { get; private set; } + public PnpDev SelectedDevice { get; set; } + + private LgTvApi _lgTvApi; + + public LgService() + { + foreach (var screen in Screen.AllScreens) + { + var name = screen.DeviceFriendlyName(); + if (name.Contains("LG")) + { + FriendlyScreenName = name; + } + } + + RefreshDevices(); + } + + ~LgService() + { + } + + public void RefreshDevices(Action callBack = null) + { + Utils.GetPnpDevices("[LG]", Utils.PKEY_PNPX_IpAddress).ContinueWith((task) => + { + SetDevicesTask(task); + callBack?.Invoke(); + if (callBack == null && SelectedDevice != null) + { + ConnectToSelectedDevice(); + } + } + ); + } + + private void SetDevicesTask(Task> task) + { + Devices = task.Result; + if (Devices?.Count > 0) + { + SelectedDevice = Devices[0]; + } + } + + public async Task ConnectToSelectedDevice(int retries = 1) + { + try + { + DisposeConnection(); + _lgTvApi = await LgTvApi.CreateLgTvApi(SelectedDevice.ipAddress, retries); + return true; + } + catch (Exception ex) + { + string logMessage = ex.ToLogString(Environment.StackTrace); + Logger.Error($"Error while connecting to {SelectedDevice.ipAddress}: {logMessage}"); + return false; + } + } + + public async Task ApplyPreset(LgPreset preset, bool reconnect = false) + { + if (SelectedDevice == null) + { + Logger.Debug("Cannot apply LG-preset: no device has been selected"); + return false; + } + + if (reconnect || _lgTvApi == null || !string.Equals(_lgTvApi.GetIpAddress(), SelectedDevice.ipAddress)) + { + if (!await ConnectToSelectedDevice()) + { + Logger.Debug("Cannot apply LG-preset: no connection could be made"); + return false; + } + } + + var hasApp = !string.IsNullOrEmpty(preset.appId); + + if (hasApp) + { + await _lgTvApi.LaunchApp(preset.appId); + } + + if (preset.steps.Any()) + { + if (hasApp) + { + await Task.Delay(1500); + } + try + { + await ExecuteSteps(_lgTvApi, preset); + } + catch (Exception ex) + { + string logMessage = ex.ToLogString(Environment.StackTrace); + Logger.Error("Error while executing steps: " + logMessage); + return false; + } + } + + return true; + } + + private async Task ExecuteSteps(LgTvApi api, LgPreset preset) + { + var mouse = await api.GetMouse(); + foreach (var step in preset.steps) + { + var keySpec = step.Split(':'); + if (keySpec.Length == 2) + { + SendKey(mouse, keySpec[0], int.Parse(keySpec[1])); + } + else + { + SendKey(mouse, keySpec[0]); + } + } + } + + private void SendKey(LgWebOsMouseService mouse, string key, int delay = 180) + { + if (key.Length == 1 && int.TryParse(key, out _)) + { + key = "_" + key; + } + var button = (ButtonType)Enum.Parse(typeof(ButtonType), key); + mouse.SendButton(button); + Thread.Sleep(delay); + } + + public async Task> RefreshApps(bool force = false) + { + if (SelectedDevice == null) + { + Logger.Debug("Cannot refresh apps: no device has been selected"); + return null; + } + + var api = await LgTvApi.CreateLgTvApi(SelectedDevice.ipAddress); + var list = await api.GetApps(force); + + return list.ToList(); + } + + internal void DisposeConnection() + { + if (_lgTvApi != null) + { + _lgTvApi.Dispose(); + _lgTvApi = null; + } + } + } +} diff --git a/ColorControl/MainForm.Designer.cs b/ColorControl/MainForm.Designer.cs new file mode 100644 index 0000000..075fca9 --- /dev/null +++ b/ColorControl/MainForm.Designer.cs @@ -0,0 +1,971 @@ +namespace ColorControl +{ + partial class MainForm + { + /// + /// 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(MainForm)); + this.tcMain = new System.Windows.Forms.TabControl(); + this.tabNVIDIA = new System.Windows.Forms.TabPage(); + this.btnAddModesNv = new System.Windows.Forms.Button(); + this.btnNvPresetDelete = new System.Windows.Forms.Button(); + this.lblError = new System.Windows.Forms.Label(); + this.btnClone = new System.Windows.Forms.Button(); + this.btnSetShortcut = new System.Windows.Forms.Button(); + this.lblShortcut = new System.Windows.Forms.Label(); + this.edtShortcut = new System.Windows.Forms.TextBox(); + this.btnChange = new System.Windows.Forms.Button(); + this.mnuNvPresets = new System.Windows.Forms.ContextMenuStrip(this.components); + this.miNvApply = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuNvDisplay = new System.Windows.Forms.ToolStripMenuItem(); + this.miNvPrimaryDisplay = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuNvPresetsColorSettings = new System.Windows.Forms.ToolStripMenuItem(); + this.miNvPresetColorSettings = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuRefreshRate = new System.Windows.Forms.ToolStripMenuItem(); + this.miRefreshRateIncluded = new System.Windows.Forms.ToolStripMenuItem(); + this.miNvPresetDithering = new System.Windows.Forms.ToolStripMenuItem(); + this.miNvPresetApplyDithering = new System.Windows.Forms.ToolStripMenuItem(); + this.miNvPresetDitheringEnabled = new System.Windows.Forms.ToolStripMenuItem(); + this.miNvHDR = new System.Windows.Forms.ToolStripMenuItem(); + this.miHDRIncluded = new System.Windows.Forms.ToolStripMenuItem(); + this.miToggleHDR = new System.Windows.Forms.ToolStripMenuItem(); + this.miHDREnabled = new System.Windows.Forms.ToolStripMenuItem(); + this.btnApply = new System.Windows.Forms.Button(); + this.lvNvPresets = new System.Windows.Forms.ListView(); + this.tabLG = new System.Windows.Forms.TabPage(); + this.btnLgAddButton = new System.Windows.Forms.Button(); + this.mnuLgButtons = new System.Windows.Forms.ContextMenuStrip(this.components); + this.label3 = new System.Windows.Forms.Label(); + this.cbxLgDevices = new System.Windows.Forms.ComboBox(); + this.btnLgRefreshApps = new System.Windows.Forms.Button(); + this.btnAddLg = new System.Windows.Forms.Button(); + this.btnDeleteLg = new System.Windows.Forms.Button(); + this.cbxLgApps = new System.Windows.Forms.ComboBox(); + this.label5 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.edtLgTvName = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.edtNameLg = new System.Windows.Forms.TextBox(); + this.edtStepsLg = new System.Windows.Forms.TextBox(); + this.lblStepsLg = new System.Windows.Forms.Label(); + this.lblLgError = new System.Windows.Forms.Label(); + this.btnCloneLg = new System.Windows.Forms.Button(); + this.btnSetShortcutLg = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.edtShortcutLg = new System.Windows.Forms.TextBox(); + this.btnApplyLg = new System.Windows.Forms.Button(); + this.lvLgPresets = new System.Windows.Forms.ListView(); + this.tabOptions = new System.Windows.Forms.TabPage(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.edtDelayDisplaySettings = new System.Windows.Forms.NumericUpDown(); + this.label6 = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.chkStartMinimized = new System.Windows.Forms.CheckBox(); + this.chkStartAfterLogin = new System.Windows.Forms.CheckBox(); + this.tabLog = new System.Windows.Forms.TabPage(); + this.edtLog = new System.Windows.Forms.TextBox(); + this.tabInfo = new System.Windows.Forms.TabPage(); + this.grpNVIDIAInfo = new System.Windows.Forms.GroupBox(); + this.btnRefreshNVIDIAInfo = new System.Windows.Forms.Button(); + this.tvNVIDIAInfo = new System.Windows.Forms.TreeView(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.lbPlugins = new System.Windows.Forms.ListBox(); + this.label7 = new System.Windows.Forms.Label(); + this.lblInfo = new System.Windows.Forms.Label(); + this.tcMain.SuspendLayout(); + this.tabNVIDIA.SuspendLayout(); + this.mnuNvPresets.SuspendLayout(); + this.tabLG.SuspendLayout(); + this.tabOptions.SuspendLayout(); + this.groupBox2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.edtDelayDisplaySettings)).BeginInit(); + this.groupBox1.SuspendLayout(); + this.tabLog.SuspendLayout(); + this.tabInfo.SuspendLayout(); + this.grpNVIDIAInfo.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.SuspendLayout(); + // + // tcMain + // + this.tcMain.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tcMain.Controls.Add(this.tabNVIDIA); + this.tcMain.Controls.Add(this.tabLG); + this.tcMain.Controls.Add(this.tabOptions); + this.tcMain.Controls.Add(this.tabLog); + this.tcMain.Controls.Add(this.tabInfo); + this.tcMain.Location = new System.Drawing.Point(12, 12); + this.tcMain.Name = "tcMain"; + this.tcMain.SelectedIndex = 0; + this.tcMain.Size = new System.Drawing.Size(849, 532); + this.tcMain.TabIndex = 3; + this.tcMain.SelectedIndexChanged += new System.EventHandler(this.tabControl1_SelectedIndexChanged); + // + // tabNVIDIA + // + this.tabNVIDIA.Controls.Add(this.btnAddModesNv); + this.tabNVIDIA.Controls.Add(this.btnNvPresetDelete); + this.tabNVIDIA.Controls.Add(this.lblError); + this.tabNVIDIA.Controls.Add(this.btnClone); + this.tabNVIDIA.Controls.Add(this.btnSetShortcut); + this.tabNVIDIA.Controls.Add(this.lblShortcut); + this.tabNVIDIA.Controls.Add(this.edtShortcut); + this.tabNVIDIA.Controls.Add(this.btnChange); + this.tabNVIDIA.Controls.Add(this.btnApply); + this.tabNVIDIA.Controls.Add(this.lvNvPresets); + this.tabNVIDIA.Location = new System.Drawing.Point(4, 22); + this.tabNVIDIA.Name = "tabNVIDIA"; + this.tabNVIDIA.Padding = new System.Windows.Forms.Padding(3); + this.tabNVIDIA.Size = new System.Drawing.Size(841, 506); + this.tabNVIDIA.TabIndex = 0; + this.tabNVIDIA.Text = "NVIDIA controller"; + this.tabNVIDIA.UseVisualStyleBackColor = true; + // + // btnAddModesNv + // + this.btnAddModesNv.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnAddModesNv.Location = new System.Drawing.Point(574, 477); + this.btnAddModesNv.Name = "btnAddModesNv"; + this.btnAddModesNv.Size = new System.Drawing.Size(75, 23); + this.btnAddModesNv.TabIndex = 9; + this.btnAddModesNv.Text = "Add modes"; + this.btnAddModesNv.UseVisualStyleBackColor = true; + this.btnAddModesNv.Click += new System.EventHandler(this.btnAddModesNv_Click); + // + // btnNvPresetDelete + // + this.btnNvPresetDelete.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnNvPresetDelete.Enabled = false; + this.btnNvPresetDelete.Location = new System.Drawing.Point(493, 477); + this.btnNvPresetDelete.Name = "btnNvPresetDelete"; + this.btnNvPresetDelete.Size = new System.Drawing.Size(75, 23); + this.btnNvPresetDelete.TabIndex = 8; + this.btnNvPresetDelete.Text = "Delete"; + this.btnNvPresetDelete.UseVisualStyleBackColor = true; + this.btnNvPresetDelete.Click += new System.EventHandler(this.btnNvPresetDelete_Click); + // + // lblError + // + this.lblError.AutoSize = true; + this.lblError.Location = new System.Drawing.Point(6, 6); + this.lblError.Name = "lblError"; + this.lblError.Size = new System.Drawing.Size(50, 13); + this.lblError.TabIndex = 7; + this.lblError.Text = "ErrorText"; + this.lblError.Visible = false; + // + // btnClone + // + this.btnClone.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnClone.Enabled = false; + this.btnClone.Location = new System.Drawing.Point(412, 477); + this.btnClone.Name = "btnClone"; + this.btnClone.Size = new System.Drawing.Size(75, 23); + this.btnClone.TabIndex = 6; + this.btnClone.Text = "Clone"; + this.btnClone.UseVisualStyleBackColor = true; + this.btnClone.Click += new System.EventHandler(this.btnClone_Click); + // + // btnSetShortcut + // + this.btnSetShortcut.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnSetShortcut.Enabled = false; + this.btnSetShortcut.Location = new System.Drawing.Point(372, 477); + this.btnSetShortcut.Name = "btnSetShortcut"; + this.btnSetShortcut.Size = new System.Drawing.Size(34, 23); + this.btnSetShortcut.TabIndex = 5; + this.btnSetShortcut.Text = "Set"; + this.btnSetShortcut.UseVisualStyleBackColor = true; + this.btnSetShortcut.Click += new System.EventHandler(this.btnSetShortcut_Click); + // + // lblShortcut + // + this.lblShortcut.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.lblShortcut.AutoSize = true; + this.lblShortcut.Location = new System.Drawing.Point(168, 482); + this.lblShortcut.Name = "lblShortcut"; + this.lblShortcut.Size = new System.Drawing.Size(50, 13); + this.lblShortcut.TabIndex = 4; + this.lblShortcut.Text = "Shortcut:"; + // + // edtShortcut + // + this.edtShortcut.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.edtShortcut.Enabled = false; + this.edtShortcut.Location = new System.Drawing.Point(224, 479); + this.edtShortcut.Name = "edtShortcut"; + this.edtShortcut.ReadOnly = true; + this.edtShortcut.Size = new System.Drawing.Size(142, 20); + this.edtShortcut.TabIndex = 3; + this.edtShortcut.TextChanged += new System.EventHandler(this.edtShortcut_TextChanged); + this.edtShortcut.KeyDown += new System.Windows.Forms.KeyEventHandler(this.edtShortcut_KeyDown); + this.edtShortcut.KeyUp += new System.Windows.Forms.KeyEventHandler(this.edtShortcut_KeyUp); + // + // btnChange + // + this.btnChange.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnChange.ContextMenuStrip = this.mnuNvPresets; + this.btnChange.Enabled = false; + this.btnChange.Location = new System.Drawing.Point(87, 477); + this.btnChange.Name = "btnChange"; + this.btnChange.Size = new System.Drawing.Size(75, 23); + this.btnChange.TabIndex = 2; + this.btnChange.Text = "Change..."; + this.btnChange.UseVisualStyleBackColor = true; + this.btnChange.Click += new System.EventHandler(this.btnChange_Click); + // + // mnuNvPresets + // + this.mnuNvPresets.ImageScalingSize = new System.Drawing.Size(20, 20); + this.mnuNvPresets.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.miNvApply, + this.toolStripSeparator1, + this.mnuNvDisplay, + this.mnuNvPresetsColorSettings, + this.mnuRefreshRate, + this.miNvPresetDithering, + this.miNvHDR}); + this.mnuNvPresets.Name = "mnuNvPresets"; + this.mnuNvPresets.Size = new System.Drawing.Size(148, 142); + this.mnuNvPresets.Opening += new System.ComponentModel.CancelEventHandler(this.mnuNvPresets_Opening); + // + // miNvApply + // + this.miNvApply.Name = "miNvApply"; + this.miNvApply.Size = new System.Drawing.Size(147, 22); + this.miNvApply.Text = "Apply"; + this.miNvApply.Click += new System.EventHandler(this.miNvApply_Click); + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(144, 6); + // + // mnuNvDisplay + // + this.mnuNvDisplay.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.miNvPrimaryDisplay}); + this.mnuNvDisplay.Name = "mnuNvDisplay"; + this.mnuNvDisplay.Size = new System.Drawing.Size(147, 22); + this.mnuNvDisplay.Text = "Display"; + // + // miNvPrimaryDisplay + // + this.miNvPrimaryDisplay.Name = "miNvPrimaryDisplay"; + this.miNvPrimaryDisplay.Size = new System.Drawing.Size(155, 22); + this.miNvPrimaryDisplay.Text = "Primary display"; + this.miNvPrimaryDisplay.Click += new System.EventHandler(this.displayMenuItem_Click); + // + // mnuNvPresetsColorSettings + // + this.mnuNvPresetsColorSettings.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.miNvPresetColorSettings}); + this.mnuNvPresetsColorSettings.Name = "mnuNvPresetsColorSettings"; + this.mnuNvPresetsColorSettings.Size = new System.Drawing.Size(147, 22); + this.mnuNvPresetsColorSettings.Text = "Color settings"; + // + // miNvPresetColorSettings + // + this.miNvPresetColorSettings.Name = "miNvPresetColorSettings"; + this.miNvPresetColorSettings.Size = new System.Drawing.Size(120, 22); + this.miNvPresetColorSettings.Text = "Included"; + this.miNvPresetColorSettings.Click += new System.EventHandler(this.miNvPresetColorSettings_Click); + // + // mnuRefreshRate + // + this.mnuRefreshRate.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.miRefreshRateIncluded}); + this.mnuRefreshRate.Name = "mnuRefreshRate"; + this.mnuRefreshRate.Size = new System.Drawing.Size(147, 22); + this.mnuRefreshRate.Text = "Refresh Rate"; + // + // miRefreshRateIncluded + // + this.miRefreshRateIncluded.Name = "miRefreshRateIncluded"; + this.miRefreshRateIncluded.Size = new System.Drawing.Size(120, 22); + this.miRefreshRateIncluded.Text = "Included"; + this.miRefreshRateIncluded.Click += new System.EventHandler(this.includedToolStripMenuItem_Click); + // + // miNvPresetDithering + // + this.miNvPresetDithering.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.miNvPresetApplyDithering, + this.miNvPresetDitheringEnabled}); + this.miNvPresetDithering.Name = "miNvPresetDithering"; + this.miNvPresetDithering.Size = new System.Drawing.Size(147, 22); + this.miNvPresetDithering.Text = "Dithering"; + // + // miNvPresetApplyDithering + // + this.miNvPresetApplyDithering.Name = "miNvPresetApplyDithering"; + this.miNvPresetApplyDithering.Size = new System.Drawing.Size(120, 22); + this.miNvPresetApplyDithering.Text = "Included"; + this.miNvPresetApplyDithering.Click += new System.EventHandler(this.miNvPresetApplyDithering_Click); + // + // miNvPresetDitheringEnabled + // + this.miNvPresetDitheringEnabled.Name = "miNvPresetDitheringEnabled"; + this.miNvPresetDitheringEnabled.Size = new System.Drawing.Size(120, 22); + this.miNvPresetDitheringEnabled.Text = "Enabled"; + this.miNvPresetDitheringEnabled.Click += new System.EventHandler(this.miNvPresetDitheringEnabled_Click); + // + // miNvHDR + // + this.miNvHDR.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.miHDRIncluded, + this.miToggleHDR, + this.miHDREnabled}); + this.miNvHDR.Name = "miNvHDR"; + this.miNvHDR.Size = new System.Drawing.Size(147, 22); + this.miNvHDR.Text = "HDR"; + // + // miHDRIncluded + // + this.miHDRIncluded.Name = "miHDRIncluded"; + this.miHDRIncluded.Size = new System.Drawing.Size(136, 22); + this.miHDRIncluded.Text = "Included"; + this.miHDRIncluded.Click += new System.EventHandler(this.miHDRIncluded_Click); + // + // miToggleHDR + // + this.miToggleHDR.Name = "miToggleHDR"; + this.miToggleHDR.Size = new System.Drawing.Size(136, 22); + this.miToggleHDR.Text = "Toggle HDR"; + this.miToggleHDR.Click += new System.EventHandler(this.miToggleHDR_Click); + // + // miHDREnabled + // + this.miHDREnabled.Name = "miHDREnabled"; + this.miHDREnabled.Size = new System.Drawing.Size(136, 22); + this.miHDREnabled.Text = "Enabled"; + this.miHDREnabled.Click += new System.EventHandler(this.miHDREnabled_Click); + // + // btnApply + // + this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnApply.Enabled = false; + this.btnApply.Location = new System.Drawing.Point(6, 477); + this.btnApply.Name = "btnApply"; + this.btnApply.Size = new System.Drawing.Size(75, 23); + this.btnApply.TabIndex = 1; + this.btnApply.Text = "Apply"; + this.btnApply.UseVisualStyleBackColor = true; + this.btnApply.Click += new System.EventHandler(this.btnApply_Click); + // + // lvNvPresets + // + this.lvNvPresets.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lvNvPresets.ContextMenuStrip = this.mnuNvPresets; + this.lvNvPresets.FullRowSelect = true; + this.lvNvPresets.HideSelection = false; + this.lvNvPresets.Location = new System.Drawing.Point(6, 6); + this.lvNvPresets.MultiSelect = false; + this.lvNvPresets.Name = "lvNvPresets"; + this.lvNvPresets.Size = new System.Drawing.Size(829, 465); + this.lvNvPresets.TabIndex = 0; + this.lvNvPresets.UseCompatibleStateImageBehavior = false; + this.lvNvPresets.View = System.Windows.Forms.View.Details; + this.lvNvPresets.SelectedIndexChanged += new System.EventHandler(this.lvNvPresets_SelectedIndexChanged); + this.lvNvPresets.DoubleClick += new System.EventHandler(this.lvNvPresets_DoubleClick); + // + // tabLG + // + this.tabLG.Controls.Add(this.btnLgAddButton); + this.tabLG.Controls.Add(this.label3); + this.tabLG.Controls.Add(this.cbxLgDevices); + this.tabLG.Controls.Add(this.btnLgRefreshApps); + this.tabLG.Controls.Add(this.btnAddLg); + this.tabLG.Controls.Add(this.btnDeleteLg); + this.tabLG.Controls.Add(this.cbxLgApps); + this.tabLG.Controls.Add(this.label5); + this.tabLG.Controls.Add(this.label4); + this.tabLG.Controls.Add(this.edtLgTvName); + this.tabLG.Controls.Add(this.label1); + this.tabLG.Controls.Add(this.edtNameLg); + this.tabLG.Controls.Add(this.edtStepsLg); + this.tabLG.Controls.Add(this.lblStepsLg); + this.tabLG.Controls.Add(this.lblLgError); + this.tabLG.Controls.Add(this.btnCloneLg); + this.tabLG.Controls.Add(this.btnSetShortcutLg); + this.tabLG.Controls.Add(this.label2); + this.tabLG.Controls.Add(this.edtShortcutLg); + this.tabLG.Controls.Add(this.btnApplyLg); + this.tabLG.Controls.Add(this.lvLgPresets); + this.tabLG.Location = new System.Drawing.Point(4, 22); + this.tabLG.Name = "tabLG"; + this.tabLG.Padding = new System.Windows.Forms.Padding(3); + this.tabLG.Size = new System.Drawing.Size(841, 506); + this.tabLG.TabIndex = 1; + this.tabLG.Text = "LG controller"; + this.tabLG.UseVisualStyleBackColor = true; + // + // btnLgAddButton + // + this.btnLgAddButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnLgAddButton.ContextMenuStrip = this.mnuLgButtons; + this.btnLgAddButton.Enabled = false; + this.btnLgAddButton.Location = new System.Drawing.Point(760, 460); + this.btnLgAddButton.Name = "btnLgAddButton"; + this.btnLgAddButton.Size = new System.Drawing.Size(75, 23); + this.btnLgAddButton.TabIndex = 32; + this.btnLgAddButton.Text = "Add button"; + this.btnLgAddButton.UseVisualStyleBackColor = true; + this.btnLgAddButton.Click += new System.EventHandler(this.btnLgAddButton_Click); + // + // mnuLgButtons + // + this.mnuLgButtons.ImageScalingSize = new System.Drawing.Size(20, 20); + this.mnuLgButtons.Name = "mnuLgButtons"; + this.mnuLgButtons.Size = new System.Drawing.Size(61, 4); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(44, 13); + this.label3.TabIndex = 31; + this.label3.Text = "Device:"; + // + // cbxLgDevices + // + this.cbxLgDevices.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbxLgDevices.FormattingEnabled = true; + this.cbxLgDevices.Location = new System.Drawing.Point(87, 6); + this.cbxLgDevices.Name = "cbxLgDevices"; + this.cbxLgDevices.Size = new System.Drawing.Size(281, 21); + this.cbxLgDevices.TabIndex = 30; + this.cbxLgDevices.SelectedIndexChanged += new System.EventHandler(this.cbxLgDevices_SelectedIndexChanged); + // + // btnLgRefreshApps + // + this.btnLgRefreshApps.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnLgRefreshApps.Location = new System.Drawing.Point(293, 407); + this.btnLgRefreshApps.Name = "btnLgRefreshApps"; + this.btnLgRefreshApps.Size = new System.Drawing.Size(75, 23); + this.btnLgRefreshApps.TabIndex = 29; + this.btnLgRefreshApps.Text = "Refresh"; + this.btnLgRefreshApps.UseVisualStyleBackColor = true; + this.btnLgRefreshApps.Click += new System.EventHandler(this.btnLgRefreshApps_Click); + // + // btnAddLg + // + this.btnAddLg.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnAddLg.Location = new System.Drawing.Point(168, 354); + this.btnAddLg.Name = "btnAddLg"; + this.btnAddLg.Size = new System.Drawing.Size(75, 23); + this.btnAddLg.TabIndex = 28; + this.btnAddLg.Text = "Add"; + this.btnAddLg.UseVisualStyleBackColor = true; + this.btnAddLg.Click += new System.EventHandler(this.btnAddLg_Click); + // + // btnDeleteLg + // + this.btnDeleteLg.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnDeleteLg.Enabled = false; + this.btnDeleteLg.Location = new System.Drawing.Point(249, 354); + this.btnDeleteLg.Name = "btnDeleteLg"; + this.btnDeleteLg.Size = new System.Drawing.Size(75, 23); + this.btnDeleteLg.TabIndex = 27; + this.btnDeleteLg.Text = "Delete"; + this.btnDeleteLg.UseVisualStyleBackColor = true; + this.btnDeleteLg.Click += new System.EventHandler(this.btnDeleteLg_Click); + // + // cbxLgApps + // + this.cbxLgApps.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.cbxLgApps.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbxLgApps.Enabled = false; + this.cbxLgApps.FormattingEnabled = true; + this.cbxLgApps.Location = new System.Drawing.Point(87, 409); + this.cbxLgApps.Name = "cbxLgApps"; + this.cbxLgApps.Size = new System.Drawing.Size(200, 21); + this.cbxLgApps.TabIndex = 26; + // + // label5 + // + this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(6, 412); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(29, 13); + this.label5.TabIndex = 25; + this.label5.Text = "App:"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(384, 10); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(110, 13); + this.label4.TabIndex = 24; + this.label4.Text = "Friendly screen name:"; + // + // edtLgTvName + // + this.edtLgTvName.Enabled = false; + this.edtLgTvName.Location = new System.Drawing.Point(497, 7); + this.edtLgTvName.Name = "edtLgTvName"; + this.edtLgTvName.Size = new System.Drawing.Size(142, 20); + this.edtLgTvName.TabIndex = 23; + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 386); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(38, 13); + this.label1.TabIndex = 20; + this.label1.Text = "Name:"; + // + // edtNameLg + // + this.edtNameLg.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.edtNameLg.Enabled = false; + this.edtNameLg.Location = new System.Drawing.Point(87, 383); + this.edtNameLg.Name = "edtNameLg"; + this.edtNameLg.Size = new System.Drawing.Size(200, 20); + this.edtNameLg.TabIndex = 19; + // + // edtStepsLg + // + this.edtStepsLg.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.edtStepsLg.Enabled = false; + this.edtStepsLg.Location = new System.Drawing.Point(87, 462); + this.edtStepsLg.Multiline = true; + this.edtStepsLg.Name = "edtStepsLg"; + this.edtStepsLg.Size = new System.Drawing.Size(667, 37); + this.edtStepsLg.TabIndex = 17; + // + // lblStepsLg + // + this.lblStepsLg.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.lblStepsLg.AutoSize = true; + this.lblStepsLg.Location = new System.Drawing.Point(6, 465); + this.lblStepsLg.Name = "lblStepsLg"; + this.lblStepsLg.Size = new System.Drawing.Size(37, 13); + this.lblStepsLg.TabIndex = 16; + this.lblStepsLg.Text = "Steps:"; + // + // lblLgError + // + this.lblLgError.AutoSize = true; + this.lblLgError.Location = new System.Drawing.Point(6, 6); + this.lblLgError.Name = "lblLgError"; + this.lblLgError.Size = new System.Drawing.Size(50, 13); + this.lblLgError.TabIndex = 15; + this.lblLgError.Text = "ErrorText"; + this.lblLgError.Visible = false; + // + // btnCloneLg + // + this.btnCloneLg.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnCloneLg.Enabled = false; + this.btnCloneLg.Location = new System.Drawing.Point(87, 354); + this.btnCloneLg.Name = "btnCloneLg"; + this.btnCloneLg.Size = new System.Drawing.Size(75, 23); + this.btnCloneLg.TabIndex = 14; + this.btnCloneLg.Text = "Clone"; + this.btnCloneLg.UseVisualStyleBackColor = true; + this.btnCloneLg.Click += new System.EventHandler(this.btnCloneLg_Click); + // + // btnSetShortcutLg + // + this.btnSetShortcutLg.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnSetShortcutLg.Enabled = false; + this.btnSetShortcutLg.Location = new System.Drawing.Point(330, 354); + this.btnSetShortcutLg.Name = "btnSetShortcutLg"; + this.btnSetShortcutLg.Size = new System.Drawing.Size(75, 23); + this.btnSetShortcutLg.TabIndex = 13; + this.btnSetShortcutLg.Text = "Save"; + this.btnSetShortcutLg.UseVisualStyleBackColor = true; + this.btnSetShortcutLg.Click += new System.EventHandler(this.btnSetShortcutLg_Click); + // + // label2 + // + this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 439); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(50, 13); + this.label2.TabIndex = 12; + this.label2.Text = "Shortcut:"; + // + // edtShortcutLg + // + this.edtShortcutLg.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.edtShortcutLg.Enabled = false; + this.edtShortcutLg.Location = new System.Drawing.Point(87, 436); + this.edtShortcutLg.Name = "edtShortcutLg"; + this.edtShortcutLg.ReadOnly = true; + this.edtShortcutLg.Size = new System.Drawing.Size(200, 20); + this.edtShortcutLg.TabIndex = 11; + this.edtShortcutLg.KeyDown += new System.Windows.Forms.KeyEventHandler(this.edtShortcut_KeyDown); + this.edtShortcutLg.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.edtShortcut_KeyPress); + // + // btnApplyLg + // + this.btnApplyLg.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnApplyLg.Enabled = false; + this.btnApplyLg.Location = new System.Drawing.Point(6, 354); + this.btnApplyLg.Name = "btnApplyLg"; + this.btnApplyLg.Size = new System.Drawing.Size(75, 23); + this.btnApplyLg.TabIndex = 9; + this.btnApplyLg.Text = "Apply"; + this.btnApplyLg.UseVisualStyleBackColor = true; + this.btnApplyLg.Click += new System.EventHandler(this.btnApplyLg_Click); + // + // lvLgPresets + // + this.lvLgPresets.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lvLgPresets.FullRowSelect = true; + this.lvLgPresets.HideSelection = false; + this.lvLgPresets.Location = new System.Drawing.Point(6, 33); + this.lvLgPresets.MultiSelect = false; + this.lvLgPresets.Name = "lvLgPresets"; + this.lvLgPresets.Size = new System.Drawing.Size(829, 315); + this.lvLgPresets.TabIndex = 8; + this.lvLgPresets.UseCompatibleStateImageBehavior = false; + this.lvLgPresets.View = System.Windows.Forms.View.Details; + this.lvLgPresets.SelectedIndexChanged += new System.EventHandler(this.lvLgPresets_SelectedIndexChanged); + this.lvLgPresets.DoubleClick += new System.EventHandler(this.lvLgPresets_DoubleClick); + // + // tabOptions + // + this.tabOptions.Controls.Add(this.groupBox2); + this.tabOptions.Controls.Add(this.groupBox1); + this.tabOptions.Location = new System.Drawing.Point(4, 22); + this.tabOptions.Name = "tabOptions"; + this.tabOptions.Padding = new System.Windows.Forms.Padding(3); + this.tabOptions.Size = new System.Drawing.Size(841, 506); + this.tabOptions.TabIndex = 2; + this.tabOptions.Text = "Options"; + this.tabOptions.UseVisualStyleBackColor = true; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.edtDelayDisplaySettings); + this.groupBox2.Controls.Add(this.label6); + this.groupBox2.Location = new System.Drawing.Point(6, 119); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(376, 107); + this.groupBox2.TabIndex = 3; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "HDR"; + // + // edtDelayDisplaySettings + // + this.edtDelayDisplaySettings.Increment = new decimal(new int[] { + 100, + 0, + 0, + 0}); + this.edtDelayDisplaySettings.Location = new System.Drawing.Point(296, 17); + this.edtDelayDisplaySettings.Maximum = new decimal(new int[] { + 5000, + 0, + 0, + 0}); + this.edtDelayDisplaySettings.Name = "edtDelayDisplaySettings"; + this.edtDelayDisplaySettings.ReadOnly = true; + this.edtDelayDisplaySettings.Size = new System.Drawing.Size(74, 20); + this.edtDelayDisplaySettings.TabIndex = 1; + this.edtDelayDisplaySettings.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.edtDelayDisplaySettings.ValueChanged += new System.EventHandler(this.edtDelayDisplaySettings_ValueChanged); + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(6, 19); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(174, 13); + this.label6.TabIndex = 0; + this.label6.Text = "Delay opening display settings (ms):"; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.chkStartMinimized); + this.groupBox1.Controls.Add(this.chkStartAfterLogin); + this.groupBox1.Location = new System.Drawing.Point(6, 6); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(376, 107); + this.groupBox1.TabIndex = 2; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "General"; + // + // chkStartMinimized + // + this.chkStartMinimized.AutoSize = true; + this.chkStartMinimized.Location = new System.Drawing.Point(6, 42); + this.chkStartMinimized.Name = "chkStartMinimized"; + this.chkStartMinimized.Size = new System.Drawing.Size(96, 17); + this.chkStartMinimized.TabIndex = 3; + this.chkStartMinimized.Text = "Start minimized"; + this.chkStartMinimized.UseVisualStyleBackColor = true; + // + // chkStartAfterLogin + // + this.chkStartAfterLogin.AutoSize = true; + this.chkStartAfterLogin.Location = new System.Drawing.Point(6, 19); + this.chkStartAfterLogin.Name = "chkStartAfterLogin"; + this.chkStartAfterLogin.Size = new System.Drawing.Size(160, 17); + this.chkStartAfterLogin.TabIndex = 2; + this.chkStartAfterLogin.Text = "Automatically start after login"; + this.chkStartAfterLogin.UseVisualStyleBackColor = true; + this.chkStartAfterLogin.CheckedChanged += new System.EventHandler(this.chkStartAfterLogin_CheckedChanged); + // + // tabLog + // + this.tabLog.Controls.Add(this.edtLog); + this.tabLog.Location = new System.Drawing.Point(4, 22); + this.tabLog.Name = "tabLog"; + this.tabLog.Padding = new System.Windows.Forms.Padding(3); + this.tabLog.Size = new System.Drawing.Size(841, 506); + this.tabLog.TabIndex = 3; + this.tabLog.Text = "Log"; + this.tabLog.UseVisualStyleBackColor = true; + // + // edtLog + // + this.edtLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.edtLog.Location = new System.Drawing.Point(6, 6); + this.edtLog.Multiline = true; + this.edtLog.Name = "edtLog"; + this.edtLog.ReadOnly = true; + this.edtLog.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.edtLog.Size = new System.Drawing.Size(832, 497); + this.edtLog.TabIndex = 0; + // + // tabInfo + // + this.tabInfo.Controls.Add(this.grpNVIDIAInfo); + this.tabInfo.Controls.Add(this.groupBox3); + this.tabInfo.Location = new System.Drawing.Point(4, 22); + this.tabInfo.Name = "tabInfo"; + this.tabInfo.Padding = new System.Windows.Forms.Padding(3); + this.tabInfo.Size = new System.Drawing.Size(841, 506); + this.tabInfo.TabIndex = 4; + this.tabInfo.Text = "Info"; + this.tabInfo.UseVisualStyleBackColor = true; + // + // grpNVIDIAInfo + // + this.grpNVIDIAInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.grpNVIDIAInfo.Controls.Add(this.btnRefreshNVIDIAInfo); + this.grpNVIDIAInfo.Controls.Add(this.tvNVIDIAInfo); + this.grpNVIDIAInfo.Location = new System.Drawing.Point(397, 6); + this.grpNVIDIAInfo.Name = "grpNVIDIAInfo"; + this.grpNVIDIAInfo.Size = new System.Drawing.Size(440, 496); + this.grpNVIDIAInfo.TabIndex = 4; + this.grpNVIDIAInfo.TabStop = false; + this.grpNVIDIAInfo.Text = "NVIDIA info"; + // + // btnRefreshNVIDIAInfo + // + this.btnRefreshNVIDIAInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnRefreshNVIDIAInfo.Location = new System.Drawing.Point(6, 467); + this.btnRefreshNVIDIAInfo.Name = "btnRefreshNVIDIAInfo"; + this.btnRefreshNVIDIAInfo.Size = new System.Drawing.Size(75, 23); + this.btnRefreshNVIDIAInfo.TabIndex = 1; + this.btnRefreshNVIDIAInfo.Text = "Refresh"; + this.btnRefreshNVIDIAInfo.UseVisualStyleBackColor = true; + this.btnRefreshNVIDIAInfo.Click += new System.EventHandler(this.btnRefreshNVIDIAInfo_Click); + // + // tvNVIDIAInfo + // + this.tvNVIDIAInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tvNVIDIAInfo.Location = new System.Drawing.Point(6, 19); + this.tvNVIDIAInfo.Name = "tvNVIDIAInfo"; + this.tvNVIDIAInfo.Size = new System.Drawing.Size(428, 442); + this.tvNVIDIAInfo.TabIndex = 0; + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.lbPlugins); + this.groupBox3.Controls.Add(this.label7); + this.groupBox3.Controls.Add(this.lblInfo); + this.groupBox3.Location = new System.Drawing.Point(6, 6); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(385, 220); + this.groupBox3.TabIndex = 5; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "Info"; + // + // lbPlugins + // + this.lbPlugins.FormattingEnabled = true; + this.lbPlugins.HorizontalScrollbar = true; + this.lbPlugins.Location = new System.Drawing.Point(9, 67); + this.lbPlugins.Name = "lbPlugins"; + this.lbPlugins.Size = new System.Drawing.Size(371, 147); + this.lbPlugins.TabIndex = 3; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(6, 51); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(236, 13); + this.label7.TabIndex = 2; + this.label7.Text = "This app contains the following 3rd party plugins:"; + // + // lblInfo + // + this.lblInfo.AutoSize = true; + this.lblInfo.Location = new System.Drawing.Point(6, 20); + this.lblInfo.Name = "lblInfo"; + this.lblInfo.Size = new System.Drawing.Size(25, 13); + this.lblInfo.TabIndex = 1; + this.lblInfo.Text = "Info"; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Control; + this.ClientSize = new System.Drawing.Size(873, 556); + this.Controls.Add(this.tcMain); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MinimumSize = new System.Drawing.Size(800, 398); + this.Name = "MainForm"; + this.Text = "ColorControl"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.MainForm_FormClosed); + this.Load += new System.EventHandler(this.MainForm_Load); + this.Shown += new System.EventHandler(this.MainForm_Shown); + this.Resize += new System.EventHandler(this.MainForm_Resize); + this.tcMain.ResumeLayout(false); + this.tabNVIDIA.ResumeLayout(false); + this.tabNVIDIA.PerformLayout(); + this.mnuNvPresets.ResumeLayout(false); + this.tabLG.ResumeLayout(false); + this.tabLG.PerformLayout(); + this.tabOptions.ResumeLayout(false); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.edtDelayDisplaySettings)).EndInit(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.tabLog.ResumeLayout(false); + this.tabLog.PerformLayout(); + this.tabInfo.ResumeLayout(false); + this.grpNVIDIAInfo.ResumeLayout(false); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TabControl tcMain; + private System.Windows.Forms.TabPage tabNVIDIA; + private System.Windows.Forms.TabPage tabLG; + private System.Windows.Forms.ListView lvNvPresets; + private System.Windows.Forms.Button btnApply; + private System.Windows.Forms.Button btnChange; + private System.Windows.Forms.Button btnSetShortcut; + private System.Windows.Forms.Label lblShortcut; + private System.Windows.Forms.TextBox edtShortcut; + private System.Windows.Forms.TabPage tabOptions; + private System.Windows.Forms.Button btnClone; + private System.Windows.Forms.ContextMenuStrip mnuNvPresets; + private System.Windows.Forms.ToolStripMenuItem miNvPresetDithering; + private System.Windows.Forms.ToolStripMenuItem miNvPresetApplyDithering; + private System.Windows.Forms.ToolStripMenuItem miNvPresetDitheringEnabled; + private System.Windows.Forms.ToolStripMenuItem mnuRefreshRate; + private System.Windows.Forms.ToolStripMenuItem miRefreshRateIncluded; + private System.Windows.Forms.ToolStripMenuItem miNvHDR; + private System.Windows.Forms.ToolStripMenuItem miHDRIncluded; + private System.Windows.Forms.ToolStripMenuItem miToggleHDR; + private System.Windows.Forms.ToolStripMenuItem miHDREnabled; + private System.Windows.Forms.Label lblError; + private System.Windows.Forms.Label lblLgError; + private System.Windows.Forms.Button btnCloneLg; + private System.Windows.Forms.Button btnSetShortcutLg; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox edtShortcutLg; + private System.Windows.Forms.Button btnApplyLg; + private System.Windows.Forms.ListView lvLgPresets; + private System.Windows.Forms.TextBox edtStepsLg; + private System.Windows.Forms.Label lblStepsLg; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox edtNameLg; + private System.Windows.Forms.Button btnNvPresetDelete; + private System.Windows.Forms.Button btnAddModesNv; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox edtLgTvName; + private System.Windows.Forms.ComboBox cbxLgApps; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.ToolStripMenuItem miNvApply; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.Button btnDeleteLg; + private System.Windows.Forms.Button btnAddLg; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.CheckBox chkStartMinimized; + private System.Windows.Forms.CheckBox chkStartAfterLogin; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.NumericUpDown edtDelayDisplaySettings; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.ToolStripMenuItem mnuNvDisplay; + private System.Windows.Forms.ToolStripMenuItem miNvPrimaryDisplay; + private System.Windows.Forms.TabPage tabLog; + private System.Windows.Forms.TextBox edtLog; + private System.Windows.Forms.TabPage tabInfo; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.ListBox lbPlugins; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label lblInfo; + private System.Windows.Forms.GroupBox grpNVIDIAInfo; + private System.Windows.Forms.TreeView tvNVIDIAInfo; + private System.Windows.Forms.Button btnLgRefreshApps; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.ComboBox cbxLgDevices; + private System.Windows.Forms.Button btnRefreshNVIDIAInfo; + private System.Windows.Forms.Button btnLgAddButton; + private System.Windows.Forms.ContextMenuStrip mnuLgButtons; + private System.Windows.Forms.ToolStripMenuItem mnuNvPresetsColorSettings; + private System.Windows.Forms.ToolStripMenuItem miNvPresetColorSettings; + } +} + diff --git a/ColorControl/MainForm.cs b/ColorControl/MainForm.cs new file mode 100644 index 0000000..7eec61a --- /dev/null +++ b/ColorControl/MainForm.cs @@ -0,0 +1,1604 @@ +using LgTv; +using Microsoft.Win32; +using Microsoft.Win32.TaskScheduler; +using NLog; +using NStandard; +using NvAPIWrapper.Display; +using NvAPIWrapper.Native.Display; +using NWin32; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Deployment.Application; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Reflection; +// 1. Import the InteropServices type +using System.Runtime.InteropServices; +using System.Security.Principal; +using System.Threading; +using System.Threading.Tasks; +using System.Web.Script.Serialization; +using System.Windows.Forms; +using Action = System.Action; + +namespace ColorControl +{ + public partial class MainForm : Form + { + //private Bitmap bitmap, bitmap2; + + [DllImport("user32.dll")] + public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc); + [DllImport("user32.dll")] + public static extern bool UnregisterHotKey(IntPtr hWnd, int id); + + [DllImport("user32.dll")] + public extern static bool ShutdownBlockReasonCreate(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string pwszReason); + + [DllImport("user32.dll")] + public extern static bool ShutdownBlockReasonDestroy(IntPtr hWnd); + + private static int WM_HOTKEY = 0x0312; + private static string TS_TASKNAME = "ColorControl"; + private static bool SystemShutdown = false; + + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + private string _dataDir; + + private NvService _nvService; + private List _presets; + private string _nvPresetsFilename; + private JavaScriptSerializer _JsonSerializer; + private JavaScriptSerializer _JsonDeserializer; + private Keys _pressedModifiers; + private string _lastDisplayRefreshRates = string.Empty; + + private NotifyIcon trayIcon; + private bool _initialized = false; + private string _configFilename; + private Config _config; + private bool _setVisibleCalled = false; + private bool _winKeyDown = false; + private RestartDetector _restartDetector; + + private LgService _lgService; + private List _lgPresets; + private string _lgPresetsFilename; + private List _lgApps; + + private MenuItem _nvTrayMenu; + private MenuItem _lgTrayMenu; + + public MainForm() + { + InitializeComponent(); + + _dataDir = Utils.GetDataPath(); + + InitLogger(); + + _nvTrayMenu = new MenuItem("NVIDIA presets"); + _lgTrayMenu = new MenuItem("LG presets"); + trayIcon = new NotifyIcon() + { + Icon = Icon, + ContextMenu = new ContextMenu(new MenuItem[] { + _nvTrayMenu, + _lgTrayMenu, + new MenuItem("-", OpenForm), + new MenuItem("Open", OpenForm), + new MenuItem("-"), + new MenuItem("Exit", Exit) + }), + Visible = true, + Text = Text + }; + trayIcon.MouseDoubleClick += trayIcon_MouseDoubleClick; + trayIcon.ContextMenu.Popup += trayIconContextMenu_Popup; + + chkStartAfterLogin.Checked = TaskExists(true); + + _JsonSerializer = new JavaScriptSerializer(); + _JsonDeserializer = new JavaScriptSerializer(); + + var converter = new ColorDataConverter(); + _JsonDeserializer.RegisterConverters(new[] { converter }); + + _nvPresetsFilename = Path.Combine(_dataDir, "NvPresets.json"); + FillNvPresets(); + + _lgPresetsFilename = Path.Combine(_dataDir, "LgPresets.json"); + var toCopy = Path.Combine(Directory.GetCurrentDirectory(), "LgPresets.json"); + if (!File.Exists(_lgPresetsFilename) && File.Exists(toCopy)) + { + try + { + File.Copy(toCopy, _lgPresetsFilename); + } + catch (Exception e) + { + Logger.Error($"Error while copying {toCopy} to {_lgPresetsFilename}: {e.Message}"); + } + } + FillLgPresets(); + + _configFilename = Path.Combine(_dataDir, "Settings.json"); + LoadConfig(); + + try + { + _nvService = new NvService(); + } + catch (Exception) + { + } + try + { + _lgService = new LgService(); + } + catch (Exception e) + { + Debug.WriteLine(e); + } + //_nvService.SetDithering(true); + //_nvService.SetRefreshRate(120); + + InitInfo(); + + var values = Enum.GetValues(typeof(ButtonType)); + foreach (var button in values) + { + var text = button.ToString(); + if (text[0] == '_') + { + text = text.Substring(1); + } + var item = mnuLgButtons.Items.Add(text); + item.Click += miLgAddButton_Click; + } + + SystemEvents.SessionEnded += new SessionEndedEventHandler(SessionEnded); + SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(PowerModeChanged); + + _restartDetector = new RestartDetector(); + + _initialized = true; + } + + private void PowerModeChanged(object sender, PowerModeChangedEventArgs e) + { + var powerOn = e.Mode == PowerModes.Resume; + + if (powerOn) + { + _lgService.DisposeConnection(); + return; + } + + Logger.Debug($"PowerModeChanged: {e.Mode}"); + + ExecPowerOffPreset(); + } + + private void SessionEnded(object sender, SessionEndedEventArgs e) + { + if (e.Reason == SessionEndReasons.SystemShutdown) + { + Logger.Debug($"SessionEnded: {e.Reason}"); + + ExecPowerOffPreset(); + } + } + + private void ExecPowerOffPreset(bool wait = false) + { + var preset = _lgPresets.FirstOrDefault(x => x.steps.Contains("POWER")); + if (preset != null) + { + Logger.Debug($"ExecPowerOffPreset: preset found: {preset.name}"); + ApplyLgPreset(preset, wait: wait); + } + } + + private void InitLogger() + { + var config = new NLog.Config.LoggingConfiguration(); + + // Targets where to log to: File and Console + var logfile = new NLog.Targets.FileTarget("logfile") { FileName = Path.Combine(_dataDir, "LogFile.txt") }; + //var logconsole = new NLog.Targets.ConsoleTarget("logconsole"); + + // Rules for mapping loggers to targets + //config.AddRule(LogLevel.Info, LogLevel.Fatal, logconsole); + config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfile); + + // Apply config + NLog.LogManager.Configuration = config; + } + + private void InitInfo() + { + var fileVersionInfo = FileVersionInfo.GetVersionInfo(Path.GetFileName(Application.ExecutablePath)); + + if (ApplicationDeployment.IsNetworkDeployed) + { + Text = Application.ProductName + " " + ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString(); + } + else + { + Text = Application.ProductName + " " + Application.ProductVersion; + } + + lblInfo.Text = Text + " - " + fileVersionInfo.LegalCopyright; + + lbPlugins.Items.Add("lgtv.net by gr4b4z"); + lbPlugins.Items.Add("Newtonsoft.Json by James Newton-King"); + lbPlugins.Items.Add("NLog by Jarek Kowalski, Kim Christensen, Julian Verdurmen"); + lbPlugins.Items.Add("NvAPIWrapper.Net by Soroush Falahati"); + lbPlugins.Items.Add("NWin32 by zmjack"); + lbPlugins.Items.Add("TaskScheduler by David Hall"); + } + + private void OpenForm(object sender, EventArgs e) + { + Show(); + WindowState = FormWindowState.Normal; + } + + void Exit(object sender, EventArgs e) + { + Close(); + } + + private void trayIcon_MouseDoubleClick(object sender, MouseEventArgs e) + { + Show(); + WindowState = FormWindowState.Normal; + } + + private void button1_Click(object sender, EventArgs e) + { + //Display.GetDisplays().First().DisplayDevice.CurrentColorData.ColorFormat = NvAPIWrapper.Native.Display.ColorDataFormat.RGB; + // var colorData = new ColorData(NvAPIWrapper.Native.Display.ColorDataFormat.YUV444, NvAPIWrapper.Native.Display.ColorDataColorimetry.Auto, NvAPIWrapper.Native.Display.ColorDataDynamicRange.Auto, NvAPIWrapper.Native.Display.ColorDataDepth.BPC8); + //var hdrColorData = new HDRColorData(NvAPIWrapper.Native.Display.ColorDataHDRMode.UHDA); + //DisplayDevice.GetGDIPrimaryDisplayDevice().SetColorData(colorData); + //Display.GetDisplays().First().DisplayDevice.SetColorData(colorData); + //pictureBox1.Load("d:\\ss.png"); + + //bitmap = new Bitmap("d:\\ss2.png"); + + //Bitmap bitmap2 = Utils.SubPixelShift(bitmap); + + //pictureBox1.Image = bitmap2; + } + + private void button2_Click(object sender, EventArgs e) + { + } + + private void FillNvPresets() + { + var colums = NvPreset.GetColumnNames(); + + foreach (var name in colums) + { + var columnName = name; + var parts = name.Split('|'); + + var width = 120; + if (parts.Length > 1) + { + width = Int32.Parse(parts[1]); + columnName = parts[0]; + } + + var header = lvNvPresets.Columns.Add(columnName); + header.Width = width; + } + + if (File.Exists(_nvPresetsFilename)) + { + var json = File.ReadAllText(_nvPresetsFilename); + + _presets = _JsonDeserializer.Deserialize>(json); + } + else + { + _presets = NvPreset.GetDefaultPresets(); + + } + + foreach (var preset in _presets) + { + AddOrUpdateItem(preset); + RegisterShortcut(preset); + } + + //UpdateTrayMenuNv(); + } + + private void RegisterShortcut(PresetBase preset, bool clear = false) + { + if (clear) + { + UnregisterHotKey(Handle, preset.id); + } + + if (!string.IsNullOrEmpty(preset.shortcut)) + { + var (mods, key) = Utils.ParseShortcut(preset.shortcut); + bool registered = RegisterHotKey(Handle, preset.id, mods, key); + } + } + + private void AddOrUpdateItem(NvPreset preset = null) + { + ListViewItem item = null; + if (preset == null) + { + item = lvNvPresets.SelectedItems[0]; + preset = (NvPreset)item.Tag; + } + + var values = preset.GetDisplayValues(); + + if (item == null) + { + item = lvNvPresets.Items.Add(values[0]); + item.Tag = preset; + for (var i = 1; i < values.Count; i++) + { + item.SubItems.Add(values[i]); + } + if (!_presets.Any(x => x.id == preset.id)) { + _presets.Add(preset); + } + } + else + { + item.Text = values[0]; + for (var i = 1; i < values.Count; i++) + { + item.SubItems[i].Text = values[i]; + } + } + } + + private void btnApply_Click(object sender, EventArgs e) + { + ApplySelectedNvPreset(); + } + + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + { + SaveNvPresets(); + SaveLgPresets(); + + SaveConfig(); + + if (SystemShutdown) + { + Logger.Debug($"MainForm_FormClosing: SystemShutdown"); + + if (_restartDetector != null && _restartDetector.RestartDetected) + { + Logger.Debug("Not powering off because of a restart"); + } + else + { + ExecPowerOffPreset(true); + } + } + } + + private void SaveNvPresets() + { + var json = _JsonSerializer.Serialize(_presets); + File.WriteAllText(_nvPresetsFilename, json); + } + + private void SaveLgPresets() + { + var json = _JsonSerializer.Serialize(_lgPresets); + File.WriteAllText(_lgPresetsFilename, json); + } + + private void button1_Click_1(object sender, EventArgs e) + { + + } + + private void lvNvPresets_SelectedIndexChanged(object sender, EventArgs e) + { + var enabled = lvNvPresets.SelectedItems.Count > 0; + btnApply.Enabled = enabled; + btnChange.Enabled = enabled; + edtShortcut.Enabled = enabled; + btnSetShortcut.Enabled = enabled; + btnClone.Enabled = enabled; + btnNvPresetDelete.Enabled = enabled; + + var preset = GetSelectedNvPreset(); + if (preset != null) + { + edtShortcut.Text = preset.shortcut; + } + else + { + edtShortcut.Text = string.Empty; + } + } + + protected override void WndProc(ref Message m) + { + // 5. Catch when a HotKey is pressed ! + if (m.Msg == WM_HOTKEY && !edtShortcut.Focused && !edtShortcutLg.Focused) + { + int id = m.WParam.ToInt32(); + // MessageBox.Show(string.Format("Hotkey #{0} pressed", id)); + + // 6. Handle what will happen once a respective hotkey is pressed + + var preset = _presets.FirstOrDefault(x => x.id == id); + if (preset != null) + { + ApplyNvPreset(preset); + } + + var lgPreset = _lgPresets.FirstOrDefault(x => x.id == id); + if (lgPreset != null) + { + ApplyLgPreset(lgPreset); + } + + //switch (id) + //{ + // case 1: + // MessageBox.Show("F9 Key Pressed ! Do something here ... "); + // break; + //} + } + else if (m.Msg == NativeConstants.WM_QUERYENDSESSION) + { + SystemShutdown = true; + } + + base.WndProc(ref m); + } + + private void edtShortcut_KeyDown(object sender, KeyEventArgs e) + { + _pressedModifiers = e.Modifiers; + + //Debug.WriteLine("KD: " + e.Modifiers + ", " + e.KeyCode); + + var shortcutString = (_pressedModifiers > 0 ? _pressedModifiers.ToString() : ""); + if (e.KeyCode == Keys.LWin || _winKeyDown) + { + _winKeyDown = true; + if (!string.IsNullOrEmpty(shortcutString)) + { + shortcutString += ", "; + } + shortcutString += "Win"; + } + + if (!string.IsNullOrEmpty(shortcutString) && e.KeyCode != Keys.ControlKey && e.KeyCode != Keys.ShiftKey && e.KeyCode != Keys.Menu && e.KeyCode != Keys.LWin) + { + shortcutString += " + " + e.KeyCode.ToString(); + } + + if (_pressedModifiers == 0 && !_winKeyDown) + { + e.SuppressKeyPress = true; + } + + ((TextBox)sender).Text = shortcutString; + } + + private void edtShortcut_KeyPress(object sender, KeyPressEventArgs e) + { + } + + private void btnSetShortcut_Click(object sender, EventArgs e) + { + var shortcut = edtShortcut.Text.Trim(); + + if (!string.IsNullOrWhiteSpace(shortcut) && !shortcut.Contains("+")) + { + WarningOk("Invalid shortcut. The shortcut should have modifiers and a normal key."); + return; + } + + var preset = GetSelectedNvPreset(); + + var clear = !string.IsNullOrEmpty(preset.shortcut); + + preset.shortcut = shortcut; + + AddOrUpdateItem(); + + RegisterShortcut(preset, clear); + } + + private void MainForm_FormClosed(object sender, FormClosedEventArgs e) + { + // Hide tray icon, otherwise it will remain shown until user mouses over it + trayIcon.Visible = false; + } + + private void MainForm_Resize(object sender, EventArgs e) + { + if (WindowState == FormWindowState.Minimized) + { + Hide(); + } + } + + private void chkStartAfterLogin_CheckedChanged(object sender, EventArgs e) + { + if (!_initialized) + { + return; + } + var enabled = chkStartAfterLogin.Checked; + RegisterTask(enabled); + } + + private void RegisterTask(bool enabled) + { + var file = Assembly.GetExecutingAssembly().Location; + var directory = Path.GetDirectoryName(file); + + using (TaskService ts = new TaskService()) + { + if (enabled) + { + TaskDefinition td = ts.NewTask(); + td.RegistrationInfo.Description = "Start ColorControl"; + + td.Triggers.Add(new LogonTrigger { UserId = WindowsIdentity.GetCurrent().Name }); + + td.Actions.Add(new ExecAction(file, null, directory)); + + ts.RootFolder.RegisterTaskDefinition(TS_TASKNAME, td); + } + else + { + ts.RootFolder.DeleteTask(TS_TASKNAME, false); + } + } + } + + private bool TaskExists(bool update) + { + var file = Assembly.GetExecutingAssembly().Location; + using (TaskService ts = new TaskService()) + { + var task = ts.RootFolder.Tasks.FirstOrDefault(x => x.Name.Equals(TS_TASKNAME)); + + if (task != null) + { + if (update && ApplicationDeployment.IsNetworkDeployed) + { + var action = task.Definition.Actions.FirstOrDefault(x => x.ActionType == TaskActionType.Execute); + if (action != null) + { + var execAction = action as ExecAction; + if (!execAction.Path.Equals(file)) + { + RegisterTask(false); + RegisterTask(true); + } + } + } + return true; + } + return false; + } + } + + private void LoadConfig() + { + if (File.Exists(_configFilename)) + { + var data = File.ReadAllText(_configFilename); + _config = _JsonDeserializer.Deserialize(data); + } + else + { + _config = new Config(); + } + + chkStartMinimized.Checked = _config.StartMinimized; + edtDelayDisplaySettings.Value = _config.DisplaySettingsDelay; + } + + private void SaveConfig() + { + _config.StartMinimized = chkStartMinimized.Checked; + + var data = _JsonSerializer.Serialize(_config); + File.WriteAllText(_configFilename, data); + } + + private void MainForm_Load(object sender, EventArgs e) + { + } + + private void ShowControls(Control parent, bool show = true, Control exclude = null) + { + for (var i = 0; i < parent.Controls.Count; i++) + { + var control = parent.Controls[i]; + if (control != exclude) + { + control.Visible = show; + } + } + } + + private void MainForm_Shown(object sender, EventArgs e) + { + if (_nvService == null) + { + ShowControls(tabNVIDIA, false, lblError); + + lblError.Text = "Error while initializing the NVIDIA-wrapper. You either don't have a NVIDIA GPU or it is disabled. NVIDIA controls will not be available."; + lblError.Visible = true; + } + + if (_lgService == null) + { + ShowControls(tabLG, false, lblLgError); + lblLgError.Text = "Error while initializing the LG-controller. You either don't have a LG TV or it is disabled."; + lblLgError.Visible = true; + } + } + + protected override void SetVisibleCore(bool value) + { + if (!_setVisibleCalled && _config.StartMinimized) + { + _setVisibleCalled = true; + value = false; + } + if (!IsDisposed) { + base.SetVisibleCore(value); + } + } + + private void edtShortcut_KeyUp(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.LWin) + { + _winKeyDown = false; + } + } + + private void edtShortcut_TextChanged(object sender, EventArgs e) + { + var text = edtShortcut.Text; + + var preset = GetSelectedNvPreset(); + + if (preset == null || string.IsNullOrEmpty(text)) + { + edtShortcut.ForeColor = SystemColors.WindowText; + } + else + { + edtShortcut.ForeColor = _presets.Any(x => x.id != preset.id && text.Equals(x.shortcut)) ? Color.Red : SystemColors.WindowText; + } + } + + private NvPreset GetSelectedNvPreset() + { + if (lvNvPresets.SelectedItems.Count > 0) + { + var item = lvNvPresets.SelectedItems[0]; + return (NvPreset)item.Tag; + } + else + { + return null; + } + } + + private void btnClone_Click(object sender, EventArgs e) + { + var preset = GetSelectedNvPreset(); + + var newPreset = preset.Clone(); + AddOrUpdateItem(newPreset); + } + + private void miNvPresetColorSettings_Click(object sender, EventArgs e) + { + var preset = GetSelectedNvPreset(); + + preset.applyColorData = !preset.applyColorData; + + AddOrUpdateItem(); + } + + private void miNvPresetApplyDithering_Click(object sender, EventArgs e) + { + var preset = GetSelectedNvPreset(); + + preset.applyDithering = !preset.applyDithering; + + AddOrUpdateItem(); + } + + private void miNvPresetDitheringEnabled_Click(object sender, EventArgs e) + { + var preset = GetSelectedNvPreset(); + + preset.ditheringEnabled = !preset.ditheringEnabled; + + AddOrUpdateItem(); + } + + private void btnChange_Click(object sender, EventArgs e) + { + mnuNvPresets.Show(btnChange, btnChange.PointToClient(Cursor.Position)); + } + + private void includedToolStripMenuItem_Click(object sender, EventArgs e) + { + var preset = GetSelectedNvPreset(); + + preset.applyRefreshRate = !preset.applyRefreshRate; + + AddOrUpdateItem(); + } + + private void mnuNvPresets_Opening(object sender, CancelEventArgs e) + { + var preset = GetSelectedNvPreset(); + + miNvApply.Enabled = preset != null; + mnuNvDisplay.Enabled = preset != null; + miNvPresetColorSettings.Enabled = preset != null; + mnuRefreshRate.Enabled = preset != null; + miNvPresetDithering.Enabled = preset != null; + miNvHDR.Enabled = preset != null; + + if (preset != null) + { + if (mnuNvDisplay.DropDownItems.Count == 1) + { + var displays = _nvService.GetDisplays(); + for (var i = 0; i < displays.Length; i++) + { + var display = displays[i]; + var name = display.Name; + var screen = Screen.AllScreens.FirstOrDefault(x => x.DeviceName.Equals(name)); + if (screen != null) + { + name += " (" + screen.DeviceFriendlyName() + ")"; + } + + var item = mnuNvDisplay.DropDownItems.Add(name); + item.Tag = display; + item.Click += displayMenuItem_Click; + } + } + + BuildDropDownMenu(mnuNvPresetsColorSettings, "Bit depth", typeof(ColorDataDepth), preset.colorData, "ColorDepth"); + BuildDropDownMenu(mnuNvPresetsColorSettings, "Format", typeof(ColorDataFormat), preset.colorData, "ColorFormat"); + BuildDropDownMenu(mnuNvPresetsColorSettings, "Dynamic range", typeof(ColorDataDynamicRange), preset.colorData, "DynamicRange"); + BuildDropDownMenu(mnuNvPresetsColorSettings, "Color space", typeof(ColorDataColorimetry), preset.colorData, "Colorimetry"); + + if (preset.displayName != _lastDisplayRefreshRates) + { + while (mnuRefreshRate.DropDownItems.Count > 1) + { + mnuRefreshRate.DropDownItems.RemoveAt(mnuRefreshRate.DropDownItems.Count - 1); + } + } + + if (mnuRefreshRate.DropDownItems.Count == 1) + { + var refreshRates = _nvService.GetAvailableRefreshRates(preset); + _lastDisplayRefreshRates = preset.displayName; + + foreach (var refreshRate in refreshRates) + { + var item = mnuRefreshRate.DropDownItems.Add(refreshRate.ToString() + "Hz"); + item.Tag = refreshRate; + item.Click += refreshRateMenuItem_Click; + } + } + + miNvPrimaryDisplay.Checked = preset.primaryDisplay; + foreach (var item in mnuNvDisplay.DropDownItems) + { + if (item is ToolStripMenuItem) + { + var menuItem = (ToolStripMenuItem)item; + if (menuItem.Tag != null) + { + menuItem.Checked = ((Display)menuItem.Tag).Name.Equals(preset.displayName); + } + } + } + + miNvPresetColorSettings.Checked = preset.applyColorData; + + miRefreshRateIncluded.Checked = preset.applyRefreshRate; + foreach (var item in mnuRefreshRate.DropDownItems) + { + if (item is ToolStripMenuItem) + { + var menuItem = (ToolStripMenuItem)item; + if (menuItem.Tag != null) + { + menuItem.Checked = (uint)menuItem.Tag == preset.refreshRate; + } + } + } + + miNvPresetApplyDithering.Checked = preset.applyDithering; + miNvPresetDitheringEnabled.Checked = preset.ditheringEnabled; + + miHDRIncluded.Checked = preset.applyHDR; + miHDREnabled.Checked = preset.HDREnabled; + miToggleHDR.Checked = preset.toggleHDR; + } + } + + private void BuildDropDownMenu(ToolStripMenuItem mnuParent, string name, Type enumType, ColorData colorData, string propertyName) + { + PropertyInfo property; + var subMenuItems = mnuParent.DropDownItems.Find("miColorSettings_" + name, false); + ToolStripMenuItem subMenuItem = null; + if (subMenuItems.Length == 0) + { + subMenuItem = (ToolStripMenuItem)mnuParent.DropDownItems.Add(name); + subMenuItem.Name = "miColorSettings_" + name; + + property = typeof(ColorData).GetDeclaredProperty(propertyName); + subMenuItem.Tag = property; + + foreach (var enumValue in Enum.GetValues(enumType)) + { + var item = subMenuItem.DropDownItems.Add(enumValue.ToString()); + item.Tag = enumValue; + item.Click += nvPresetColorDataMenuItem_Click; + } + } + else + { + subMenuItem = (ToolStripMenuItem)subMenuItems[0]; + property = (PropertyInfo)subMenuItem.Tag; + } + + var value = property.GetValue(colorData); + + foreach (var item in subMenuItem.DropDownItems) + { + if (item is ToolStripMenuItem) + { + var menuItem = (ToolStripMenuItem)item; + if (menuItem.Tag != null) + { + menuItem.Checked = menuItem.Tag.Equals(value); + } + } + } + } + + private void nvPresetColorDataMenuItem_Click(object sender, EventArgs e) + { + var menuItem = (ToolStripMenuItem)sender; + var property = (PropertyInfo)menuItem.OwnerItem.Tag; + + var value = menuItem.Tag; + + var preset = GetSelectedNvPreset(); + + var dictionary = new Dictionary + { + { "ColorFormat", preset.colorData.ColorFormat }, + { "ColorDepth", preset.colorData.ColorDepth }, + { "Colorimetry", preset.colorData.Colorimetry }, + { "DynamicRange", preset.colorData.DynamicRange }, + { "SelectionPolicy", preset.colorData.SelectionPolicy } + }; + + dictionary[property.Name] = value; + + var colorData = NvPreset.GenerateColorData(dictionary); + + preset.colorData = colorData; + + AddOrUpdateItem(); + } + + private void refreshRateMenuItem_Click(object sender, EventArgs e) + { + var refreshRate = (uint)((ToolStripItem)sender).Tag; + + var preset = GetSelectedNvPreset(); + + preset.refreshRate = refreshRate; + + AddOrUpdateItem(); + } + + private void displayMenuItem_Click(object sender, EventArgs e) + { + var preset = GetSelectedNvPreset(); + + var menuItem = (ToolStripItem)sender; + if (menuItem.Tag != null) + { + var display = (Display)menuItem.Tag; + + preset.displayName = display.Name; + preset.primaryDisplay = false; + } + else + { + preset.primaryDisplay = true; + preset.displayName = null; + } + + AddOrUpdateItem(); + } + + private void miHDRIncluded_Click(object sender, EventArgs e) + { + var preset = GetSelectedNvPreset(); + + preset.applyHDR = !preset.applyHDR; + + AddOrUpdateItem(); + } + + private void miToggleHDR_Click(object sender, EventArgs e) + { + var preset = GetSelectedNvPreset(); + + preset.toggleHDR = !preset.toggleHDR; + + if (preset.toggleHDR) + { + preset.HDREnabled = false; + } + + AddOrUpdateItem(); + } + + private void miHDREnabled_Click(object sender, EventArgs e) + { + var preset = GetSelectedNvPreset(); + + preset.HDREnabled = !preset.HDREnabled; + preset.toggleHDR = false; + + AddOrUpdateItem(); + } + + private void FillLgPresets() + { + var columns = LgPreset.GetColumnNames(); + + foreach (var name in columns) + { + var columnName = name; + var parts = name.Split('|'); + + var width = 120; + if (parts.Length > 1) + { + width = Int32.Parse(parts[1]); + columnName = parts[0]; + } + + var header = lvLgPresets.Columns.Add(columnName); + header.Width = width; + } + + if (File.Exists(_lgPresetsFilename)) + { + var json = File.ReadAllText(_lgPresetsFilename); + + _lgPresets = _JsonDeserializer.Deserialize>(json); + } + else + { + _lgPresets = new List(); + } + + foreach (var preset in _lgPresets) + { + AddOrUpdateItemLg(preset); + RegisterShortcut(preset); + } + } + + private void AddOrUpdateItemLg(LgPreset preset = null, ListViewItem specItem = null) + { + ListViewItem item = null; + if (preset == null) + { + item = lvLgPresets.SelectedItems[0]; + preset = (LgPreset)item.Tag; + } + else + { + item = specItem; + } + + if (preset.id == 0) + { + preset.id = preset.GetHashCode(); + } + + var values = preset.GetDisplayValues(); + + if (item == null) + { + item = lvLgPresets.Items.Add(values[0]); + item.Tag = preset; + for (var i = 1; i < values.Count; i++) + { + item.SubItems.Add(values[i]); + } + if (!_lgPresets.Any(x => x.id == preset.id)) + { + _lgPresets.Add(preset); + } + } + else + { + item.Text = values[0]; + for (var i = 1; i < values.Count; i++) + { + item.SubItems[i].Text = values[i]; + } + } + } + + private void btnCloneLg_Click(object sender, EventArgs e) + { + var preset = GetSelectedLgPreset(); + + var newPreset = preset.Clone(); + AddOrUpdateItemLg(newPreset); + } + + private LgPreset GetSelectedLgPreset() + { + if (lvLgPresets.SelectedItems.Count > 0) + { + var item = lvLgPresets.SelectedItems[0]; + return (LgPreset)item.Tag; + } + else + { + return null; + } + } + + private void lvLgPresets_SelectedIndexChanged(object sender, EventArgs e) + { + var enabled = lvLgPresets.SelectedItems.Count > 0; + btnApplyLg.Enabled = enabled; + btnCloneLg.Enabled = enabled; + edtNameLg.Enabled = enabled; + edtShortcutLg.Enabled = enabled; + btnSetShortcutLg.Enabled = enabled; + edtStepsLg.Enabled = enabled; + btnLgAddButton.Enabled = enabled; + cbxLgApps.Enabled = enabled; + btnDeleteLg.Enabled = enabled; + + var preset = GetSelectedLgPreset(); + + if (preset != null) + { + edtNameLg.Text = preset.name; + cbxLgApps.SelectedIndex = _lgApps == null ? -1 : _lgApps.FindIndex(x => x.appId.Equals(preset.appId)); + edtShortcutLg.Text = preset.shortcut; + edtStepsLg.Text = preset.steps.Aggregate("", (a, b) => (string.IsNullOrEmpty(a) ? "" : a + ", ") + b); + } + else + { + edtNameLg.Text = string.Empty; + cbxLgApps.SelectedIndex = -1; + edtShortcutLg.Text = string.Empty; + edtStepsLg.Text = string.Empty; + } + } + + private void btnApplyLg_Click(object sender, EventArgs e) + { + var preset = GetSelectedLgPreset(); + + ApplyLgPreset(preset); + } + + private void btnSetShortcutLg_Click(object sender, EventArgs e) + { + var shortcut = edtShortcutLg.Text.Trim(); + if (!string.IsNullOrWhiteSpace(shortcut) && !shortcut.Contains("+")) + { + WarningOk("Invalid shortcut. The shortcut should have modifiers and a normal key."); + return; + } + + var preset = GetSelectedLgPreset(); + + var name = edtNameLg.Text.Trim(); + + if (name.Length == 0 || _lgPresets.Any(x => x.id != preset.id && x.name.Equals(name, StringComparison.OrdinalIgnoreCase))) + { + WarningOk("The name can not be empty and must be unique."); + return; + } + + var clear = !string.IsNullOrEmpty(preset.shortcut); + + preset.name = name; + + if (cbxLgApps.SelectedIndex == -1) + { + preset.appId = string.Empty; + } + else + { + var lgApp = (LgApp)cbxLgApps.SelectedItem; + preset.appId = lgApp.appId; + } + + var shortcutChanged = !shortcut.Equals(preset.shortcut); + if (shortcutChanged) + { + preset.shortcut = shortcut; + } + + var text = edtStepsLg.Text; + var clearSteps = string.IsNullOrEmpty(text); + + preset.steps.Clear(); + if (!clearSteps) + { + text = text.Replace(" ", string.Empty); + var steps = text.Split(','); + preset.steps.AddRange(steps); + } + + AddOrUpdateItemLg(); + + SaveLgPresets(); + + if (shortcutChanged) + { + RegisterShortcut(preset, clear); + } + } + + private void btnNvPresetDelete_Click(object sender, EventArgs e) + { + var preset = GetSelectedNvPreset(); + + if (preset == null) + { + return; + } + + if (!string.IsNullOrEmpty(preset.shortcut)) + { + UnregisterHotKey(Handle, preset.id); + } + + _presets.Remove(preset); + + var item = lvNvPresets.SelectedItems[0]; + lvNvPresets.Items.Remove(item); + } + + private void btnAddModesNv_Click(object sender, EventArgs e) + { + var presets = NvPreset.GetDefaultPresets(); + var added = false; + + foreach (var preset in presets) + { + if (!_presets.Any(x => x.colorData.Equals(preset.colorData))) + { + AddOrUpdateItem(preset); + added = true; + } + } + + if (added) + { + InfoOk("Missing presets added."); + } + else + { + InfoOk("All presets for every color setting already exist."); + } + } + + private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) + { + if (tcMain.SelectedTab == tabLG) + { + if (cbxLgDevices.Items.Count == 0) + { + var devices = _lgService.Devices; + if (devices == null || !devices.Any()) + { + _lgService.RefreshDevices(() => BeginInvoke(new Action(FillLgDevices))); + } + else + { + FillLgDevices(); + } + } + } + else if (tcMain.SelectedTab == tabLog) + { + LoadLog(); + } + else if (tcMain.SelectedTab == tabInfo) + { + LoadInfo(); + } + } + + private void FillLgDevices() + { + var devices = _lgService.Devices; + foreach (var device in devices) + { + cbxLgDevices.Items.Add(device); + } + if (_lgService.SelectedDevice != null) + { + cbxLgDevices.SelectedIndex = cbxLgDevices.Items.IndexOf(_lgService.SelectedDevice); + } + + if (!devices.Any()) + { + WarningOk("It seems there's no LG TV available! Please make sure it's connected to the same network as this PC."); + } + + if (cbxLgApps.Items.Count == 0 && _lgService.SelectedDevice != null) + { + _lgService.RefreshApps().ContinueWith((task) => BeginInvoke(new Action>>(FillLgApps), new[] { task })); + edtLgTvName.Text = _lgService.FriendlyScreenName; + } + } + + private void FillLgApps(Task> task) + { + _lgApps = task.Result; + if (_lgApps == null || !_lgApps.Any()) + { + WarningOk("Could not refresh the apps. Check the log for details."); + return; + } + InitLgApps(); + } + + private void InitLgApps() { + LgPreset.LgApps = _lgApps; + cbxLgApps.Items.Clear(); + cbxLgApps.Items.AddRange(_lgApps.ToArray()); + + for (var i = 0; i < lvLgPresets.Items.Count; i++) + { + var item = lvLgPresets.Items[i]; + AddOrUpdateItemLg((LgPreset)item.Tag, item); + } + + var preset = GetSelectedLgPreset(); + if (preset != null) + { + cbxLgApps.SelectedIndex = _lgApps == null ? -1 : _lgApps.FindIndex(x => x.appId.Equals(preset.appId)); + } + } + + private void UpdateTrayMenuNv() + { + var presets = _presets.Where(x => x.applyColorData || x.applyDithering || x.applyHDR || x.applyRefreshRate); + + _nvTrayMenu.MenuItems.Clear(); + + foreach (var preset in presets) + { + var name = preset.GetTextForMenuItem(); + if (!string.IsNullOrEmpty(preset.shortcut)) + { + name += "\t" + preset.shortcut; + } + + var item = new MenuItem(name); + item.Tag = preset; + item.Click += TrayMenuItemNv_Click; + _nvTrayMenu.MenuItems.Add(item); + } + } + + private void TrayMenuItemNv_Click(object sender, EventArgs e) + { + var item = sender as MenuItem; + var preset = (NvPreset)item.Tag; + + ApplyNvPreset(preset); + } + + private void trayIconContextMenu_Popup(object sender, EventArgs e) + { + _nvTrayMenu.Visible = _nvService != null; + + if (_nvTrayMenu.Visible) + { + UpdateTrayMenuNv(); + } + + _lgTrayMenu.Visible = _lgService != null; + + if (_lgTrayMenu.Visible) + { + UpdateTrayMenuLg(); + } + } + + private void UpdateTrayMenuLg() + { + var presets = _lgPresets.Where(x => !string.IsNullOrEmpty(x.appId) || x.steps.Any()); + + _lgTrayMenu.MenuItems.Clear(); + + foreach (var preset in presets) + { + var name = preset.name; + if (!string.IsNullOrEmpty(preset.shortcut)) + { + name += "\t" + preset.shortcut; + } + + var item = new MenuItem(name); + item.Tag = preset; + item.Click += TrayMenuItemLg_Click; + _lgTrayMenu.MenuItems.Add(item); + } + } + + private void TrayMenuItemLg_Click(object sender, EventArgs e) + { + var item = sender as MenuItem; + var preset = (LgPreset)item.Tag; + + ApplyLgPreset(preset); + } + + private void lvNvPresets_DoubleClick(object sender, EventArgs e) + { + ApplySelectedNvPreset(); + } + + private void miNvApply_Click(object sender, EventArgs e) + { + ApplySelectedNvPreset(); + } + + private void ApplySelectedNvPreset() + { + var preset = GetSelectedNvPreset(); + ApplyNvPreset(preset); + } + + private void btnDeleteLg_Click(object sender, EventArgs e) + { + var preset = GetSelectedLgPreset(); + + if (preset == null) + { + return; + } + + if (!string.IsNullOrEmpty(preset.shortcut)) + { + UnregisterHotKey(Handle, preset.id); + } + + _lgPresets.Remove(preset); + + var item = lvLgPresets.SelectedItems[0]; + lvLgPresets.Items.Remove(item); + } + + private void btnAddLg_Click(object sender, EventArgs e) + { + var preset = new LgPreset(); + var name = "New preset"; + string fullname; + var number = 1; + do + { + fullname = $"{name} ({number})"; + number++; + } while (_lgPresets.Any(x => x.name.Equals(fullname))); + + preset.name = fullname; + + AddOrUpdateItemLg(preset); + } + + private void edtDelayDisplaySettings_ValueChanged(object sender, EventArgs e) + { + _config.DisplaySettingsDelay = (int)edtDelayDisplaySettings.Value; + } + + private void ApplyNvPreset(NvPreset preset) + { + if (preset == null) + { + return; + } + try + { + var result = _nvService.ApplyPreset(preset, _config); + if (!result) + { + throw new Exception("Error while applying NVIDIA preset"); + } + } + catch (Exception e) + { + ErrorOk($"Error applying NVIDIA-preset ({e.TargetSite.Name}): {e.Message}"); + } + } + + private void ApplyLgPreset(LgPreset preset, bool reconnect = false, bool wait = false) + { + if (preset == null) + { + return; + } + + var applyTask = _lgService.ApplyPreset(preset, reconnect).ContinueWith((task) => BeginInvoke(new Action>(LgPresetApplied), new[] { task })); + if (wait) + { + while (applyTask != null && (applyTask.Status < TaskStatus.WaitingForChildrenToComplete)) + { + Thread.Sleep(100); + Application.DoEvents(); + } + } + } + + private void LgPresetApplied(Task task) + { + var result = task.Result; + if (!result) + { + WarningOk("Could not apply the preset (entirely). Check the log for details."); + } + } + + private void LoadLog() + { + var filename = Path.Combine(_dataDir, "LogFile.txt"); + + var log = "No log file found"; + if (File.Exists(filename)) + { + log = File.ReadAllText(filename); + } + edtLog.Text = log; + } + + private void LoadInfo() + { + grpNVIDIAInfo.Visible = _nvService != null; + } + + private void btnLgRefreshApps_Click(object sender, EventArgs e) + { + _lgService.RefreshApps(true).ContinueWith((task) => BeginInvoke(new Action>>(FillLgApps), new[] { task })); + } + + private void cbxLgDevices_SelectedIndexChanged(object sender, EventArgs e) + { + if (cbxLgDevices.SelectedIndex == -1) + { + _lgService.SelectedDevice = null; + } + else + { + _lgService.SelectedDevice = (PnpDev)cbxLgDevices.SelectedItem; + } + } + + private void WarningOk(string text) + { + MessageBox.Show(text, Text, MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + + private void ErrorOk(string text) + { + MessageBox.Show(text, Text, MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + private void InfoOk(string text) + { + MessageBox.Show(text, Text, MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void lvLgPresets_DoubleClick(object sender, EventArgs e) + { + ApplySelectedLgPreset(); + } + + private void ApplySelectedLgPreset() + { + var preset = GetSelectedLgPreset(); + ApplyLgPreset(preset); + } + + private void btnRefreshNVIDIAInfo_Click(object sender, EventArgs e) + { + if (_nvService != null) + { + tvNVIDIAInfo.Nodes.Clear(); + var displays = Display.GetDisplays(); + for (var i = 0; i < displays.Length; i++) + { + var display = displays[i]; + var node = TreeNodeBuilder.CreateTree(display, $"Display[{i}]"); + tvNVIDIAInfo.Nodes.Add(node); + } + } + } + + private void btnLgAddButton_Click(object sender, EventArgs e) + { + mnuLgButtons.Show(btnLgAddButton, btnLgAddButton.PointToClient(Cursor.Position)); + } + + private void miLgAddButton_Click(object sender, EventArgs e) + { + var item = sender as ToolStripItem; + + var button = item.Text; + + var text = edtStepsLg.Text; + if (string.IsNullOrWhiteSpace(text)) + { + text = button; + } + else + { + var pos = edtStepsLg.SelectionStart; + while (pos < text.Length && text.CharAt(pos) != ',') + { + pos++; + } + if (pos == text.Length) + { + text += ", " + button; + } + else + { + text = text.Substring(0, pos + 1) + " " + button + ", " + text.Substring(pos + 1).Trim(); + } + } + edtStepsLg.Text = text.Trim(); + } + } +} \ No newline at end of file diff --git a/ColorControl/MainForm.resx b/ColorControl/MainForm.resx new file mode 100644 index 0000000..7b37833 --- /dev/null +++ b/ColorControl/MainForm.resx @@ -0,0 +1,1906 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + 17, 17 + + + 147, 17 + + + + + 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 + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAEA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACnFZK0hxWStIyp5PpcqeT6XlsljR5bJY0eSxV9Lk + sVfSxppNqcaaTalkTiVSZE4lUgAAABIAAAASAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoA + AAAKcVkrSHFZK0jKnk+lyp5PpeWyWNHlsljR5LFX0uSxV9LGmk2pxppNqWROJVJkTiVSAAAAEgAAABIA + AAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAFAAAABb+UTIO/lEyD/MNj/vzDY/78w2P//MNj//zDY//8w2P//MNj//zDY//8 + w2P//MNj//zDY//8w2P//MNj//zDY//7w2P++8Nj/quGRZGrhkWRAAAADQAAAA0AAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAFv5RMg7+UTIP8 + w2P+/MNj/vzDY//8w2P//MNj//zDY//8w2P//MNj//zDY//8w2P//MNj//zDY//8w2P//MNj//vDY/77 + w2P+q4ZFkauGRZEAAAANAAAADQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAsAAAAL8bpi6fG6Yun5wGX/+cBl//nAZf/5wGX/+cFl//nBZf/5wWX/+cFl//nBZf/5 + wWX/+cFl//nBZf/5wWX/+cFl//nBZf/5wWX/+cBl//nAZf/5wGX/+cBl/+23YOztt2DsAAAAHQAAAB0A + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAvxumLp8bpi6fnAZf/5 + wGX/+cBl//nAZf/5wWX/+cFl//nBZf/5wWX/+cFl//nBZf/5wWX/+cFl//nBZf/5wWX/+cFl//nBZf/5 + wGX/+cBl//nAZf/5wGX/7bdg7O23YOwAAAAdAAAAHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAABgAAAAbzu2Ty87tk8ve+Zv/3vmb/9r5m//a+Zv/3vmb/975m//a+Zv/2vmb/975m//e+Zv/2 + vmb/9r5m//e+Zv/3vmb/9r5m//a+Zv/3vmb/975m//a+Zv/2vmb/975m//e+Zv/2vmb/9r5m//C5Y/Tw + uWP0AAAAFAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAABvO7ZPLzu2Ty975m//e+Zv/2 + vmb/9r5m//e+Zv/3vmb/9r5m//a+Zv/3vmb/975m//a+Zv/2vmb/975m//e+Zv/2vmb/9r5m//e+Zv/3 + vmb/9r5m//a+Zv/3vmb/975m//a+Zv/2vmb/8Llj9PC5Y/QAAAAUAAAAFAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAOOuYLzjrmC89Ltn//S7Z//0u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0 + u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0 + u2f/9Ltn/9KiWcjSolnIAAAAAwAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA465gvOOuYLz0u2f/9Ltn//S7aP/0 + u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0 + u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0u2j/9Lto//S7Z//0u2f/0qJZyNKiWcgAAAADAAAAAwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAEAAAABAAAABAAAAAQAAAAFAAAABQAAAAMAAAADAAAAAQAAAAEAAAAAAAAAAAAAAAAA + AAAAdVU1GHVVNRjxuGj/8bho//G5aP/xuWj/8bho//G4aP/xuGj/8bho//G4aP/xuGj/8bho//G4aP/x + uGj/8bho//G4aP/xuGj/8bho//G4aP/xuGj/8bho//G4aP/xuGj/8bho//G4aP/xuGj/8bho//G4aP/x + uGj/8bho//G4aP/xuGj/8bho/zIoFDMyKBQzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAIA + AAAFAAAABQAAAAUAAAAFAAAAAgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAAEAAAABAAAAAUA + AAAFAAAAAwAAAAMAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAB1VTUYdVU1GPG4aP/xuGj/8blo//G5aP/x + uGj/8bho//G4aP/xuGj/8bho//G4aP/xuGj/8bho//G4aP/xuGj/8bho//G4aP/xuGj/8bho//G4aP/x + uGj/8bho//G4aP/xuGj/8bho//G4aP/xuGj/8bho//G4aP/xuGj/8bho//G4aP/xuGj/MigUMzIoFDMA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAgAAAAUAAAAFAAAABQAAAAUAAAACAAAAAgAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4A + AAAOfU1Xan1NV2q2cX/WtnF/1sN6i/fDeov3xXuO+8V7jvvAeo3xwHqN8aZqe76manu+QSkzS0EpM0sA + AAAKAAAACuCqY7TgqmO07rVp/+61af/utWn/7rVp/+61af/utWn/7rZp/+62af/utmn/7rZp/+62af/u + tmn/7rZp/+62af/utmn/7rZp/+62af/utmn/7rZp/+62af/utmn/7rZp/+62af/utmn/7rVp/+61af/u + tWn/7rVp/+61af/utWn/7rVp/+61af/OnFvCzpxbwgAAAAIAAAACJi0aKCYtGih1nFGjdZxRo4i6X+uI + ul/ricBj+onAY/qGwGL5hsBi+Xy1XeN8tV3jWINCjliDQo4HBwckBwcHJAAAAAIAAAACAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAA59TVdqfU1XarZxf9a2cX/Ww3qL98N6i/fF + e477xXuO+8B6jfHAeo3xpmp7vqZqe75BKTNLQSkzSwAAAAoAAAAK4KpjtOCqY7TutWn/7rVp/+61af/u + tWn/7rVp/+61af/utmn/7rZp/+62af/utmn/7rZp/+62af/utmn/7rZp/+62af/utmn/7rZp/+62af/u + tmn/7rZp/+62af/utmn/7rZp/+62af/utWn/7rVp/+61af/utWn/7rVp/+61af/utWn/7rVp/86cW8LO + nFvCAAAAAgAAAAImLRooJi0aKHWcUaN1nFGjiLpf64i6X+uJwGP6icBj+obAYvmGwGL5fLVd43y1XeNY + g0KOWINCjgcHByQHBwckAAAAAgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAADmF1ngZhdZ4HH + eon/x3qJ/8d7i//He4v/x3yN/8d8jf/HfY//x32P/8d+kv/HfpL/x36U/8d+lP/Hf5b/x3+W/8aAmP/G + gJj/wX2W9sF9lvbnqmb956pm/e2yav/tsmr/7bJq/+2yav/ts2r/7bNq/+2yav/tsmr/7bJq/+2yav/t + smr/7bJq/+2zav/ts2r/7bJq/+2yav/tsmr/7bJq/+2yav/tsmr/7bNq/+2zav/tsmr/7bJq/+2yav/t + smr/7bJq/+2yav/ts2r/7bNq/+2yav/tsmr/6rFp/eqxaf2RtmDgkbZg4JfBZv+XwWb/lMFl/5TBZf+R + wWX/kcFl/47CZf+OwmX/i8Jk/4vCZP+IwmT/iMJk/4XBY/+FwWP/gsJi/4LCYv9ooFG8aKBRvAAAABUA + AAAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAwAAAAOYXWeBmF1ngcd6if/Heon/x3uL/8d7i//HfI3/x3yN/8d9j//H + fY//x36S/8d+kv/HfpT/x36U/8d/lv/Hf5b/xoCY/8aAmP/BfZb2wX2W9ueqZv3nqmb97bJq/+2yav/t + smr/7bJq/+2zav/ts2r/7bJq/+2yav/tsmr/7bJq/+2yav/tsmr/7bNq/+2zav/tsmr/7bJq/+2yav/t + smr/7bJq/+2yav/ts2r/7bNq/+2yav/tsmr/7bJq/+2yav/tsmr/7bJq/+2zav/ts2r/7bJq/+2yav/q + sWn96rFp/ZG2YOCRtmDgl8Fm/5fBZv+UwWX/lMFl/5HBZf+RwWX/jsJl/47CZf+LwmT/i8Jk/4jCZP+I + wmT/hcFj/4XBY/+CwmL/gsJi/2igUbxooFG8AAAAFQAAABUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAW9c4DYvXOA2Md6if/H + eon/x3uL/8d7i//HfI3/x3yN/8d9j//HfY//x36S/8d+kv/HfpT/x36U/8d/lv/Hf5b/xoCY/8aAmP/G + gZr/xoGa/8aBnP/GgZz/tVhB/7VYQf/Ykl3/2JJd/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//q + r2v/6q9r/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//q + r2v/6q9r/+qva//qr2v/6q9r/+qva//gqmP/4Kpj/5GEKv+RhCr/nMFm/5zBZv+awWb/msFm/5fBZv+X + wWb/lMFl/5TBZf+RwmX/kcJl/47CZf+OwmX/i8Jk/4vCZP+IwmT/iMJk/4XBY/+FwWP/gsJi/4LCYv98 + vmD4fL5g+AcHByUHBwclAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAFAAAABb1zgNi9c4DYx3qJ/8d6if/He4v/x3uL/8d8jf/HfI3/x32P/8d9j//H + fpL/x36S/8d+lP/HfpT/x3+W/8d/lv/GgJj/xoCY/8aBmv/GgZr/xoGc/8aBnP+1WEH/tVhB/9iSXf/Y + kl3/6q9r/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//q + r2v/6q9r/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+CqY//g + qmP/kYQq/5GEKv+cwWb/nMFm/5rBZv+awWb/l8Fm/5fBZv+UwWX/lMFl/5HCZf+RwmX/jsJl/47CZf+L + wmT/i8Jk/4jCZP+IwmT/hcFj/4XBY/+CwmL/gsJi/3y+YPh8vmD4BwcHJQcHByUAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAb1zgNS9c4DUx3qJ/8d6if/H + e4v/x3uL/8d8jf/HfI3/x32Q/8d9kP/HfpL/x36S/8d/lP/Hf5T/x3+W/8d/lv/GgJj/xoCY/8aBmv/G + gZr/xoGc/8aBnP/Ggp3/xoKd/7NXQv+zV0L/sldD/7JXQ//UjV3/1I1d/+esbP/nrGz/56xs/+esbP/n + rGz/56xs/+esbP/nrGz/56xs/+esbP/nrGz/56xs/+esbP/nrGz/56xs/+esbP/nrGz/56xs/+esbP/n + rGz/56xs/+esbP/nrGz/56xs/92nZP/dp2T/lYEq/5WBKv+SgSr/koEq/5/BZv+fwWb/nMFm/5zBZv+a + wWb/msFm/5fBZv+XwWb/lMFl/5TBZf+RwmX/kcJl/47CZf+OwmX/i8Jk/4vCZP+IwmT/iMJk/4XBY/+F + wWP/gsJj/4LCY/98wGH5fMBh+QAAABcAAAAXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAEAAAABvXOA1L1zgNTHeon/x3qJ/8d7i//He4v/x3yN/8d8jf/HfZD/x32Q/8d+kv/H + fpL/x3+U/8d/lP/Hf5b/x3+W/8aAmP/GgJj/xoGa/8aBmv/GgZz/xoGc/8aCnf/Ggp3/s1dC/7NXQv+y + V0P/sldD/9SNXf/UjV3/56xs/+esbP/nrGz/56xs/+esbP/nrGz/56xs/+esbP/nrGz/56xs/+esbP/n + rGz/56xs/+esbP/nrGz/56xs/+esbP/nrGz/56xs/+esbP/nrGz/56xs/+esbP/nrGz/3adk/92nZP+V + gSr/lYEq/5KBKv+SgSr/n8Fm/5/BZv+cwWb/nMFm/5rBZv+awWb/l8Fm/5fBZv+UwWX/lMFl/5HCZf+R + wmX/jsJl/47CZf+LwmT/i8Jk/4jCZP+IwmT/hcFj/4XBY/+CwmP/gsJj/3zAYfl8wGH5AAAAFwAAABcA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo2FtaaNhbWnHeon/x3qJ/8d7i//H + e4v/x3yN/8d8jf/HfZD/x32Q/8d+kv/HfpL/x36U/8d+lP/Hf5b/x3+W/8aAmP/GgJj/xoGa/8aBmv/G + gZz/xoGc/8aCnf/Ggp3/xYKf/8WCn/+xVUT/sVVE/7BWRP+wVkT/sFZF/7BWRf/Ril7/0Ype/+SobP/k + qGz/5Khs/+SobP/kqGz/5Khs/+SobP/kqGz/5Khs/+SobP/kqGz/5Khs/+SobP/kqGz/5Khs/+SobP/k + qGz/5Khs/+SobP/kqGz/26Nk/9ujZP+Yfir/mH4q/5V+Kv+Vfir/k34r/5N+K/+iwGb/osBm/5/BZv+f + wWb/nMFm/5zBZv+awWb/msFm/5fBZv+XwWb/lMFl/5TBZf+RwmX/kcJl/47CZf+OwmX/i8Jk/4vCZP+I + wmT/iMJk/4XBY/+FwWP/gsJi/4LCYv9uqVXKbqlVygAAAAMAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAACjYW1po2Ftacd6if/Heon/x3uL/8d7i//HfI3/x3yN/8d9kP/HfZD/x36S/8d+kv/H + fpT/x36U/8d/lv/Hf5b/xoCY/8aAmP/GgZr/xoGa/8aBnP/GgZz/xoKd/8aCnf/Fgp//xYKf/7FVRP+x + VUT/sFZE/7BWRP+wVkX/sFZF/9GKXv/Ril7/5Khs/+SobP/kqGz/5Khs/+SobP/kqGz/5Khs/+SobP/k + qGz/5Khs/+SobP/kqGz/5Khs/+SobP/kqGz/5Khs/+SobP/kqGz/5Khs/+SobP/bo2T/26Nk/5h+Kv+Y + fir/lX4q/5V+Kv+Tfiv/k34r/6LAZv+iwGb/n8Fm/5/BZv+cwWb/nMFm/5rBZv+awWb/l8Fm/5fBZv+U + wWX/lMFl/5HCZf+RwmX/jsJl/47CZf+LwmT/i8Jk/4jCZP+IwmT/hcFj/4XBY/+CwmL/gsJi/26pVcpu + qVXKAAAAAwAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAA8d6iP7Heoj+x3uL/8d7i//H + fI3/x3yN/8d9kP/HfZD/x36S/8d+kv/HfpT/x36U/8d/lv/Hf5b/xoCY/8aAmP/GgZr/xoGa/8aBnP/G + gZz/xoKd/8aCnf/Fgp//xYKf/8WCof/FgqH/rlRE/65URP+tU0X/rVNF/61URv+tVEb/rVRH/61UR//O + iF//zohf/+Glbf/hpW3/4aVs/+GlbP/hpWz/4aVs/+GlbP/hpWz/4aVs/+GlbP/hpWz/4aVs/+Glbf/h + pW3/4aVt/+Glbf/Zn2T/2Z9k/5p6Kv+aeir/mHoq/5h6Kv+Veyr/lXsq/5N8Kv+TfCr/pcBm/6XAZv+i + wGb/osBm/5/BZv+fwWb/nMFm/5zBZv+awWb/msFm/5fCZv+Xwmb/lMFl/5TBZf+RwmX/kcJl/47CZf+O + wmX/i8Jk/4vCZP+IwmT/iMJk/4XBY/+FwWP/gsJi/4LCYv8SHhIrEh4SKwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAMAAAADx3qI/sd6iP7He4v/x3uL/8d8jf/HfI3/x32Q/8d9kP/HfpL/x36S/8d+lP/H + fpT/x3+W/8d/lv/GgJj/xoCY/8aBmv/GgZr/xoGc/8aBnP/Ggp3/xoKd/8WCn//Fgp//xYKh/8WCof+u + VET/rlRE/61TRf+tU0X/rVRG/61URv+tVEf/rVRH/86IX//OiF//4aVt/+Glbf/hpWz/4aVs/+GlbP/h + pWz/4aVs/+GlbP/hpWz/4aVs/+GlbP/hpWz/4aVt/+Glbf/hpW3/4aVt/9mfZP/Zn2T/mnoq/5p6Kv+Y + eir/mHoq/5V7Kv+Veyr/k3wq/5N8Kv+lwGb/pcBm/6LAZv+iwGb/n8Fm/5/BZv+cwWb/nMFm/5rBZv+a + wWb/l8Jm/5fCZv+UwWX/lMFl/5HCZf+RwmX/jsJl/47CZf+LwmT/i8Jk/4jCZP+IwmT/hcFj/4XBY/+C + wmL/gsJi/xIeEisSHhIrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl19oO5dfaDvHe4v/x3uL/8d8jf/H + fI3/x32Q/8d9kP/HfpL/x36S/8d+lP/HfpT/x3+W/8d/lv/GgJj/xoCY/8aBmv/GgZr/xoGc/8aBnP/G + gp3/xoKd/8WCn//Fgp//xYKh/8WCof/Fg6L/xYOi/6tSRv+rUkb/q1JG/6tSRv+qUkf/qlJH/6pSR/+q + Ukf/qVJI/6lSSP/LhF//y4Rf/96hbP/eoWz/3qFs/96hbP/eoWz/3qFs/96hbP/eoWz/3qFs/96hbP/e + oWz/3qFs/9abZP/Wm2T/nHcr/5x3K/+bdyv/m3cr/5h4K/+YeCv/lngq/5Z4Kv+TeCr/k3gq/6e/Zv+n + v2b/pcBm/6XAZv+iwGb/osBm/5/BZv+fwWb/nMFm/5zBZv+awWb/msFm/5fCZv+Xwmb/lMFl/5TBZf+R + wmX/kcJl/47CZf+OwmX/i8Jk/4vCZP+IwmT/iMJk/4XBY/+FwWP/aZ1QrGmdUKwAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAACXX2g7l19oO8d7i//He4v/x3yN/8d8jf/HfZD/x32Q/8d+kv/HfpL/x36U/8d+lP/H + f5b/x3+W/8aAmP/GgJj/xoGa/8aBmv/GgZz/xoGc/8aCnf/Ggp3/xYKf/8WCn//FgqH/xYKh/8WDov/F + g6L/q1JG/6tSRv+rUkb/q1JG/6pSR/+qUkf/qlJH/6pSR/+pUkj/qVJI/8uEX//LhF//3qFs/96hbP/e + oWz/3qFs/96hbP/eoWz/3qFs/96hbP/eoWz/3qFs/96hbP/eoWz/1ptk/9abZP+cdyv/nHcr/5t3K/+b + dyv/mHgr/5h4K/+WeCr/lngq/5N4Kv+TeCr/p79m/6e/Zv+lwGb/pcBm/6LAZv+iwGb/n8Fm/5/BZv+c + wWb/nMFm/5rBZv+awWb/l8Jm/5fCZv+UwWX/lMFl/5HCZf+RwmX/jsJl/47CZf+LwmT/i8Jk/4jCZP+I + wmT/hcFj/4XBY/9pnVCsaZ1QrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALx1hLC8dYSwx3yN/8d8jf/H + fY//x32P/8d+kv/HfpL/x36U/8d+lP/Hf5b/x3+W/8aAmP/GgJj/xoGa/8aBmv/GgZz/xoGc/8aCnf/G + gp3/xYKf/8WCn//FgqH/xYKh/8SCov/EgqL/xIKk/8SCpP+pUEb/qVBG/6hQR/+oUEf/p1FI/6dRSP+n + UUn/p1FJ/6ZRSf+mUUn/plFK/6ZRSv/IgWD/yIFg/9udbf/bnW3/251s/9udbP/bnWz/251s/9udbP/b + nWz/1Jhk/9SYZP+ecyr/nnMq/5x0Kv+cdCr/mnQq/5p0Kv+YdCr/mHQq/5Z1K/+WdSv/lHYr/5R2K/+p + v2b/qb9m/6fAZv+nwGb/pcBm/6XAZv+iwGb/osBm/5/BZv+fwWb/nMFm/5zBZv+awWb/msFm/5fCZv+X + wmb/lMFl/5TBZf+RwmX/kcJl/47CZf+OwmX/i8Jk/4vCZP+IwmT/iMJk/4K9YfWCvWH1AAAAAwAAAAMA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAvHWEsLx1hLDHfI3/x3yN/8d9j//HfY//x36S/8d+kv/HfpT/x36U/8d/lv/H + f5b/xoCY/8aAmP/GgZr/xoGa/8aBnP/GgZz/xoKd/8aCnf/Fgp//xYKf/8WCof/FgqH/xIKi/8SCov/E + gqT/xIKk/6lQRv+pUEb/qFBH/6hQR/+nUUj/p1FI/6dRSf+nUUn/plFJ/6ZRSf+mUUr/plFK/8iBYP/I + gWD/251t/9udbf/bnWz/251s/9udbP/bnWz/251s/9udbP/UmGT/1Jhk/55zKv+ecyr/nHQq/5x0Kv+a + dCr/mnQq/5h0Kv+YdCr/lnUr/5Z1K/+Udiv/lHYr/6m/Zv+pv2b/p8Bm/6fAZv+lwGb/pcBm/6LAZv+i + wGb/n8Fm/5/BZv+cwWb/nMFm/5rBZv+awWb/l8Jm/5fCZv+UwWX/lMFl/5HCZf+RwmX/jsJl/47CZf+L + wmT/i8Jk/4jCZP+IwmT/gr1h9YK9YfUAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDeovkw3qL5Md9j//H + fY//x36S/8d+kv/Hf5T/x3+U/8d/lv/Hf5b/xoCY/8aAmP/GgZr/xoGa/8aBnP/GgZz/xoKd/8aCnf/F + gp//xYKf/8WCof/FgqH/xIKi/8SCov/EgqT/xIKk/8ODpv/Dg6b/pk5H/6ZOR/+lT0j/pU9I/6VPSf+l + T0n/pE9J/6RPSf+kT0r/pE9K/6NPSv+jT0r/o09L/6NPS//FfmH/xX5h/9iZbP/YmWz/2Jlt/9iZbf/R + lGT/0ZRk/6BwK/+gcCv/nnAr/55wK/+ccCv/nHAr/5pxK/+acSv/mHEr/5hxK/+Wcir/lnIq/5RyK/+U + civ/rL5m/6y+Zv+pv2b/qb9m/6e/Zv+nv2b/pMBm/6TAZv+iwGb/osBm/5/BZv+fwWb/nMFm/5zBZv+a + wWb/msFm/5fCZv+Xwmb/lMFl/5TBZf+RwmX/kcJl/47CZf+OwmX/i8Jk/4vCZP+IwWP/iMFj/wAAAAcA + AAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAMN6i+TDeovkx32P/8d9j//HfpL/x36S/8d/lP/Hf5T/x3+W/8d/lv/G + gJj/xoCY/8aBmv/GgZr/xoGc/8aBnP/Ggp3/xoKd/8WCn//Fgp//xYKh/8WCof/EgqL/xIKi/8SCpP/E + gqT/w4Om/8ODpv+mTkf/pk5H/6VPSP+lT0j/pU9J/6VPSf+kT0n/pE9J/6RPSv+kT0r/o09K/6NPSv+j + T0v/o09L/8V+Yf/FfmH/2Jls/9iZbP/YmW3/2Jlt/9GUZP/RlGT/oHAr/6BwK/+ecCv/nnAr/5xwK/+c + cCv/mnEr/5pxK/+YcSv/mHEr/5ZyKv+Wcir/lHIr/5RyK/+svmb/rL5m/6m/Zv+pv2b/p79m/6e/Zv+k + wGb/pMBm/6LAZv+iwGb/n8Fm/5/BZv+cwWb/nMFm/5rBZv+awWb/l8Jm/5fCZv+UwWX/lMFl/5HCZf+R + wmX/jsJl/47CZf+LwmT/i8Jk/4jBY/+IwWP/AAAABwAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxXuO68V7juvH + fpL/x36S/8d+lP/HfpT/x3+W/8d/lv/GgJj/xoCY/8aBmv/GgZr/xoGc/8aBnP/Ggp3/xoKd/8WCn//F + gp//xYKh/8WCof/EgqL/xIKi/8SCpP/EgqT/w4Ol/8ODpf/Dgqf/w4Kn/6JMSP+iTEj/ok1J/6JNSf+h + TUn/oU1J/6FNSv+hTUr/oExK/6BMSv+gTUv/oE1L/59MS/+fTEv/n01M/59NTP/GgWP/xoFj/9KSaP/S + kmj/omwr/6JsK/+fbCr/n2wq/51tKv+dbSr/m20q/5ttKv+abiv/mm4r/5duK/+Xbiv/lW4r/5VuK/+T + byv/k28r/669Zf+uvWX/rL5l/6y+Zf+pvmb/qb5m/6e/Zv+nv2b/pMBm/6TAZv+iwGb/osBm/5/BZv+f + wWb/nMFm/5zBZv+awWb/msFm/5fBZv+XwWb/lMFl/5TBZf+RwmX/kcJl/47CZf+OwmX/i8Jk/4vCZP8A + AAAIAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFe47rxXuO68d+kv/HfpL/x36U/8d+lP/Hf5b/x3+W/8aAmP/G + gJj/xoGa/8aBmv/GgZz/xoGc/8aCnf/Ggp3/xYKf/8WCn//FgqH/xYKh/8SCov/EgqL/xIKk/8SCpP/D + g6X/w4Ol/8OCp//Dgqf/okxI/6JMSP+iTUn/ok1J/6FNSf+hTUn/oU1K/6FNSv+gTEr/oExK/6BNS/+g + TUv/n0xL/59MS/+fTUz/n01M/8aBY//GgWP/0pJo/9KSaP+ibCv/omwr/59sKv+fbCr/nW0q/51tKv+b + bSr/m20q/5puK/+abiv/l24r/5duK/+Vbiv/lW4r/5NvK/+Tbyv/rr1l/669Zf+svmX/rL5l/6m+Zv+p + vmb/p79m/6e/Zv+kwGb/pMBm/6LAZv+iwGb/n8Fm/5/BZv+cwWb/nMFm/5rBZv+awWb/l8Fm/5fBZv+U + wWX/lMFl/5HCZf+RwmX/jsJl/47CZf+LwmT/i8Jk/wAAAAgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMN7j9DD + e4/Qx36U/8d+lP/Hf5b/x3+W/8aAmP/GgJj/xoGa/8aBmv/GgZz/xoGc/8aCnf/Ggp3/xYKf/8WCn//F + gqH/xYKh/8SCov/EgqL/xIKk/8SCpP/Dg6X/w4Ol/8ODp//Dg6f/woOo/8KDqP+gS0n/oEtJ/59LSf+f + S0n/nktK/55LSv+dSkr/nUpK/51KS/+dSkv/nEpL/5xKS/+cSkz/nEpM/5tKTP+bSkz/m0pN/5tKTf+k + aCz/pGgs/6BoKv+gaCr/n2gq/59oKv+caSr/nGkq/5tqKv+bair/mGoq/5hqKv+Xayr/l2sq/5VsK/+V + bCv/k2wr/5NsK/+wvWX/sL1l/669Zf+uvWX/q75l/6u+Zf+pvmb/qb5m/6e/Zv+nv2b/pMBm/6TAZv+i + wGb/osBm/5/BZv+fwWb/nMFm/5zBZv+awWb/msFm/5fBZv+XwWb/lMFl/5TBZf+RwWX/kcFl/43BZPyN + wWT8AAAAAwAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw3uP0MN7j9DHfpT/x36U/8d/lv/Hf5b/xoCY/8aAmP/G + gZr/xoGa/8aBnP/GgZz/xoKd/8aCnf/Fgp//xYKf/8WCof/FgqH/xIKi/8SCov/EgqT/xIKk/8ODpf/D + g6X/w4On/8ODp//Cg6j/woOo/6BLSf+gS0n/n0tJ/59LSf+eS0r/nktK/51KSv+dSkr/nUpL/51KS/+c + Skv/nEpL/5xKTP+cSkz/m0pM/5tKTP+bSk3/m0pN/6RoLP+kaCz/oGgq/6BoKv+faCr/n2gq/5xpKv+c + aSr/m2oq/5tqKv+Yair/mGoq/5drKv+Xayr/lWwr/5VsK/+TbCv/k2wr/7C9Zf+wvWX/rr1l/669Zf+r + vmX/q75l/6m+Zv+pvmb/p79m/6e/Zv+kwGb/pMBm/6LAZv+iwGb/n8Fm/5/BZv+cwWb/nMFm/5rBZv+a + wWb/l8Fm/5fBZv+UwWX/lMFl/5HBZf+RwWX/jcFk/I3BZPwAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC6 + d4tyuneLcsd/lv/Hf5b/xoCY/8aAmP/GgZr/xoGa/8aBnP/GgZz/xoKd/8aCnf/Fgp//xYKf/8WCof/F + gqH/xIKi/8SCov/EgqT/xIKk/8ODpf/Dg6X/woOn/8KDp//Cg6j/woOo/8GCqf/Bgqn/nUlK/51JSv+c + SEr/nEhK/5tISv+bSEr/mkhL/5pIS/+aSEv/mkhL/5lIS/+ZSEv/mEhM/5hITP+YSE3/mEhN/4xBPP+M + QTz/gkEh/4JBIf+gZCn/oGQp/55lKf+eZSn/m2Uq/5tlKv+aZir/mmYq/5hmKv+YZir/lmcq/5ZnKv+U + aCv/lGgr/5NpK/+TaSv/srxk/7K8ZP+wvWX/sL1l/669Zf+uvWX/q75l/6u+Zf+pvmb/qb5m/6e/Zv+n + v2b/pcBm/6XAZv+iwGb/osBm/5/BZv+fwWb/nMFm/5zBZv+awWb/msFm/5fBZv+XwWb/lMFl/5TBZf+J + t2DZibdg2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALp3i3K6d4tyx3+W/8d/lv/GgJj/xoCY/8aBmv/G + gZr/xoGc/8aBnP/Ggp3/xoKd/8WCn//Fgp//xYKh/8WCof/EgqL/xIKi/8SCpP/EgqT/w4Ol/8ODpf/C + g6f/woOn/8KDqP/Cg6j/wYKp/8GCqf+dSUr/nUlK/5xISv+cSEr/m0hK/5tISv+aSEv/mkhL/5pIS/+a + SEv/mUhL/5lIS/+YSEz/mEhM/5hITf+YSE3/jEE8/4xBPP+CQSH/gkEh/6BkKf+gZCn/nmUp/55lKf+b + ZSr/m2Uq/5pmKv+aZir/mGYq/5hmKv+WZyr/lmcq/5RoK/+UaCv/k2kr/5NpK/+yvGT/srxk/7C9Zf+w + vWX/rr1l/669Zf+rvmX/q75l/6m+Zv+pvmb/p79m/6e/Zv+lwGb/pcBm/6LAZv+iwGb/n8Fm/5/BZv+c + wWb/nMFm/5rBZv+awWb/l8Fm/5fBZv+UwWX/lMFl/4m3YNmJt2DZAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAcVVVCXFVVQnGgJj/xoCY/8aBmv/GgZr/xoGc/8aBnP/Ggp3/xoKd/8WCn//Fgp//xYKh/8WCof/E + gqL/xIKi/8SCpP/EgqT/w4Ol/8ODpf/Cg6f/woOn/8KDqP/Cg6j/wYKq/8GCqv/Agqr/wIKq/5lGSv+Z + Rkr/mEZL/5hGS/+YRkv/mEZL/5dGS/+XRkv/lkZL/5ZGS/+VRkz/lUZM/5VFTP+VRUz/lEVN/5RFTf95 + Mx//eTMf/3YyHv92Mh7/nmAp/55gKf+cYSn/nGEp/5phKf+aYSn/mGIp/5hiKf+XYyr/l2Mq/5VkKv+V + ZCr/lGQq/5RkKv+SZSv/kmUr/7S7ZP+0u2T/srxk/7K8ZP+wvWX/sL1l/669Zf+uvWX/q75l/6u+Zf+p + v2b/qb9m/6e/Zv+nv2b/pcBm/6XAZv+iwGb/osBm/5/BZv+fwWb/nMFm/5zBZv+awWb/msFm/5fBZv+X + wWb/ZIBEUmSARFIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABxVVUJcVVVCcaAmP/GgJj/xoGa/8aBmv/G + gZz/xoGc/8aCnf/Ggp3/xYKf/8WCn//FgqH/xYKh/8SCov/EgqL/xIKk/8SCpP/Dg6X/w4Ol/8KDp//C + g6f/woOo/8KDqP/Bgqr/wYKq/8CCqv/Agqr/mUZK/5lGSv+YRkv/mEZL/5hGS/+YRkv/l0ZL/5dGS/+W + Rkv/lkZL/5VGTP+VRkz/lUVM/5VFTP+URU3/lEVN/3kzH/95Mx//djIe/3YyHv+eYCn/nmAp/5xhKf+c + YSn/mmEp/5phKf+YYin/mGIp/5djKv+XYyr/lWQq/5VkKv+UZCr/lGQq/5JlK/+SZSv/tLtk/7S7ZP+y + vGT/srxk/7C9Zf+wvWX/rr1l/669Zf+rvmX/q75l/6m/Zv+pv2b/p79m/6e/Zv+lwGb/pcBm/6LAZv+i + wGb/n8Fm/5/BZv+cwWb/nMFm/5rBZv+awWb/l8Fm/5fBZv9kgERSZIBEUgAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAEAAAABwH2W1MB9ltTGgZz/xoGc/8SBnf/EgZ3/xIGf/8SBn//EgaH/xIGh/8OBov/D + gaL/woGk/8KBpP/CgqX/woKl/8GBpv/Bgab/wIGo/8CBqP/Agan/wIGp/7+Bqv+/gar/v4Ks/7+CrP+W + REv/lkRL/5VES/+VREv/lENL/5RDS/+TQ0v/k0NL/5JDTP+SQ0z/kkNM/5JDTP+RQ0z/kUNM/5FDTP+R + Q0z/djAe/3YwHv90MB7/dDAe/5dXJ/+XVyf/m10p/5tdKf+aXin/ml4p/5deKf+XXin/ll8q/5ZfKv+U + YCr/lGAq/5NhKv+TYSr/kWIr/5FiK/+2umP/trpj/7O7Y/+zu2P/sLxk/7C8ZP+uvGT/rrxk/6y9ZP+s + vWT/qr1l/6q9Zf+nvmX/p75l/6W/Zf+lv2X/o79m/6O/Zv+gwGb/oMBm/53AZv+dwGb/nMFm/5zBZv+Z + wGX7mcBl+wAAAAYAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAHAfZbUwH2W1MaBnP/G + gZz/xIGd/8SBnf/EgZ//xIGf/8SBof/EgaH/w4Gi/8OBov/CgaT/woGk/8KCpf/CgqX/wYGm/8GBpv/A + gaj/wIGo/8CBqf/Agan/v4Gq/7+Bqv+/gqz/v4Ks/5ZES/+WREv/lURL/5VES/+UQ0v/lENL/5NDS/+T + Q0v/kkNM/5JDTP+SQ0z/kkNM/5FDTP+RQ0z/kUNM/5FDTP92MB7/djAe/3QwHv90MB7/l1cn/5dXJ/+b + XSn/m10p/5peKf+aXin/l14p/5deKf+WXyr/ll8q/5RgKv+UYCr/k2Eq/5NhKv+RYiv/kWIr/7a6Y/+2 + umP/s7tj/7O7Y/+wvGT/sLxk/668ZP+uvGT/rL1k/6y9ZP+qvWX/qr1l/6e+Zf+nvmX/pb9l/6W/Zf+j + v2b/o79m/6DAZv+gwGb/ncBm/53AZv+cwWb/nMFm/5nAZfuZwGX7AAAABgAAAAYAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA + AAABPCtHLzwrRy+eecTOnnnEzqqD1v6qg9b+gkCG/4JAhv9/QIf/f0CH/3w/iv98P4r/ej6M/3o+jP92 + PY7/dj2O/3M8kP9zPJD/cDuS/3A7kv9tOpT/bTqU/2o5lv9qOZb/ZjiY/2Y4mP9jNpn/YzaZ/2A1m/9g + NZv/TB5O/0weTv9pLEj/aSxI/5BBS/+QQUv/kEFM/5BBTP+PQUz/j0FM/45ATP+OQEz/jUBM/41ATP+L + P0n/iz9J/3QuHf90Lh3/ci4e/3IuHv+LSST/i0kk/5pZKP+aWSj/mFoo/5haKP+WWyn/llsp/5VcKf+V + XCn/kl0p/5JdKf9mVB//ZlQf/0NVGf9DVRn/T5U0/0+VNP9Nlzb/TZc2/0uZOP9LmTj/SZo6/0maOv9H + mzv/R5s7/0ScPf9EnD3/Qp4+/0KePv9An0D/QJ9A/z6gQf8+oEH/O6FD/zuhQ/84okT/OKJE/zaiRv82 + okb/UdCj/1HQo/9LwKLSS8Ci0hQ1LT8UNS0/AAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAE8K0cvPCtHL555xM6eecTOqoPW/qqD1v6C + QIb/gkCG/39Ah/9/QIf/fD+K/3w/iv96Poz/ej6M/3Y9jv92PY7/czyQ/3M8kP9wO5L/cDuS/206lP9t + OpT/ajmW/2o5lv9mOJj/ZjiY/2M2mf9jNpn/YDWb/2A1m/9MHk7/TB5O/2ksSP9pLEj/kEFL/5BBS/+Q + QUz/kEFM/49BTP+PQUz/jkBM/45ATP+NQEz/jUBM/4s/Sf+LP0n/dC4d/3QuHf9yLh7/ci4e/4tJJP+L + SST/mlko/5pZKP+YWij/mFoo/5ZbKf+WWyn/lVwp/5VcKf+SXSn/kl0p/2ZUH/9mVB//Q1UZ/0NVGf9P + lTT/T5U0/02XNv9Nlzb/S5k4/0uZOP9Jmjr/SZo6/0ebO/9Hmzv/RJw9/0ScPf9Cnj7/Qp4+/0CfQP9A + n0D/PqBB/z6gQf87oUP/O6FD/ziiRP84okT/NqJG/zaiRv9R0KP/UdCj/0vAotJLwKLSFDUtPxQ1LT8A + AAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAij + fMDDo3zAw7GH1f+xh9X/roXW/66F1v+rhNj/q4TY/6N5zf+jec3/fkCJ/35Aif98P4v/fD+L/3k+jf95 + Po3/dj2Q/3Y9kP9zPJL/czyS/3A7k/9wO5P/bDqV/2w6lf9pOZf/aTmX/2Y3mf9mN5n/Yjaa/2I2mv9f + NJz/XzSc/1UshP9VLIT/QxhF/0MYRf9BGEX/QRhF/3ExSf9xMUn/iz5M/4s+TP+KPkz/ij5M/4k9TP+J + PUz/hjtH/4Y7R/9yKx3/cisd/3ArHf9wKx3/hkIj/4ZCI/+YVSf/mFUn/5ZWKP+WVij/lVco/5VXKP93 + USH/d1Eh/0FHFP9BRxT/QEgV/0BIFf9Mfir/TH4q/0+UM/9PlDP/TpY1/06WNf9LmDf/S5g3/0maOf9J + mjn/R5o7/0eaO/9FnDz/RZw8/0OePv9Dnj7/QZ9A/0GfQP8+n0H/Pp9B/zyhQ/88oUP/OaFE/zmhRP9L + woX/S8KF/1bYs/9W2LP/VNi2/1TYtv9R2bn/Udm5/0S8o8tEvKPLAAAAFAAAABQAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAACKN8wMOjfMDDsYfV/7GH1f+uhdb/roXW/6uE2P+r + hNj/o3nN/6N5zf9+QIn/fkCJ/3w/i/98P4v/eT6N/3k+jf92PZD/dj2Q/3M8kv9zPJL/cDuT/3A7k/9s + OpX/bDqV/2k5l/9pOZf/ZjeZ/2Y3mf9iNpr/Yjaa/180nP9fNJz/VSyE/1UshP9DGEX/QxhF/0EYRf9B + GEX/cTFJ/3ExSf+LPkz/iz5M/4o+TP+KPkz/iT1M/4k9TP+GO0f/hjtH/3IrHf9yKx3/cCsd/3ArHf+G + QiP/hkIj/5hVJ/+YVSf/llYo/5ZWKP+VVyj/lVco/3dRIf93USH/QUcU/0FHFP9ASBX/QEgV/0x+Kv9M + fir/T5Qz/0+UM/9OljX/TpY1/0uYN/9LmDf/SZo5/0maOf9Hmjv/R5o7/0WcPP9FnDz/Q54+/0OePv9B + n0D/QZ9A/z6fQf8+n0H/PKFD/zyhQ/85oUT/OaFE/0vChf9LwoX/Vtiz/1bYs/9U2Lb/VNi2/1HZuf9R + 2bn/RLyjy0S8o8sAAAAUAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAACLOIzu+z + iM7vtInT/7SJ0/+xh9X/sYfV/66F1v+uhdb/q4TY/6uE2P+ogtn/qILZ/592zf+fds3/fD+N/3w/jf94 + P4//eD+P/3Y9kf92PZH/cj2T/3I9k/9vO5T/bzuU/2w6l/9sOpf/aDiY/2g4mP9lN5r/ZTea/2I2m/9i + Npv/XjSd/140nf9aM57/WjOe/0IYR/9CGEf/PxdG/z8XRv88Fkb/PBZG/1glSP9YJUj/hjtL/4Y7S/+F + Okv/hTpL/4M6Sv+DOkr/bykc/28pHP9tKR3/bSkd/4pFI/+KRSP/llEm/5ZRJv+UUif/lFIn/2NIGv9j + SBr/QkIT/0JCE/9ARBT/QEQU/0BHFf9ARxX/UpEx/1KRMf9QkzP/UJMz/06VNf9OlTX/TJc3/0yXN/9K + mTn/Spk5/0iaO/9Imjv/Rps8/0abPP9EnT7/RJ0+/0GfQP9Bn0D/QJ9C/0CfQv89oEP/PaBD/03Agf9N + wIH/Wdiw/1nYsP9W2LP/Vtiz/1TZtv9U2bb/Udm6/1HZuv9O2rz/Ttq8/0rTufJK07nyAAAAGAAAABgA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAIs4jO77OIzu+0idP/tInT/7GH1f+xh9X/roXW/66F1v+r + hNj/q4TY/6iC2f+ogtn/n3bN/592zf98P43/fD+N/3g/j/94P4//dj2R/3Y9kf9yPZP/cj2T/287lP9v + O5T/bDqX/2w6l/9oOJj/aDiY/2U3mv9lN5r/Yjab/2I2m/9eNJ3/XjSd/1oznv9aM57/QhhH/0IYR/8/ + F0b/PxdG/zwWRv88Fkb/WCVI/1glSP+GO0v/hjtL/4U6S/+FOkv/gzpK/4M6Sv9vKRz/bykc/20pHf9t + KR3/ikUj/4pFI/+WUSb/llEm/5RSJ/+UUif/Y0ga/2NIGv9CQhP/QkIT/0BEFP9ARBT/QEcV/0BHFf9S + kTH/UpEx/1CTM/9QkzP/TpU1/06VNf9Mlzf/TJc3/0qZOf9KmTn/SJo7/0iaO/9Gmzz/Rps8/0SdPv9E + nT7/QZ9A/0GfQP9An0L/QJ9C/z2gQ/89oEP/TcCB/03Agf9Z2LD/Wdiw/1bYs/9W2LP/VNm2/1TZtv9R + 2br/Udm6/07avP9O2rz/StO58krTufIAAAAYAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABs4bJ3LOGydy3 + itL/t4rS/7SJ1P+0idT/sYfV/7GH1f+uhdf/roXX/6uE2P+rhNj/qILZ/6iC2f+lgNr/pYDa/5x0z/+c + dM//eD+Q/3g/kP91PpL/dT6S/3I8lP9yPJT/bzuW/287lv9sOpj/bDqY/2g4mf9oOJn/ZDeb/2Q3m/9h + NZz/YTWc/100nv9dNJ7/WjKf/1oyn/9TLZX/Uy2V/zwWRv88Fkb/OhVG/zoVRv83FEX/NxRF/2QqSf9k + Kkn/gDhM/4A4TP+AN0v/gDdL/2wnHP9sJxz/aycc/2snHP+TSiX/k0ol/5RNJv+UTSb/c0ce/3NHHv9B + PhL/QT4S/0BAEv9AQBL/P0EU/z9BFP9RhSv/UYUr/1KQMf9SkDH/UJIz/1CSM/9OlDX/TpQ1/02WN/9N + ljf/S5g5/0uYOf9Jmjv/SZo7/0ebPP9Hmzz/RJ0+/0SdPv9CnkD/Qp5A/0GfQv9Bn0L/UL9+/1C/fv9b + 163/W9et/1nYsP9Z2LD/Vtiz/1bYs/9U2bb/VNm2/1HZuv9R2br/T9q8/0/avP9M2r//TNq//0TMteJE + zLXiAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAQAAAAGzhsncs4bJ3LeK0v+3itL/tInU/7SJ1P+xh9X/sYfV/66F1/+u + hdf/q4TY/6uE2P+ogtn/qILZ/6WA2v+lgNr/nHTP/5x0z/94P5D/eD+Q/3U+kv91PpL/cjyU/3I8lP9v + O5b/bzuW/2w6mP9sOpj/aDiZ/2g4mf9kN5v/ZDeb/2E1nP9hNZz/XTSe/100nv9aMp//WjKf/1Mtlf9T + LZX/PBZG/zwWRv86FUb/OhVG/zcURf83FEX/ZCpJ/2QqSf+AOEz/gDhM/4A3S/+AN0v/bCcc/2wnHP9r + Jxz/aycc/5NKJf+TSiX/lE0m/5RNJv9zRx7/c0ce/0E+Ev9BPhL/QEAS/0BAEv8/QRT/P0EU/1GFK/9R + hSv/UpAx/1KQMf9QkjP/UJIz/06UNf9OlDX/TZY3/02WN/9LmDn/S5g5/0maO/9Jmjv/R5s8/0ebPP9E + nT7/RJ0+/0KeQP9CnkD/QZ9C/0GfQv9Qv37/UL9+/1vXrf9b163/Wdiw/1nYsP9W2LP/Vtiz/1TZtv9U + 2bb/Udm6/1HZuv9P2rz/T9q8/0zav/9M2r//RMy14kTMteIAAAAIAAAACAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRbqJYkW6iWLmL0f+5 + i9H/t4rS/7eK0v+0idT/tInU/7GH1f+xh9X/robX/66G1/+rhNj/q4TY/6iC2f+ogtn/pYDa/6WA2v+h + ftv/oX7b/5hx0P+YcdD/dT6U/3U+lP9yPJX/cjyV/288l/9vPJf/azqZ/2s6mf9nOJr/Zzia/2Q3nP9k + N5z/YDWe/2A1nv9cNJ//XDSf/1kyoP9ZMqD/VTCi/1Uwov9KJ4b/SieG/zgURv84FEb/NRNF/zUTRf8y + EkX/MhJF/3s1S/97NUv/ezRL/3s0S/9tJyP/bScj/2klHP9pJRz/k0gk/5NIJP+RSSX/kUkl/0E5EP9B + ORD/QDsR/0A7Ef8/PBL/PzwS/090Jf9PdCX/VI4u/1SOLv9TjzH/U48x/1GRMv9RkTL/T5M1/0+TNf9N + ljf/TZY3/0yYOP9MmDj/SZk6/0mZOv9Imzz/SJs8/0WcPv9FnD7/Q55A/0OeQP9Svnv/Ur57/13Wqf9d + 1qn/W9et/1vXrf9Z2LD/Wdiw/1bYs/9W2LP/VNm2/1TZtv9R2bn/Udm5/0/avP9P2rz/TNq//0zav/9J + 28L/SdvC/yiAcnIogHJyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAJFuoliRbqJYuYvR/7mL0f+3itL/t4rS/7SJ1P+0idT/sYfV/7GH1f+u + htf/robX/6uE2P+rhNj/qILZ/6iC2f+lgNr/pYDa/6F+2/+hftv/mHHQ/5hx0P91PpT/dT6U/3I8lf9y + PJX/bzyX/288l/9rOpn/azqZ/2c4mv9nOJr/ZDec/2Q3nP9gNZ7/YDWe/1w0n/9cNJ//WTKg/1kyoP9V + MKL/VTCi/0onhv9KJ4b/OBRG/zgURv81E0X/NRNF/zISRf8yEkX/ezVL/3s1S/97NEv/ezRL/20nI/9t + JyP/aSUc/2klHP+TSCT/k0gk/5FJJf+RSSX/QTkQ/0E5EP9AOxH/QDsR/z88Ev8/PBL/T3Ql/090Jf9U + ji7/VI4u/1OPMf9TjzH/UZEy/1GRMv9PkzX/T5M1/02WN/9Nljf/TJg4/0yYOP9JmTr/SZk6/0ibPP9I + mzz/RZw+/0WcPv9DnkD/Q55A/1K+e/9Svnv/Xdap/13Wqf9b163/W9et/1nYsP9Z2LD/Vtiz/1bYs/9U + 2bb/VNm2/1HZuf9R2bn/T9q8/0/avP9M2r//TNq//0nbwv9J28L/KIByciiAcnIAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABu4zO+buMzvm5 + i9H/uYvR/7eK0v+3itL/tInU/7SJ1P+xh9X/sYfV/66G1/+uhtf/q4TY/6uE2P+ogtn/qILZ/6WA2v+l + gNr/oX7b/6F+2/+ee9z/nnvc/5Rv0f+Ub9H/cT2X/3E9l/9uPJn/bjyZ/2o6m/9qOpv/Zzic/2c4nP9j + N53/Yzed/181n/9fNZ//XDOg/1wzoP9YMqL/WDKi/1Qvo/9UL6P/UC6k/1AupP9JKZj/SSmY/zMSR/8z + Ekf/MBJF/zASRf9KHUf/Sh1H/3YxSv92MUr/dC9F/3QvRf9/NSD/fzUg/5FEJP+RRCT/XjsX/147F/8/ + NxD/PzcQ/z85Ef8/ORH/VH0m/1R9Jv9Wiiv/Voor/1WMLf9VjC3/U44w/1OOMP9SkTL/UpEy/1CTNP9Q + kzT/TpU2/06VNv9Nlzj/TZc4/0qZOv9KmTr/SZo8/0maPP9GnD7/Rpw+/1S9eP9UvXj/X9Wm/1/Vpv9d + 1qn/Xdap/1vXrf9b163/Wdiw/1nYsP9W2LP/Vtiz/1TZt/9U2bf/Udm5/1HZuf9P2rz/T9q8/0zav/9M + 2r//SdvC/0nbwv9G2MP6RtjD+gAAAAgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAQAAAAG7jM75u4zO+bmL0f+5i9H/t4rS/7eK0v+0idT/tInU/7GH1f+x + h9X/robX/66G1/+rhNj/q4TY/6iC2f+ogtn/pYDa/6WA2v+hftv/oX7b/5573P+ee9z/lG/R/5Rv0f9x + PZf/cT2X/248mf9uPJn/ajqb/2o6m/9nOJz/Zzic/2M3nf9jN53/XzWf/181n/9cM6D/XDOg/1gyov9Y + MqL/VC+j/1Qvo/9QLqT/UC6k/0kpmP9JKZj/MxJH/zMSR/8wEkX/MBJF/0odR/9KHUf/djFK/3YxSv90 + L0X/dC9F/381IP9/NSD/kUQk/5FEJP9eOxf/XjsX/z83EP8/NxD/PzkR/z85Ef9UfSb/VH0m/1aKK/9W + iiv/VYwt/1WMLf9TjjD/U44w/1KRMv9SkTL/UJM0/1CTNP9OlTb/TpU2/02XOP9Nlzj/Spk6/0qZOv9J + mjz/SZo8/0acPv9GnD7/VL14/1S9eP9f1ab/X9Wm/13Wqf9d1qn/W9et/1vXrf9Z2LD/Wdiw/1bYs/9W + 2LP/VNm3/1TZt/9R2bn/Udm5/0/avP9P2rz/TNq//0zav/9J28L/SdvC/0bYw/pG2MP6AAAACAAAAAgA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmTWYUZk1mFLyMz/+8 + jM//uovR/7qL0f+3itL/t4rS/7SJ1P+0idT/sYfV/7GH1f+uhtf/robX/6uE2P+rhNj/qILZ/6iC2f+l + gNr/pYDa/6F92/+hfdv/nnvc/5573P+aeN3/mnjd/5Bt0/+QbdP/bjya/248mv9qOpz/ajqc/2Y4nf9m + OJ3/Yzee/2M3nv9eNaD/XjWg/1s0of9bNKH/VzKj/1cyo/9TL6T/Uy+k/08tpf9PLaX/Syym/0sspv9H + Kqj/Ryqo/zwgiP88IIj/LRJN/y0STf9yLkn/ci5J/3MwSv9zMEr/lUYx/5VGMf+OPyL/jj8i/0E4EP9B + OBD/UWge/1FoHv9ZhCb/WYQm/1iGKf9Yhin/Vokr/1aJK/9VjC3/VYwt/1SOMP9UjjD/UpAy/1KQMv9R + kjT/UZI0/0+UNv9PlDb/TZY4/02WOP9LmDr/S5g6/0qaPP9Kmjz/Vrt1/1a7df9g1KH/YNSh/1/Vpv9f + 1ab/Xdap/13Wqf9b163/W9et/1nYsP9Z2LD/Vtiz/1bYs/9U2bf/VNm3/1HZuf9R2bn/T9q8/0/avP9M + 2r//TNq//0nbwv9J28L/RtvF/0bbxf8RLCwuESwsLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAGZNZhRmTWYUvIzP/7yMz/+6i9H/uovR/7eK0v+3itL/tInU/7SJ1P+x + h9X/sYfV/66G1/+uhtf/q4TY/6uE2P+ogtn/qILZ/6WA2v+lgNr/oX3b/6F92/+ee9z/nnvc/5p43f+a + eN3/kG3T/5Bt0/9uPJr/bjya/2o6nP9qOpz/Zjid/2Y4nf9jN57/Yzee/141oP9eNaD/WzSh/1s0of9X + MqP/VzKj/1MvpP9TL6T/Ty2l/08tpf9LLKb/Syym/0cqqP9HKqj/PCCI/zwgiP8tEk3/LRJN/3IuSf9y + Lkn/czBK/3MwSv+VRjH/lUYx/44/Iv+OPyL/QTgQ/0E4EP9RaB7/UWge/1mEJv9ZhCb/WIYp/1iGKf9W + iSv/Vokr/1WMLf9VjC3/VI4w/1SOMP9SkDL/UpAy/1GSNP9RkjT/T5Q2/0+UNv9Nljj/TZY4/0uYOv9L + mDr/Spo8/0qaPP9Wu3X/Vrt1/2DUof9g1KH/X9Wm/1/Vpv9d1qn/Xdap/1vXrf9b163/Wdiw/1nYsP9W + 2LP/Vtiz/1TZt/9U2bf/Udm5/1HZuf9P2rz/T9q8/0zav/9M2r//SdvC/0nbwv9G28X/RtvF/xEsLC4R + LCwuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApXuxW6V7sVu8 + jM//vIzP/7qL0f+6i9H/t4rS/7eK0v+0idT/tInU/7GH1f+xh9X/robX/66G1/+rhNj/q4TY/6iC2f+o + gtn/pYDa/6WA2v+hfdv/oX3b/5573P+ee9z/mnjd/5p43f+Wdt7/lnbe/4xq1P+MatT/ajqd/2o6nf9m + OZ//Zjmf/2I3oP9iN6D/XjWi/141ov9aM6P/WjOj/1EvpP9RL6T/SSyk/0kspP9KLKb/Siym/0orqP9K + K6j/Rimp/0Ypqf9BJ6r/QSeq/z0lrP89Jaz/qXS8/ql0vP5AJkAUQCZAFEAAQARAAEAE2KNQ7tijUO5b + fSH/W30h/1qAJP9agCT/WYMm/1mDJv9YhSj/WIUo/1SHKv9Uhyr/TYgs/02ILP9Niy7/TYsu/1KPMv9S + jzL/UpE0/1KRNP9QlDb/UJQ2/06WOP9Oljj/TJg6/0yYOv9ZunL/Wbpy/2LTnf9i053/YNSh/2DUof9f + 1aX/X9Wl/13Wqf9d1qn/W9et/1vXrf9Z2LD/Wdiw/1bYs/9W2LP/VNm3/1TZt/9R2bn/Udm5/0/avP9P + 2rz/TNq//0zav/9K28L/StvC/0bbxf9G28X/LJGEdCyRhHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACle7FbpXuxW7yMz/+8jM//uovR/7qL0f+3itL/t4rS/7SJ1P+0 + idT/sYfV/7GH1f+uhtf/robX/6uE2P+rhNj/qILZ/6iC2f+lgNr/pYDa/6F92/+hfdv/nnvc/5573P+a + eN3/mnjd/5Z23v+Wdt7/jGrU/4xq1P9qOp3/ajqd/2Y5n/9mOZ//Yjeg/2I3oP9eNaL/XjWi/1ozo/9a + M6P/US+k/1EvpP9JLKT/SSyk/0ospv9KLKb/Siuo/0orqP9GKan/Rimp/0Enqv9BJ6r/PSWs/z0lrP+p + dLz+qXS8/kAmQBRAJkAUQABABEAAQATYo1Du2KNQ7lt9If9bfSH/WoAk/1qAJP9Zgyb/WYMm/1iFKP9Y + hSj/VIcq/1SHKv9NiCz/TYgs/02LLv9Niy7/Uo8y/1KPMv9SkTT/UpE0/1CUNv9QlDb/TpY4/06WOP9M + mDr/TJg6/1m6cv9ZunL/YtOd/2LTnf9g1KH/YNSh/1/Vpf9f1aX/Xdap/13Wqf9b163/W9et/1nYsP9Z + 2LD/Vtiz/1bYs/9U2bf/VNm3/1HZuf9R2bn/T9q8/0/avP9M2r//TNq//0rbwv9K28L/RtvF/0bbxf8s + kYR0LJGEdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALCEv4uw + hL+LvI3P/7yNz/+6i9H/uovR/7eK0v+3itL/tInU/7SJ1P+xh9X/sYfV/66G1/+uhtf/q4TY/6uE2P+o + gtn/qILZ/6WA2v+lgNr/oX3b/6F92/+ee9z/nnvc/5p43f+aeN3/lnbe/5Z23v+Sc9//knPf/4pr2f+K + a9n/Zjmh/2Y5of9ILqD/SC6g/xodnf8aHZ3/Fhue/xYbnv8VG5//FRuf/xQaoP8UGqD/Ehmh/xIZof8R + GKL/ERii/xQYpf8UGKX/NiOq/zYjqv8+JrH/Piax/yIdSjQiHUo0AAAAAAAAAAAAAAAAAAAAAEN6NxdD + ejcXXoks/16JLP9VfSL/VX0i/yBxHv8gcR7/FHAf/xRwH/8UcyH/FHMh/xR2JP8UdiT/FHgm/xR4Jv8T + eyj/E3so/xR+Kv8Ufir/MIkx/zCJMf9Pljj/T5Y4/13Aev9dwHr/Y9KZ/2PSmf9i053/YtOd/2DUof9g + 1KH/X9Wl/1/Vpf9d1qn/Xdap/1vXrf9b163/Wdiw/1nYsP9W2LP/Vtiz/1TZt/9U2bf/Udm6/1HZuv9P + 2rz/T9q8/0zav/9M2r//StvC/0rbwv9G28X/RtvF/zewoJ83sKCfAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsIS/i7CEv4u8jc//vI3P/7qL0f+6i9H/t4rS/7eK0v+0 + idT/tInU/7GH1f+xh9X/robX/66G1/+rhNj/q4TY/6iC2f+ogtn/pYDa/6WA2v+hfdv/oX3b/5573P+e + e9z/mnjd/5p43f+Wdt7/lnbe/5Jz3/+Sc9//imvZ/4pr2f9mOaH/Zjmh/0guoP9ILqD/Gh2d/xodnf8W + G57/Fhue/xUbn/8VG5//FBqg/xQaoP8SGaH/Ehmh/xEYov8RGKL/FBil/xQYpf82I6r/NiOq/z4msf8+ + JrH/Ih1KNCIdSjQAAAAAAAAAAAAAAAAAAAAAQ3o3F0N6NxdeiSz/Xoks/1V9Iv9VfSL/IHEe/yBxHv8U + cB//FHAf/xRzIf8UcyH/FHYk/xR2JP8UeCb/FHgm/xN7KP8Teyj/FH4q/xR+Kv8wiTH/MIkx/0+WOP9P + ljj/XcB6/13Aev9j0pn/Y9KZ/2LTnf9i053/YNSh/2DUof9f1aX/X9Wl/13Wqf9d1qn/W9et/1vXrf9Z + 2LD/Wdiw/1bYs/9W2LP/VNm3/1TZt/9R2br/Udm6/0/avP9P2rz/TNq//0zav/9K28L/StvC/0bbxf9G + 28X/N7CgnzewoJ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACy + hMCFsoTAhbyNz/+8jc//uovR/7qL0f+3itL/t4rS/7SJ1P+0idT/sYfV/7GH1f+uhtf/robX/6uE2P+r + hNj/qILZ/6iC2f+lgNr/pYDa/6F92/+hfdv/nnvc/5573P+aeN3/mnjd/5Z23v+Wdt7/knPf/5Jz3/+J + bt//iW7f/yc61/8nOtf/HSm5/x0puf8XHJ7/Fxye/xYboP8WG6D/FRuh/xUbof8UGqL/FBqi/xIZo/8S + GaP/ERik/xEYpP8QF6f/EBen/xIjy/8SI8v/HCzh/xws4f8SEjE5EhIxOQAAAAAAAAAAAAAAAAAAAAA3 + ZDcXN2Q3FzGmTf8xpk3/FpRB/xaUQf8UcSH/FHEh/xRwH/8UcB//FHMi/xRzIv8UdiT/FHYk/xR5Jv8U + eSb/E3sp/xN7Kf8Tfiv/E34r/xSPQ/8Uj0P/GLN4/xizeP9XzJH/V8yR/2PSmf9j0pn/YtOd/2LTnf9g + 1KH/YNSh/1/Vpf9f1aX/Xdap/13Wqf9b163/W9et/1nYsP9Z2LD/Vtiz/1bYs/9U2bf/VNm3/1HZuv9R + 2br/T9q8/0/avP9M2r//TNq//0rbwv9K28L/RtvF/0bbxf83sp+YN7KfmAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKEwIWyhMCFvI3P/7yNz/+6i9H/uovR/7eK0v+3 + itL/tInU/7SJ1P+xh9X/sYfV/66G1/+uhtf/q4TY/6uE2P+ogtn/qILZ/6WA2v+lgNr/oX3b/6F92/+e + e9z/nnvc/5p43f+aeN3/lnbe/5Z23v+Sc9//knPf/4lu3/+Jbt//JzrX/yc61/8dKbn/HSm5/xccnv8X + HJ7/Fhug/xYboP8VG6H/FRuh/xQaov8UGqL/Ehmj/xIZo/8RGKT/ERik/xAXp/8QF6f/EiPL/xIjy/8c + LOH/HCzh/xISMTkSEjE5AAAAAAAAAAAAAAAAAAAAADdkNxc3ZDcXMaZN/zGmTf8WlEH/FpRB/xRxIf8U + cSH/FHAf/xRwH/8UcyL/FHMi/xR2JP8UdiT/FHkm/xR5Jv8Teyn/E3sp/xN+K/8Tfiv/FI9D/xSPQ/8Y + s3j/GLN4/1fMkf9XzJH/Y9KZ/2PSmf9i053/YtOd/2DUof9g1KH/X9Wl/1/Vpf9d1qn/Xdap/1vXrf9b + 163/Wdiw/1nYsP9W2LP/Vtiz/1TZt/9U2bf/Udm6/1HZuv9P2rz/T9q8/0zav/9M2r//StvC/0rbwv9G + 28X/RtvF/zeyn5g3sp+YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAqH62Sah+tkm8jM//vIzP/7qL0f+6i9H/t4rS/7eK0v+0idT/tInU/7GH1f+xh9X/robX/66G1/+r + hNj/q4TY/6iC2f+ogtn/pYDa/6WA2v+hfdv/oX3b/5573P+ee9z/mnjd/5p43f+Wdt7/lnbe/4lu3v+J + bt7/JTjW/yU41v8jN9f/IzfX/yI22P8iNtj/ITXZ/yE12f8eM9b/HjPW/xwtzv8cLc7/GSrL/xkqy/8Y + K9L/GCvS/xgt3P8YLdz/Fize/xYs3v8VKt//FSrf/xMo4P8TKOD/L4Dy/C+A8vwFChAxBQoQMQAPDyIA + Dw8iLsix4i7IseIWnEf/FpxH/xefTP8Xn0z/F6FR/xehUf8XpFb/F6RW/xegU/8XoFP/F5xQ/xecUP8X + oFf/F6BX/xirZ/8Yq2f/F7Bw/xewcP8YsnX/GLJ1/xi0ev8YtHr/F7Z//xe2f/9Ny5P/TcuT/2LTnf9i + 053/YNSh/2DUof9f1aX/X9Wl/13Wqf9d1qn/W9et/1vXrf9Z2LD/Wdiw/1bYs/9W2LP/VNm3/1TZt/9R + 2bn/Udm5/0/avP9P2rz/TNq//0zav/9K28L/StvC/0bbxf9G28X/LZKFYC2ShWAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACofrZJqH62SbyMz/+8jM//uovR/7qL0f+3 + itL/t4rS/7SJ1P+0idT/sYfV/7GH1f+uhtf/robX/6uE2P+rhNj/qILZ/6iC2f+lgNr/pYDa/6F92/+h + fdv/nnvc/5573P+aeN3/mnjd/5Z23v+Wdt7/iW7e/4lu3v8lONb/JTjW/yM31/8jN9f/IjbY/yI22P8h + Ndn/ITXZ/x4z1v8eM9b/HC3O/xwtzv8ZKsv/GSrL/xgr0v8YK9L/GC3c/xgt3P8WLN7/Fize/xUq3/8V + Kt//Eyjg/xMo4P8vgPL8L4Dy/AUKEDEFChAxAA8PIgAPDyIuyLHiLsix4hacR/8WnEf/F59M/xefTP8X + oVH/F6FR/xekVv8XpFb/F6BT/xegU/8XnFD/F5xQ/xegV/8XoFf/GKtn/xirZ/8XsHD/F7Bw/xiydf8Y + snX/GLR6/xi0ev8Xtn//F7Z//03Lk/9Ny5P/YtOd/2LTnf9g1KH/YNSh/1/Vpf9f1aX/Xdap/13Wqf9b + 163/W9et/1nYsP9Z2LD/Vtiz/1bYs/9U2bf/VNm3/1HZuf9R2bn/T9q8/0/avP9M2r//TNq//0rbwv9K + 28L/RtvF/0bbxf8tkoVgLZKFYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAGBggAhgYIAIvIzP/7yMz/+6i9H/uovR/7eK0v+3itL/tInU/7SJ1P+xh9X/sYfV/66G1/+u + htf/q4TY/6uE2P+ogtn/qILZ/6WA2v+lgNr/oX3b/6F92/+ee9z/nnvc/5p43f+aeN3/jHHd/4xx3f8o + ONX/KDjV/yY31v8mN9b/JDbX/yQ21/8jNdj/IzXY/yE02f8hNNn/HzPZ/x8z2f8eMtr/HjLa/xww2/8c + MNv/Gi/b/xov2/8YLd3/GC3d/xcs3v8XLN7/Dije/w4o3v8DJd7/AyXe/wZw8v8GcPL/CHrz/wh68/8N + wM//DcDP/wa0uv8GtLr/BItK/wSLSv8QmE3/EJhN/xejU/8Xo1P/GKVY/xilWP8YqF3/GKhd/xirYv8Y + q2L/GK1n/xitZ/8Yr2z/GK9s/xixcf8YsXH/GLN2/xizdv8YtXv/GLV7/xe3gP8Xt4D/F7mF/xe5hf9M + zJf/TMyX/2DUof9g1KH/X9Wm/1/Vpv9d1qn/Xdap/1vXrf9b163/Wdiw/1nYsP9W2LP/Vtiz/1TZt/9U + 2bf/Udm5/1HZuf9P2rz/T9q8/0zav/9M2r//SdvC/0nbwv9G28X/RtvF/wsqIBgLKiAYAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYGCACGBggAi8jM//vIzP/7qL0f+6 + i9H/t4rS/7eK0v+0idT/tInU/7GH1f+xh9X/robX/66G1/+rhNj/q4TY/6iC2f+ogtn/pYDa/6WA2v+h + fdv/oX3b/5573P+ee9z/mnjd/5p43f+Mcd3/jHHd/yg41f8oONX/JjfW/yY31v8kNtf/JDbX/yM12P8j + Ndj/ITTZ/yE02f8fM9n/HzPZ/x4y2v8eMtr/HDDb/xww2/8aL9v/Gi/b/xgt3f8YLd3/Fyze/xcs3v8O + KN7/Dije/wMl3v8DJd7/BnDy/wZw8v8IevP/CHrz/w3Az/8NwM//BrS6/wa0uv8Ei0r/BItK/xCYTf8Q + mE3/F6NT/xejU/8YpVj/GKVY/xioXf8YqF3/GKti/xirYv8YrWf/GK1n/xivbP8Yr2z/GLFx/xixcf8Y + s3b/GLN2/xi1e/8YtXv/F7eA/xe3gP8XuYX/F7mF/0zMl/9MzJf/YNSh/2DUof9f1ab/X9Wm/13Wqf9d + 1qn/W9et/1vXrf9Z2LD/Wdiw/1bYs/9W2LP/VNm3/1TZt/9R2bn/Udm5/0/avP9P2rz/TNq//0zav/9J + 28L/SdvC/0bbxf9G28X/CyogGAsqIBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAALuLzu27i87tuYvR/7mL0f+3itL/t4rS/7SJ1P+0idT/sYfV/7GH1f+u + htf/robX/6uE2P+rhNj/qILZ/6iC2f+lgNr/pYDa/6F+2/+hftv/nnvc/5573P+Qc9z/kHPc/yk31P8p + N9T/KDfV/yg31f8mNtb/JjbW/yQ11v8kNdb/IzXY/yM12P8hM9j/ITPY/yAy2f8gMtn/HjHa/x4x2v8c + MNr/HDDa/xsv3P8bL9z/FSzc/xUs3P8DJtv/Aybb/wIl3P8CJdz/BUvo/wVL6P8Hb/L/B2/y/wZv7f8G + b+3/BJa4/wSWuP8Hs73/B7O9/wWghv8FoIb/AotP/wKLT/8DjVP/A41T/xSjWf8Uo1n/GKle/xipXv8Y + rGP/GKxj/xiuaP8Yrmj/GLBu/xiwbv8YsXL/GLFy/xezeP8Xs3j/GLZ8/xi2fP8Xt4H/F7eB/xe5hv8X + uYb/FruK/xa7iv9KzZz/Ss2c/1/Vpv9f1ab/Xdap/13Wqf9b163/W9et/1nYsP9Z2LD/Vtiz/1bYs/9U + 2bf/VNm3/1HZuf9R2bn/T9q8/0/avP9M2r//TNq//0nbwv9J28L/RdbB8EXWwfAAAAABAAAAAQAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu4vO7buLzu25 + i9H/uYvR/7eK0v+3itL/tInU/7SJ1P+xh9X/sYfV/66G1/+uhtf/q4TY/6uE2P+ogtn/qILZ/6WA2v+l + gNr/oX7b/6F+2/+ee9z/nnvc/5Bz3P+Qc9z/KTfU/yk31P8oN9X/KDfV/yY21v8mNtb/JDXW/yQ11v8j + Ndj/IzXY/yEz2P8hM9j/IDLZ/yAy2f8eMdr/HjHa/xww2v8cMNr/Gy/c/xsv3P8VLNz/FSzc/wMm2/8D + Jtv/AiXc/wIl3P8FS+j/BUvo/wdv8v8Hb/L/Bm/t/wZv7f8Elrj/BJa4/wezvf8Hs73/BaCG/wWghv8C + i0//AotP/wONU/8DjVP/FKNZ/xSjWf8YqV7/GKle/xisY/8YrGP/GK5o/xiuaP8YsG7/GLBu/xixcv8Y + sXL/F7N4/xezeP8Ytnz/GLZ8/xe3gf8Xt4H/F7mG/xe5hv8Wu4r/FruK/0rNnP9KzZz/X9Wm/1/Vpv9d + 1qn/Xdap/1vXrf9b163/Wdiw/1nYsP9W2LP/Vtiz/1TZt/9U2bf/Udm5/1HZuf9P2rz/T9q8/0zav/9M + 2r//SdvC/0nbwv9F1sHwRdbB8AAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmebkopnm5KLmL0f+5i9H/t4rS/7eK0v+0idT/tInU/7GH1f+x + h9X/robX/66G1/+rhNj/q4TY/6iC2f+ogtn/pYDa/6WA2v+hftv/oX7b/5R12/+Uddv/KzjT/ys40/8p + N9P/KTfT/yg31f8oN9X/JjXW/yY11v8lNdf/JTXX/yM02P8jNNj/ITTY/yE02P8gMtn/IDLZ/x4x2f8e + Mdn/HTDb/x0w2/8TLNv/Eyzb/wMn2v8DJ9r/Aybb/wMm2/8DJd3/AyXd/wdt8f8HbfH/B27y/wdu8v8C + YcH/AmHB/wFht/8BYbf/B7O//wezv/8HtML/B7TC/wOLUf8Di1H/A41V/wONVf8Dj1r/A49a/xGiYP8R + omD/GK1l/xitZf8Yr2r/GK9q/xiwb/8YsG//GLJ0/xiydP8YtHn/GLR5/xe2ff8Xtn3/F7iC/xe4gv8X + uof/F7qH/xa7i/8Wu4v/FbyQ/xW8kP9JzqD/Sc6g/13Wqf9d1qn/W9et/1vXrf9Z2LD/Wdiw/1bZs/9W + 2bP/VNm3/1TZt/9R2bn/Udm5/0/avP9P2rz/TNq//0zav/9J28L/SdvC/y6EdjguhHY4AAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZ5uSim + ebkouYvR/7mL0f+3itL/t4rS/7SJ1P+0idT/sYfV/7GH1f+uhtf/robX/6uE2P+rhNj/qILZ/6iC2f+l + gNr/pYDa/6F+2/+hftv/lHXb/5R12/8rONP/KzjT/yk30/8pN9P/KDfV/yg31f8mNdb/JjXW/yU11/8l + Ndf/IzTY/yM02P8hNNj/ITTY/yAy2f8gMtn/HjHZ/x4x2f8dMNv/HTDb/xMs2/8TLNv/Ayfa/wMn2v8D + Jtv/Aybb/wMl3f8DJd3/B23x/wdt8f8HbvL/B27y/wJhwf8CYcH/AWG3/wFht/8Hs7//B7O//we0wv8H + tML/A4tR/wOLUf8DjVX/A41V/wOPWv8Dj1r/EaJg/xGiYP8YrWX/GK1l/xivav8Yr2r/GLBv/xiwb/8Y + snT/GLJ0/xi0ef8YtHn/F7Z9/xe2ff8XuIL/F7iC/xe6h/8Xuof/FruL/xa7i/8VvJD/FbyQ/0nOoP9J + zqD/Xdap/13Wqf9b163/W9et/1nYsP9Z2LD/Vtmz/1bZs/9U2bf/VNm3/1HZuf9R2bn/T9q8/0/avP9M + 2r//TNq//0nbwv9J28L/LoR2OC6EdjgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC1iMyptYjMqbeK0v+3itL/tInU/7SJ1P+x + h9X/sYfV/66F1/+uhdf/q4TY/6uE2P+ogtn/qILZ/6WA2v+lgNr/mHja/5h42v8sN9H/LDfR/ys30/8r + N9P/KTbT/yk20/8oNtX/KDbV/yc11v8nNdb/JTTX/yU01/8jNNf/IzTX/yIz2f8iM9n/IDLZ/yAy2f8f + Mdr/HzHa/xov2v8aL9r/BCjZ/wQo2f8EJ9r/BCfa/wMm2/8DJtv/B13t/wdd7f8HbPH/B2zx/wdt8f8H + bfH/AV24/wFduP8BX7r/AV+6/weuwv8HrsL/B7PF/wezxf8Hq6//B6uv/wOMV/8DjFf/A45c/wOOXP8D + kWH/A5Fh/xaqZv8Wqmb/GLBs/xiwbP8YsXD/GLFw/xizdf8Ys3X/GLV6/xi1ev8Xt3//F7d//xe5g/8X + uYP/F7qI/xe6iP8Wu4z/FruM/xW8kf8VvJH/Fb6V/xW+lf9Hz6X/R8+l/1vXrf9b163/Wdiw/1nYsP9W + 2LP/Vtiz/1TZtv9U2bb/Udm6/1HZuv9P2rz/T9q8/0zav/9M2r//RMqzsUTKs7EAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAALWIzKm1iMypt4rS/7eK0v+0idT/tInU/7GH1f+xh9X/roXX/66F1/+rhNj/q4TY/6iC2f+o + gtn/pYDa/6WA2v+YeNr/mHja/yw30f8sN9H/KzfT/ys30/8pNtP/KTbT/yg21f8oNtX/JzXW/yc11v8l + NNf/JTTX/yM01/8jNNf/IjPZ/yIz2f8gMtn/IDLZ/x8x2v8fMdr/Gi/a/xov2v8EKNn/BCjZ/wQn2v8E + J9r/Aybb/wMm2/8HXe3/B13t/wds8f8HbPH/B23x/wdt8f8BXbj/AV24/wFfuv8BX7r/B67C/weuwv8H + s8X/B7PF/werr/8Hq6//A4xX/wOMV/8Djlz/A45c/wORYf8DkWH/Fqpm/xaqZv8YsGz/GLBs/xixcP8Y + sXD/GLN1/xizdf8YtXr/GLV6/xe3f/8Xt3//F7mD/xe5g/8Xuoj/F7qI/xa7jP8Wu4z/FbyR/xW8kf8V + vpX/Fb6V/0fPpf9Hz6X/W9et/1vXrf9Z2LD/Wdiw/1bYs/9W2LP/VNm2/1TZtv9R2br/Udm6/0/avP9P + 2rz/TNq//0zav/9EyrOxRMqzsQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0iM/BtIjPwbSJ0/+0 + idP/sYfV/7GH1f+uhdf/roXX/6uE2P+rhNj/qILZ/6iC2f+betn/m3rZ/y420P8uNtD/LTbR/y020f8r + NtL/KzbS/yo11P8qNdT/KDXU/yg11P8nNdb/JzXW/yU01/8lNNf/JDPY/yQz2P8iM9n/IjPZ/yEy2f8h + Mtn/HzHa/x8x2v8EKNn/BCjZ/wQn2v8EJ9r/BCbb/wQm2/8HUun/B1Lp/wlq8f8JavH/CGrw/whq8P8I + a+//CGvv/wFcu/8BXLv/AV68/wFevP8Gm8P/BpvD/wiyx/8Issf/CLPJ/wizyf8GpqT/Bqak/wOOXv8D + jl7/A5Bi/wOQYv8Dkmf/A5Jn/xiwbf8YsG3/GLJy/xiycv8YtHf/GLR3/xi2e/8Ytnv/F7iA/xe4gP8X + uYX/F7mF/xe7if8Xu4n/FryN/xa8jf8VvZL/Fb2S/xW+lv8Vvpb/Fb+b/xW/m/9G0an/RtGp/1nYsP9Z + 2LD/Vtiz/1bYs/9U2bb/VNm2/1HZuv9R2br/Ttq8/07avP9J0bfGSdG3xgAAAAIAAAACAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAALSIz8G0iM/BtInT/7SJ0/+xh9X/sYfV/66F1/+uhdf/q4TY/6uE2P+o + gtn/qILZ/5t62f+betn/LjbQ/y420P8tNtH/LTbR/ys20v8rNtL/KjXU/yo11P8oNdT/KDXU/yc11v8n + Ndb/JTTX/yU01/8kM9j/JDPY/yIz2f8iM9n/ITLZ/yEy2f8fMdr/HzHa/wQo2f8EKNn/BCfa/wQn2v8E + Jtv/BCbb/wdS6f8HUun/CWrx/wlq8f8IavD/CGrw/whr7/8Ia+//AVy7/wFcu/8BXrz/AV68/wabw/8G + m8P/CLLH/wiyx/8Is8n/CLPJ/wampP8GpqT/A45e/wOOXv8DkGL/A5Bi/wOSZ/8Dkmf/GLBt/xiwbf8Y + snL/GLJy/xi0d/8YtHf/GLZ7/xi2e/8XuID/F7iA/xe5hf8XuYX/F7uJ/xe7if8WvI3/FryN/xW9kv8V + vZL/Fb6W/xW+lv8Vv5v/Fb+b/0bRqf9G0an/Wdiw/1nYsP9W2LP/Vtiz/1TZtv9U2bb/Udm6/1HZuv9O + 2rz/Ttq8/0nRt8ZJ0bfGAAAAAgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACs + gstsrILLbLGH1f+xh9X/roXW/66F1v+rhNj/q4TY/5982P+ffNj/MDXP/zA1z/8uNdD/LjXQ/y010P8t + NdD/LDXS/yw10v8rNdT/KzXU/yg01P8oNNT/JzTW/yc01v8mM9f/JjPX/yQz2P8kM9j/IzLZ/yMy2f8h + Mdr/ITHa/xgu2v8YLtr/BCjZ/wQo2f8EKdv/BCnb/whf7f8IX+3/CWjw/wlo8P8JaPH/CWjx/wlp8f8J + afH/CGns/whp7P8BXL3/AVy9/wFev/8BXr//BY3F/wWNxf8Iscr/CLHK/wiyzP8Issz/CLTO/wi0zv8H + sML/B7DC/wORZ/8DkWf/A5Fo/wORaP8SqG7/Eqhu/xizdP8Ys3T/GLV4/xi1eP8Ytn3/GLZ9/xe4gv8X + uIL/F7qG/xe6hv8Xu4r/F7uK/xa8j/8WvI//Fb2T/xW9k/8Vv5f/Fb+X/xXAnP8VwJz/FMGg/xTBoP9F + 0q3/RdKt/1bYs/9W2LP/VNi2/1TYtv9R2bn/Udm5/0XDqHJFw6hyAAAAAQAAAAEAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKyCy2ysgstssYfV/7GH1f+uhdb/roXW/6uE2P+r + hNj/n3zY/5982P8wNc//MDXP/y410P8uNdD/LTXQ/y010P8sNdL/LDXS/ys11P8rNdT/KDTU/yg01P8n + NNb/JzTW/yYz1/8mM9f/JDPY/yQz2P8jMtn/IzLZ/yEx2v8hMdr/GC7a/xgu2v8EKNn/BCjZ/wQp2/8E + Kdv/CF/t/whf7f8JaPD/CWjw/wlo8f8JaPH/CWnx/wlp8f8Iaez/CGns/wFcvf8BXL3/AV6//wFev/8F + jcX/BY3F/wixyv8Iscr/CLLM/wiyzP8ItM7/CLTO/wewwv8HsML/A5Fn/wORZ/8DkWj/A5Fo/xKobv8S + qG7/GLN0/xizdP8YtXj/GLV4/xi2ff8Ytn3/F7iC/xe4gv8Xuob/F7qG/xe7iv8Xu4r/FryP/xa8j/8V + vZP/Fb2T/xW/l/8Vv5f/FcCc/xXAnP8UwaD/FMGg/0XSrf9F0q3/Vtiz/1bYs/9U2Lb/VNi2/1HZuf9R + 2bn/RcOockXDqHIAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAIACAACAAqeAzG6ngMxuqYLV7KmC1ewyNM7/MjTO/zA0z/8wNM//LzTQ/y800P8t + NNH/LTTR/yw00v8sNNL/KzTT/ys00/8pNNT/KTTU/ygz1f8oM9X/JjPX/yYz1/8lMtj/JTLY/yQy2f8k + Mtn/IjLa/yIy2v8IM93/CDPd/wlX6/8JV+v/CmXw/wpl8P8KZvD/Cmbw/wlm8P8JZvD/CWfw/wln8P8J + aPD/CWjw/who7f8IaO3/AVvA/wFbwP8BXcH/AV3B/wWQx/8FkMf/CLHM/wixzP8Isc7/CLHO/wiy0P8I + stD/CbTS/wm00v8JtNT/CbTU/witvv8Irb7/BpyC/wacgv8ZtHb/GbR2/xi2ev8Ytnr/F7d+/xe3fv8Y + uYP/GLmD/xe6iP8Xuoj/FryL/xa8i/8WvJD/FryQ/xW+lP8VvpT/Fb+Z/xW/mf8VwJz/FcCc/xTBof8U + waH/E8Kl/xPCpf9P0a/zT9Gv807HqHJOx6hyAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAIAAIACp4DMbqeAzG6p + gtXsqYLV7DI0zv8yNM7/MDTP/zA0z/8vNND/LzTQ/y000f8tNNH/LDTS/yw00v8rNNP/KzTT/yk01P8p + NNT/KDPV/ygz1f8mM9f/JjPX/yUy2P8lMtj/JDLZ/yQy2f8iMtr/IjLa/wgz3f8IM93/CVfr/wlX6/8K + ZfD/CmXw/wpm8P8KZvD/CWbw/wlm8P8JZ/D/CWfw/wlo8P8JaPD/CGjt/who7f8BW8D/AVvA/wFdwf8B + XcH/BZDH/wWQx/8Iscz/CLHM/wixzv8Isc7/CLLQ/wiy0P8JtNL/CbTS/wm01P8JtNT/CK2+/witvv8G + nIL/BpyC/xm0dv8ZtHb/GLZ6/xi2ev8Xt37/F7d+/xi5g/8YuYP/F7qI/xe6iP8WvIv/FryL/xa8kP8W + vJD/Fb6U/xW+lP8Vv5n/Fb+Z/xXAnP8VwJz/FMGh/xTBof8TwqX/E8Kl/0/Rr/NP0a/zTseock7HqHIA + AAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEhf5MdIX+THTWbx/01m8f9MaPH/TGjx/0xq8f9M + avH/S2zx/0ts8f9KbvL/Sm7y/0pv8v9Kb/L/SXHy/0lx8v9JcvP/SXLz/0hz8/9Ic/P/R3Xz/0d18/9G + dvL/Rnby/0V38/9Fd/P/C2Hv/wth7/8LYvD/C2Lw/wtj8P8LY/D/CmTw/wpk8P8KZe//CmXv/wpm8P8K + ZvD/CWfw/wln8P8JaPD/CWjw/wFbwv8BW8L/AV3E/wFdxP8Ho8z/B6PM/wmwz/8JsM//CbDQ/wmw0P8J + sdL/CbHS/wmy1P8JstT/CbPW/wmz1v8JtNj/CbTY/wm12v8Jtdr/OuDf/zrg3/864eH/OuHh/zvi4/87 + 4uP/O+Ll/zvi5f874ub/O+Lm/zvj5/874+f/O+Tp/zvk6f875Or/O+Tq/zvl7P875ez/OuXt/zrl7f86 + 5e//OuXv/zrm8P865vD/OOLs+Dji7PgAAAALAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAASF/kx0hf5MdNZvH/TWbx/0xo8f9MaPH/TGrx/0xq8f9LbPH/S2zx/0pu8v9KbvL/Sm/y/0pv8v9J + cfL/SXHy/0ly8/9JcvP/SHPz/0hz8/9HdfP/R3Xz/0Z28v9GdvL/RXfz/0V38/8LYe//C2Hv/wti8P8L + YvD/C2Pw/wtj8P8KZPD/CmTw/wpl7/8KZe//Cmbw/wpm8P8JZ/D/CWfw/wlo8P8JaPD/AVvC/wFbwv8B + XcT/AV3E/wejzP8Ho8z/CbDP/wmwz/8JsND/CbDQ/wmx0v8JsdL/CbLU/wmy1P8Js9b/CbPW/wm02P8J + tNj/CbXa/wm12v864N//OuDf/zrh4f864eH/O+Lj/zvi4/874uX/O+Ll/zvi5v874ub/O+Pn/zvj5/87 + 5On/O+Tp/zvk6v875Or/O+Xs/zvl7P865e3/OuXt/zrl7/865e//Oubw/zrm8P844uz4OOLs+AAAAAsA + AAALAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxdGCxcXRgtNYvD/TWLw/01k8P9NZPD/TWbx/01m8f9M + aPH/TGjx/0xq8f9MavH/S2zx/0ts8f9KbfL/Sm3y/0pv8v9Kb/L/SXHy/0lx8v9IcvP/SHLz/0hz8/9I + c/P/R3Xz/0d18/9GdvL/Rnby/wtf7/8LX+//C2Dv/wtg7/8LYe//C2Hv/wti8P8LYvD/C2Pw/wtj8P8L + ZPD/C2Tw/wpl8P8KZfD/Cmfw/wpn8P8BWsX/AVrF/wFbxv8BW8b/Ca/P/wmvz/8Jr9H/Ca/R/wmw0v8J + sNL/CbDU/wmw1P8Jsdb/CbHW/wmx2P8Jsdj/CbLa/wmy2v8Js9z/CbPc/zrh4f864eH/O+Lj/zvi4/87 + 4uX/O+Ll/zvi5v874ub/O+Pn/zvj5/864+n/OuPp/zvk6v875Or/O+Xs/zvl7P865e7/OuXu/zrl7/86 + 5e//Oubw/zrm8P855vH/Oebx/znm8/855vP/Gm50WBpudFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX + F0YLFxdGC01i8P9NYvD/TWTw/01k8P9NZvH/TWbx/0xo8f9MaPH/TGrx/0xq8f9LbPH/S2zx/0pt8v9K + bfL/Sm/y/0pv8v9JcfL/SXHy/0hy8/9IcvP/SHPz/0hz8/9HdfP/R3Xz/0Z28v9GdvL/C1/v/wtf7/8L + YO//C2Dv/wth7/8LYe//C2Lw/wti8P8LY/D/C2Pw/wtk8P8LZPD/CmXw/wpl8P8KZ/D/Cmfw/wFaxf8B + WsX/AVvG/wFbxv8Jr8//Ca/P/wmv0f8Jr9H/CbDS/wmw0v8JsNT/CbDU/wmx1v8Jsdb/CbHY/wmx2P8J + str/CbLa/wmz3P8Js9z/OuHh/zrh4f874uP/O+Lj/zvi5f874uX/O+Lm/zvi5v874+f/O+Pn/zrj6f86 + 4+n/O+Tq/zvk6v875ez/O+Xs/zrl7v865e7/OuXv/zrl7/865vD/Oubw/znm8f855vH/Oebz/znm8/8a + bnRYGm50WAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJT0mxCU9JsTWDw/01g8P9NYvD/TWLw/01k8P9N + ZPD/TWbx/01m8f9MaPH/TGjx/0xq8f9MavH/S2zx/0ts8f9KbfL/Sm3y/0pv8v9Kb/L/SXDy/0lw8v9I + cvP/SHLz/0hz8/9Ic/P/R3Xz/0d18/8LXu//C17v/wtf7/8LX+//C1/v/wtf7/8LYO//C2Dv/wti8P8L + YvD/C2Pw/wtj8P8LZPD/C2Tw/wtl8P8LZfD/B2He/wdh3v8Da8r/A2vK/wmt0f8JrdH/Ca7T/wmu0/8J + r9X/Ca/V/wmv1v8Jr9b/CbDY/wmw2P8Jsdr/CbHa/wmx2/8Jsdv/CbLd/wmy3f874uP/O+Lj/zvi5f87 + 4uX/O+Lm/zvi5v874+f/O+Pn/zrj6f864+n/OuTq/zrk6v875ez/O+Xs/zrl7f865e3/OuXv/zrl7/86 + 5vD/Oubw/znm8f855vH/Oebz/znm8/845/T/OOf0/zPT4NUz0+DVAAAAAQAAAAEAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAQlPSbEJT0mxNYPD/TWDw/01i8P9NYvD/TWTw/01k8P9NZvH/TWbx/0xo8f9MaPH/TGrx/0xq8f9L + bPH/S2zx/0pt8v9KbfL/Sm/y/0pv8v9JcPL/SXDy/0hy8/9IcvP/SHPz/0hz8/9HdfP/R3Xz/wte7/8L + Xu//C1/v/wtf7/8LX+//C1/v/wtg7/8LYO//C2Lw/wti8P8LY/D/C2Pw/wtk8P8LZPD/C2Xw/wtl8P8H + Yd7/B2He/wNryv8Da8r/Ca3R/wmt0f8JrtP/Ca7T/wmv1f8Jr9X/Ca/W/wmv1v8JsNj/CbDY/wmx2v8J + sdr/CbHb/wmx2/8Jst3/CbLd/zvi4/874uP/O+Ll/zvi5f874ub/O+Lm/zvj5/874+f/OuPp/zrj6f86 + 5Or/OuTq/zvl7P875ez/OuXt/zrl7f865e//OuXv/zrm8P865vD/Oebx/znm8f855vP/Oebz/zjn9P84 + 5/T/M9Pg1TPT4NUAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLWunNS1rpzU1e8P9NXvD/TWDw/01g8P9N + YvD/TWLw/01k8P9NZPD/TWbx/01m8f9MaPH/TGjx/0tq8f9LavH/S2zx/0ts8f9KbfL/Sm3y/0pv8v9K + b/L/SXDy/0lw8v9IcvP/SHLz/0dz8/9Hc/P/DFzv/wxc7/8LXe//C13v/wte7/8LXu//C1/v/wtf7/8L + YO//C2Dv/wth7/8LYe//C2Lw/wti8P8LZPD/C2Tw/wtl8P8LZfD/CqnS/wqp0v8KrNP/CqzT/wqt1f8K + rdX/Cq7W/wqu1v8Jrtj/Ca7Y/wmv2v8Jr9r/Ca/b/wmv2/8JsN3/CbDd/wqx3/8Ksd//O+Ll/zvi5f87 + 4ub/O+Lm/zvj5/874+f/OuPp/zrj6f865Or/OuTq/zvl7P875ez/OuXt/zrl7f865e//OuXv/zrm8P86 + 5vD/Oebx/znm8f855vP/Oebz/zjn9P845/T/OOf2/zjn9v835fX8N+X1/AAAAAUAAAAFAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAEta6c1LWunNTV7w/01e8P9NYPD/TWDw/01i8P9NYvD/TWTw/01k8P9NZvH/TWbx/0xo8f9M + aPH/S2rx/0tq8f9LbPH/S2zx/0pt8v9KbfL/Sm/y/0pv8v9JcPL/SXDy/0hy8/9IcvP/R3Pz/0dz8/8M + XO//DFzv/wtd7/8LXe//C17v/wte7/8LX+//C1/v/wtg7/8LYO//C2Hv/wth7/8LYvD/C2Lw/wtk8P8L + ZPD/C2Xw/wtl8P8KqdL/CqnS/wqs0/8KrNP/Cq3V/wqt1f8Krtb/Cq7W/wmu2P8Jrtj/Ca/a/wmv2v8J + r9v/Ca/b/wmw3f8JsN3/CrHf/wqx3/874uX/O+Ll/zvi5v874ub/O+Pn/zvj5/864+n/OuPp/zrk6v86 + 5Or/O+Xs/zvl7P865e3/OuXt/zrl7/865e//Oubw/zrm8P855vH/Oebx/znm8/855vP/OOf0/zjn9P84 + 5/b/OOf2/zfl9fw35fX8AAAABQAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATFjs6kxY7OpNXO//TVzv/01e8P9N + XvD/TWDw/01g8P9NYvD/TWLw/01k8P9NZPD/TGbx/0xm8f9MaPH/TGjx/0xq8f9MavH/S2zx/0ts8f9K + bfL/Sm3y/0pv8v9Kb/L/SXHy/0lx8v9IcvP/SHLz/wxZ7/8MWe//DFrv/wxa7/8MXO//DFzv/wxd7/8M + Xe//C17v/wte7/8LX+//C1/v/wth7/8LYe//C2Lv/wti7/8gnvb/IJ72/ynB9f8pwfX/CqvV/wqr1f8K + rNf/CqzX/wqs2P8KrNj/Cq3a/wqt2v8Krdz/Cq3c/wqu3f8Krt3/Cq7f/wqu3/8Kr+D/Cq/g/zvi5v87 + 4ub/O+Pn/zvj5/864+n/OuPp/zrk6v865Or/O+Xs/zvl7P865e3/OuXt/zrl7/865e//Oubw/zrm8P85 + 5vH/Oebx/znm8/855vP/OOf0/zjn9P845/b/OOf2/zjn9/845/f/Nuf4/zbn+P8AAAAIAAAACAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAABMWOzqTFjs6k1c7/9NXO//TV7w/01e8P9NYPD/TWDw/01i8P9NYvD/TWTw/01k8P9M + ZvH/TGbx/0xo8f9MaPH/TGrx/0xq8f9LbPH/S2zx/0pt8v9KbfL/Sm/y/0pv8v9JcfL/SXHy/0hy8/9I + cvP/DFnv/wxZ7/8MWu//DFrv/wxc7/8MXO//DF3v/wxd7/8LXu//C17v/wtf7/8LX+//C2Hv/wth7/8L + Yu//C2Lv/yCe9v8gnvb/KcH1/ynB9f8Kq9X/CqvV/wqs1/8KrNf/CqzY/wqs2P8Krdr/Cq3a/wqt3P8K + rdz/Cq7d/wqu3f8Krt//Cq7f/wqv4P8Kr+D/O+Lm/zvi5v874+f/O+Pn/zrj6f864+n/OuTq/zrk6v87 + 5ez/O+Xs/zrl7f865e3/OuXv/zrl7/865vD/Oubw/znm8f855vH/Oebz/znm8/845/T/OOf0/zjn9v84 + 5/b/OOf3/zjn9/825/j/Nuf4/wAAAAgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAExW7OVMVuzlTVnv/01Z7/9N + XO//TVzv/01e8P9NXvD/TWDw/01g8P9NYvD/TWLw/01k8P9NZPD/TGbx/0xm8f9MaPH/TGjx/0xq8f9M + avH/S2zx/0ts8f9KbfL/Sm3y/0pv8v9Kb/L/SXHy/0lx8v8NV+7/DVfu/w1Y7v8NWO7/DVrv/w1a7/8N + W+//DVvv/w1c7/8NXO//DF7v/wxe7/8MX+//DF/v/x2S9f8dkvX/LsL6/y7C+v8uwvr/LsL6/ye98/8n + vfP/C6vZ/wur2f8LrNr/C6za/wus3P8LrNz/Cqzd/wqs3f8KrN//Cqzf/wqt4P8KreD/Cq3i/wqt4v87 + 4+f/O+Pn/zrj6f864+n/OuTq/zrk6v875ez/O+Xs/zrl7f865e3/OuXv/zrl7/865vD/Oubw/znm8f85 + 5vH/Oebz/znm8/845/T/OOf0/zjn9v845/b/OOf3/zjn9/835/n/N+f5/zbn+v825/r/AAAABgAAAAYA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAATFbs5UxW7OVNWe//TVnv/01c7/9NXO//TV7w/01e8P9NYPD/TWDw/01i8P9N + YvD/TWTw/01k8P9MZvH/TGbx/0xo8f9MaPH/TGrx/0xq8f9LbPH/S2zx/0pt8v9KbfL/Sm/y/0pv8v9J + cfL/SXHy/w1X7v8NV+7/DVju/w1Y7v8NWu//DVrv/w1b7/8NW+//DVzv/w1c7/8MXu//DF7v/wxf7/8M + X+//HZL1/x2S9f8uwvr/LsL6/y7C+v8uwvr/J73z/ye98/8Lq9n/C6vZ/wus2v8LrNr/C6zc/wus3P8K + rN3/Cqzd/wqs3/8KrN//Cq3g/wqt4P8KreL/Cq3i/zvj5/874+f/OuPp/zrj6f865Or/OuTq/zvl7P87 + 5ez/OuXt/zrl7f865e//OuXv/zrm8P865vD/Oebx/znm8f855vP/Oebz/zjn9P845/T/OOf2/zjn9v84 + 5/f/OOf3/zfn+f835/n/Nuf6/zbn+v8AAAAGAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLVOe0S1TntE1X7/9N + V+//TVnv/01Z7/9NXO//TVzv/01e8P9NXvD/TWDw/01g8P9NYvD/TWLw/01k8P9NZPD/TGbx/0xm8f9M + aPH/TGjx/0tq8f9LavH/S2zx/0ts8f9KbfL/Sm3y/0pv8v9Kb/L/DVXu/w1V7v8NV+7/DVfu/w1X7v8N + V+7/DVnu/w1Z7v8NWu//DVrv/w1b7/8NW+//Ho/1/x6P9f8wwPr/MMD6/zDA+v8wwPr/MMD6/zDA+v8w + wPr/MMD6/yi78/8ou/P/C6rc/wuq3P8Lqt3/C6rd/wur3/8Lq9//Cqvg/wqr4P8KrOH/Cqzh/wqs4/8K + rOP/O+Tp/zvk6f875Or/O+Tq/zvl7P875ez/OuXt/zrl7f865e//OuXv/zrm8P865vD/Oebx/znm8f85 + 5vP/Oebz/zjn9P845/T/OOf2/zjn9v845/f/OOf3/zfn+f835/n/Nuf6/zbn+v815Pj2NeT49gAAAAIA + AAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAEtU57RLVOe0TVfv/01X7/9NWe//TVnv/01c7/9NXO//TV7w/01e8P9N + YPD/TWDw/01i8P9NYvD/TWTw/01k8P9MZvH/TGbx/0xo8f9MaPH/S2rx/0tq8f9LbPH/S2zx/0pt8v9K + bfL/Sm/y/0pv8v8NVe7/DVXu/w1X7v8NV+7/DVfu/w1X7v8NWe7/DVnu/w1a7/8NWu//DVvv/w1b7/8e + j/X/Ho/1/zDA+v8wwPr/MMD6/zDA+v8wwPr/MMD6/zDA+v8wwPr/KLvz/yi78/8Lqtz/C6rc/wuq3f8L + qt3/C6vf/wur3/8Kq+D/Cqvg/wqs4f8KrOH/Cqzj/wqs4/875On/O+Tp/zvk6v875Or/O+Xs/zvl7P86 + 5e3/OuXt/zrl7/865e//Oubw/zrm8P855vH/Oebx/znm8/855vP/OOf0/zjn9P845/b/OOf2/zjn9/84 + 5/f/N+f5/zfn+f825/r/Nuf6/zXk+PY15Pj2AAAAAgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARkrWPkZK1j5N + Ve//TVXv/01X7/9NV+//TVnv/01Z7/9NXO//TVzv/01e8P9NXvD/TWDw/01g8P9NYvD/TWLw/01k8P9N + ZPD/TGbx/0xm8f9MaPH/TGjx/0xq8f9MavH/S2zx/0ts8f9KbvL/Sm7y/w1T7f8NU+3/DVTu/w1U7v8N + Ve7/DVXu/w1X7v8NV+7/DVju/w1Y7v8fjPX/H4z1/zG++v8xvvr/Mb76/zG++v8wvvr/ML76/zC++v8w + vvr/Mb76/zG++v8xv/r/Mb/6/ym69P8puvT/C6nf/wup3/8LqeD/C6ng/wqq4v8KquL/Cqrj/wqq4/8K + q+X/Cqvl/zvk6v875Or/O+Xs/zvl7P865e3/OuXt/zrl7/865e//Oubw/zrm8P855vH/Oebx/znm8/85 + 5vP/OOf0/zjn9P845/b/OOf2/zjn9/845/f/N+f5/zfn+f825/r/Nuf6/zbn+/825/v/L8zfri/M364A + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGStY+RkrWPk1V7/9NVe//TVfv/01X7/9NWe//TVnv/01c7/9N + XO//TV7w/01e8P9NYPD/TWDw/01i8P9NYvD/TWTw/01k8P9MZvH/TGbx/0xo8f9MaPH/TGrx/0xq8f9L + bPH/S2zx/0pu8v9KbvL/DVPt/w1T7f8NVO7/DVTu/w1V7v8NVe7/DVfu/w1X7v8NWO7/DVju/x+M9f8f + jPX/Mb76/zG++v8xvvr/Mb76/zC++v8wvvr/ML76/zC++v8xvvr/Mb76/zG/+v8xv/r/Kbr0/ym69P8L + qd//C6nf/wup4P8LqeD/Cqri/wqq4v8KquP/Cqrj/wqr5f8Kq+X/O+Tq/zvk6v875ez/O+Xs/zrl7f86 + 5e3/OuXv/zrl7/865vD/Oubw/znm8f855vH/Oebz/znm8/845/T/OOf0/zjn9v845/b/OOf3/zjn9/83 + 5/n/N+f5/zbn+v825/r/Nuf7/zbn+/8vzN+uL8zfrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA + AAABTVLu/01S7v9NVe//TVXv/01X7/9NV+//TVrv/01a7/9NXO//TVzv/01e8P9NXvD/TWDw/01g8P9N + YvD/TWLw/01k8P9NZPD/TGbx/0xm8f9MaPH/TGjx/0xq8f9MavH/S2zx/0ts8f8NUO3/DVDt/w1R7f8N + Ue3/DVPt/w1T7f8NVO7/DVTu/yCJ9P8gifT/Mrz6/zK8+v8yvPr/Mrz6/zK8+v8yvPr/Mrz6/zK8+v8y + vPr/Mrz6/zK8+v8yvPr/Mrz6/zK8+v8yvPr/Mrz6/ym49P8puPT/C6fi/wun4v8LqOP/C6jj/wqo5f8K + qOX/Cqnm/wqp5v875ez/O+Xs/zrl7f865e3/OuXv/zrl7/865vD/Oubw/znm8f855vH/Oebz/znm8/84 + 5/T/OOf0/zjn9v845/b/OOf3/zjn9/836Pn/N+j5/zbn+v825/r/Nuf7/zbn+/816P3/Nej9/xBYYCAQ + WGAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAFNUu7/TVLu/01V7/9NVe//TVfv/01X7/9N + Wu//TVrv/01c7/9NXO//TV7w/01e8P9NYPD/TWDw/01i8P9NYvD/TWTw/01k8P9MZvH/TGbx/0xo8f9M + aPH/TGrx/0xq8f9LbPH/S2zx/w1Q7f8NUO3/DVHt/w1R7f8NU+3/DVPt/w1U7v8NVO7/IIn0/yCJ9P8y + vPr/Mrz6/zK8+v8yvPr/Mrz6/zK8+v8yvPr/Mrz6/zK8+v8yvPr/Mrz6/zK8+v8yvPr/Mrz6/zK8+v8y + vPr/Kbj0/ym49P8Lp+L/C6fi/wuo4/8LqOP/Cqjl/wqo5f8Kqeb/Cqnm/zvl7P875ez/OuXt/zrl7f86 + 5e//OuXv/zrm8P865vD/Oebx/znm8f855vP/Oebz/zjn9P845/T/OOf2/zjn9v845/f/OOf3/zfo+f83 + 6Pn/Nuf6/zbn+v825/v/Nuf7/zXo/f816P3/EFhgIBBYYCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAElO4nNJTuJzTVLu/01S7v9NVe//TVXv/01X7/9NV+//TVrv/01a7/9NXO//TVzv/01e8P9N + XvD/TWDw/01g8P9NYvD/TWLw/01k8P9NZPD/TWbx/01m8f9MaPH/TGjx/0xq8f9MavH/Dk7t/w5O7f8O + UO3/DlDt/w5R7f8OUe3/IYb0/yGG9P8zuvr/M7r6/zO6+v8zuvr/M7r6/zO6+v8zuvr/M7r6/zO6+v8z + uvr/M7r6/zO6+v8zuvr/M7r6/zO6+v8zuvr/M7r6/zO6+v8zuvr/M7r6/yu29f8rtvX/C6bl/wum5f8L + p+b/C6fm/wqn6P8Kp+j/OuXt/zrl7f865e//OuXv/zrm8P865vD/Oebx/znm8f855vP/Oebz/zjn9P84 + 5/T/OOf2/zjn9v845/f/OOf3/zfo+f836Pn/Nuf6/zbn+v825/v/Nuf7/zXo/f816P3/Mdvy0DHb8tAA + AAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASU7ic0lO4nNNUu7/TVLu/01V7/9N + Ve//TVfv/01X7/9NWu//TVrv/01c7/9NXO//TV7w/01e8P9NYPD/TWDw/01i8P9NYvD/TWTw/01k8P9N + ZvH/TWbx/0xo8f9MaPH/TGrx/0xq8f8OTu3/Dk7t/w5Q7f8OUO3/DlHt/w5R7f8hhvT/IYb0/zO6+v8z + uvr/M7r6/zO6+v8zuvr/M7r6/zO6+v8zuvr/M7r6/zO6+v8zuvr/M7r6/zO6+v8zuvr/M7r6/zO6+v8z + uvr/M7r6/zO6+v8zuvr/K7b1/yu29f8LpuX/C6bl/wun5v8Lp+b/Cqfo/wqn6P865e3/OuXt/zrl7/86 + 5e//Oubw/zrm8P855vH/Oebx/znm8/855vP/OOf0/zjn9P845/b/OOf2/zjn9/845/f/N+j5/zfo+f82 + 5/r/Nuf6/zbn+/825/v/Nej9/zXo/f8x2/LQMdvy0AAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAE1Q7OBNUOzgTVLu/01S7v9NVe//TVXv/01X7/9NV+//TVnv/01Z7/9N + XO//TVzv/01e8P9NXvD/TWDw/01g8P9NYvD/TWLw/01k8P9NZPD/TWbx/01m8f9MaPH/TGjx/w5M7f8O + TO3/Dk3t/w5N7f8hhPP/IYTz/zS4+v80uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80 + uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80uPr/NLj6/yu09f8r + tPX/C6Xn/wul5/8Lpen/C6Xp/zrl7/865e//Oubw/zrm8P855vH/Oebx/znm8/855vP/OOf0/zjn9P84 + 5/b/OOf2/zjn9/845/f/N+f5/zfn+f825/r/Nuf6/zbn+/825/v/Nej9/zXo/f805/78NOf+/AAgIAgA + ICAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATVDs4E1Q7OBN + Uu7/TVLu/01V7/9NVe//TVfv/01X7/9NWe//TVnv/01c7/9NXO//TV7w/01e8P9NYPD/TWDw/01i8P9N + YvD/TWTw/01k8P9NZvH/TWbx/0xo8f9MaPH/Dkzt/w5M7f8OTe3/Dk3t/yGE8/8hhPP/NLj6/zS4+v80 + uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80 + uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80uPr/K7T1/yu09f8Lpef/C6Xn/wul6f8Lpen/OuXv/zrl7/86 + 5vD/Oubw/znm8f855vH/Oebz/znm8/845/T/OOf0/zjn9v845/b/OOf3/zjn9/835/n/N+f5/zbn+v82 + 5/r/Nuf7/zbn+/816P3/Nej9/zTn/vw05/78ACAgCAAgIAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAU1Q7eZNUO3mTVLu/01S7v9NVe//TVXv/01X7/9N + V+//TVnv/01Z7/9NXO//TVzv/01e8P9NXvD/TWDw/01g8P9NYvD/TWLw/01k8P9NZPD/TWbx/01m8f8O + Sez/Dkns/yKD8/8ig/P/Nbb5/zW2+f81tvn/Nbb5/zW2+v81tvr/Nbb6/zW2+v81tvn/Nbb5/zW2+f81 + tvn/Nbb6/zW2+v81tvr/Nbb6/zW1+f81tfn/Nbb5/zW2+f81tvr/Nbb6/zW2+v81tvr/Nbb5/zW2+f81 + tvn/Nbb5/yyy9v8ssvb/C6Pq/wuj6v865vD/Oubw/znm8f855vH/Oebz/znm8/845/T/OOf0/zjn9v84 + 5/b/OOf3/zjn9/835/n/N+f5/zbn+v825/r/Nuf7/zbn+/816P3/Nej9/zTn/vw05/78G15rExteaxMA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA + AAABTVDt5k1Q7eZNUu7/TVLu/01V7/9NVe//TVfv/01X7/9NWe//TVnv/01c7/9NXO//TV7w/01e8P9N + YPD/TWDw/01i8P9NYvD/TWTw/01k8P9NZvH/TWbx/w5J7P8OSez/IoPz/yKD8/81tvn/Nbb5/zW2+f81 + tvn/Nbb6/zW2+v81tvr/Nbb6/zW2+f81tvn/Nbb5/zW2+f81tvr/Nbb6/zW2+v81tvr/NbX5/zW1+f81 + tvn/Nbb5/zW2+v81tvr/Nbb6/zW2+v81tvn/Nbb5/zW2+f81tvn/LLL2/yyy9v8Lo+r/C6Pq/zrm8P86 + 5vD/Oebx/znm8f855vP/Oebz/zjn9P845/T/OOf2/zjn9v845/f/OOf3/zfn+f835/n/Nuf6/zbn+v82 + 5/v/Nuf7/zXo/f816P3/NOf+/DTn/vwbXmsTG15rEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEpQ5pBKUOaQTVLu/01S7v9N + Ve//TVXv/01X7/9NV+//TVnv/01Z7/9NXO//TVzv/01e8P9NXvD/TWDw/01g8P9NYvD/TWLw/0xk8PxM + ZPD8L5/2/S+f9v02s/n/NrP5/zWz+f81s/n/NbP5/zWz+f81s/n/NbP5/zaz+f82s/n/NbP5/zWz+f81 + s/n/NbP5/zWz+f81s/n/NrP5/zaz+f81s/n/NbP5/zWz+f81s/n/NbP5/zWz+f82s/n/NrP5/zWz+f81 + s/n/NbP5/zWz+f81s/n/NbP5/zOx9/wzsff8OeTw7Tnk8O055vP/Oebz/zjn9P845/T/OOf2/zjn9v84 + 5/f/OOf3/zfn+f835/n/Nuf6/zbn+v825/v/Nuf7/zXo/f816P3/MuD2yDLg9sgAADMFAAAzBQAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAASlDmkEpQ5pBNUu7/TVLu/01V7/9NVe//TVfv/01X7/9NWe//TVnv/01c7/9N + XO//TV7w/01e8P9NYPD/TWDw/01i8P9NYvD/TGTw/Exk8Pwvn/b9L5/2/Taz+f82s/n/NbP5/zWz+f81 + s/n/NbP5/zWz+f81s/n/NrP5/zaz+f81s/n/NbP5/zWz+f81s/n/NbP5/zWz+f82s/n/NrP5/zWz+f81 + s/n/NbP5/zWz+f81s/n/NbP5/zaz+f82s/n/NbP5/zWz+f81s/n/NbP5/zWz+f81s/n/M7H3/DOx9/w5 + 5PDtOeTw7Tnm8/855vP/OOf0/zjn9P845/b/OOf2/zjn9/845/f/N+f5/zfn+f825/r/Nuf6/zbn+/82 + 5/v/Nej9/zXo/f8y4PbIMuD2yAAAMwUAADMFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVVQMA + VVUDSVDkc0lQ5HNNVO3mTVTt5k1X7/1NV+/9TVnv/k1Z7/5NW+/6TVvv+kxc681MXOvNRFTLQERUy0AA + AAABAAAAATar8qs2q/KrNrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82 + sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82 + sPn/NrD5/zaw+f82sPn/NrD5/zaw+f8xn+C3MZ/gtwAAAAAAAAAANsnYITbJ2CE34fG1N+HxtTfm9vY3 + 5vb2Nuf4/jbn+P425/r+Nuf6/jXm+vA15vrwM9vwljPb8JYiiJkPIoiZDwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVVAwBVVQNJUORzSVDkc01U7eZNVO3mTVfv/U1X7/1N + We/+TVnv/k1b7/pNW+/6TFzrzUxc681EVMtARFTLQAAAAAEAAAABNqvyqzar8qs2sPn/NrD5/zaw+f82 + sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82 + sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zGf4Lcx + n+C3AAAAAAAAAAA2ydghNsnYITfh8bU34fG1N+b29jfm9vY25/j+Nuf4/jbn+v425/r+Neb68DXm+vAz + 2/CWM9vwliKImQ8iiJkPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAnibENJ4mxDTeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83 + rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83 + rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/EjdSHBI3UhwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACeJsQ0nibENN675/zeu+f83 + rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83 + rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f8S + N1IcEjdSHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2p/OuNqfzrjeq+f83qvn/N6r5/zeq+f83q/n/N6v5/zer+f83 + q/n/N6v5/zer+f83q/n/N6v5/zer+f83q/n/N6v5/zer+f83q/n/N6v5/zer+f83q/n/N6v5/zer+f83 + q/n/N6v5/zeq+f83qvn/N6r5/zeq+f8ynea2Mp3mtgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADan8642 + p/OuN6r5/zeq+f83qvn/N6r5/zer+f83q/n/N6v5/zer+f83q/n/N6v5/zer+f83q/n/N6v5/zer+f83 + q/n/N6v5/zer+f83q/n/N6v5/zer+f83q/n/N6v5/zer+f83q/n/N6r5/zeq+f83qvn/N6r5/zKd5rYy + nea2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3p/ftN6f37Ten+f83p/n/OKf5/zin+f84 + p/n/OKf5/zin+f84p/n/OKf5/zin+f84qPn/OKj5/zio+f84qPn/OKf5/zin+f84p/n/OKf5/zin+f84 + p/n/OKf5/zin+f83p/n/N6f5/zel9e43pfXuAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAADen9+03p/ftN6f5/zen+f84p/n/OKf5/zin+f84p/n/OKf5/zin+f84p/n/OKf5/zio+f84 + qPn/OKj5/zio+f84p/n/OKf5/zin+f84p/n/OKf5/zin+f84p/n/OKf5/zen+f83p/n/N6X17jel9e4A + AAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAE3pPbfN6T23zil+P84 + pfj/OKX4/zil+P84pfj/OKX4/zil+P84pfj/OKX4/zil+P84pfj/OKX4/zil+P84pfj/OKX4/zil+P84 + pfj/OKX4/zil+P84pfj/OKHz4Tih8+EAAAAFAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAABAAAAATek9t83pPbfOKX4/zil+P84pfj/OKX4/zil+P84pfj/OKX4/zil+P84 + pfj/OKX4/zil+P84pfj/OKX4/zil+P84pfj/OKX4/zil+P84pfj/OKX4/zil+P84ofPhOKHz4QAAAAUA + AAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2 + mexfNpnsXzih+P04ofj9OKH4/zih+P84ofj/OKH4/zih+P84ofj/OKH4/zih+P84ofj/OKH4/zih+P84 + ofj/OKH4/Tih+P0ykNxlMpDcZQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADaZ7F82mexfOKH4/Tih+P04ofj/OKH4/zih+P84 + ofj/OKH4/zih+P84ofj/OKH4/zih+P84ofj/OKH4/zih+P84ofj9OKH4/TKQ3GUykNxlAAAAAQAAAAEA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAADGM1h8xjNYfNpnvfzaZ7382m/K3Npvytzab8rc2m/K3NZbpgTWW6YEu + fMEhLnzBIQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMYzWHzGM1h82 + me9/Npnvfzab8rc2m/K3Npvytzab8rc1lumBNZbpgS58wSEufMEhAAAAAQAAAAEAAAAAAAAAAAAAAAAA + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////// + /////////////////////////////////////////////////////////////////////////D////// + //////////////w///////////////////8AAD//////////////////AAA/////////////////8AAA + D/////////////////AAAA/////////////////AAAAD////////////////wAAAA/////////////// + /wAAAAD///////////////8AAAAA////////////////AAAAAD///////////////wAAAAA///////// + ////ADwAAAAAPwD//////////wA8AAAAAD8A//////////AAAAAAAAAAAAP////////wAAAAAAAAAAAD + ////////AAAAAAAAAAAAAP///////wAAAAAAAAAAAAD///////wAAAAAAAAAAAAAP//////8AAAAAAAA + AAAAAD//////8AAAAAAAAAAAAAAP//////AAAAAAAAAAAAAAD//////wAAAAAAAAAAAAAAP/////8AAA + AAAAAAAAAAAD/////8AAAAAAAAAAAAAAA//////AAAAAAAAAAAAAAAP/////wAAAAAAAAAAAAAAD//// + /8AAAAAAAAAAAAAAA//////AAAAAAAAAAAAAAAD/////wAAAAAAAAAAAAAAA/////8AAAAAAAAAAAAAA + AP/////AAAAAAAAAAAAAAAD/////wAAAAAAAAAAAAAAA/////8AAAAAAAAAAAAAAAP/////AAAAAAAAA + AAAAAAD/////wAAAAAAAAAAAAAAA/////8AAAAAAAAAAAAAAA//////AAAAAAAAAAAAAAAP/////wAAA + AAAAAAAAAAAD/////8AAAAAAAAAAAAAAA//////AAAAAAAAAAAAAAAP/////wAAAAAAAAAAAAAAD//// + /AAAAAAAAAAAAAAAAD////wAAAAAAAAAAAAAAAA////wAAAAAAAAAAAAAAAAD///8AAAAAAAAAAAAAAA + AA///8AAAAAAAAAAAAAAAAAD///AAAAAAAAAAAAAAAAAA///AAAAAAAAAAAAAAAAAAD//wAAAAAAAAAA + AAAAAAAA//8AAAAAAAAAAAAAAAAAAP//AAAAAAAAAAAAAAAAAAD//AAAAAAAAAAAAAAAAAAAP/wAAAAA + AAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAD/8 + AAAAAAAAAAAAAAAAAAA//AAAAAAAAAPAAAAAAAAAP/wAAAAAAAADwAAAAAAAAD/8AAAAAAAAA8AAAAAA + AAA//AAAAAAAAAPAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAA//AAAAAAAAAAA + AAAAAAAAP/wAAAAAAAAAAAAAAAAAAD//AAAAAAAAAAAAAAAAAAA//wAAAAAAAAAAAAAAAAAAP/8AAAAA + AAAAAAAAAAAAAP//AAAAAAAAAAAAAAAAAAD//8AAAAAAAAAAAAAAAAAD///AAAAAAAAAAAAAAAAAA/// + 8AAAAAAAAAAAAAAAAAP///AAAAAAAAAAAAAAAAAD///8AAAAAAAAAAAAAAAAD////AAAAAAAAAAAAAAA + AA////8AAAAAAAAAAAAAAAD/////AAAAAAAAAAAAAAAA//////AAAAAAAAAAAAAAA//////wAAAAAAAA + AAAAAAP/////wAAAAAAAAAAAAAAD/////8AAAAAAAAAAAAAAA//////AAAAAAAAAAAAAAAD/////wAAA + AAAAAAAAAAAA/////8AAAAAAAAAAAAAAAP/////AAAAAAAAAAAAAAAD/////wAAAAAAAAAAAAAAA//// + /8AAAAAAAAAAAAAAAP/////AAAAAAAAAAAAAAAD/////wAAAAAAAAAAAAAAA/////8AAAAAAAAAAAAAA + AP/////AAAAAAAAAAAAAAAD/////wAAAAAAAAAAAAAAD/////8AAAAAAAAAAAAAAA//////AAAAAAAAA + AAAAAAP/////wAAAAAAAAAAAAAAD//////AAAAAAAAAAAAAAA//////wAAAAAAAAAAAAAAP//////AAA + AAAAAAAAAAAP//////wAAAAAAAAAAAAAD//////8AAAAAAAAAAAAAD///////AAAAAAAAAAAAAA///// + ///AAAAAAAAAAAAA////////wAAAAAAAAAAAAP////////AAAAAAAAAwAA/////////wAAAAAAAAMAAP + ///////////8AAAAAD///////////////AAAAAA///////////////8AAAAA////////////////AAAA + AP///////////////8AAAAD////////////////AAAAA////////////////wAAAA/////////////// + /8AAAAP////////////////8AAAP/////////////////AAAD//////////////////AAP////////// + ////////wAD///////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////KAAAAEAAAACA + AAAAAQAgAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAKcVkrSMqeT6XlsljR5LFX0saaTalkTiVSAAAAEgAAAAEAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW/lEyD/MNj/vzDY//8w2P//MNj//zDY//8w2P//MNj//vDY/6r + hkWRAAAADQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvxumLp+cBl//nAZf/5wWX/+cFl//nBZf/5 + wWX/+cFl//nBZf/5wGX/+cBl/+23YOwAAAAdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbzu2Ty975m//a+Zv/3 + vmb/9r5m//e+Zv/2vmb/975m//a+Zv/3vmb/9r5m//e+Zv/2vmb/8Llj9AAAABQAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADj + rmC89Ltn//S7aP/0u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0u2j/9Lto//S7aP/0u2j/9Lto//S7Z//S + olnIAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAEAAAABQAAAAMA + AAABAAAAAAAAAAB1VTUY8bho//G5aP/xuGj/8bho//G4aP/xuGj/8bho//G4aP/xuGj/8bho//G4aP/x + uGj/8bho//G4aP/xuGj/8bho/zIoFDMAAAAAAAAAAAAAAAAAAAACAAAABQAAAAUAAAACAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADn1NV2q2 + cX/Ww3qL98V7jvvAeo3xpmp7vkEpM0sAAAAK4KpjtO61af/utWn/7rVp/+62af/utmn/7rZp/+62af/u + tmn/7rZp/+62af/utmn/7rZp/+61af/utWn/7rVp/+61af/OnFvCAAAAAiYtGih1nFGjiLpf64nAY/qG + wGL5fLVd41iDQo4HBwckAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAADmF1ngcd6if/He4v/x3yN/8d9j//HfpL/x36U/8d/lv/GgJj/wX2W9ueqZv3tsmr/7bJq/+2zav/t + smr/7bJq/+2yav/ts2r/7bJq/+2yav/tsmr/7bNq/+2yav/tsmr/7bJq/+2zav/tsmr/6rFp/ZG2YOCX + wWb/lMFl/5HBZf+OwmX/i8Jk/4jCZP+FwWP/gsJi/2igUbwAAAAVAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAFvXOA2Md6if/He4v/x3yN/8d9j//HfpL/x36U/8d/lv/GgJj/xoGa/8aBnP+1 + WEH/2JJd/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//qr2v/6q9r/+qva//q + r2v/4Kpj/5GEKv+cwWb/msFm/5fBZv+UwWX/kcJl/47CZf+LwmT/iMJk/4XBY/+CwmL/fL5g+AcHByUA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvXOA1Md6if/He4v/x3yN/8d9kP/HfpL/x3+U/8d/lv/G + gJj/xoGa/8aBnP/Ggp3/s1dC/7JXQ//UjV3/56xs/+esbP/nrGz/56xs/+esbP/nrGz/56xs/+esbP/n + rGz/56xs/+esbP/nrGz/3adk/5WBKv+SgSr/n8Fm/5zBZv+awWb/l8Fm/5TBZf+RwmX/jsJl/4vCZP+I + wmT/hcFj/4LCY/98wGH5AAAAFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo2Ftacd6if/He4v/x3yN/8d9kP/H + fpL/x36U/8d/lv/GgJj/xoGa/8aBnP/Ggp3/xYKf/7FVRP+wVkT/sFZF/9GKXv/kqGz/5Khs/+SobP/k + qGz/5Khs/+SobP/kqGz/5Khs/+SobP/kqGz/26Nk/5h+Kv+Vfir/k34r/6LAZv+fwWb/nMFm/5rBZv+X + wWb/lMFl/5HCZf+OwmX/i8Jk/4jCZP+FwWP/gsJi/26pVcoAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8d6iP7H + e4v/x3yN/8d9kP/HfpL/x36U/8d/lv/GgJj/xoGa/8aBnP/Ggp3/xYKf/8WCof+uVET/rVNF/61URv+t + VEf/zohf/+Glbf/hpWz/4aVs/+GlbP/hpWz/4aVs/+Glbf/hpW3/2Z9k/5p6Kv+Yeir/lXsq/5N8Kv+l + wGb/osBm/5/BZv+cwWb/msFm/5fCZv+UwWX/kcJl/47CZf+LwmT/iMJk/4XBY/+CwmL/Eh4SKwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAJdfaDvHe4v/x3yN/8d9kP/HfpL/x36U/8d/lv/GgJj/xoGa/8aBnP/Ggp3/xYKf/8WCof/F + g6L/q1JG/6tSRv+qUkf/qlJH/6lSSP/LhF//3qFs/96hbP/eoWz/3qFs/96hbP/eoWz/1ptk/5x3K/+b + dyv/mHgr/5Z4Kv+TeCr/p79m/6XAZv+iwGb/n8Fm/5zBZv+awWb/l8Jm/5TBZf+RwmX/jsJl/4vCZP+I + wmT/hcFj/2mdUKwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC8dYSwx3yN/8d9j//HfpL/x36U/8d/lv/GgJj/xoGa/8aBnP/G + gp3/xYKf/8WCof/EgqL/xIKk/6lQRv+oUEf/p1FI/6dRSf+mUUn/plFK/8iBYP/bnW3/251s/9udbP/b + nWz/1Jhk/55zKv+cdCr/mnQq/5h0Kv+WdSv/lHYr/6m/Zv+nwGb/pcBm/6LAZv+fwWb/nMFm/5rBZv+X + wmb/lMFl/5HCZf+OwmX/i8Jk/4jCZP+CvWH1AAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw3qL5Md9j//HfpL/x3+U/8d/lv/G + gJj/xoGa/8aBnP/Ggp3/xYKf/8WCof/EgqL/xIKk/8ODpv+mTkf/pU9I/6VPSf+kT0n/pE9K/6NPSv+j + T0v/xX5h/9iZbP/YmW3/0ZRk/6BwK/+ecCv/nHAr/5pxK/+YcSv/lnIq/5RyK/+svmb/qb9m/6e/Zv+k + wGb/osBm/5/BZv+cwWb/msFm/5fCZv+UwWX/kcJl/47CZf+LwmT/iMFj/wAAAAcAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMV7juvH + fpL/x36U/8d/lv/GgJj/xoGa/8aBnP/Ggp3/xYKf/8WCof/EgqL/xIKk/8ODpf/Dgqf/okxI/6JNSf+h + TUn/oU1K/6BMSv+gTUv/n0xL/59NTP/GgWP/0pJo/6JsK/+fbCr/nW0q/5ttKv+abiv/l24r/5VuK/+T + byv/rr1l/6y+Zf+pvmb/p79m/6TAZv+iwGb/n8Fm/5zBZv+awWb/l8Fm/5TBZf+RwmX/jsJl/4vCZP8A + AAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAADDe4/Qx36U/8d/lv/GgJj/xoGa/8aBnP/Ggp3/xYKf/8WCof/EgqL/xIKk/8ODpf/D + g6f/woOo/6BLSf+fS0n/nktK/51KSv+dSkv/nEpL/5xKTP+bSkz/m0pN/6RoLP+gaCr/n2gq/5xpKv+b + air/mGoq/5drKv+VbCv/k2wr/7C9Zf+uvWX/q75l/6m+Zv+nv2b/pMBm/6LAZv+fwWb/nMFm/5rBZv+X + wWb/lMFl/5HBZf+NwWT8AAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuneLcsd/lv/GgJj/xoGa/8aBnP/Ggp3/xYKf/8WCof/E + gqL/xIKk/8ODpf/Cg6f/woOo/8GCqf+dSUr/nEhK/5tISv+aSEv/mkhL/5lIS/+YSEz/mEhN/4xBPP+C + QSH/oGQp/55lKf+bZSr/mmYq/5hmKv+WZyr/lGgr/5NpK/+yvGT/sL1l/669Zf+rvmX/qb5m/6e/Zv+l + wGb/osBm/5/BZv+cwWb/msFm/5fBZv+UwWX/ibdg2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFVVQnGgJj/xoGa/8aBnP/G + gp3/xYKf/8WCof/EgqL/xIKk/8ODpf/Cg6f/woOo/8GCqv/Agqr/mUZK/5hGS/+YRkv/l0ZL/5ZGS/+V + Rkz/lUVM/5RFTf95Mx//djIe/55gKf+cYSn/mmEp/5hiKf+XYyr/lWQq/5RkKv+SZSv/tLtk/7K8ZP+w + vWX/rr1l/6u+Zf+pv2b/p79m/6XAZv+iwGb/n8Fm/5zBZv+awWb/l8Fm/2SARFIAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAABwH2W1MaBnP/EgZ3/xIGf/8SBof/DgaL/woGk/8KCpf/Bgab/wIGo/8CBqf+/gar/v4Ks/5ZES/+V + REv/lENL/5NDS/+SQ0z/kkNM/5FDTP+RQ0z/djAe/3QwHv+XVyf/m10p/5peKf+XXin/ll8q/5RgKv+T + YSr/kWIr/7a6Y/+zu2P/sLxk/668ZP+svWT/qr1l/6e+Zf+lv2X/o79m/6DAZv+dwGb/nMFm/5nAZfsA + AAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAE8K0cvnnnEzqqD1v6CQIb/f0CH/3w/iv96Poz/dj2O/3M8kP9wO5L/bTqU/2o5lv9m + OJj/YzaZ/2A1m/9MHk7/aSxI/5BBS/+QQUz/j0FM/45ATP+NQEz/iz9J/3QuHf9yLh7/i0kk/5pZKP+Y + Wij/llsp/5VcKf+SXSn/ZlQf/0NVGf9PlTT/TZc2/0uZOP9Jmjr/R5s7/0ScPf9Cnj7/QJ9A/z6gQf87 + oUP/OKJE/zaiRv9R0KP/S8Ci0hQ1LT8AAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAijfMDDsYfV/66F1v+rhNj/o3nN/35Aif98P4v/eT6N/3Y9kP9z + PJL/cDuT/2w6lf9pOZf/ZjeZ/2I2mv9fNJz/VSyE/0MYRf9BGEX/cTFJ/4s+TP+KPkz/iT1M/4Y7R/9y + Kx3/cCsd/4ZCI/+YVSf/llYo/5VXKP93USH/QUcU/0BIFf9Mfir/T5Qz/06WNf9LmDf/SZo5/0eaO/9F + nDz/Q54+/0GfQP8+n0H/PKFD/zmhRP9LwoX/Vtiz/1TYtv9R2bn/RLyjywAAABQAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiziM7vtInT/7GH1f+uhdb/q4TY/6iC2f+f + ds3/fD+N/3g/j/92PZH/cj2T/287lP9sOpf/aDiY/2U3mv9iNpv/XjSd/1oznv9CGEf/PxdG/zwWRv9Y + JUj/hjtL/4U6S/+DOkr/bykc/20pHf+KRSP/llEm/5RSJ/9jSBr/QkIT/0BEFP9ARxX/UpEx/1CTM/9O + lTX/TJc3/0qZOf9Imjv/Rps8/0SdPv9Bn0D/QJ9C/z2gQ/9NwIH/Wdiw/1bYs/9U2bb/Udm6/07avP9K + 07nyAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzhsnct4rS/7SJ1P+x + h9X/roXX/6uE2P+ogtn/pYDa/5x0z/94P5D/dT6S/3I8lP9vO5b/bDqY/2g4mf9kN5v/YTWc/100nv9a + Mp//Uy2V/zwWRv86FUb/NxRF/2QqSf+AOEz/gDdL/2wnHP9rJxz/k0ol/5RNJv9zRx7/QT4S/0BAEv8/ + QRT/UYUr/1KQMf9QkjP/TpQ1/02WN/9LmDn/SZo7/0ebPP9EnT7/Qp5A/0GfQv9Qv37/W9et/1nYsP9W + 2LP/VNm2/1HZuv9P2rz/TNq//0TMteIAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACR + bqJYuYvR/7eK0v+0idT/sYfV/66G1/+rhNj/qILZ/6WA2v+hftv/mHHQ/3U+lP9yPJX/bzyX/2s6mf9n + OJr/ZDec/2A1nv9cNJ//WTKg/1Uwov9KJ4b/OBRG/zUTRf8yEkX/ezVL/3s0S/9tJyP/aSUc/5NIJP+R + SSX/QTkQ/0A7Ef8/PBL/T3Ql/1SOLv9TjzH/UZEy/0+TNf9Nljf/TJg4/0mZOv9Imzz/RZw+/0OeQP9S + vnv/Xdap/1vXrf9Z2LD/Vtiz/1TZtv9R2bn/T9q8/0zav/9J28L/KIBycgAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAABu4zO+bmL0f+3itL/tInU/7GH1f+uhtf/q4TY/6iC2f+lgNr/oX7b/5573P+U + b9H/cT2X/248mf9qOpv/Zzic/2M3nf9fNZ//XDOg/1gyov9UL6P/UC6k/0kpmP8zEkf/MBJF/0odR/92 + MUr/dC9F/381IP+RRCT/XjsX/z83EP8/ORH/VH0m/1aKK/9VjC3/U44w/1KRMv9QkzT/TpU2/02XOP9K + mTr/SZo8/0acPv9UvXj/X9Wm/13Wqf9b163/Wdiw/1bYs/9U2bf/Udm5/0/avP9M2r//SdvC/0bYw/oA + AAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZk1mFLyMz/+6i9H/t4rS/7SJ1P+xh9X/robX/6uE2P+o + gtn/pYDa/6F92/+ee9z/mnjd/5Bt0/9uPJr/ajqc/2Y4nf9jN57/XjWg/1s0of9XMqP/Uy+k/08tpf9L + LKb/Ryqo/zwgiP8tEk3/ci5J/3MwSv+VRjH/jj8i/0E4EP9RaB7/WYQm/1iGKf9WiSv/VYwt/1SOMP9S + kDL/UZI0/0+UNv9Nljj/S5g6/0qaPP9Wu3X/YNSh/1/Vpv9d1qn/W9et/1nYsP9W2LP/VNm3/1HZuf9P + 2rz/TNq//0nbwv9G28X/ESwsLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKV7sVu8jM//uovR/7eK0v+0 + idT/sYfV/66G1/+rhNj/qILZ/6WA2v+hfdv/nnvc/5p43f+Wdt7/jGrU/2o6nf9mOZ//Yjeg/141ov9a + M6P/US+k/0kspP9KLKb/Siuo/0Ypqf9BJ6r/PSWs/6l0vP5AJkAUQABABNijUO5bfSH/WoAk/1mDJv9Y + hSj/VIcq/02ILP9Niy7/Uo8y/1KRNP9QlDb/TpY4/0yYOv9ZunL/YtOd/2DUof9f1aX/Xdap/1vXrf9Z + 2LD/Vtiz/1TZt/9R2bn/T9q8/0zav/9K28L/RtvF/yyRhHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACw + hL+LvI3P/7qL0f+3itL/tInU/7GH1f+uhtf/q4TY/6iC2f+lgNr/oX3b/5573P+aeN3/lnbe/5Jz3/+K + a9n/Zjmh/0guoP8aHZ3/Fhue/xUbn/8UGqD/Ehmh/xEYov8UGKX/NiOq/z4msf8iHUo0AAAAAAAAAABD + ejcXXoks/1V9Iv8gcR7/FHAf/xRzIf8UdiT/FHgm/xN7KP8Ufir/MIkx/0+WOP9dwHr/Y9KZ/2LTnf9g + 1KH/X9Wl/13Wqf9b163/Wdiw/1bYs/9U2bf/Udm6/0/avP9M2r//StvC/0bbxf83sKCfAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAsoTAhbyNz/+6i9H/t4rS/7SJ1P+xh9X/robX/6uE2P+ogtn/pYDa/6F92/+e + e9z/mnjd/5Z23v+Sc9//iW7f/yc61/8dKbn/Fxye/xYboP8VG6H/FBqi/xIZo/8RGKT/EBen/xIjy/8c + LOH/EhIxOQAAAAAAAAAAN2Q3FzGmTf8WlEH/FHEh/xRwH/8UcyL/FHYk/xR5Jv8Teyn/E34r/xSPQ/8Y + s3j/V8yR/2PSmf9i053/YNSh/1/Vpf9d1qn/W9et/1nYsP9W2LP/VNm3/1HZuv9P2rz/TNq//0rbwv9G + 28X/N7KfmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKh+tkm8jM//uovR/7eK0v+0idT/sYfV/66G1/+r + hNj/qILZ/6WA2v+hfdv/nnvc/5p43f+Wdt7/iW7e/yU41v8jN9f/IjbY/yE12f8eM9b/HC3O/xkqy/8Y + K9L/GC3c/xYs3v8VKt//Eyjg/y+A8vwFChAxAA8PIi7IseIWnEf/F59M/xehUf8XpFb/F6BT/xecUP8X + oFf/GKtn/xewcP8YsnX/GLR6/xe2f/9Ny5P/YtOd/2DUof9f1aX/Xdap/1vXrf9Z2LD/Vtiz/1TZt/9R + 2bn/T9q8/0zav/9K28L/RtvF/y2ShWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgYIAIvIzP/7qL0f+3 + itL/tInU/7GH1f+uhtf/q4TY/6iC2f+lgNr/oX3b/5573P+aeN3/jHHd/yg41f8mN9b/JDbX/yM12P8h + NNn/HzPZ/x4y2v8cMNv/Gi/b/xgt3f8XLN7/Dije/wMl3v8GcPL/CHrz/w3Az/8GtLr/BItK/xCYTf8X + o1P/GKVY/xioXf8Yq2L/GK1n/xivbP8YsXH/GLN2/xi1e/8Xt4D/F7mF/0zMl/9g1KH/X9Wm/13Wqf9b + 163/Wdiw/1bYs/9U2bf/Udm5/0/avP9M2r//SdvC/0bbxf8LKiAYAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAALuLzu25i9H/t4rS/7SJ1P+xh9X/robX/6uE2P+ogtn/pYDa/6F+2/+ee9z/kHPc/yk31P8o + N9X/JjbW/yQ11v8jNdj/ITPY/yAy2f8eMdr/HDDa/xsv3P8VLNz/Aybb/wIl3P8FS+j/B2/y/wZv7f8E + lrj/B7O9/wWghv8Ci0//A41T/xSjWf8YqV7/GKxj/xiuaP8YsG7/GLFy/xezeP8Ytnz/F7eB/xe5hv8W + u4r/Ss2c/1/Vpv9d1qn/W9et/1nYsP9W2LP/VNm3/1HZuf9P2rz/TNq//0nbwv9F1sHwAAAAAQAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmebkouYvR/7eK0v+0idT/sYfV/66G1/+rhNj/qILZ/6WA2v+h + ftv/lHXb/ys40/8pN9P/KDfV/yY11v8lNdf/IzTY/yE02P8gMtn/HjHZ/x0w2/8TLNv/Ayfa/wMm2/8D + Jd3/B23x/wdu8v8CYcH/AWG3/wezv/8HtML/A4tR/wONVf8Dj1r/EaJg/xitZf8Yr2r/GLBv/xiydP8Y + tHn/F7Z9/xe4gv8Xuof/FruL/xW8kP9JzqD/Xdap/1vXrf9Z2LD/Vtmz/1TZt/9R2bn/T9q8/0zav/9J + 28L/LoR2OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALWIzKm3itL/tInU/7GH1f+u + hdf/q4TY/6iC2f+lgNr/mHja/yw30f8rN9P/KTbT/yg21f8nNdb/JTTX/yM01/8iM9n/IDLZ/x8x2v8a + L9r/BCjZ/wQn2v8DJtv/B13t/wds8f8HbfH/AV24/wFfuv8HrsL/B7PF/werr/8DjFf/A45c/wORYf8W + qmb/GLBs/xixcP8Ys3X/GLV6/xe3f/8XuYP/F7qI/xa7jP8VvJH/Fb6V/0fPpf9b163/Wdiw/1bYs/9U + 2bb/Udm6/0/avP9M2r//RMqzsQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAtIjPwbSJ0/+xh9X/roXX/6uE2P+ogtn/m3rZ/y420P8tNtH/KzbS/yo11P8oNdT/JzXW/yU01/8k + M9j/IjPZ/yEy2f8fMdr/BCjZ/wQn2v8EJtv/B1Lp/wlq8f8IavD/CGvv/wFcu/8BXrz/BpvD/wiyx/8I + s8n/Bqak/wOOXv8DkGL/A5Jn/xiwbf8YsnL/GLR3/xi2e/8XuID/F7mF/xe7if8WvI3/Fb2S/xW+lv8V + v5v/RtGp/1nYsP9W2LP/VNm2/1HZuv9O2rz/SdG3xgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsgstssYfV/66F1v+rhNj/n3zY/zA1z/8uNdD/LTXQ/yw10v8r + NdT/KDTU/yc01v8mM9f/JDPY/yMy2f8hMdr/GC7a/wQo2f8EKdv/CF/t/wlo8P8JaPH/CWnx/whp7P8B + XL3/AV6//wWNxf8Iscr/CLLM/wi0zv8HsML/A5Fn/wORaP8SqG7/GLN0/xi1eP8Ytn3/F7iC/xe6hv8X + u4r/FryP/xW9k/8Vv5f/FcCc/xTBoP9F0q3/Vtiz/1TYtv9R2bn/RcOocgAAAAEAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAKngMxuqYLV7DI0zv8w + NM//LzTQ/y000f8sNNL/KzTT/yk01P8oM9X/JjPX/yUy2P8kMtn/IjLa/wgz3f8JV+v/CmXw/wpm8P8J + ZvD/CWfw/wlo8P8IaO3/AVvA/wFdwf8FkMf/CLHM/wixzv8IstD/CbTS/wm01P8Irb7/BpyC/xm0dv8Y + tnr/F7d+/xi5g/8Xuoj/FryL/xa8kP8VvpT/Fb+Z/xXAnP8UwaH/E8Kl/0/Rr/NOx6hyAAAABAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAEhf5MdNZvH/TGjx/0xq8f9LbPH/Sm7y/0pv8v9JcfL/SXLz/0hz8/9HdfP/Rnby/0V38/8L + Ye//C2Lw/wtj8P8KZPD/CmXv/wpm8P8JZ/D/CWjw/wFbwv8BXcT/B6PM/wmwz/8JsND/CbHS/wmy1P8J + s9b/CbTY/wm12v864N//OuHh/zvi4/874uX/O+Lm/zvj5/875On/O+Tq/zvl7P865e3/OuXv/zrm8P84 + 4uz4AAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAABcXRgtNYvD/TWTw/01m8f9MaPH/TGrx/0ts8f9KbfL/Sm/y/0lx8v9I + cvP/SHPz/0d18/9GdvL/C1/v/wtg7/8LYe//C2Lw/wtj8P8LZPD/CmXw/wpn8P8BWsX/AVvG/wmvz/8J + r9H/CbDS/wmw1P8Jsdb/CbHY/wmy2v8Js9z/OuHh/zvi4/874uX/O+Lm/zvj5/864+n/O+Tq/zvl7P86 + 5e7/OuXv/zrm8P855vH/Oebz/xpudFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCU9JsTWDw/01i8P9NZPD/TWbx/0xo8f9M + avH/S2zx/0pt8v9Kb/L/SXDy/0hy8/9Ic/P/R3Xz/wte7/8LX+//C1/v/wtg7/8LYvD/C2Pw/wtk8P8L + ZfD/B2He/wNryv8JrdH/Ca7T/wmv1f8Jr9b/CbDY/wmx2v8Jsdv/CbLd/zvi4/874uX/O+Lm/zvj5/86 + 4+n/OuTq/zvl7P865e3/OuXv/zrm8P855vH/Oebz/zjn9P8z0+DVAAAAAQAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS1rpzU1e8P9N + YPD/TWLw/01k8P9NZvH/TGjx/0tq8f9LbPH/Sm3y/0pv8v9JcPL/SHLz/0dz8/8MXO//C13v/wte7/8L + X+//C2Dv/wth7/8LYvD/C2Tw/wtl8P8KqdL/CqzT/wqt1f8Krtb/Ca7Y/wmv2v8Jr9v/CbDd/wqx3/87 + 4uX/O+Lm/zvj5/864+n/OuTq/zvl7P865e3/OuXv/zrm8P855vH/Oebz/zjn9P845/b/N+X1/AAAAAUA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAExY7OpNXO//TV7w/01g8P9NYvD/TWTw/0xm8f9MaPH/TGrx/0ts8f9KbfL/Sm/y/0lx8v9I + cvP/DFnv/wxa7/8MXO//DF3v/wte7/8LX+//C2Hv/wti7/8gnvb/KcH1/wqr1f8KrNf/CqzY/wqt2v8K + rdz/Cq7d/wqu3/8Kr+D/O+Lm/zvj5/864+n/OuTq/zvl7P865e3/OuXv/zrm8P855vH/Oebz/zjn9P84 + 5/b/OOf3/zbn+P8AAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMVuzlTVnv/01c7/9NXvD/TWDw/01i8P9NZPD/TGbx/0xo8f9M + avH/S2zx/0pt8v9Kb/L/SXHy/w1X7v8NWO7/DVrv/w1b7/8NXO//DF7v/wxf7/8dkvX/LsL6/y7C+v8n + vfP/C6vZ/wus2v8LrNz/Cqzd/wqs3/8KreD/Cq3i/zvj5/864+n/OuTq/zvl7P865e3/OuXv/zrm8P85 + 5vH/Oebz/zjn9P845/b/OOf3/zfn+f825/r/AAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS1TntE1X7/9NWe//TVzv/01e8P9N + YPD/TWLw/01k8P9MZvH/TGjx/0tq8f9LbPH/Sm3y/0pv8v8NVe7/DVfu/w1X7v8NWe7/DVrv/w1b7/8e + j/X/MMD6/zDA+v8wwPr/MMD6/yi78/8Lqtz/C6rd/wur3/8Kq+D/Cqzh/wqs4/875On/O+Tq/zvl7P86 + 5e3/OuXv/zrm8P855vH/Oebz/zjn9P845/b/OOf3/zfn+f825/r/NeT49gAAAAIAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEZK1j5N + Ve//TVfv/01Z7/9NXO//TV7w/01g8P9NYvD/TWTw/0xm8f9MaPH/TGrx/0ts8f9KbvL/DVPt/w1U7v8N + Ve7/DVfu/w1Y7v8fjPX/Mb76/zG++v8wvvr/ML76/zG++v8xv/r/Kbr0/wup3/8LqeD/Cqri/wqq4/8K + q+X/O+Tq/zvl7P865e3/OuXv/zrm8P855vH/Oebz/zjn9P845/b/OOf3/zfn+f825/r/Nuf7/y/M364A + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAABTVLu/01V7/9NV+//TVrv/01c7/9NXvD/TWDw/01i8P9NZPD/TGbx/0xo8f9M + avH/S2zx/w1Q7f8NUe3/DVPt/w1U7v8gifT/Mrz6/zK8+v8yvPr/Mrz6/zK8+v8yvPr/Mrz6/zK8+v8p + uPT/C6fi/wuo4/8KqOX/Cqnm/zvl7P865e3/OuXv/zrm8P855vH/Oebz/zjn9P845/b/OOf3/zfo+f82 + 5/r/Nuf7/zXo/f8QWGAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAElO4nNNUu7/TVXv/01X7/9NWu//TVzv/01e8P9N + YPD/TWLw/01k8P9NZvH/TGjx/0xq8f8OTu3/DlDt/w5R7f8hhvT/M7r6/zO6+v8zuvr/M7r6/zO6+v8z + uvr/M7r6/zO6+v8zuvr/M7r6/yu29f8LpuX/C6fm/wqn6P865e3/OuXv/zrm8P855vH/Oebz/zjn9P84 + 5/b/OOf3/zfo+f825/r/Nuf7/zXo/f8x2/LQAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATVDs4E1S7v9N + Ve//TVfv/01Z7/9NXO//TV7w/01g8P9NYvD/TWTw/01m8f9MaPH/Dkzt/w5N7f8hhPP/NLj6/zS4+v80 + uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80uPr/NLj6/zS4+v80uPr/K7T1/wul5/8Lpen/OuXv/zrm8P85 + 5vH/Oebz/zjn9P845/b/OOf3/zfn+f825/r/Nuf7/zXo/f805/78ACAgCAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAFNUO3mTVLu/01V7/9NV+//TVnv/01c7/9NXvD/TWDw/01i8P9NZPD/TWbx/w5J7P8i + g/P/Nbb5/zW2+f81tvr/Nbb6/zW2+f81tvn/Nbb6/zW2+v81tfn/Nbb5/zW2+v81tvr/Nbb5/zW2+f8s + svb/C6Pq/zrm8P855vH/Oebz/zjn9P845/b/OOf3/zfn+f825/r/Nuf7/zXo/f805/78G15rEwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEpQ5pBNUu7/TVXv/01X7/9NWe//TVzv/01e8P9N + YPD/TWLw/0xk8Pwvn/b9NrP5/zWz+f81s/n/NbP5/zaz+f81s/n/NbP5/zWz+f82s/n/NbP5/zWz+f81 + s/n/NrP5/zWz+f81s/n/NbP5/zOx9/w55PDtOebz/zjn9P845/b/OOf3/zfn+f825/r/Nuf7/zXo/f8y + 4PbIAAAzBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVVA0lQ5HNN + VO3mTVfv/U1Z7/5NW+/6TFzrzURUy0AAAAABNqvyqzaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82 + sPn/NrD5/zaw+f82sPn/NrD5/zaw+f82sPn/NrD5/zaw+f8xn+C3AAAAADbJ2CE34fG1N+b29jbn+P42 + 5/r+Neb68DPb8JYiiJkPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACeJsQ03rvn/N675/zeu+f83 + rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/N675/zeu+f83rvn/EjdSHAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAANqfzrjeq+f83qvn/N6v5/zer+f83q/n/N6v5/zer+f83q/n/N6v5/zer+f83q/n/N6v5/zeq+f83 + qvn/Mp3mtgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3p/ftN6f5/zin+f84p/n/OKf5/zin+f84qPn/OKj5/zin+f84 + p/n/OKf5/zin+f83p/n/N6X17gAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATek9t84pfj/OKX4/zil+P84 + pfj/OKX4/zil+P84pfj/OKX4/zil+P84pfj/OKHz4QAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAANpnsXzih+P04ofj/OKH4/zih+P84ofj/OKH4/zih+P84ofj9MpDcZQAAAAEAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMYzWHzaZ7382m/K3NpvytzWW6YEufMEhAAAAAQAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////////////////n////// + ///wB////////8AD////////gAH///////8AAP///////wAAf/////8GAABw/////AAAAAAf///wAAAA + AA///+AAAAAAB///wAAAAAAD///AAAAAAAH//4AAAAAAAf//gAAAAAAB//+AAAAAAAD//4AAAAAAAP// + gAAAAAAA//+AAAAAAAD//4AAAAAAAf//gAAAAAAB//+AAAAAAAH//gAAAAAAAH/8AAAAAAAAP/gAAAAA + AAAf8AAAAAAAAA/wAAAAAAAAD+AAAAAAAAAH4AAAAAAAAAfgAAAAAAAAB+AAAAGAAAAH4AAAAYAAAAfg + AAAAAAAAB+AAAAAAAAAH8AAAAAAAAAfwAAAAAAAAD/gAAAAAAAAf/AAAAAAAAB/+AAAAAAAAP/8AAAAA + AAD//8AAAAAAAf//gAAAAAAB//+AAAAAAAD//4AAAAAAAP//gAAAAAAA//+AAAAAAAD//4AAAAAAAP// + gAAAAAAB//+AAAAAAAH//8AAAAAAAf//4AAAAAAD///gAAAAAAf///gAAAAAD////AAAAEA//////gAA + f///////AAD///////+AAP///////4AB////////4AP////////4D/////////////////////////// + /////////ygAAAAwAAAAYAAAAAEAIAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQPx4Tr4lEWd+uVpXdrFWWpoFAXjwvFhoA + AAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2adYINemV4n7wmT++8Nk//vDZP/7 + w2T/+8Nk//vCZP7InFGTuI5LJgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADZp1ki8Lljufe+Zfz4 + v2b/+MBm//jAZv/4wGb/+MBm//i/Zv/2vmX96LNfv7CISSoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADo + smKq9Ltn/fW8aP/1vGj/9bxo//W8aP/1vGj/9bxo//W8aP/1vGj/9Ltn/tmnXLMAAAACAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnhKUxW1cX85unSFQrl1h0CY + YXEpOSQtC7+QVTDwt2j/8Lho//C3aP/wuGj/8Lho//C4aP/wuGj/8Lho//C4aP/wt2j/8Ldo//C3aP+J + aTxBJCsZBW+UTSGEtV0+gLVdQnqyWzxSeT0dBwcHBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOV2ARsWx5ZLRvfanB + eIjvxnyP/MR8kPm2dInQsHGIk92ibMLutGr/7rRq/+60av/utGr/7rRq/+60av/utGr/7rRq/+60av/u + tGr/7rRq/+60av/TqmLEi7BdgoixXcKMv2P3isFk/IS9YfR0q1e5bqZUeE13PCAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO9 + dIGyxHiI78d8jP/HfY//x36S/8d/lf/GgJj/xYCa/sJxXv7hn2P/67Br/+uwa//rsGv/67Br/+uwa//r + sGv/67Br/+uwa//rsGv/67Br/+WtZv+km0T9mcBl+5fBZv+TwWX/j8Jl/4vCZP+HwmT/gb5h93q6XssH + BwcVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAnl5qDr90gq7He4r/x3yN/8d9kP/HfpP/x3+W/8aAmP/GgZv/xoKd/7dhWf+4YUj/1pFg/+Wpa//m + q2z/5qts/+arbP/mq2z/5qts/+arbP/mq2z/2KNg/6OHNf+WkDn/nsFm/5vBZv+XwWb/k8Fl/5DCZf+L + wmT/h8Jk/4TCY/96u17NUX0/IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAu3J/W8V5iOzHfI3/x32Q/8d+k//Hf5b/xoCY/8aBm//Ggp3/xYKf/7VgW/+v + VUX/t2JM/9OOYf/jp2z/46ds/+OnbP/jp2z/46ds/+Onbf/WnmD/qYU5/5Z8Kv+Xjjn/osBm/57BZv+a + wWb/l8Fm/5PCZf+PwmX/i8Jk/4fCZP+Bv2H4cKlVfhEcEQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUXWYLv3aFlsd8jP/HfZD/x36T/8d/lf/GgJj/xoGb/8aCnP/F + gp//xYKh/7JfXf+rUkb/q1NH/7BcTP/UkmX/36Js/9+ibP/fomz/36Js/9qfaP+nfzb/mXgr/5Z5Kv+Y + izn/pcBm/6LAZv+ewWb/msFm/5fCZv+TwWX/j8Jl/4vCZP+HwmT/eLFaxWKTSyMAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC+d4Yvw3qK3sd9j//HfpP/x3+W/8aAmP/G + gZv/xoKd/8WCn//FgqL/xIKk/69cXv+nUEj/plFJ/6ZRSf+sWk7/yoVi/9mabP/anGz/0JRg/6h5Nf+c + cyr/mXMq/5d0K/+Zhzr/qb9m/6bAZv+iwGb/nsFm/5vBZv+Xwmb/k8Jl/5DCZf+LwmT/hsBj+321XUEA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEe406xnyP88d+kv/H + f5b/xoCY/8aBm//Ggp3/xYKf/8WCof/EgqP/w4Om/6xaX/+jTkn/o05J/6JOSv+hTkv/qlpR/8iDY//O + kGL/rXc5/55uK/+bbyv/mXAr/5ZwK/+ahDr/rL5m/6m/Zv+lwGb/osBm/57BZv+awWb/l8Fm/5PBZf+P + wmX/i8Jk/36yW0UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADE + e482xX2R68d/lf/GgJj/xoGb/8aCnP/Fgp//xYKh/8SCo//Dg6X/w4On/6lZYf+gTEn/nktK/55LS/+d + S0v/nEtM/6NVUf+scDf/oGkq/51qKv+aayr/mGsq/5ZsK/+agTr/r71l/6u+Zf+ov2b/pcBm/6LAZv+e + wWb/msFm/5fBZv+TwWX/jsFl/oa4X0IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAC4dooWw32Tq8aAmP/GgZv/xoKd/8WCn//FgqL/xIKj/8ODpf/Cg6j/wYKp/6VXYv+b + SEr/mkhL/5lIS/+YR0v/l0dN/4tAO/+HRyL/n2Qp/5tkKv+ZZSr/l2Yq/5RnK/+bfTn/srxk/6+9Zf+r + vmX/qb9m/6bAZv+iwGb/nsFm/5vBZv+XwWb/jrpi24WxXS4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmTU0BwX6Wd8WAmvrFgZ3/xYKf/8SCof/DgqP/w4Kl/8GCp//B + gqn/wIKr/6JUY/+WRUv/lkVL/5RFS/+TREz/k0RM/342Kv9+PCH/m10p/5pfKf+XYCn/lmIq/5RiKv+a + eTn/tLtk/7G8ZP+tvWX/q75l/6i+Zv+kwGb/ocBm/53BZv+awWb/j7ZglV13PwsAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF2WZFBqH7Gx5pcmvyQUI3/jU+Q/4pOk/+G + TZX/g0yY/4BLmv98Sp3/eUme/2UwYv97Nkn/kUJL/5BCTP+PQUz/jUBL/3szKP95NiD/lFMn/5lbKP+W + XCn/lF0p/3pZJP9baib/aJ9B/2WhQ/9io0X/X6RG/1ymSP9Zp0r/VqhL/1KpTP9Usl//WceZzzF+aksA + AAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnni2IqiAxa6wh9X/rYXX/6Z90v+E + Spb/ej+N/3c9kP9yPJP/bjuU/2o5l/9lN5r/YDWb/1gvj/9CGEX/UiFH/3g0Sv+JPUz/hzxK/3YvKP91 + MR//j0sl/5ZVKP+BUiP/VUoZ/0BHFf9Ohy7/T5U0/0yXN/9Jmjr/Rps8/0SdPv9An0D/PaBC/z6nT/9Q + zJn/Vdi1/1LZuP9Gwqi1N52JKQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqgL8dsofMtbSJ0/2w + h9X/rYXX/6mD2f+dc8r/gkyf/3Y+kf9xPJT/bjuW/2k5mP9kN5v/YDWd/1sznv9HIGT/PBZG/0QbRv94 + NEr/gjlL/3MsKP91MB7/kksl/4hNI/9OQxX/QEIT/0ZdHf9SkTL/T5Q0/02WN/9KmTr/SJs8/0WdPv9B + n0H/RKdR/1HFif9Y2LH/Vdm1/1LZuf9O2bz9Rsy0uziolSIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACm + fbtvt4rR+7WJ1P+wh9b/rYXY/6mD2f+kf9r/mHDM/3xIn/9xPJX/bTuY/2g5mv9jN5z/XjWe/1ozoP9R + LJX/QBxe/zYURf9OH0f/fDVL/3EqLP90Lh7/kkkl/19AGP9APBH/RVIZ/1GDKv9SkDH/UJI0/02VN/9L + mDn/SJo7/0acPv9GpEv/VMOG/1vVqf9Y2LH/Vdm1/1LZuP9O2r3/Stm/+zeploAAAAAAAAAAAAAAAAAA + AAAAAAAAAFlDWQS7jM/8uIvS/7WJ1P+wh9b/rYXY/6mD2f+kf9r/oHzc/5h01v92RqP/bDua/2g5nP9i + N57/XTSg/1kyov9TL6T/TSyg/zwcbv83F1L/XCVJ/3QwR/+HPCT/dD8c/0hBFP9JWRr/VoUp/1WLLf9T + jzH/UZIz/0+UNv9Mlzn/Spk7/0qhSP9Zx4v/Xtao/1zXrP9Y2LH/Vdm1/1LZuf9O2r3/S9vB/0fZw/wL + HR0NAAAAAAAAAAAAAAAAAAAAAJpzoyq8jND/uYvS/7WJ1P+wh9b/rYXY/6mD2f+kf9r/oHzc/5t53f+O + atD/dEeq/2c5nv9hN6D/XDSi/1Yxo/9OLaT/TCym/0gqqP88IpL/YTZ//3s8X6efVTSff2Uo+1RuH/9Z + hCf/V4cq/1KKLP9RjTD/UpEz/1CTNv9Nlzn/T6FJ/1nAff9g1KL/Xtan/1zXrP9Y2LH/Vdm1/1LZuf9O + 2r3/S9vB/0fbxP8kdGs9AAAAAAAAAAAAAAAAAAAAAK6CvF+8jND/uYvS/7WJ1P+wh9b/rYXY/6mD2f+k + f9r/oHzc/5t53f+Vdd7/iWjT/21Cq/9GLaD/KSKf/yUgoP8hHqH/IB2j/yAcpf86JKv/TjOns29Nhh2y + lEoUcosxpliAJP8sdSD/JXci/yN6Jf8ifin/I4Es/zOKMf9RnkX/XcF9/2LRmv9g1KL/Xtan/1zXrP9Y + 2LH/Vdm1/1LZuf9O2r3/S9vB/0fbxP81qptvAAAAAAAAAAAAAAAAAAAAALCDvlm8jND/uYvS/7WJ1P+w + h9b/rYXY/6mD2f+kf9r/oHzc/5t53f+Udd7/gGne/zlD2P8dKrz/GSKt/xcgrf8VHq3/Ex2w/xIdtP8V + JtT/HTfPtBtBfiQkh3IZLKZcpBuaRv8VfS3/FX4u/xV/L/8VhDT/FIk6/xWUS/8kuH7/UsuS/2HSnP9g + 1KL/Xtan/1zXrP9Y2LH/Vdm1/1LZuf9O2r3/S9vB/0fbxP81rJpoAAAAAAAAAAAAAAAAAAAAAKF7sR68 + jND/uYvS/7WJ1P+wh9b/rYXY/6mD2f+kf9r/oHzc/5t53f+Da93/P0XY/yQ31/8iNdj/IDTY/x0w1f8a + LdT/GS3a/xcs3v8QKN//E0/o/g5u27EQsrepE6h++BKaTP8Xo1P/GKRY/xikWf8YqGL/GK9t/xiydP8Y + tXz/JbyG/07Ml/9g1KL/Xtan/1zXrP9Y2LH/Vdm1/1LZuf9O2r3/S9vB/0fbxP8mfXEtAAAAAAAAAAAA + AAAAAAAAAGBggAK7i8/1uIvS/7WJ1P+wh9b/rYXY/6mD2f+kf9r/oHzc/5V23P87Qtb/JzfW/yU21v8j + Ndj/IDPZ/x4y2v8cMNv/GC7c/wsp3P8FLd//Bljs/wdx7/8Gpb3/Bqea/wWRWf8Ll1T/F6Zb/xirYv8Y + rmn/GLBw/xezdv8Ytn3/F7iD/yC+i/9T0J//Xtao/1zXrP9Y2LH/Vdm1/1LZuf9O2r3/S9vB/0bYwvcK + JRwFAAAAAAAAAAAAAAAAAAAAAAAAAACzhspRuIrR9LWJ1P+wh9b/rYXY/6mD2f+jf9r/jHHa/z9D1P8p + N9T/JzbW/yU11/8jNNj/ITPZ/x8x2f8ZL9v/CSna/wMm2/8FQeX/B23x/wNjzP8Ddbr/B7PB/wWbf/8D + jVf/CJZd/xWpZP8YsGz/GLFy/xi0eP8Xt3//F7mF/xa7iv8fwJT/Ss+j/1rWrP9Y2LH/Vdm1/1LZuf9O + 2r3/Stm/9T+7ploAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC1iMwVtonPmrSJ0/ewh9b/rYXY/6mD2f+R + dNj/SEfT/ys30v8pNtT/KDXV/yY01/8jM9j/ITPZ/x8x2v8MK9r/BCfa/wU34P8IZe//CGzw/wNgx/8C + cL3/B6zE/wiwv/8ElnX/A49f/wqbZf8YsG7/GLN0/xi1ef8XuIH/F7qG/xa7jP8VvZP/IsOb/0jRqP9Y + 2LH/Vdm1/1LZuf9O2bz4SdK5nkPIsRYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtIjPGLCFz3mw + h9X/rYXX/6R/2P9EQtH/LjXQ/yw10v8qNdT/KDTV/yY01/8kM9j/IjLZ/xwv2v8EKNn/Bj3i/whe7f8J + afH/CGnv/wNfyf8Ca8D/B6HH/wiyy/8Hrr3/BZyH/wORZ/8VrG//GLR2/xi2e/8XuIP/F7qI/xa8jf8V + vZT/Fb+Z/x7Eof9N1a//Vdi1/1LZuP9JzbF9R8yyGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAACeecgWmXzVm05O1/g3Qdj/NULZ/zRC2v8yQ9v/MUPc/y9D3v8tQ9//LEPg/xFA4f8K + XO3/CmXw/wlm8P8JZ/D/CWjv/wNezP8Ca8P/B6PL/wixzv8IstH/CbTU/wiwyf8NqZb/IcCS/yDClv8h + w53/IMWh/x/Gpf8fyKv/Hsmv/x7Ks/8nzbn8StC3pkWvlBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXF0YBSl/ndExk7/hMaPH/TGrx/0tt8f9Kb/L/SXHy/0hy8/9H + dPP/Rnbz/xpm8P8LYfD/C2Pw/wtk8P8KZfD/Cmfw/wNez/8Db8f/CazP/wmw0f8JsdT/CbLW/wmz2f8V + v9z/OuHh/zvi5P874ub/O+Pn/zvk6f875ez/OuXu/zrl7/855vD+M8/ZlxdiZwwAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBUc0VSl3nqU1i8P9NZfD/TGjx/0xq8f9L + bfH/Sm/y/0lw8v9Ic/P/R3Tz/xpk8P8LX+//C2Dv/wti8P8LZPD/C2Xw/wdh3v8Eecv/Ca7S/wmv1P8J + sNb/CbHZ/wmx2v8Vvt7/O+Lk/zvi5f874+f/OuPp/zvl6/865e3/OuXv/znm8f855vP/Ndnm2i/E0C4A + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLWeo1TFzt6k1f8P9N + YvD/TWXw/0xn8f9LavH/S2zx/0pu8v9JcPL/SHLz/xth8P8LXe//C17v/wtf7/8LYe//C2Pw/w9v8f8Q + rtn/CqzV/wqt1v8Jrtn/Ca/b/wmv3f8WveH/O+Lm/zvj5/865Or/O+Xr/zrl7f865fD/Oebx/znm8/84 + 5/X/N+b2/jPX5kQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABM + V+w6TVnu801c7/9NYPD/TWLw/01l8P9MaPH/TGrx/0ts8f9Kb/L/SXHy/xxe8P8NWu//DVzv/wxd7/8M + X+//EG3x/yKj9/8nvvP/ErDe/wus2f8Krdv/Cq3d/wqt3/8Wu+L/O+Pn/zrj6f875ev/OuXt/zrl7/85 + 5vH/Oebz/zjn9f845/f/N+f5/zLV5kUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAABLVegwTFbs4E1Z7/9NXe//TWDw/01i8P9NZfD/TGjx/0tq8f9LbfH/Sm/y/xxc7/8N + V+7/DVnu/w1a7/8QZvD/Ipz2/y6++v8vwPr/J7vy/xCu4P8Lq93/Cqvf/wqs4f8WuuT/O+Tp/zvl6/86 + 5e3/OuXv/znm8f855vP/OOf1/zjn9v835/n/Nub5/DPd8EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGStUMTFPrl01W7/9NWe//TV3v/01f8P9NYvD/TWXw/0xn8f9M + avH/S23x/xxZ7v8NVO7/DVXu/xFh7/8noff/Mb76/zG++v8xvvr/Mb76/y279/8RrOP/C6nh/wqq4/8W + uef/O+Xr/zrl7f865fD/Oebx/znm8/845/X/OOf3/zfn+f825/v/M9vvxS3F2CMAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATFHqXU1T7u5NV+//TVrv/01d7/9N + YPD/TWLw/01l8P9MaPH/TGrx/x1W7v8OUe3/EmDv/yWU9v8zu/r/M7v6/zO7+v8zu/r/M7v6/zO7+v8p + tvT/E6vo/wun5f8Wt+j/OuXt/zrl7/855vH/Oebz/zjn9f845/f/N+j5/zbn+v815vv5MdnufBBVXQQA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASU7iDk1Q7LVN + U+7/TVfv/01Z7/9NXe//TWDw/01i8P9NZfD/TGjx/x5U7v8SWO7/JpH1/zO1+v80ufr/NLn6/zS5+v80 + ufr/NLn6/zS5+v8zuPr/KrT1/xGo6f8Xter/OuXv/znm8f855vP/OOf1/zjn9v835/n/Nuf6/zXo/P80 + 5fvMLMfbHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAFNUe26TVPu8U1W7/9NWe//TVzv/01f8P9NYvD/TWXw/yRg7/4rmfb/NbX5/zW1+v81 + tfr/NbX5/zW1+v81tfr/NbX5/zW1+v81tfr/NbX5/zCz9/8etu79Oebx/Tnm8/845/X/OOf3/zfn+f82 + 5/v/Nef8+DTm/MsbXmsLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABKUOYSS1HqZUxT7KtNVu71TVnv/k1c7/1MXu3US2HrjzaZ9L82 + svn/NrL5/zay+f82svn/NrL5/zay+f82svn/NrL5/zay+f82svn/NrL5/zay+f8zsu7BOePwgzjk8sg3 + 5/b8N+f4/zbn+vk14/e6M+L3di/Q6BsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVVAEhQ4xZNVe47TVjvP01a7z9L + W+gqQ1PICDOk5ic3r/n/N6/5/zev+f83r/n/N6/5/zev+f83r/n/N6/5/zev+f83r/n/N6/5/zev+f8n + frMyNsnYBDfg8CQ35vc+Nuf5QDXm+j0y2O0dIoiZAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2qPWhN6n5/Teq+f83qvn/N6r5/zeq+f83qvn/N6r5/zeq+f83 + qvn/N6n5/TSh7KYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3pvYeN6b3szim+Ps4pvn/OKb5/zim+f84 + pvn/OKb5/zim+f84pvj7N6P0tTOa5SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN6P1HDef8nM4 + ovj+OKL4/zii+P84ovj/OKL4/zii+P41mup3NpvrHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAxjNYGNZbqOzab8X82mvB/NJHhPSpysQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////8AAP///n///wAA///4D///AAD//8AD//8AAP//wAP/ + /wAA///AAf//AAD/wAAAAf8AAP+AAAAB/wAA/wAAAAD/AAD+AAAAAD8AAPwAAAAAPwAA/AAAAAA/AAD8 + AAAAAD8AAPwAAAAAPwAA/AAAAAA/AAD8AAAAAD8AAPwAAAAAPwAA+AAAAAAfAADgAAAAAAcAAOAAAAAA + BwAA4AAAAAAHAADAAAAAAAMAAMAAAAAAAwAAwAAAAAADAADAAAAAAAMAAMAAAAAAAwAAwAAAAAADAADg + AAAAAAcAAOAAAAAABwAA8AAAAAAHAAD8AAAAAD8AAPwAAAAAPwAA/AAAAAA/AAD8AAAAAD8AAPwAAAAA + PwAA/AAAAAA/AAD8AAAAAD8AAPwAAAAAPwAA/gAAAAA/AAD/AAAAAP8AAP+AAAAB/wAA/8AAAAP/AAD/ + /8AD//8AAP//wAP//wAA///AA///AAD///gf//8AAP///////wAA////////AAAoAAAAIAAAAEAAAAAB + ACAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGNOJhXZqVRe1qZSX1JAHhkAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPos16c+sJk//vCZP/7wmT/+sJk/96sWqIA + AAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7bZjrfW9Z//1vWf/9b1n//W9Z//1 + vWf/9b1n/+KuX7QAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbkRNHrt1hHW/eYt9iVdmQ8qZWTbwt2n/8Ldp//C3af/w + t2n/8Ldp//C3af/wt2n/8Ldp/6yDTD5lhkYzh7pge3+4XnlIajYtAAAAAQAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbhxfpfHe4v/x32P/8d+lP/GgJj/yYB2/OepZ//s + sWv/7LFr/+yxa//ssWv/7LFr/+yxa//psGn/q6tW95fBZv+RwmX/i8Jk/4XCY/91slqyBwcHCQAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC8c4CPx3uL/8d9kP/Hf5T/xoCY/8aBnP+8 + bHH/umRK/+Gjaf/mqmz/5qps/+aqbP/mqmz/46lq/6iJOf+aoEj/nMFm/5fBZv+RwmX/i8Jk/4XCY/92 + tFu2AAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkFpjEMd7i//HfZD/x36U/8aAmP/G + gZz/xYKf/7lrc/+sU0b/tGBN/9ucaf/go2z/4KNs/96ia/+rgjn/l3kq/52dSP+iwGb/nMFm/5fCZv+R + wmX/i8Jk/4XCY/9YhEQ2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAeIhlx32P/8d/lP/G + gJj/xoGc/8WCn//EgqL/tml2/6ZQSP+lUEn/rVxQ/9WUav/Ymmr/rHs5/5tyK/+Xcyv/n5lJ/6fAZv+i + wGb/nMFm/5fCZv+RwmX/i8Jk/4K7YIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMR7jm/H + fpT/xoCY/8aBnP/Fgp//xIKi/8ODpf+yZ3j/oExJ/59LSv+eS0v/p1lS/650Ov+eayr/mmwq/5ZtK/+h + lUj/rL5l/6e/Zv+iwGb/nMFm/5fBZv+RwmX/ib1iggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAtXWHH8aAmP/GgZz/xYKf/8SCov/Dg6X/woOo/65lev+aR0v/mEdL/5dHTP+MQD3/jk4k/5xjKf+Y + ZCr/lWYq/6ORSP+wvWX/q75l/6e/Zv+iwGb/nMFm/5fBZv9/qFhLAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAACLaqxArHCk9KFgk/+eX5f/ml+b/5Zdnv+SXKH/gEZ4/4k9Sv+RQkz/kEJM/4I4NP+C + QCL/mlwp/5ZdKf+IXSf/doI3/3+qTf97rE//dq1R/3KvU/9ssVX/b71t/j2chEYAAAABAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAACrYPKrrCG1v+ogdb/hU2c/3c+j/9xPJP/ajmX/2Q3mv9bMpf/QRhG/2QrSf+I + PEz/ezIz/3s3IP+WVCf/bE0e/0BHFf9PjjD/TZc2/0maOv9FnT3/QJ9B/0CpU/9U06f/U9m4/0jJr7QA + AAAGAAAAAAAAAAAAAAAAAAAAALCExo22itP/sIbW/6qD2f+ifdj/f0ui/3E8lv9qOZn/Yjac/1szn/9M + J4H/OBRG/2QqSf91LjX/fzgg/3ZGHv9APRL/TXIl/1KRMv9OlTb/Spk6/0acPf9Gpk//WdGg/1jYsv9T + 2bj/Ttq+/0DBq5cAAAAAAAAAAAAAAABhSWEFuovQ/raK0/+wh9b/qoPZ/6N/2/+bd9r/d0mn/2g5nP9h + Np//WjOi/1IupP9EJIv/ORhY/3QwSf+NQCb/TEUV/1FwIv9Wiyz/U48x/1CUNf9MmDn/TKNL/13Pmf9c + 16v/WNiy/1PZuP9O2r7/SNrD/g4lJQ4AAAAAAAAAAKyAuTq7jND/torT/7CH1v+qg9n/o3/b/5x63f+T + ctz/cEau/0kuoP82JqH/LiOj/y0hpv89Jaz/jWGiUsmdTkJagSX/OXoj/zJ+J/8ygyz/Oosx/1KhSf9g + zZH/YNWj/1zXq/9Y2LL/U9m4/07avv9I28T/MqOURQAAAAAAAAAAroK8NLuM0P+2itP/sIfW/6qD2f+j + f9v/nHrd/5Jz3v8+Rtn/HizC/xkmuf8WIrn/FCLB/xYo2/8lXrRaKaqURx2dSP8Wijr/Fok6/xaQQ/8W + nFX/KLqB/13Rmv9g1aP/XNer/1jYsv9T2bj/Ttq+/0jbxP8zppU+AAAAAAAAAABgYIACuovQ+7aK0/+w + h9b/qoPZ/6N/2/+aeNz/QUbX/yU21v8iNNj/HzLa/xsw2/8SK93/Bi/g/wdy8f8Ir8D/B5Rb/xKeVv8Y + qmD/GK9q/xiydP8Ytn7/JL6L/1rTov9c16v/WNiy/1PZuP9O2r7/R9rD+wsoHwYAAAAAAAAAAAAAAAC2 + iM10torT/7CG1v+qg9n/oX7a/0ZH1f8pN9T/JjXX/yI02P8fMtn/FC3a/wMn2/8GV+v/BGbX/wSIvf8G + p6L/A45Z/xGjY/8YsG3/GLR3/xe4gP8Xu4r/IsGW/1fVqv9Y2LL/U9m4/07avv9Ey7R6AAAAAAAAAAAA + AAAAAAAAAAAAAACyh9CLsIbW/6eC2P9KR9L/LDbR/yk11P8mNNf/IzPZ/x4x2v8EKNr/B1Do/wlp8f8F + Y9X/A3nB/wiyyv8GpqX/A5Fm/xevcP8YtXr/F7mD/xe8jP8VvpX/IcSg/1PXsf9T2bj/StK2jgAAAAEA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkfsscXF7e7D5P4P88UeL/OlLj/zhT5f82VOb/H0/m/wpg7/8K + ZfD/CWfw/wVi2P8Ee8b/CbHO/wmy0v8JstD/Gbms/ynMr/8pzrb/KdC7/yjSwf8n08b/NdfM+kWwlCAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5NxR5NYvD/TWbx/0xq8f9KbfL/SXHy/0hz8/8p + avH/C2Dv/wti8P8LZPD/B2Lh/waJzP8Jr9P/CbDW/wmx2v8iyt//O+Ll/zvj5/875Or/OuXu/zrm8P85 + 5vP/LLXATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATFnrbk1e8P9NYvD/TWbx/0xq8f9K + bfL/SXHy/ypn8f8MXO//C1/v/wth7/8QcvH/ErDc/wqt1/8Krtr/Cq/d/yPJ4/874+f/OuTq/zrl7f86 + 5vD/Oebz/zjn9v814PCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMVepmTVnv/01e8P9N + YvD/TGbx/0xq8f9KbfL/K2Pw/w1Y7v8NW+//EWrx/yu1+f8twPj/Eq/h/wur3f8KrOD/I8jl/zvk6v86 + 5e3/Oubw/znm8/845/b/N+f5/zXi9X8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEVJ0xBN + Ve//TVrv/01e8P9NYvD/TGbx/0xq8f8sX+//DVPu/xJj8P8tsfn/Mb36/zG9+v8wvPn/E6zl/wqp4/8j + x+j/OuXt/zrm8P855vP/OOf2/zfn+f825/v/KrrLNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAExQ65VNVe//TVrv/01e8P9NYvD/TWbx/y1b7/8TXe//L6z5/zS5+v80ufr/NLn6/zS5+v8y + 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 + + + \ No newline at end of file diff --git a/ColorControl/NvPreset.cs b/ColorControl/NvPreset.cs new file mode 100644 index 0000000..aa64bbe --- /dev/null +++ b/ColorControl/NvPreset.cs @@ -0,0 +1,186 @@ +using NvAPIWrapper.Display; +using NvAPIWrapper.Native.Display; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ColorControl +{ + class NvPreset : PresetBase + { + public bool applyColorData { get; set; } + public ColorData colorData { get; set; } + public bool applyHDR { get; set; } + public bool HDREnabled { get; set; } + public bool toggleHDR { get; set; } + public bool applyDithering { get; set; } + public bool ditheringEnabled { get; set; } + public bool applyRefreshRate { get; set; } + public uint refreshRate { get; set; } + public bool primaryDisplay { get; set; } + public string displayName { get; set; } + + public NvPreset() + { + applyColorData = true; + applyDithering = false; + ditheringEnabled = true; + applyHDR = false; + HDREnabled = false; + toggleHDR = false; + applyRefreshRate = false; + refreshRate = 60; + primaryDisplay = true; + } + + public NvPreset(ColorData colorData) : this() + { + id = GetNewId(); + this.colorData = colorData; + } + + public NvPreset(NvPreset preset): this() + { + id = GetNewId(); + + primaryDisplay = preset.primaryDisplay; + displayName = preset.displayName; + + var colorData = preset.colorData; + this.colorData = new ColorData(colorData.ColorFormat, dynamicRange: colorData.DynamicRange, colorDepth: colorData.ColorDepth, colorSelectionPolicy: colorData.SelectionPolicy); + applyColorData = preset.applyColorData; + + applyHDR = preset.applyHDR; + HDREnabled = preset.HDREnabled; + toggleHDR = preset.toggleHDR; + applyDithering = preset.applyDithering; + ditheringEnabled = preset.ditheringEnabled; + applyRefreshRate = preset.applyRefreshRate; + refreshRate = preset.refreshRate; + } + + public NvPreset Clone() + { + var preset = new NvPreset(this); + + return preset; + } + + public static string[] GetColumnNames() + { + //return new[] { "BPC", "Format", "Dynamic range", "Toggle HDR", "Shortcut" }; + return new[] { "Display|80", "Color settings (BPC, format, dyn. range, color space)|260", "Refresh rate|100", "Dithering", "HDR", "Shortcut" }; + } + + public List GetDisplayValues() + { + var values = new List(); + + var display = string.Format("{0}", primaryDisplay ? "Primary" : displayName); + values.Add(display); + + var colorSettings = string.Format("{0}: {1}, {2}, {3}, {4}", applyColorData ? "Included" : "Excluded", colorData.ColorDepth, colorData.ColorFormat, colorData.DynamicRange, colorData.Colorimetry); + + values.Add(colorSettings); + values.Add(string.Format("{0}: {1}Hz", applyRefreshRate ? "Included" : "Excluded", refreshRate)); + values.Add(string.Format("{0}: {1}", applyDithering ? "Included" : "Excluded", ditheringEnabled ? "Enabled" : "Disabled")); + values.Add(string.Format("{0}: {1}", applyHDR ? "Included" : "Excluded", toggleHDR ? "Toggle" : HDREnabled ? "Enabled" : "Disabled")); + + //values.Add(colorData.ColorDepth.ToString()); + //values.Add(colorData.ColorFormat.ToString()); + //values.Add(colorData.DynamicRange.ToString()); + //values.Add(toggleHDR.ToString()); + values.Add(shortcut); + + return values; + } + + public static List GetDefaultPresets() + { + var presets = new List(); + + presets.Add(new NvPreset(new ColorData(ColorDataFormat.Auto, dynamicRange: ColorDataDynamicRange.Auto, colorDepth: ColorDataDepth.Default, colorSelectionPolicy: ColorDataSelectionPolicy.BestQuality))); + + for (var dynamicRange = ColorDataDynamicRange.VESA; dynamicRange <= ColorDataDynamicRange.CEA; dynamicRange++) + { + presets.Add(new NvPreset(new ColorData(ColorDataFormat.RGB, dynamicRange: dynamicRange, colorDepth: ColorDataDepth.BPC8, colorSelectionPolicy: ColorDataSelectionPolicy.User))); + presets.Add(new NvPreset(new ColorData(ColorDataFormat.RGB, dynamicRange: dynamicRange, colorDepth: ColorDataDepth.BPC10, colorSelectionPolicy: ColorDataSelectionPolicy.User))); + presets.Add(new NvPreset(new ColorData(ColorDataFormat.RGB, dynamicRange: dynamicRange, colorDepth: ColorDataDepth.BPC12, colorSelectionPolicy: ColorDataSelectionPolicy.User))); + } + + for (var format = ColorDataFormat.YUV422; format <= ColorDataFormat.YUV420; format++) + { + presets.Add(new NvPreset(new ColorData(format, dynamicRange: ColorDataDynamicRange.Auto, colorDepth: ColorDataDepth.BPC8, colorSelectionPolicy: ColorDataSelectionPolicy.User))); + presets.Add(new NvPreset(new ColorData(format, dynamicRange: ColorDataDynamicRange.Auto, colorDepth: ColorDataDepth.BPC10, colorSelectionPolicy: ColorDataSelectionPolicy.User))); + presets.Add(new NvPreset(new ColorData(format, dynamicRange: ColorDataDynamicRange.Auto, colorDepth: ColorDataDepth.BPC12, colorSelectionPolicy: ColorDataSelectionPolicy.User))); + } + + return presets; + } + + public string GetTextForMenuItem() + { + var sb = new StringBuilder(); + if (displayName != null) + { + sb.AppendFormat("Display: {0} / ", displayName); + } + if (applyColorData) + { + var colorSettings = string.Format("Format: {0}, {1}, {2}", colorData.ColorDepth, colorData.ColorFormat, colorData.DynamicRange); + sb.Append(colorSettings); + sb.Append(" / "); + } + if (applyRefreshRate) + { + sb.AppendFormat("{0}Hz", refreshRate); + sb.Append(" / "); + } + if (applyDithering) + { + sb.AppendFormat("Dithering: {0}", ditheringEnabled ? "Yes" : "No"); + sb.Append(" / "); + } + if (applyHDR) + { + sb.AppendFormat("HDR: {0}", toggleHDR ? "Toggle" : HDREnabled ? "Enabled" : "Disabled"); + sb.Append(" / "); + } + + return sb.ToString(0, Math.Max(0, sb.Length - 3)); + } + + public static ColorData GenerateColorData(IDictionary dictionary) + { + var format = ColorDataFormat.RGB; + var dynamicRange = ColorDataDynamicRange.VESA; + var colorDepth = ColorDataDepth.BPC8; + var colorimetry = ColorDataColorimetry.Auto; + var selectionPolicy = ColorDataSelectionPolicy.User; + object value; + if (dictionary.TryGetValue("ColorFormat", out value)) + { + format = (ColorDataFormat)Enum.ToObject(typeof(ColorDataFormat), value); + } + if (dictionary.TryGetValue("ColorDepth", out value)) + { + colorDepth = (ColorDataDepth)Enum.ToObject(typeof(ColorDataDepth), value); + } + if (dictionary.TryGetValue("Colorimetry", out value)) + { + colorimetry = (ColorDataColorimetry)Enum.ToObject(typeof(ColorDataColorimetry), value); + } + if (dictionary.TryGetValue("DynamicRange", out value)) + { + dynamicRange = (ColorDataDynamicRange)Enum.ToObject(typeof(ColorDataDynamicRange), value); + } + if (dictionary.TryGetValue("SelectionPolicy", out value)) + { + selectionPolicy = (ColorDataSelectionPolicy)Enum.ToObject(typeof(ColorDataSelectionPolicy), value); + } + return new ColorData(format, dynamicRange: dynamicRange, colorimetry: colorimetry, colorDepth: colorDepth, colorSelectionPolicy: selectionPolicy); + } + + } +} + diff --git a/ColorControl/NvService.cs b/ColorControl/NvService.cs new file mode 100644 index 0000000..e9b682d --- /dev/null +++ b/ColorControl/NvService.cs @@ -0,0 +1,221 @@ +using NvAPIWrapper; +using NvAPIWrapper.Display; +using NvAPIWrapper.Native; +using NvAPIWrapper.Native.Display; +using NvAPIWrapper.Native.Display.Structures; +using NvAPIWrapper.Native.Exceptions; +using NvAPIWrapper.Native.GPU.Structures; +using NWin32; +using NWin32.NativeTypes; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; + +namespace ColorControl +{ + class NvService + { + const UInt32 WM_KEYDOWN = 0x0100; + const UInt32 WM_KEYUP = 0x0101; + const int VK_TAB = 0x09; + const int VK_SPACE = 0x20; + + [DllImport("user32.dll")] + static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam); + + [DllImport(@"nvapi64", EntryPoint = @"nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl, + PreserveSig = true)] + private static extern IntPtr NvAPI64_QueryInterface(uint interfaceId); + + + public delegate long NvAPI_Disp_SetDitherControl( + [In] PhysicalGPUHandle physicalGpu, + [In] uint OutputId, + [In] uint state, + [In] uint bits, + [In] uint mode + ); + + private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + private Display _currentDisplay; + + public NvService() + { + NVIDIA.Initialize(); + } + + ~NvService() + { + NVIDIA.Unload(); + } + + public Display GetCurrentDisplay() + { + if (_currentDisplay == null) + { + _currentDisplay = Display.GetDisplays()[0]; + } + + return _currentDisplay; + } + + private void SetCurrentDisplay(NvPreset preset) + { + if (preset.primaryDisplay) + { + var displayId = DisplayDevice.GetGDIPrimaryDisplayDevice().DisplayId; + _currentDisplay = Display.GetDisplays().FirstOrDefault(x => x.DisplayDevice.DisplayId == displayId); + } + else + { + _currentDisplay = Display.GetDisplays().FirstOrDefault(x => x.Name.Equals(preset.displayName)); + } + } + + + public bool ApplyPreset(NvPreset preset, Config config) + { + SetCurrentDisplay(preset); + + if (preset.applyHDR) + { + if (preset.toggleHDR || preset.HDREnabled != IsHDREnabled()) + { + ToggleHDR(config.DisplaySettingsDelay); + } + } + + if (preset.applyRefreshRate) + { + SetRefreshRate(preset.refreshRate); + } + + if (preset.applyColorData) + { + var display = GetCurrentDisplay(); + //var data = new ColorData(ColorDataFormat.YUV444, ColorDataColorimetry.YCC709, ColorDataDynamicRange.Auto, ColorDataDepth.BPC8, preset.colorData.SelectionPolicy, ColorDataDesktopDepth.Default); + display.DisplayDevice.SetColorData(preset.colorData); + + //var master = display.DisplayDevice.HDRColorData.MasteringDisplayData; + //var newMaster = new MasteringDisplayColorData(master.FirstColorCoordinate, master.SecondColorCoordinate, master.ThirdColorCoordinate, new ColorDataColorCoordinate(0.25f, 0.25f), 50, 0, 50, 50); + //var hdr = new HDRColorData(ColorDataHDRMode.UHDA, newMaster, ColorDataFormat.YUV444, ColorDataDynamicRange.Auto, ColorDataDepth.BPC8); + //display.DisplayDevice.SetHDRColorData(hdr); + } + + if (preset.applyDithering) + { + SetDithering(preset.ditheringEnabled); + } + + return true; + } + + public void ToggleHDR(int delay = 1000) + { + Process.Start("ms-settings:display"); + Thread.Sleep(delay); + + var process = Process.GetProcessesByName("SystemSettings").FirstOrDefault(); + if (process != null) + { + System.Windows.Forms.SendKeys.SendWait("{TAB}"); + System.Windows.Forms.SendKeys.SendWait("{TAB}"); + System.Windows.Forms.SendKeys.SendWait(" "); + System.Windows.Forms.SendKeys.SendWait("%{F4}"); + } + } + + public void SetDithering(bool enabled) + { + var ptr = NvAPI64_QueryInterface(0xDF0DFCDD); + if (ptr != IntPtr.Zero) + { + var delegateValue = Marshal.GetDelegateForFunctionPointer(ptr, typeof(NvAPI_Disp_SetDitherControl)) as NvAPI_Disp_SetDitherControl; + + var displayDevice = GetCurrentDisplay().DisplayDevice; + + var gpuHandle = displayDevice.PhysicalGPU.Handle; + var displayId = displayDevice.DisplayId; + + var result = delegateValue(gpuHandle, displayId, (uint)(enabled ? 1 : 2), 1, 4); + if (result != 0) + { + Logger.Error($"Could not set dithering because NvAPI_Disp_SetDitherControl returned a non-zero return code: {result}"); + } + } + } + + public bool SetRefreshRate(uint refreshRate) + { + var display = GetCurrentDisplay(); + var portrait = new[] { Rotate.Degree90, Rotate.Degree270 }.Contains(display.DisplayDevice.ScanOutInformation.SourceToTargetRotation); + var timing = display.DisplayDevice.CurrentTiming; + + uint i = 0; + DEVMODEA devMode; + while (NativeMethods.EnumDisplaySettingsA(display.Name, i, out devMode)) + { + // Also compare width with vertical and height with horizontal in case of portrait mode + if (((!portrait && devMode.dmPelsWidth == timing.HorizontalVisible && devMode.dmPelsHeight == timing.VerticalVisible) || + (portrait && devMode.dmPelsWidth == timing.VerticalVisible && devMode.dmPelsHeight == timing.HorizontalVisible)) + && devMode.dmBitsPerPel == 32 && devMode.dmDisplayFrequency == refreshRate) + { + IntPtr bla = Marshal.AllocHGlobal(Marshal.SizeOf(devMode)); + Marshal.StructureToPtr(devMode, bla, false); + var result = NativeMethods.ChangeDisplaySettingsExA(display.Name, bla, IntPtr.Zero, 0, IntPtr.Zero); + if (result != NativeConstants.DISP_CHANGE_SUCCESSFUL) + { + Logger.Error($"Could not set refreshrate {refreshRate} on display {display.Name} because ChangeDisplaySettingsExA returned a non-zero return code: {result}"); + } + return result == NativeConstants.DISP_CHANGE_SUCCESSFUL; + } + i++; + } + Logger.Info($"Could not set refreshrate {refreshRate} on display {display.Name} because EnumDisplaySettings did not report it as a valid refreshrate"); + return false; + } + + public List GetAvailableRefreshRates(NvPreset preset = null) + { + var list = new List(); + + if (preset != null) + { + SetCurrentDisplay(preset); + } + + var display = GetCurrentDisplay(); + var portrait = new[] { Rotate.Degree90, Rotate.Degree270 }.Contains(display.DisplayDevice.ScanOutInformation.SourceToTargetRotation); + var timing = display.DisplayDevice.CurrentTiming; + + uint i = 0; + DEVMODEA devMode; + while (NativeMethods.EnumDisplaySettingsA(display.Name, i, out devMode)) + { + if ((!portrait && devMode.dmPelsWidth == timing.HorizontalVisible && devMode.dmPelsHeight == timing.VerticalVisible) || + (portrait && devMode.dmPelsWidth == timing.VerticalVisible && devMode.dmPelsHeight == timing.HorizontalVisible)) + { + list.Add(devMode.dmDisplayFrequency); + } + i++; + } + return list; + } + + public bool IsHDREnabled() + { + var displayDevice = GetCurrentDisplay().DisplayDevice; + var hdr = displayDevice.HDRColorData; + return hdr?.HDRMode == ColorDataHDRMode.UHDA; + } + + public Display[] GetDisplays() + { + return Display.GetDisplays(); + } + } +} diff --git a/ColorControl/PnpDev.cs b/ColorControl/PnpDev.cs new file mode 100644 index 0000000..922dfcb --- /dev/null +++ b/ColorControl/PnpDev.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ColorControl +{ + class PnpDev + { + public string name { get; set; } + public string ipAddress { get; set; } + + public PnpDev(string name, string ipAddress) + { + this.name = name; + this.ipAddress = ipAddress; + } + + public override string ToString() + { + return name + " (" + ipAddress + ")"; + } + } +} diff --git a/ColorControl/PresetBase.cs b/ColorControl/PresetBase.cs new file mode 100644 index 0000000..a4301b7 --- /dev/null +++ b/ColorControl/PresetBase.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; + +namespace ColorControl +{ + internal abstract class PresetBase + { + public string shortcut { get; set; } + + private int _id; + + public int id + { + get + { + return _id; + } + set + { + if (value == 0 || ids.Contains(value)) + { + value = GetNewId(); + } + else + { + ids.Add(value); + } + _id = value; + } + } + + public static List ids = new List(); + + public static int GetNewId() + { + int id; + do + { + id = new Random().Next(); + } + while (ids.Contains(id)); + + ids.Add(id); + + return id; + } + + } +} \ No newline at end of file diff --git a/ColorControl/Program.cs b/ColorControl/Program.cs new file mode 100644 index 0000000..03ccad2 --- /dev/null +++ b/ColorControl/Program.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace ColorControl +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + string mutexId = $"Global\\{typeof(MainForm).GUID}"; + bool mutexCreated; + var mutex = new Mutex(true, mutexId, out mutexCreated); + try + { + if (!mutexCreated) + { + MessageBox.Show("Only one instance of this program can be active.", "ColorControl"); + } + else + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainForm()); + } + } + finally + { + if (mutexCreated) + { + mutex.Dispose(); + } + } + } + } +} diff --git a/ColorControl/Properties/AssemblyInfo.cs b/ColorControl/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a9a23a4 --- /dev/null +++ b/ColorControl/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ColorControl")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Maassoft")] +[assembly: AssemblyProduct("ColorControl")] +[assembly: AssemblyCopyright("Copyright © Maassoft 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a6005d08-70f0-44cb-a384-9219eba84f21")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.3.0")] +[assembly: AssemblyFileVersion("1.0.3.0")] diff --git a/ColorControl/Properties/Resources.Designer.cs b/ColorControl/Properties/Resources.Designer.cs new file mode 100644 index 0000000..e406eea --- /dev/null +++ b/ColorControl/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// 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 ColorControl.Properties +{ + + + /// + /// 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", "4.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 ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ColorControl.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; + } + } + } +} diff --git a/ColorControl/Properties/Resources.resx b/ColorControl/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/ColorControl/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ColorControl/Properties/Settings.Designer.cs b/ColorControl/Properties/Settings.Designer.cs new file mode 100644 index 0000000..cfaea48 --- /dev/null +++ b/ColorControl/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// 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 ColorControl.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/ColorControl/Properties/Settings.settings b/ColorControl/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/ColorControl/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/ColorControl/Properties/app.manifest b/ColorControl/Properties/app.manifest new file mode 100644 index 0000000..b7a60b2 --- /dev/null +++ b/ColorControl/Properties/app.manifest @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ColorControl/RestartDetector.cs b/ColorControl/RestartDetector.cs new file mode 100644 index 0000000..9e35821 --- /dev/null +++ b/ColorControl/RestartDetector.cs @@ -0,0 +1,90 @@ +using NLog; +using System; +using System.Diagnostics.Eventing.Reader; + +namespace ColorControl +{ + public class RestartDetector : IDisposable + { + public bool RestartDetected { get; private set; } + + private EventLogWatcher watcher = null; + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + public RestartDetector() + { + try + { + EventLogQuery subscriptionQuery = new EventLogQuery( + "System", PathType.LogName, "*[System[Provider[@Name='USER32'] and (EventID=1074)]]"); + + watcher = new EventLogWatcher(subscriptionQuery); + + // Make the watcher listen to the EventRecordWritten + // events. When this event happens, the callback method + // (EventLogEventRead) is called. + watcher.EventRecordWritten += + new EventHandler( + EventLogEventRead); + + // Activate the subscription + watcher.Enabled = true; + } + catch (EventLogReadingException e) + { + } + } + + public void EventLogEventRead(object obj, EventRecordWrittenEventArgs arg) + { + RestartDetected = false; + try + { + Logger.Debug("Logging event: " + arg); + // Make sure there was no error reading the event. + if (arg.EventRecord != null) + { + foreach (EventProperty x in ((EventLogRecord)arg.EventRecord).Properties) + { + Logger.Debug("Event value: " + x.Value); + if (x.Value.Equals("restart")) + { + RestartDetected = true; + break; + } + } + } + + //if (arg.EventRecord != null) + //{ + // String[] xPathRefs = new String[1]; + // xPathRefs[0] = "Event/EventData/Data"; + // IEnumerable xPathEnum = xPathRefs; + + // EventLogPropertySelector logPropertyContext = new EventLogPropertySelector(xPathEnum); + // IList logEventProps = ((EventLogRecord)arg.EventRecord).GetPropertyValues(logPropertyContext); + + // string[] eventData = (string[])logEventProps[0]; + + // foreach (string attribute in eventData) + // { + // if (attribute.Contains("restart")) { restart = true; break; } + // } + //} + } + catch (Exception e) + { + } + } + + public void Dispose() + { + // Stop listening to events + if (watcher != null) + { + watcher.Enabled = false; + watcher.Dispose(); + } + } + } +} diff --git a/ColorControl/ScreenInterrogatory.cs b/ColorControl/ScreenInterrogatory.cs new file mode 100644 index 0000000..013a67b --- /dev/null +++ b/ColorControl/ScreenInterrogatory.cs @@ -0,0 +1,313 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace ColorControl +{ + public static class ScreenInterrogatory + { + public const int ERROR_SUCCESS = 0; + + #region enums + + public enum QUERY_DEVICE_CONFIG_FLAGS : uint + { + QDC_ALL_PATHS = 0x00000001, + QDC_ONLY_ACTIVE_PATHS = 0x00000002, + QDC_DATABASE_CURRENT = 0x00000004 + } + + public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY : uint + { + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = 0xFFFFFFFF, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = 0x80000000, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCE_UINT32 = 0xFFFFFFFF + } + + public enum DISPLAYCONFIG_SCANLINE_ORDERING : uint + { + DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0, + DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3, + DISPLAYCONFIG_SCANLINE_ORDERING_FORCE_UINT32 = 0xFFFFFFFF + } + + public enum DISPLAYCONFIG_ROTATION : uint + { + DISPLAYCONFIG_ROTATION_IDENTITY = 1, + DISPLAYCONFIG_ROTATION_ROTATE90 = 2, + DISPLAYCONFIG_ROTATION_ROTATE180 = 3, + DISPLAYCONFIG_ROTATION_ROTATE270 = 4, + DISPLAYCONFIG_ROTATION_FORCE_UINT32 = 0xFFFFFFFF + } + + public enum DISPLAYCONFIG_SCALING : uint + { + DISPLAYCONFIG_SCALING_IDENTITY = 1, + DISPLAYCONFIG_SCALING_CENTERED = 2, + DISPLAYCONFIG_SCALING_STRETCHED = 3, + DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4, + DISPLAYCONFIG_SCALING_CUSTOM = 5, + DISPLAYCONFIG_SCALING_PREFERRED = 128, + DISPLAYCONFIG_SCALING_FORCE_UINT32 = 0xFFFFFFFF + } + + public enum DISPLAYCONFIG_PIXELFORMAT : uint + { + DISPLAYCONFIG_PIXELFORMAT_8BPP = 1, + DISPLAYCONFIG_PIXELFORMAT_16BPP = 2, + DISPLAYCONFIG_PIXELFORMAT_24BPP = 3, + DISPLAYCONFIG_PIXELFORMAT_32BPP = 4, + DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5, + DISPLAYCONFIG_PIXELFORMAT_FORCE_UINT32 = 0xffffffff + } + + public enum DISPLAYCONFIG_MODE_INFO_TYPE : uint + { + DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1, + DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2, + DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFFF + } + + public enum DISPLAYCONFIG_DEVICE_INFO_TYPE : uint + { + DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3, + DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4, + DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6, + DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF + } + + #endregion + + #region structs + + [StructLayout(LayoutKind.Sequential)] + public struct LUID + { + public uint LowPart; + public int HighPart; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_PATH_SOURCE_INFO + { + public LUID adapterId; + public uint id; + public uint modeInfoIdx; + public uint statusFlags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_PATH_TARGET_INFO + { + public LUID adapterId; + public uint id; + public uint modeInfoIdx; + private DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology; + private DISPLAYCONFIG_ROTATION rotation; + private DISPLAYCONFIG_SCALING scaling; + private DISPLAYCONFIG_RATIONAL refreshRate; + private DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering; + public bool targetAvailable; + public uint statusFlags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_RATIONAL + { + public uint Numerator; + public uint Denominator; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_PATH_INFO + { + public DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo; + public DISPLAYCONFIG_PATH_TARGET_INFO targetInfo; + public uint flags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_2DREGION + { + public uint cx; + public uint cy; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO + { + public ulong pixelRate; + public DISPLAYCONFIG_RATIONAL hSyncFreq; + public DISPLAYCONFIG_RATIONAL vSyncFreq; + public DISPLAYCONFIG_2DREGION activeSize; + public DISPLAYCONFIG_2DREGION totalSize; + public uint videoStandard; + public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_TARGET_MODE + { + public DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo; + } + + [StructLayout(LayoutKind.Sequential)] + public struct POINTL + { + private int x; + private int y; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_SOURCE_MODE + { + public uint width; + public uint height; + public DISPLAYCONFIG_PIXELFORMAT pixelFormat; + public POINTL position; + } + + [StructLayout(LayoutKind.Explicit)] + public struct DISPLAYCONFIG_MODE_INFO_UNION + { + [FieldOffset(0)] + public DISPLAYCONFIG_TARGET_MODE targetMode; + + [FieldOffset(0)] + public DISPLAYCONFIG_SOURCE_MODE sourceMode; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_MODE_INFO + { + public DISPLAYCONFIG_MODE_INFO_TYPE infoType; + public uint id; + public LUID adapterId; + public DISPLAYCONFIG_MODE_INFO_UNION modeInfo; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS + { + public uint value; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_DEVICE_INFO_HEADER + { + public DISPLAYCONFIG_DEVICE_INFO_TYPE type; + public uint size; + public LUID adapterId; + public uint id; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct DISPLAYCONFIG_TARGET_DEVICE_NAME + { + public DISPLAYCONFIG_DEVICE_INFO_HEADER header; + public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags; + public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology; + public ushort edidManufactureId; + public ushort edidProductCodeId; + public uint connectorInstance; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string monitorFriendlyDeviceName; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string monitorDevicePath; + } + + #endregion + + #region DLL-Imports + + [DllImport("user32.dll")] + public static extern int GetDisplayConfigBufferSizes( + QUERY_DEVICE_CONFIG_FLAGS flags, out uint numPathArrayElements, out uint numModeInfoArrayElements); + + [DllImport("user32.dll")] + public static extern int QueryDisplayConfig( + QUERY_DEVICE_CONFIG_FLAGS flags, + ref uint numPathArrayElements, [Out] DISPLAYCONFIG_PATH_INFO[] PathInfoArray, + ref uint numModeInfoArrayElements, [Out] DISPLAYCONFIG_MODE_INFO[] ModeInfoArray, + IntPtr currentTopologyId + ); + + [DllImport("user32.dll")] + public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName); + + #endregion + + private static string MonitorFriendlyName(LUID adapterId, uint targetId) + { + var deviceName = new DISPLAYCONFIG_TARGET_DEVICE_NAME + { + header = + { + size = (uint)Marshal.SizeOf(typeof (DISPLAYCONFIG_TARGET_DEVICE_NAME)), + adapterId = adapterId, + id = targetId, + type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME + } + }; + var error = DisplayConfigGetDeviceInfo(ref deviceName); + if (error != ERROR_SUCCESS) + throw new Win32Exception(error); + return deviceName.monitorFriendlyDeviceName; + } + + private static IEnumerable GetAllMonitorsFriendlyNames() + { + uint pathCount, modeCount; + var error = GetDisplayConfigBufferSizes(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount); + if (error != ERROR_SUCCESS) + throw new Win32Exception(error); + + var displayPaths = new DISPLAYCONFIG_PATH_INFO[pathCount]; + var displayModes = new DISPLAYCONFIG_MODE_INFO[modeCount]; + error = QueryDisplayConfig(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS, + ref pathCount, displayPaths, ref modeCount, displayModes, IntPtr.Zero); + if (error != ERROR_SUCCESS) + throw new Win32Exception(error); + + for (var i = 0; i < modeCount; i++) + if (displayModes[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_TARGET) + yield return MonitorFriendlyName(displayModes[i].adapterId, displayModes[i].id); + } + + public static string DeviceFriendlyName(this Screen screen) + { + var allFriendlyNames = GetAllMonitorsFriendlyNames(); + for (var index = 0; index < Screen.AllScreens.Length; index++) + if (Equals(screen, Screen.AllScreens[index])) + return allFriendlyNames.ToArray()[index]; + return null; + } + + } +} diff --git a/ColorControl/TreeNodeBuilder.cs b/ColorControl/TreeNodeBuilder.cs new file mode 100644 index 0000000..0771904 --- /dev/null +++ b/ColorControl/TreeNodeBuilder.cs @@ -0,0 +1,99 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.Script.Serialization; +using System.Windows.Forms; + +namespace ColorControl +{ + public class TreeNodeBuilder + { + public string Name { get; set; } + public string Value { get; set; } + public List Children { get; set; } = new List(); + + public static TreeNode CreateTree(object obj, string text) + { + JavaScriptSerializer jss = new JavaScriptSerializer(); + var serialized = JsonConvert.SerializeObject(obj, Formatting.None, + new JsonSerializerSettings { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + Error = delegate (object sender, ErrorEventArgs args) + { + //errors.Add(args.ErrorContext.Error.Message); + args.ErrorContext.Handled = true; + }, + Converters = new [] { new Newtonsoft.Json.Converters.StringEnumConverter() } + }); + Dictionary dic = jss.Deserialize>(serialized); + var root = new TreeNode(); + root.Text = text; + BuildTree(dic, root); + return root; + } + + private static void BuildTree(object item, TreeNode node) + { + if (item is KeyValuePair) + { + KeyValuePair kv = (KeyValuePair)item; + TreeNode keyValueNode = new TreeNode(); + keyValueNode.Name = kv.Key; + keyValueNode.Text = kv.Key + ": " + GetValueAsString(kv.Value); + node.Nodes.Add(keyValueNode); + BuildTree(kv.Value, keyValueNode); + } + else if (item is ArrayList) + { + ArrayList list = (ArrayList)item; + int index = 0; + foreach (object value in list) + { + TreeNode arrayItem = new TreeNode(); + arrayItem.Name = $"[{index}]"; + arrayItem.Text = $"[{index}]"; + node.Nodes.Add(arrayItem); + BuildTree(value, arrayItem); + index++; + } + } + else if (item is Dictionary) + { + Dictionary dictionary = (Dictionary)item; + foreach (KeyValuePair d in dictionary) + { + BuildTree(d, node); + } + } + } + + private static string GetValueAsString(object value) + { + if (value == null) + return "null"; + var type = value.GetType(); + if (type.IsArray) + { + return "[]"; + } + + if (value is ArrayList) + { + var arr = value as ArrayList; + return $"[{arr.Count}]"; + } + + if (type.IsGenericType) + { + return "{}"; + } + + return value.ToString(); + } + } +} diff --git a/ColorControl/Utils.cs b/ColorControl/Utils.cs new file mode 100644 index 0000000..efd212b --- /dev/null +++ b/ColorControl/Utils.cs @@ -0,0 +1,231 @@ +using NWin32.NativeTypes; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; +using Windows.Devices.Enumeration; +using Windows.Devices.Enumeration.Pnp; + +namespace ColorControl +{ + class Utils + { + [Flags] + public enum ModKeys : int + { + Alt = 1, + Control = 2, + Shift = 4, + Win = 8 + } + + public static string PKEY_PNPX_IpAddress = "{656a3bb3-ecc0-43fd-8477-4ae0404a96cd} 12297"; + + private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + + public static Bitmap SubPixelShift(Bitmap bitmap) + { + Bitmap bitmap2 = (Bitmap) bitmap.Clone(); + + int shift = -1; + bool shiftRed = true; + bool shiftGreen = true; + bool shiftBlue = false; + + for (int i = 0; i < bitmap.Width; i++) + { + for (int j = 0; j < bitmap.Height; j++) + { + Color pixel = bitmap.GetPixel(i, j); + + if (shift > 0 && i < bitmap.Width - shift) + { + Color pixel2 = bitmap2.GetPixel(i + shift, j); + + Color pixel3 = Color.FromArgb(shiftRed ? pixel.R : pixel2.R, shiftGreen ? pixel.G : pixel2.G, shiftBlue ? pixel.B : pixel2.B); + + bitmap2.SetPixel(i + shift, j, pixel3); + + } + else if (i + shift >= 0) + { + Color pixel2 = bitmap2.GetPixel(i + shift, j); + + Color pixel3 = Color.FromArgb(shiftRed ? pixel.R : pixel2.R, shiftGreen ? pixel.G : pixel2.G, shiftBlue ? pixel.B : pixel2.B); + + bitmap2.SetPixel(i + shift, j, pixel3); + + } + } + } + + return bitmap2; + //bitmap2.Save("d:\\ss_shifted.bmp"); + } + + public static string GetDataPath(string subDir = "") + { + var path = Directory.GetParent(Application.UserAppDataPath).FullName; + if (!string.IsNullOrEmpty(subDir)) + { + path = Path.Combine(path, subDir); + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + } + return path; + } + + public static (int mods, int key) ParseShortcut(string shortcut) + { + int mods = 0; + var key = 0; + + shortcut = shortcut.Replace(",", ""); + shortcut = shortcut.Replace("+", ""); + shortcut = shortcut.Replace(" ", " "); + var parts = shortcut.Split(' '); + + if (parts.Length > 0) + { + for (int i = 0; i + 1 < parts.Length; i++) + { + switch (parts[i]) + { + case "Alt": + mods += (int)ModKeys.Alt; + break; + case "Control": + mods += (int)ModKeys.Control; + break; + case "Shift": + mods += (int)ModKeys.Shift; + break; + case "Win": + mods += (int)ModKeys.Win; + break; + } + } + + var keyName = parts[parts.Length - 1]; + + key = (int)Enum.Parse(typeof(Keys), keyName); + } + + return (mods, key); + } + + public static async Task GetDeviceProperty(string deviceName, string propertyName) + { + string value = null; + string name = null; + var list = await DeviceInformation.FindAllAsync("", new List()); + + var reqs = new List(); + reqs.Add(propertyName); + + foreach (var dev in list) + { + name = dev.Name; + if (dev.IsEnabled && dev.Name.Contains(deviceName)) + { + //Debug.WriteLine(dev.Name); + //foreach (var key in dev.Properties.Keys) + //{ + // Debug.WriteLine($"* {key}: {dev.Properties[key]}"); + //} + + var guid = dev.Properties["System.Devices.DeviceInstanceId"]; + + var aqs = "System.Devices.DeviceInstanceId:=\"" + guid + "\""; + var list2 = await PnpObject.FindAllAsync(PnpObjectType.Device, reqs, aqs); + + foreach (var dev2 in list2) + { + foreach (var key in dev2.Properties.Keys) + { + var obj = dev2.Properties[key]; + string newValue = null; + if (obj is string[]) + { + var arr = obj as string[]; + if (arr.Length > 0) + { + newValue = arr[0]; + } + } + else + { + newValue = dev2.Properties[key].ToString(); + } + if (newValue != value) + { + value = newValue; + Logger.Debug($"LG TV with name {dev.Name} found at {value}"); + } + //Debug.WriteLine($"* {key}: {value}"); + } + } + + } + } + return value; + } + + public static async Task> GetPnpDevices(string deviceName, string propertyName) + { + var devices = new List(); + + var list = await DeviceInformation.FindAllAsync("", new List()); + + var reqs = new List(); + reqs.Add(propertyName); + + foreach (var dev in list) + { + string name = dev.Name; + if (dev.IsEnabled && dev.Name.Contains(deviceName)) + { + var guid = dev.Properties["System.Devices.DeviceInstanceId"]; + + var aqs = "System.Devices.DeviceInstanceId:=\"" + guid + "\""; + var list2 = await PnpObject.FindAllAsync(PnpObjectType.Device, reqs, aqs); + + foreach (var dev2 in list2) + { + foreach (var key in dev2.Properties.Keys) + { + var obj = dev2.Properties[key]; + string value = null; + if (obj is string[]) + { + var arr = obj as string[]; + if (arr.Length > 0) + { + value = arr[0]; + } + } + else + { + value = dev2.Properties[key].ToString(); + } + if (!devices.Any(x => x.name.Equals(name) && x.ipAddress.Equals(value))) + { + var device = new PnpDev(name, value); + devices.Add(device); + } + } + } + + } + } + return devices; + } + } +} diff --git a/ColorControl/lgtv/App.cs b/ColorControl/lgtv/App.cs new file mode 100644 index 0000000..d0b4a19 --- /dev/null +++ b/ColorControl/lgtv/App.cs @@ -0,0 +1,11 @@ +namespace LgTv +{ + public class App + { + public string Id { get; set; } + public string LaunchPointId { get; set; } + public string Icon { get; set; } + public string Title { get; set; } + + } +} \ No newline at end of file diff --git a/ColorControl/lgtv/Channel.cs b/ColorControl/lgtv/Channel.cs new file mode 100644 index 0000000..1852cfc --- /dev/null +++ b/ColorControl/lgtv/Channel.cs @@ -0,0 +1,10 @@ +namespace LgTv +{ + public class Channel + { + public string Id { get; set; } + public int Number { get; set; } + public string Name { get; set; } + + } +} \ No newline at end of file diff --git a/ColorControl/lgtv/ClientKeyStore.cs b/ColorControl/lgtv/ClientKeyStore.cs new file mode 100644 index 0000000..954240d --- /dev/null +++ b/ColorControl/lgtv/ClientKeyStore.cs @@ -0,0 +1,28 @@ +using ColorControl; +using System.IO; + +namespace LgTv +{ + public class ClientKeyStore + { + private string ip; + public ClientKeyStore(string ip) + { + this.ip = ip; + } + public string GetClientKey() + { + var filename = Path.Combine(Utils.GetDataPath(), ip + "_ClientKey.txt"); + if (File.Exists(filename)) + { + return File.ReadAllText(filename); + } + return null; + } + public void SaveClientKey(string key) + { + var filename = Path.Combine(Utils.GetDataPath(), ip + "_ClientKey.txt"); + File.WriteAllText(filename, key); + } + } +} diff --git a/ColorControl/lgtv/ExternalInput.cs b/ColorControl/lgtv/ExternalInput.cs new file mode 100644 index 0000000..0c28581 --- /dev/null +++ b/ColorControl/lgtv/ExternalInput.cs @@ -0,0 +1,15 @@ +namespace LgTv +{ + public class ExternalInput + { + public ExternalInput(string id,string label) + { + Id = id; + Label = label; + } + public string Id { get; set; } + public string Label { get; set; } + public string Icon { get; set; } + + } +} \ No newline at end of file diff --git a/ColorControl/lgtv/IsConnectedDelegate.cs b/ColorControl/lgtv/IsConnectedDelegate.cs new file mode 100644 index 0000000..de1e679 --- /dev/null +++ b/ColorControl/lgtv/IsConnectedDelegate.cs @@ -0,0 +1,4 @@ +namespace LgTv +{ + public delegate void IsConnectedDelegate(bool status); +} \ No newline at end of file diff --git a/ColorControl/lgtv/LgApp.cs b/ColorControl/lgtv/LgApp.cs new file mode 100644 index 0000000..57f897f --- /dev/null +++ b/ColorControl/lgtv/LgApp.cs @@ -0,0 +1,19 @@ +namespace LgTv +{ + public class LgApp + { + public string title { get; set; } + public string appId { get; set; } + + public LgApp(string appId, string title) + { + this.appId = appId; + this.title = title; + } + + public override string ToString() + { + return title; + } + } +} diff --git a/ColorControl/lgtv/LgTvApi.cs b/ColorControl/lgtv/LgTvApi.cs new file mode 100644 index 0000000..cf17c4e --- /dev/null +++ b/ColorControl/lgtv/LgTvApi.cs @@ -0,0 +1,371 @@ +using ColorControl; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Windows.Foundation; +using Windows.Storage; + +namespace LgTv +{ + //https://mym.hackpad.com/ep/pad/static/rLlshKkzdNj + + public enum ControlButtons + { + Back,Down,Left,Right, + OK, + Exit + } + public class LgTvApi:IDisposable + { + private readonly LgTvApiCore _connection; + private LgWebOsMouseService _mouseConnection; + + private readonly ClientKeyStore _keyStore; + + private List _channelList; + private List _appList; + private string _ip; + + private const string BEFORE_PAIR_HAND_SHAKE = "{\"type\":\"register\",\"id\":\"register_0\",\"payload\":{\"forcePairing\":false,\"pairingType\":\"PROMPT\",\"manifest\":{\"manifestVersion\":1,\"appVersion\":\"1.1\",\"signed\":{\"created\":\"20140509\",\"appId\":\"com.lge.test\",\"vendorId\":\"com.lge\",\"localizedAppNames\":{\"\":\"LG Remote App\",\"ko-KR\":\"리모컨 앱\",\"zxx-XX\":\"ЛГ Rэмotэ AПП\"},\"localizedVendorNames\":{\"\":\"LG Electronics\"},\"permissions\":[\"TEST_SECURE\",\"CONTROL_INPUT_TEXT\",\"CONTROL_MOUSE_AND_KEYBOARD\",\"READ_INSTALLED_APPS\",\"READ_LGE_SDX\",\"READ_NOTIFICATIONS\",\"SEARCH\",\"WRITE_SETTINGS\",\"WRITE_NOTIFICATION_ALERT\",\"CONTROL_POWER\",\"READ_CURRENT_CHANNEL\",\"READ_RUNNING_APPS\",\"READ_UPDATE_INFO\",\"UPDATE_FROM_REMOTE_APP\",\"READ_LGE_TV_INPUT_EVENTS\",\"READ_TV_CURRENT_TIME\"],\"serial\":\"2f930e2d2cfe083771f68e4fe7bb07\"},\"permissions\":[\"LAUNCH\",\"LAUNCH_WEBAPP\",\"APP_TO_APP\",\"CLOSE\",\"TEST_OPEN\",\"TEST_PROTECTED\",\"CONTROL_AUDIO\",\"CONTROL_DISPLAY\",\"CONTROL_INPUT_JOYSTICK\",\"CONTROL_INPUT_MEDIA_RECORDING\",\"CONTROL_INPUT_MEDIA_PLAYBACK\",\"CONTROL_INPUT_TV\",\"CONTROL_POWER\",\"READ_APP_STATUS\",\"READ_CURRENT_CHANNEL\",\"READ_INPUT_DEVICE_LIST\",\"READ_NETWORK_STATE\",\"READ_RUNNING_APPS\",\"READ_TV_CHANNEL_LIST\",\"WRITE_NOTIFICATION_TOAST\",\"READ_POWER_STATE\",\"READ_COUNTRY_INFO\"],\"signatures\":[{\"signatureVersion\":1,\"signature\":\"eyJhbGdvcml0aG0iOiJSU0EtU0hBMjU2Iiwia2V5SWQiOiJ0ZXN0LXNpZ25pbmctY2VydCIsInNpZ25hdHVyZVZlcnNpb24iOjF9.hrVRgjCwXVvE2OOSpDZ58hR+59aFNwYDyjQgKk3auukd7pcegmE2CzPCa0bJ0ZsRAcKkCTJrWo5iDzNhMBWRyaMOv5zWSrthlf7G128qvIlpMT0YNY+n/FaOHE73uLrS/g7swl3/qH/BGFG2Hu4RlL48eb3lLKqTt2xKHdCs6Cd4RMfJPYnzgvI4BNrFUKsjkcu+WD4OO2A27Pq1n50cMchmcaXadJhGrOqH5YmHdOCj5NSHzJYrsW0HPlpuAx/ECMeIZYDh6RMqaFM2DXzdKX9NmmyqzJ3o/0lkk/N97gfVRLW5hA29yeAwaCViZNCP8iC9aO0q9fQojoa7NQnAtw==\"}]}}}"; + + private const string AFTER_PAIR_HAND_SHAKE = "{\"type\":\"register\",\"id\":\"register_0\",\"payload\":{\"forcePairing\":false,\"pairingType\":\"PROMPT\",\"client-key\":\"CLIENTKEYGOESHERE\",\"manifest\":{\"manifestVersion\":1,\"appVersion\":\"1.1\",\"signed\":{\"created\":\"20140509\",\"appId\":\"com.lge.test\",\"vendorId\":\"com.lge\",\"localizedAppNames\":{\"\":\"LG Remote App\",\"ko-KR\":\"리모컨 앱\",\"zxx-XX\":\"ЛГ Rэмotэ AПП\"},\"localizedVendorNames\":{\"\":\"LG Electronics\"},\"permissions\":[\"TEST_SECURE\",\"CONTROL_INPUT_TEXT\",\"CONTROL_MOUSE_AND_KEYBOARD\",\"READ_INSTALLED_APPS\",\"READ_LGE_SDX\",\"READ_NOTIFICATIONS\",\"SEARCH\",\"WRITE_SETTINGS\",\"WRITE_NOTIFICATION_ALERT\",\"CONTROL_POWER\",\"READ_CURRENT_CHANNEL\",\"READ_RUNNING_APPS\",\"READ_UPDATE_INFO\",\"UPDATE_FROM_REMOTE_APP\",\"READ_LGE_TV_INPUT_EVENTS\",\"READ_TV_CURRENT_TIME\"],\"serial\":\"2f930e2d2cfe083771f68e4fe7bb07\"},\"permissions\":[\"LAUNCH\",\"LAUNCH_WEBAPP\",\"APP_TO_APP\",\"CLOSE\",\"TEST_OPEN\",\"TEST_PROTECTED\",\"CONTROL_AUDIO\",\"CONTROL_DISPLAY\",\"CONTROL_INPUT_JOYSTICK\",\"CONTROL_INPUT_MEDIA_RECORDING\",\"CONTROL_INPUT_MEDIA_PLAYBACK\",\"CONTROL_INPUT_TV\",\"CONTROL_POWER\",\"READ_APP_STATUS\",\"READ_CURRENT_CHANNEL\",\"READ_INPUT_DEVICE_LIST\",\"READ_NETWORK_STATE\",\"READ_RUNNING_APPS\",\"READ_TV_CHANNEL_LIST\",\"WRITE_NOTIFICATION_TOAST\",\"READ_POWER_STATE\",\"READ_COUNTRY_INFO\"],\"signatures\":[{\"signatureVersion\":1,\"signature\":\"eyJhbGdvcml0aG0iOiJSU0EtU0hBMjU2Iiwia2V5SWQiOiJ0ZXN0LXNpZ25pbmctY2VydCIsInNpZ25hdHVyZVZlcnNpb24iOjF9.hrVRgjCwXVvE2OOSpDZ58hR+59aFNwYDyjQgKk3auukd7pcegmE2CzPCa0bJ0ZsRAcKkCTJrWo5iDzNhMBWRyaMOv5zWSrthlf7G128qvIlpMT0YNY+n/FaOHE73uLrS/g7swl3/qH/BGFG2Hu4RlL48eb3lLKqTt2xKHdCs6Cd4RMfJPYnzgvI4BNrFUKsjkcu+WD4OO2A27Pq1n50cMchmcaXadJhGrOqH5YmHdOCj5NSHzJYrsW0HPlpuAx/ECMeIZYDh6RMqaFM2DXzdKX9NmmyqzJ3o/0lkk/N97gfVRLW5hA29yeAwaCViZNCP8iC9aO0q9fQojoa7NQnAtw==\"}]}}}"; + + public Task ControlButton(object oK) + { + // throw new NotImplementedException(); + return null; + } + + private string _currentPariKey; + private string webSocketUri; + + public static async Task CreateLgTvApi(string ip, int retries = 1) + { + var instance = new LgTvApi(ip, new LgTvApiCore(), new ClientKeyStore(ip)); + while (retries > 0) + { + var connected = await instance.Connect(); + if (connected) + { + await instance.MakeHandShake(); + return instance; + } + retries--; + await Task.Delay(500); + } + instance.Dispose(); + return null; + } + + public LgTvApi(string ip, LgTvApiCore connection, ClientKeyStore keyStore) + { + webSocketUri = "ws://" + ip + ":3000"; + _ip = ip; + _connection = connection; + _keyStore = keyStore; + } + + public string GetIpAddress() + { + return _ip; + } + + public async Task MakeHandShake() + { + _currentPariKey = _keyStore.GetClientKey(); + if (_currentPariKey != null) + { + var key = AFTER_PAIR_HAND_SHAKE.Replace("CLIENTKEYGOESHERE", _currentPariKey); + var conn = await _connection.SendCommandAsync(key); + _keyStore.SaveClientKey((string)conn.clientKey); + return; + } + + dynamic result = await _connection.SendCommandAsync(BEFORE_PAIR_HAND_SHAKE); + _keyStore.SaveClientKey(result.clientKey); + } + + + public async Task Connect() + { + + var ctx = _connection.Connect(new Uri(webSocketUri)); + return await ctx; + } + + public async Task GetMouse() + { + if (_mouseConnection != null) return _mouseConnection; + var requestMessage = new RequestMessage("ssap://com.webos.service.networkinput/getPointerInputSocket", new { }); + var s = await _connection.SendCommandAsync(requestMessage); + var socketPath = (string)s.socketPath; + + _mouseConnection = new LgWebOsMouseService(new LgTvApiCore()); + await _mouseConnection.Connect(socketPath); + return _mouseConnection; + } + + public async Task> ChannelList() + { + _channelList = new List(); + var requestMessage = new RequestMessage("channels", "ssap://tv/getChannelList"); + var command = _connection.SendCommandAsync(requestMessage); + var res = await command; + foreach (var c in res.channelList) + { + _channelList.Add(new Channel + { + Id = c.channelId, + Name = c.channelName, + Number = int.Parse((string)c.channelNumber) + }); + } + return _channelList.OrderBy(e => e.Number); + } + + public async Task GetChannel() + { + var requestMessage = new RequestMessage("channels", "ssap://tv/getCurrentChannel"); + var command = _connection.SendCommandAsync(requestMessage); + + var res = await command; + return new Channel() { Id = res.channelId, Name = res.channelName, Number = int.Parse(res.channelNumber) }; + } + public async Task ShowToast() + { + var requestMessage = new RequestMessage("ssap://system.notifications/createToast",new {message = "Co tam u Ciebie?"}); + await _connection.SendCommandAsync(requestMessage); + } + + //public async Task LaunchApp(string appId,Uri uri) + //{ + // var url = uri.ToString(); + // var requestMessage = new RequestMessage("ssap://system.launcher/launch", new { id = appId, @params={contentTarget } }); + // var response = await _connection.SendCommandAsync(requestMessage); + // return (string)response.sessionId; + //} + + public async Task VolumeDown() + { + var requestMessage = new RequestMessage("volumedown", "ssap://audio/volumeDown"); + await _connection.SendCommandAsync(requestMessage); + } + public async Task VolumeUp() + { + var requestMessage = new RequestMessage("volumeup", "ssap://audio/volumeUp"); + await _connection.SendCommandAsync(requestMessage); + } + public async Task ChannelInfo() + { + var requestMessage = new RequestMessage("programinfo", "ssap://tv/getChannelProgramInfo"); + await _connection.SendCommandAsync(requestMessage); + } + + public async Task SetChannel(string channelId) + { + var requestMessage = new RequestMessage("ssap://tv/openChannel", new { channelId }); + await _connection.SendCommandAsync(requestMessage); + } + public async Task SetMute(bool value) + { + var requestMessage = new RequestMessage("ssap://audio/setMute", new { mute = value }); + await _connection.SendCommandAsync(requestMessage); + } + public async Task ToogleMute() + { + await SetMute(!await IsMuted()); + } + public async Task IsMuted() + { + var requestMessage = new RequestMessage("status", "ssap://audio/getStatus"); + var command = _connection.SendCommandAsync(requestMessage); + return (bool)(await command).mute; + } + + public async Task SetVolume(int value) + { + if (value >= 0 && value <= 100) + { + var requestMessage = new RequestMessage("ssap://audio/setVolume", new { volume = value }); + await _connection.SendCommandAsync(requestMessage); + } + } + public async Task TurnOff() + { + await _connection.SendCommandAsync(new RequestMessage("","ssap://system/turnOff")); + } + public async Task Play() + { + await _connection.SendCommandAsync(new RequestMessage("play", "ssap://media.controls/play")); + } + public async Task Pause() + { + await _connection.SendCommandAsync(new RequestMessage("pause", "ssap://media.controls/pause")); + } + + public async Task ChannelUp() + { + await _connection.SendCommandAsync(new RequestMessage("channelUp", "ssap://tv/channelUp")); + } + public async Task ChannelDown() + { + await _connection.SendCommandAsync(new RequestMessage("channelDown", "ssap://tv/channelDown")); + } + + public async Task Stop() + { + await _connection.SendCommandAsync(new RequestMessage("stop", "ssap://media.controls/stop")); + } + + public async Task TurnOn3D() + { + await _connection.SendCommandAsync(new RequestMessage("3d", "ssap://com.webos.service.tv.display/set3DOn")); + } + public async Task TurnOff3D() + { + await _connection.SendCommandAsync(new RequestMessage("3d", "ssap://com.webos.service.tv.display/set3DOff")); + } + public async Task IsTurnedOn3D() + { + //Response: { returnValue: true, status3D: { status: true, pattern: ’2Dto3D’ } } + var requestMessage = new RequestMessage("status3D", "ssap://com.webos.service.tv.display/get3DStatus"); + var o = await _connection.SendCommandAsync(requestMessage); + return (bool)o.status3D.status; + } + + public async Task GetVolume() + { + // { + // "type": "response", + // "id": "status_1", + // "payload": { + // "muted": false, + // "scenario": "mastervolume_tv_speaker", + // "active": false, + // "action": "requested", + // "volume": 7, + // "returnValue": true, + // "subscribed": true + // } + // } + var requestMessage = new RequestMessage("status", "ssap://audio/getVolume"); + var o = await _connection.SendCommandAsync(requestMessage); + return( (bool)o.muted) ? -1 :(int) o.volume; + } + public async Task> GetInputList() + { + var requestMessage = new RequestMessage("input","ssap://tv/getExternalInputList"); + var results = await _connection.SendCommandAsync(requestMessage); + var l = new List(); + foreach (var result in results) + { + l.Add(new ExternalInput(result.id, result.label) + { + Icon = result.icon + }); + } + return l; + } + + public async Task SetInput(string id) + { + var requestMessage = new RequestMessage("ssap://tv/switchInput", new { inputId = id }); + await _connection.SendCommandAsync(requestMessage); + } + + public async Task> GetLaunchPoints() + { + _appList = new List(); + var requestMessage = new RequestMessage("launcher", "ssap://com.webos.applicationManager/listLaunchPoints"); + var command = _connection.SendCommandAsync(requestMessage); + var res = await command; + foreach (var c in res.launchpoints) + { + _appList.Add(new App + { + Id = c.id, + LaunchPointId = c.launchPointId, + Title = c.title, + Icon = c.icon + }); + } + return _appList.OrderBy(e => e.Title); + } + + public async Task> GetApps(bool force = false) + { + var appList = new List(); + + dynamic res; + + var filename = Path.Combine(Utils.GetDataPath(), _ip + "_listApps.json"); + if (!force && File.Exists(filename)) + { + var json = File.ReadAllText(filename); + res = JToken.Parse(json); + } + else + { + var requestMessage = new RequestMessage("ssap://com.webos.applicationManager/listApps", new { }); + var command = _connection.SendCommandAsync(requestMessage); + res = await command; + + var json = Convert.ToString(res); + File.WriteAllText(filename, json); + } + + foreach (var c in res.apps) + { + appList.Add(new LgApp((string)c.id, (string)c.title)); + } + + return appList.OrderBy(e => e.title); + } + + public async Task LaunchApp(string appId) + { + var requestMessage = new RequestMessage("ssap://system.launcher/launch", new { id = appId }); + var response = await _connection.SendCommandAsync(requestMessage); + return (string)response.sessionId; + } + public async Task CloseApp(string appId) + { + var requestMessage = new RequestMessage("ssap://system.launcher/close", new { id = appId }); + var response = await _connection.SendCommandAsync(requestMessage); + return (string)response.sessionId; + } + public async Task OpenWebBrowser(Uri uri) + { + var url = uri.ToString(); + var requestMessage = new RequestMessage("ssap://system.launcher/open", new { target = url }); + var response = await _connection.SendCommandAsync(requestMessage); + return (string)response.sessionId; + } + + public async Task LaunchYouTube(string videoId) + { + return await LaunchYouTube(new Uri($"http://www.youtube.com/tv?v={videoId}")); + } + public async Task LaunchYouTube(Uri uri) + { + var url = uri.ToString(); + var requestMessage = new RequestMessage("ssap://system.launcher/launch", new { id = "youtube.leanback.v4", @params = new { contentTarget = url } }); + var response = await _connection.SendCommandAsync(requestMessage); + return (string)response.sessionId; + } + + + public void Close() + { + _connection.Close(); + } + public void Dispose() + { + _connection?.Dispose(); + } + } +} \ No newline at end of file diff --git a/ColorControl/lgtv/LgTvConnection.cs b/ColorControl/lgtv/LgTvConnection.cs new file mode 100644 index 0000000..c4485e3 --- /dev/null +++ b/ColorControl/lgtv/LgTvConnection.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Windows.Networking.Sockets; +using Windows.Storage.Streams; +using Windows.Web; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json.Linq; +using Windows.Foundation; + +namespace LgTv +{ + public class SendMessageException : Exception + { + public SendMessageException(string message, Exception e) : base(message, e) + { + + } + } + + public class LgTvApiCore : IDisposable + { + private MessageWebSocket _connection; + private DataWriter _messageWriter; + private int _commandCount; + + public event IsConnectedDelegate IsConnected; + private readonly ConcurrentDictionary> _tokens = new ConcurrentDictionary>(); + + private static void Log(RawRequestMessage message) { } + + + public async Task Connect(Uri uri, bool ignoreReceiver = false) + { + try + { + _commandCount = 0; + _connection = new MessageWebSocket(); + _connection.Control.MessageType = SocketMessageType.Utf8; + // if(ignoreReceiver==false) + _connection.MessageReceived += Connection_MessageReceived; + + _connection.Closed += Connection_Closed; + await _connection.ConnectAsync(uri); + + IsConnected?.Invoke(true); + + _messageWriter = new DataWriter(_connection.OutputStream); + return true; + } + catch (Exception e) + { + switch (SocketError.GetStatus(e.HResult)) + { + case SocketErrorStatus.HostNotFound: + // Handle HostNotFound Error + break; + default: + // Handle Unknown Error + break; + } + return false; + } + + } + public async void SendMessageAsync(string message) + { + _messageWriter.WriteString(message); + await _messageWriter.StoreAsync(); + } + public Task SendCommandAsync(string message) + { + var obj = JsonConvert.DeserializeObject(message); + return SendCommandAsync((string)obj.id, message); + } + + private Task SendCommandAsync(string id, string message) + { + try + { + var taskSource = new TaskCompletionSource(); + _tokens.TryAdd(id, taskSource); + SendMessageAsync(message); + return taskSource.Task; + } + catch (Exception e) + { + throw new SendMessageException("Can't send message", e); + } + + } + + + public Task SendCommandAsync(RequestMessage message) + { + var rawMessage = new RawRequestMessage(message, ++_commandCount); + var serialized = JsonConvert.SerializeObject(rawMessage, new JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore, + ContractResolver = new CamelCasePropertyNamesContractResolver() + }); + return SendCommandAsync(rawMessage.Id, serialized); + } + + private void Connection_Closed(IWebSocket sender, WebSocketClosedEventArgs args) + { + MessageWebSocket webSocket = Interlocked.Exchange(ref _connection, null); + webSocket?.Dispose(); + } + + private void Connection_MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args) + { + try + { + using (var dr = args.GetDataReader()) + { + dr.UnicodeEncoding = UnicodeEncoding.Utf8; + var message = dr.ReadString(dr.UnconsumedBufferLength); + var obj = JsonConvert.DeserializeObject(message); + var id = (string)obj.id; + var type = (string)obj.type; + + TaskCompletionSource taskCompletion; + if (type == "registered") + { + if (_tokens.TryRemove(id, out taskCompletion)) + { + var key = (string)JObject.Parse(message)["payload"]["client-key"]; + taskCompletion.TrySetResult(new { clientKey = key }); + } + + } + else + if (_tokens.TryGetValue(id, out taskCompletion)) + { + if (id == "register_0") return; + if (obj.type == "error") + { + taskCompletion.SetException(new Exception(obj.error)); + } + //else if (args.Cancelled) + //{ + // taskSource.SetCanceled(); + //} + taskCompletion.TrySetResult(obj.payload); + } + } + } + catch (Exception ex) + { + WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult); + } + } + public void Close() + { + _connection?.Close(1, ""); + } + + public void Dispose() + { + _connection?.Dispose(); + } + } +} diff --git a/ColorControl/lgtv/LgWebOsMouseService.cs b/ColorControl/lgtv/LgWebOsMouseService.cs new file mode 100644 index 0000000..69384d7 --- /dev/null +++ b/ColorControl/lgtv/LgWebOsMouseService.cs @@ -0,0 +1,82 @@ +using NStandard; +using System; +using System.Threading.Tasks; + +namespace LgTv +{ + public enum ButtonType + { + HOME, + BACK, + ENTER, + EXIT, + UP, + DOWN, + LEFT, + RIGHT, + RED, + GREEN, + YELLOW, + BLUE, + _1, + _2, + _3, + _4, + _5, + _6, + _7, + _8, + _9, + _0, + POWER + } + + public class LgWebOsMouseService : IDisposable + { + private readonly LgTvApiCore _connection; + public LgWebOsMouseService(LgTvApiCore connection) + { + _connection = connection; + } + + public async Task Connect(string uri) + { + var ctx = _connection.Connect(new Uri(uri), ignoreReceiver: true); + return (await ctx); + } + public void SendButton(int number) + { + _connection.SendMessageAsync($"type:button\nname:{number}\n\n"); + } + public void SendButton(ButtonType bt) + { + var text = bt.ToString(); + if (text[0] == '_') + { + text = text.Substring(1); + } + _connection.SendMessageAsync($"type:button\nname:{text}\n\n"); + } + + + public void Move(double dx, double dy, bool drag = false) + { + _connection.SendMessageAsync($"type:move\ndx:{dx}\ndy:{dy}\ndown:{(drag ? 1 : 0)}\n\n"); + } + + public void Scroll(double dx, double dy) + { + _connection.SendMessageAsync($"type:scroll\ndx:{dx}\ndy:{dy}\n\n"); + } + + public void Click() + { + _connection.SendMessageAsync("type:click\n\n"); + } + + public void Dispose() + { + _connection?.Dispose(); + } + } +} diff --git a/ColorControl/lgtv/MessageType.cs b/ColorControl/lgtv/MessageType.cs new file mode 100644 index 0000000..7b2b411 --- /dev/null +++ b/ColorControl/lgtv/MessageType.cs @@ -0,0 +1,4 @@ +namespace LgTv +{ + public enum MessageType { Request} +} \ No newline at end of file diff --git a/ColorControl/lgtv/README.md b/ColorControl/lgtv/README.md new file mode 100644 index 0000000..1105a47 --- /dev/null +++ b/ColorControl/lgtv/README.md @@ -0,0 +1,30 @@ +# lgtv.net +LG TV WebOS API for .NET + +For now, there is only API, example app will be added in the future. + +## inspiration: +* https://github.com/msloth/lgtv.js/blob/master/index.js + +## references: +* https://github.com/ConnectSDK/Connect-SDK-Android-Core +* https://github.com/CODeRUS/harbour-lgremote-webos +* https://github.com/openwebos +* https://mym.hackpad.com/ep/pad/static/rLlshKkzdNj + +## Usage +```C# + // Initalization + var _instance = new LgTvApi(ip,new LgTvApiCore(), new ClientKeyStore(ip)); + await _instance.Connect(); + await _instance.MakeHandShake(); + await _instance.GetMouse(); + +//control + await _instance.VolumeDown(); + await _instance.TurnOff(); + ...... + (await _instance.GetMouse()).SendButton(ButtonType.RED); + (await _instance.GetMouse()).SendButton(ButtonType.LEFT); + .. +``` diff --git a/ColorControl/lgtv/RawRequestMessage.cs b/ColorControl/lgtv/RawRequestMessage.cs new file mode 100644 index 0000000..498776f --- /dev/null +++ b/ColorControl/lgtv/RawRequestMessage.cs @@ -0,0 +1,18 @@ +namespace LgTv +{ + internal class RawRequestMessage + { + public RawRequestMessage(RequestMessage rm, int commandCount) + { + var prefix = (rm.Prefix ?? ""); + Id = prefix + (prefix.Length>0?"_":"") + commandCount; + Type = rm.Type??"request"; + Uri = rm.Uri; + Payload = rm.Payload; + } + public string Id { get; set; } + public string Type { get; set; } + public string Uri { get; set; } + public string Payload { get; set; } + } +} \ No newline at end of file diff --git a/ColorControl/lgtv/RequestMessage.cs b/ColorControl/lgtv/RequestMessage.cs new file mode 100644 index 0000000..fb769db --- /dev/null +++ b/ColorControl/lgtv/RequestMessage.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; + +namespace LgTv +{ + public class RequestMessage + { + public RequestMessage(string prefix, string uri) + { + Prefix = prefix; + Uri = uri; + } + public RequestMessage(string uri,object payload) + { + Uri = uri; + Payload = JsonConvert.SerializeObject(payload); + } + + public string Prefix { get; set; } + public string Type { get; set; } + public string Uri { get; set; } + public string Payload { get; set; } + } +} \ No newline at end of file diff --git a/ColorControl/packages.config b/ColorControl/packages.config new file mode 100644 index 0000000..5f53336 --- /dev/null +++ b/ColorControl/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/ColorControl/pngbarn.ico b/ColorControl/pngbarn.ico new file mode 100644 index 0000000000000000000000000000000000000000..b609bf19442990139d2b34abed8d001049ca77c9 GIT binary patch literal 106479 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 Ujur8Xy%+yYysX7`b@