From 5c87967c3fbf6365e8fa86c7977278d51174cbe6 Mon Sep 17 00:00:00 2001 From: Marco Batzinger Date: Mon, 19 Oct 2020 17:44:50 +0200 Subject: [PATCH] Implemented VirtualPrinterDriver project --- .gitignore | 363 +++++ Agent/VirtualPrinter.Agent.Console/Program.cs | 41 + .../Properties/AssemblyInfo.cs | 35 + .../VirtualPrinter.Agent.Console.csproj | 74 + Agent/VirtualPrinter.Agent.Service/Program.cs | 35 + .../ProjectInstaller.Designer.cs | 60 + .../ProjectInstaller.cs | 14 + .../ProjectInstaller.resx | 129 ++ .../Properties/AssemblyInfo.cs | 22 + .../VirtualPrinter.Agent.Service.csproj | 136 ++ .../VirtualPrinterService.Designer.cs | 40 + .../VirtualPrinterService.cs | 52 + .../VirtualPrinterService.resx | 123 ++ .../GhostScriptRedirector.cs | 98 ++ Agent/VirtualPrinter.Delivery/Program.cs | 38 + .../Properties/AssemblyInfo.cs | 18 + Agent/VirtualPrinter.Delivery/Redirector.cs | 51 + .../VirtualPrinter.Delivery.csproj | 77 + .../Properties/AssemblyInfo.cs | 32 + .../VirtualPrinter.Agent.Autofac.csproj | 81 + .../VirtualPrinterModule.cs | 33 + .../Enums/IntermediateFormat.cs | 8 + .../Interfaces/IConfig.cs | 20 + .../Interfaces/IDirectoryHelper.cs | 7 + .../Interfaces/IExConfig.cs | 36 + .../Interfaces/IJob.cs | 34 + .../Interfaces/IJobFactory.cs | 15 + .../Interfaces/IJobInfo.cs | 15 + .../Interfaces/IJobProcessor.cs | 18 + .../Interfaces/IJobRedirector.cs | 17 + .../Interfaces/IJobService.cs | 47 + .../Interfaces/IPostScriptConverter.cs | 15 + .../Interfaces/IRegistryRepository.cs | 29 + .../Interfaces/ISessionInfo.cs | 11 + .../Interfaces/IShell.cs | 16 + .../Interfaces/IUserConfig.cs | 26 + .../Interfaces/IVirtualPrinter.cs | 12 + .../Interfaces/IVirtualPrinterService.cs | 8 + .../Interfaces/JobStatus.cs | 9 + .../Model/JobInfo.cs | 15 + .../Model/PostScriptConversionException.cs | 19 + .../Model/PostScriptRenderOptions.cs | 9 + .../Model/PostScriptRenderPdfOptions.cs | 8 + .../Model/PostScriptRenderTiffOptions.cs | 7 + .../Model/PrintExts.cs | 13 + .../Model/PrintStatus.cs | 15 + .../Model/ProgressUpdateArgs.cs | 22 + .../Model/RegistryConfig.cs | 49 + .../Model/SessionInfo.cs | 11 + .../Model/UserRegistryConfig.cs | 13 + .../Properties/AssemblyInfo.cs | 35 + .../VirtualPrinter.Agent.Core.csproj | 77 + .../Misc/GhostScriptConverter.cs | 218 +++ Common/VirtualPrinter.Agent.Lib/Misc/Job.cs | 15 + .../Misc/JobFactory.cs | 243 +++ .../Misc/JobProcessor.cs | 150 ++ .../Misc/JobRedirector.cs | 106 ++ .../Misc/JobService.cs | 170 ++ .../Misc/VirtualTcpInputPrinter.cs | 276 ++++ .../Model/ProgressUpdateArgs.cs | 22 + .../Properties/AssemblyInfo.cs | 32 + .../VirtualPrinter.Agent.Lib.csproj | 100 ++ .../VirtualPrinterService.cs | 27 + .../IVirtualPrinterLogger.cs | 81 + Common/VirtualPrinter.Logging/LoggerModule.cs | 17 + Common/VirtualPrinter.Logging/NLog.config | 25 + .../Properties/AssemblyInfo.cs | 35 + .../VirtualPrinter.Logging.csproj | 71 + .../VirtualPrinterLogger.cs | 103 ++ Common/VirtualPrinter.Utils/Consts.cs | 51 + .../VirtualPrinter.Utils/DirectoryHelper.cs | 24 + .../Properties/AssemblyInfo.cs | 35 + .../RegistryRepository.cs | 170 ++ Common/VirtualPrinter.Utils/Shell.cs | 95 ++ .../VirtualPrinter.Utils.csproj | 69 + Common/VirtualPrinter.Utils/Win32Sys.cs | 239 +++ Common/VirtualPrinter.Utils/Windows.cs | 14 + .../VirtualPrinter.SetupDriver/Defaults.cs | 15 + .../VirtualPrinter.SetupDriver/Program.cs | 125 ++ .../Properties/AssemblyInfo.cs | 21 + Installer/VirtualPrinter.SetupDriver/Shell.cs | 84 + .../VirtualPrinter.SetupDriver.csproj | 62 + .../VirtualPrinter.SetupDriver/Windows.cs | 93 ++ .../Properties/AssemblyInfo.cs | 35 + .../Script.cs | 171 ++ .../VirtualPrinter.WixSharpInstaller.csproj | 69 + .../app.config | 3 + NuGet.Config | 7 + .../ProgressInfoModule.cs | 23 + .../Properties/AssemblyInfo.cs | 35 + ...VirtualPrinter.ProgressInfo.Autofac.csproj | 65 + .../IProgressInfo.cs | 11 + .../Message/IFinal.cs | 6 + .../Message/IMessage.cs | 6 + .../Message/IMessageFactory.cs | 16 + .../Message/IStart.cs | 6 + .../Message/IStep.cs | 7 + .../Message/Message.cs | 17 + .../Message/MessageType.cs | 11 + .../Properties/AssemblyInfo.cs | 35 + .../VirtualPrinter.ProgressInfo.Core.csproj | 57 + .../Interfaces/IProgressInfoProcessManager.cs | 13 + .../Interfaces/IProgressInfoServer.cs | 18 + .../Interfaces/IProgressInfoServerFactory.cs | 7 + .../Message/MessageFactory.cs | 37 + .../ProgressInfoBroker.cs | 88 ++ .../ProgressInfoProcessManager.cs | 47 + .../ProgressInfoServer.cs | 42 + .../ProgressInfoServerFactory.cs | 46 + .../Properties/AssemblyInfo.cs | 35 + .../VirtualPrinter.ProgressInfo.Lib.csproj | 74 + UI/VirtualPrinter.ProgressInfo/Program.cs | 19 + .../ProgressForm.Designer.cs | 84 + .../ProgressForm.cs | 84 + .../ProgressForm.resx | 1373 +++++++++++++++++ .../Properties/AssemblyInfo.cs | 35 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 ++ .../Properties/Settings.Designer.cs | 30 + .../Properties/Settings.settings | 8 + .../Resources/printer.ico | Bin 0 -> 4286 bytes .../Resources/waiting.gif | Bin 0 -> 9559 bytes .../VirtualPrinter.ProgressInfo.csproj | 90 ++ VirtualPrinter.sln | 306 ++++ create_msi.ps1 | 2 + 125 files changed, 8191 insertions(+) create mode 100644 .gitignore create mode 100644 Agent/VirtualPrinter.Agent.Console/Program.cs create mode 100644 Agent/VirtualPrinter.Agent.Console/Properties/AssemblyInfo.cs create mode 100644 Agent/VirtualPrinter.Agent.Console/VirtualPrinter.Agent.Console.csproj create mode 100644 Agent/VirtualPrinter.Agent.Service/Program.cs create mode 100644 Agent/VirtualPrinter.Agent.Service/ProjectInstaller.Designer.cs create mode 100644 Agent/VirtualPrinter.Agent.Service/ProjectInstaller.cs create mode 100644 Agent/VirtualPrinter.Agent.Service/ProjectInstaller.resx create mode 100644 Agent/VirtualPrinter.Agent.Service/Properties/AssemblyInfo.cs create mode 100644 Agent/VirtualPrinter.Agent.Service/VirtualPrinter.Agent.Service.csproj create mode 100644 Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.Designer.cs create mode 100644 Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.cs create mode 100644 Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.resx create mode 100644 Agent/VirtualPrinter.Delivery/GhostScriptRedirector.cs create mode 100644 Agent/VirtualPrinter.Delivery/Program.cs create mode 100644 Agent/VirtualPrinter.Delivery/Properties/AssemblyInfo.cs create mode 100644 Agent/VirtualPrinter.Delivery/Redirector.cs create mode 100644 Agent/VirtualPrinter.Delivery/VirtualPrinter.Delivery.csproj create mode 100644 Common/VirtualPrinter.Agent.Autofac/Properties/AssemblyInfo.cs create mode 100644 Common/VirtualPrinter.Agent.Autofac/VirtualPrinter.Agent.Autofac.csproj create mode 100644 Common/VirtualPrinter.Agent.Autofac/VirtualPrinterModule.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Enums/IntermediateFormat.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IConfig.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IDirectoryHelper.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IExConfig.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IJob.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IJobFactory.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IJobInfo.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IJobProcessor.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IJobRedirector.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IJobService.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IPostScriptConverter.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IRegistryRepository.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/ISessionInfo.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IShell.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IUserConfig.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IVirtualPrinter.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/IVirtualPrinterService.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Interfaces/JobStatus.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Model/JobInfo.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Model/PostScriptConversionException.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderOptions.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderPdfOptions.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderTiffOptions.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Model/PrintExts.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Model/PrintStatus.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Model/ProgressUpdateArgs.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Model/RegistryConfig.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Model/SessionInfo.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Model/UserRegistryConfig.cs create mode 100644 Common/VirtualPrinter.Agent.Core/Properties/AssemblyInfo.cs create mode 100644 Common/VirtualPrinter.Agent.Core/VirtualPrinter.Agent.Core.csproj create mode 100644 Common/VirtualPrinter.Agent.Lib/Misc/GhostScriptConverter.cs create mode 100644 Common/VirtualPrinter.Agent.Lib/Misc/Job.cs create mode 100644 Common/VirtualPrinter.Agent.Lib/Misc/JobFactory.cs create mode 100644 Common/VirtualPrinter.Agent.Lib/Misc/JobProcessor.cs create mode 100644 Common/VirtualPrinter.Agent.Lib/Misc/JobRedirector.cs create mode 100644 Common/VirtualPrinter.Agent.Lib/Misc/JobService.cs create mode 100644 Common/VirtualPrinter.Agent.Lib/Misc/VirtualTcpInputPrinter.cs create mode 100644 Common/VirtualPrinter.Agent.Lib/Model/ProgressUpdateArgs.cs create mode 100644 Common/VirtualPrinter.Agent.Lib/Properties/AssemblyInfo.cs create mode 100644 Common/VirtualPrinter.Agent.Lib/VirtualPrinter.Agent.Lib.csproj create mode 100644 Common/VirtualPrinter.Agent.Lib/VirtualPrinterService.cs create mode 100644 Common/VirtualPrinter.Logging/IVirtualPrinterLogger.cs create mode 100644 Common/VirtualPrinter.Logging/LoggerModule.cs create mode 100644 Common/VirtualPrinter.Logging/NLog.config create mode 100644 Common/VirtualPrinter.Logging/Properties/AssemblyInfo.cs create mode 100644 Common/VirtualPrinter.Logging/VirtualPrinter.Logging.csproj create mode 100644 Common/VirtualPrinter.Logging/VirtualPrinterLogger.cs create mode 100644 Common/VirtualPrinter.Utils/Consts.cs create mode 100644 Common/VirtualPrinter.Utils/DirectoryHelper.cs create mode 100644 Common/VirtualPrinter.Utils/Properties/AssemblyInfo.cs create mode 100644 Common/VirtualPrinter.Utils/RegistryRepository.cs create mode 100644 Common/VirtualPrinter.Utils/Shell.cs create mode 100644 Common/VirtualPrinter.Utils/VirtualPrinter.Utils.csproj create mode 100644 Common/VirtualPrinter.Utils/Win32Sys.cs create mode 100644 Common/VirtualPrinter.Utils/Windows.cs create mode 100644 Installer/VirtualPrinter.SetupDriver/Defaults.cs create mode 100644 Installer/VirtualPrinter.SetupDriver/Program.cs create mode 100644 Installer/VirtualPrinter.SetupDriver/Properties/AssemblyInfo.cs create mode 100644 Installer/VirtualPrinter.SetupDriver/Shell.cs create mode 100644 Installer/VirtualPrinter.SetupDriver/VirtualPrinter.SetupDriver.csproj create mode 100644 Installer/VirtualPrinter.SetupDriver/Windows.cs create mode 100644 Installer/VirtualPrinter.WixSharpInstaller/Properties/AssemblyInfo.cs create mode 100644 Installer/VirtualPrinter.WixSharpInstaller/Script.cs create mode 100644 Installer/VirtualPrinter.WixSharpInstaller/VirtualPrinter.WixSharpInstaller.csproj create mode 100644 Installer/VirtualPrinter.WixSharpInstaller/app.config create mode 100644 NuGet.Config create mode 100644 UI/VirtualPrinter.ProgressInfo.Autofac/ProgressInfoModule.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Autofac/Properties/AssemblyInfo.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Autofac/VirtualPrinter.ProgressInfo.Autofac.csproj create mode 100644 UI/VirtualPrinter.ProgressInfo.Core/IProgressInfo.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Core/Message/IFinal.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Core/Message/IMessage.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Core/Message/IMessageFactory.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Core/Message/IStart.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Core/Message/IStep.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Core/Message/Message.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Core/Message/MessageType.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Core/Properties/AssemblyInfo.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Core/VirtualPrinter.ProgressInfo.Core.csproj create mode 100644 UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoProcessManager.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoServer.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoServerFactory.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Lib/Message/MessageFactory.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoBroker.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoProcessManager.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoServer.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoServerFactory.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Lib/Properties/AssemblyInfo.cs create mode 100644 UI/VirtualPrinter.ProgressInfo.Lib/VirtualPrinter.ProgressInfo.Lib.csproj create mode 100644 UI/VirtualPrinter.ProgressInfo/Program.cs create mode 100644 UI/VirtualPrinter.ProgressInfo/ProgressForm.Designer.cs create mode 100644 UI/VirtualPrinter.ProgressInfo/ProgressForm.cs create mode 100644 UI/VirtualPrinter.ProgressInfo/ProgressForm.resx create mode 100644 UI/VirtualPrinter.ProgressInfo/Properties/AssemblyInfo.cs create mode 100644 UI/VirtualPrinter.ProgressInfo/Properties/Resources.Designer.cs create mode 100644 UI/VirtualPrinter.ProgressInfo/Properties/Resources.resx create mode 100644 UI/VirtualPrinter.ProgressInfo/Properties/Settings.Designer.cs create mode 100644 UI/VirtualPrinter.ProgressInfo/Properties/Settings.settings create mode 100644 UI/VirtualPrinter.ProgressInfo/Resources/printer.ico create mode 100644 UI/VirtualPrinter.ProgressInfo/Resources/waiting.gif create mode 100644 UI/VirtualPrinter.ProgressInfo/VirtualPrinter.ProgressInfo.csproj create mode 100644 VirtualPrinter.sln create mode 100644 create_msi.ps1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e101678 --- /dev/null +++ b/.gitignore @@ -0,0 +1,363 @@ +## 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 + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# 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 +nunit-*.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/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# 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 + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# 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 +# NuGet Symbol Packages +*.snupkg +# 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 +*.appxbundle +*.appxupload + +# 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 +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).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/ + +# 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 + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd +.idea/ diff --git a/Agent/VirtualPrinter.Agent.Console/Program.cs b/Agent/VirtualPrinter.Agent.Console/Program.cs new file mode 100644 index 0000000..b17da27 --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Console/Program.cs @@ -0,0 +1,41 @@ +using System; + +using Autofac; + +using VirtualPrinter.Agent.Autofac; +using VirtualPrinter.Agent.Core; +using VirtualPrinter.Logging; +using VirtualPrinter.ProgressInfo.Autofac; + +namespace VirtualPrinter.Agent.Console +{ + internal static class Program + { + // ReSharper disable once UnusedParameter.Local + // Start the console application to debug through the solution + private static void Main(string[] args) + { + var builder = new ContainerBuilder(); + + builder.RegisterModule(new ProgressInfoModule()); + builder.RegisterModule(new VirtualPrinterModule()); + builder.RegisterModule(new LoggerModule()); + + var container = builder.Build(); + + var service = container.Resolve(); + + service.Start(); + + System.Console.WriteLine(@"Press Ctrl + C to shutdown"); + ConsoleKeyInfo key; + do + { + key = System.Console.ReadKey(); + } + while (key.Key != ConsoleKey.C && key.Modifiers != ConsoleModifiers.Control); + + service.Stop(); + } + } +} diff --git a/Agent/VirtualPrinter.Agent.Console/Properties/AssemblyInfo.cs b/Agent/VirtualPrinter.Agent.Console/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2babed9 --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Console/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("VirtualPrinter.AgentConsole")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("3d3a379b-f9b8-466d-a04d-fd5ef948ff1c")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/Agent/VirtualPrinter.Agent.Console/VirtualPrinter.Agent.Console.csproj b/Agent/VirtualPrinter.Agent.Console/VirtualPrinter.Agent.Console.csproj new file mode 100644 index 0000000..442e6ed --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Console/VirtualPrinter.Agent.Console.csproj @@ -0,0 +1,74 @@ + + + + + Debug + AnyCPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C} + Exe + VirtualPrinter.Agent.Console + VirtualPrinter.AgentConsole + v4.6.1 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + none + true + bin\Release + TRACE + prompt + 4 + + + + + + + + + + + + + + {1b2f0781-82d7-4576-b936-c6a26053d6ed} + VirtualPrinter.Agent.Autofac + + + {135c85eb-2116-4cc4-8ccb-b6804b9d6467} + VirtualPrinter.Agent.Core + + + {94e8105f-5001-403b-b9f1-b0b0b236ad65} + VirtualPrinter.Agent.Lib + + + {aa25364d-22d5-44b0-86a5-6fb14c686308} + VirtualPrinter.Logging + + + {17e2cf8a-462c-4130-9faf-f1ca5fc4e06d} + VirtualPrinter.ProgressInfo.Autofac + + + + + + + + + + + \ No newline at end of file diff --git a/Agent/VirtualPrinter.Agent.Service/Program.cs b/Agent/VirtualPrinter.Agent.Service/Program.cs new file mode 100644 index 0000000..82201ac --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Service/Program.cs @@ -0,0 +1,35 @@ +using System.ServiceProcess; + +using Autofac; + +using VirtualPrinter.Agent.Autofac; +using VirtualPrinter.Logging; +using VirtualPrinter.ProgressInfo.Autofac; + +namespace VirtualPrinter.Agent.Service +{ + /// + /// The Windows service that is registered during an installation + /// + public static class Program + { + public static void Main() + { + var builder = new ContainerBuilder(); + + builder.RegisterModule(new VirtualPrinterModule()); + builder.RegisterModule(new ProgressInfoModule()); + builder.RegisterModule(new LoggerModule()); + builder.RegisterType().As(); + + var container = builder.Build(); + + var servicesToRun = new[] + { + container.Resolve() + }; + + ServiceBase.Run(servicesToRun); + } + } +} \ No newline at end of file diff --git a/Agent/VirtualPrinter.Agent.Service/ProjectInstaller.Designer.cs b/Agent/VirtualPrinter.Agent.Service/ProjectInstaller.Designer.cs new file mode 100644 index 0000000..a65076e --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Service/ProjectInstaller.Designer.cs @@ -0,0 +1,60 @@ +namespace VirtualPrinter.Agent.Service +{ + partial class ProjectInstaller + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller(); + this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller(); + // + // serviceProcessInstaller1 + // + this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem; + this.serviceProcessInstaller1.Password = null; + this.serviceProcessInstaller1.Username = null; + // + // serviceInstaller1 + // + this.serviceInstaller1.ServiceName = VirtualPrinterService.PrinterServiceName; + this.serviceInstaller1.Description = VirtualPrinterService.PrinterDescription; + this.serviceInstaller1.ServicesDependedOn = new[] {"Spooler"}; + this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic; + // + // ProjectInstaller + // + this.Installers.AddRange(new System.Configuration.Install.Installer[] { + this.serviceProcessInstaller1, + this.serviceInstaller1}); + + } + + #endregion + + private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1; + private System.ServiceProcess.ServiceInstaller serviceInstaller1; + } +} \ No newline at end of file diff --git a/Agent/VirtualPrinter.Agent.Service/ProjectInstaller.cs b/Agent/VirtualPrinter.Agent.Service/ProjectInstaller.cs new file mode 100644 index 0000000..041d9b9 --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Service/ProjectInstaller.cs @@ -0,0 +1,14 @@ +using System.ComponentModel; +using System.Configuration.Install; + +namespace VirtualPrinter.Agent.Service +{ + [RunInstaller(true)] + public partial class ProjectInstaller : Installer + { + public ProjectInstaller() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/Agent/VirtualPrinter.Agent.Service/ProjectInstaller.resx b/Agent/VirtualPrinter.Agent.Service/ProjectInstaller.resx new file mode 100644 index 0000000..235f1b0 --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Service/ProjectInstaller.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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, 56 + + + 196, 17 + + + False + + \ No newline at end of file diff --git a/Agent/VirtualPrinter.Agent.Service/Properties/AssemblyInfo.cs b/Agent/VirtualPrinter.Agent.Service/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f3f86b8 --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Service/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("VirtualPrinter.Agent.Service")] +[assembly: AssemblyDescription("The agent for the virtual printer")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("8c4f0640-4628-4cea-8e31-143d68a3a70f")] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +// For testing +[assembly: InternalsVisibleTo("VirtualPrinter.Test")] \ No newline at end of file diff --git a/Agent/VirtualPrinter.Agent.Service/VirtualPrinter.Agent.Service.csproj b/Agent/VirtualPrinter.Agent.Service/VirtualPrinter.Agent.Service.csproj new file mode 100644 index 0000000..5c23d2a --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Service/VirtualPrinter.Agent.Service.csproj @@ -0,0 +1,136 @@ + + + + + Debug + AnyCPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F} + WinExe + VirtualPrinter.Agent.Service + VPDAgent + v4.6.1 + 512 + true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + none + true + ..\..\Files\ + TRACE + prompt + 4 + + + VirtualPrinter.Agent.Service.Program + + + + + + + + + + + + + Component + + + ProjectInstaller.cs + + + Component + + + VirtualPrinterService.cs + + + + + + + NLog.config + + + + + ProjectInstaller.cs + + + VirtualPrinterService.cs + + + + + {1b2f0781-82d7-4576-b936-c6a26053d6ed} + VirtualPrinter.Agent.Autofac + + + {135c85eb-2116-4cc4-8ccb-b6804b9d6467} + VirtualPrinter.Agent.Core + + + {94e8105f-5001-403b-b9f1-b0b0b236ad65} + VirtualPrinter.Agent.Lib + + + {aa25364d-22d5-44b0-86a5-6fb14c686308} + VirtualPrinter.Logging + + + {17e2cf8a-462c-4130-9faf-f1ca5fc4e06d} + VirtualPrinter.ProgressInfo.Autofac + + + + + False + Microsoft .NET Framework 4.6.1 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.Designer.cs b/Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.Designer.cs new file mode 100644 index 0000000..8c9f2aa --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.Designer.cs @@ -0,0 +1,40 @@ +namespace VirtualPrinter.Agent.Service +{ + partial class VirtualPrinterService + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + // + // VirtualPrinterService + // + this.ServiceName = VirtualPrinterService.PrinterServiceName; + + } + + #endregion + } +} diff --git a/Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.cs b/Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.cs new file mode 100644 index 0000000..bbd723c --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.cs @@ -0,0 +1,52 @@ +using System; +using System.ServiceProcess; + +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core; + +namespace VirtualPrinter.Agent.Service +{ + public partial class VirtualPrinterService : ServiceBase + { + public const string PrinterServiceName = "VirtualPrinterService"; + public const string PrinterDescription = "Handles virtual printers"; + + [NotNull] + private readonly IVirtualPrinterService _virtualPrinterService; + + public VirtualPrinterService([NotNull]IVirtualPrinterService virtualPrinterService) + { + if (virtualPrinterService == null) + { + throw new ArgumentNullException(nameof(virtualPrinterService)); + } + + InitializeComponent(); + + _virtualPrinterService = virtualPrinterService; + } + + protected override void OnStart(string[] args) + { + OnServiceStart(); + } + + public void OnServiceStart() + { + // Insert additional code here to define processing. + _virtualPrinterService.Start(); + } + + protected override void OnStop() + { + OnServiceStop(); + } + + public void OnServiceStop() + { + // Insert additional code here to define processing. + _virtualPrinterService.Stop(); + } + } +} \ No newline at end of file diff --git a/Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.resx b/Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.resx new file mode 100644 index 0000000..e5858cc --- /dev/null +++ b/Agent/VirtualPrinter.Agent.Service/VirtualPrinterService.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + \ No newline at end of file diff --git a/Agent/VirtualPrinter.Delivery/GhostScriptRedirector.cs b/Agent/VirtualPrinter.Delivery/GhostScriptRedirector.cs new file mode 100644 index 0000000..120025b --- /dev/null +++ b/Agent/VirtualPrinter.Delivery/GhostScriptRedirector.cs @@ -0,0 +1,98 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Printing; +using JetBrains.Annotations; +using VirtualPrinter.Logging; +using VirtualPrinter.Utils; + +namespace VirtualPrinter.Delivery +{ + /// + /// Redirects instructions to Ghostscript + /// + public class GhostScriptRedirector + { + private const string GsWin64 = "gswin64c.exe"; + private const string GsWin32 = "gswin32c.exe"; + + [NotNull] + private readonly PrintQueue _queue; + + public GhostScriptRedirector([NotNull]PrintQueue queue) + { + if (queue == null) + { + throw new ArgumentNullException(nameof(queue)); + } + + _queue = queue; + } + + /// + /// Starts the Ghostscript process for the specified + /// + /// The .redirect file located in the PrinterOutput directory + public void Redirect([NotNull]string file) + { + if (file == null) + { + throw new ArgumentNullException(nameof(file)); + } + + var logger = new VirtualPrinterLogger(); + var ghostScriptExe = GetGhostScriptPath(); + + if (ghostScriptExe == null) + { + throw new FileNotFoundException("Can not find Ghostscript."); + } + + // More details about the arguments can be find at https://www.ghostscript.com/doc/current/Use.htm + var ghostScriptArguments = $"-dPrinted -dBATCH -dNOPAUSE -dNoCancel -dNOSAFER -q -dNumCopies=1 -sDEVICE=mswinpr2 -sOutputFile=\"%printer%{ _queue.FullName}\" \"{file}\""; + logger.Info("Try to start the process {ghostScriptExe} with the following arguments: {ghostScriptArguments}.", ghostScriptExe, ghostScriptArguments); + + var processStartInfo = new ProcessStartInfo + { + FileName = ghostScriptExe, + Arguments = ghostScriptArguments, + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = false, + WindowStyle = ProcessWindowStyle.Hidden + }; + + try + { + using(var process = Process.Start(processStartInfo)) + { + process.WaitForExit(); + } + } + catch (Exception exception) + { + logger.Error(exception, "Failed to start {ghostScriptExe} with the following arguments: {ghostScriptArguments}", ghostScriptExe, ghostScriptArguments); + } + } + + [CanBeNull] + private string GetGhostScriptPath() + { + return GetGhostScriptPath(GsWin64) ?? GetGhostScriptPath(GsWin32); + } + + [CanBeNull] + private string GetGhostScriptPath(string execName) + { + if (!new RegistryRepository().TryGetGhostscriptPath(out var path)) + { + return null; + } + + var ghostScriptBinPath = Path.Combine(path, "bin"); + var fullPath = Path.Combine(ghostScriptBinPath, execName); + + return File.Exists(fullPath) ? fullPath : null; + } + } +} \ No newline at end of file diff --git a/Agent/VirtualPrinter.Delivery/Program.cs b/Agent/VirtualPrinter.Delivery/Program.cs new file mode 100644 index 0000000..8c471ee --- /dev/null +++ b/Agent/VirtualPrinter.Delivery/Program.cs @@ -0,0 +1,38 @@ +using System; + +using JetBrains.Annotations; + +using static VirtualPrinter.Delivery.Redirector; + +namespace VirtualPrinter.Delivery +{ + internal class Program + { + private const string RedirectCmd = "redirect"; + + [STAThread] + private static void Main([CanBeNull]string[] args) + { + if (args == null || args.Length < 1) { + NotUseful(); + return; + } + + switch (args[0]) { + case RedirectCmd: { + RedirectToPrinter(args[1], args[2]); + break; + } + default: { + NotUseful(); + break; + } + } + } + + private static void NotUseful() + { + throw new ArgumentNullException($"Use '{RedirectCmd}'!"); + } + } +} \ No newline at end of file diff --git a/Agent/VirtualPrinter.Delivery/Properties/AssemblyInfo.cs b/Agent/VirtualPrinter.Delivery/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..629e4ca --- /dev/null +++ b/Agent/VirtualPrinter.Delivery/Properties/AssemblyInfo.cs @@ -0,0 +1,18 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("VirtualPrinter.Delivery")] +[assembly: AssemblyDescription("The delivery man for the virtual printer")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("74fa80b3-7cf1-4b68-8aa3-4c3d37bbe855")] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/Agent/VirtualPrinter.Delivery/Redirector.cs b/Agent/VirtualPrinter.Delivery/Redirector.cs new file mode 100644 index 0000000..23bcdbe --- /dev/null +++ b/Agent/VirtualPrinter.Delivery/Redirector.cs @@ -0,0 +1,51 @@ +using System; +using System.IO; +using System.Printing; + +using JetBrains.Annotations; + +namespace VirtualPrinter.Delivery +{ + public static class Redirector + { + public static void RedirectToPrinter([NotNull]string filePath, [NotNull]string printerName) + { + if (filePath == null) + { + throw new ArgumentNullException(nameof(filePath)); + } + + if (printerName == null) + { + throw new ArgumentNullException(nameof(printerName)); + } + + var file = Path.GetFullPath(filePath); + // e.g. "Dell C2665dnf Color MFP" + using (var localSystem = new LocalPrintServer()) + { + using (var queue = localSystem.GetPrintQueueSafe(printerName)) + { + if (queue != null) + { + var ghostScriptRedirector = new GhostScriptRedirector(queue); + ghostScriptRedirector.Redirect(file); + } + } + } + } + + [CanBeNull] + private static PrintQueue GetPrintQueueSafe(this PrintServer server, string name) + { + try + { + return server.GetPrintQueue(name); + } + catch + { + return null; + } + } + } +} \ No newline at end of file diff --git a/Agent/VirtualPrinter.Delivery/VirtualPrinter.Delivery.csproj b/Agent/VirtualPrinter.Delivery/VirtualPrinter.Delivery.csproj new file mode 100644 index 0000000..c779e4b --- /dev/null +++ b/Agent/VirtualPrinter.Delivery/VirtualPrinter.Delivery.csproj @@ -0,0 +1,77 @@ + + + + + Debug + AnyCPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855} + Exe + VirtualPrinter.Delivery + delivery + v4.6.1 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + none + true + ..\..\Files + TRACE + prompt + 4 + + + VirtualPrinter.Delivery.Program + + + + + + + + + + + + + + + + + + + + {aa25364d-22d5-44b0-86a5-6fb14c686308} + VirtualPrinter.Logging + + + {cd1c8e9d-5335-41ac-b0c0-88fd7c7c55f3} + VirtualPrinter.Utils + + + {AA25364D-22D5-44B0-86A5-6FB14C686308} + VirtualPrinter.Logging + + + {cd1c8e9d-5335-41ac-b0c0-88fd7c7c55f3} + VirtualPrinter.Utils + + + + + 2020.1.0 + + + + \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Autofac/Properties/AssemblyInfo.cs b/Common/VirtualPrinter.Agent.Autofac/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2a3bd49 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Autofac/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; +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("VirtualPrinter.Agent.Autofac")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[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("fc76a2af-b0db-4ec8-a6b7-dbd25d461ab5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Common/VirtualPrinter.Agent.Autofac/VirtualPrinter.Agent.Autofac.csproj b/Common/VirtualPrinter.Agent.Autofac/VirtualPrinter.Agent.Autofac.csproj new file mode 100644 index 0000000..8be0f08 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Autofac/VirtualPrinter.Agent.Autofac.csproj @@ -0,0 +1,81 @@ + + + + + Debug + AnyCPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED} + Library + VirtualPrinter.Agent.Autofac + VirtualPrinter.Agent.Autofac + v4.6.1 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + none + true + ..\..\Files\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + {135c85eb-2116-4cc4-8ccb-b6804b9d6467} + VirtualPrinter.Agent.Core + + + {94e8105f-5001-403b-b9f1-b0b0b236ad65} + VirtualPrinter.Agent.Lib + + + {AA25364D-22D5-44B0-86A5-6FB14C686308} + VirtualPrinter.Logging + + + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3} + VirtualPrinter.Utils + + + + + + + + + + + + \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Autofac/VirtualPrinterModule.cs b/Common/VirtualPrinter.Agent.Autofac/VirtualPrinterModule.cs new file mode 100644 index 0000000..750f229 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Autofac/VirtualPrinterModule.cs @@ -0,0 +1,33 @@ +using Autofac; + +using VirtualPrinter.Agent.Core; +using VirtualPrinter.Agent.Lib; +using VirtualPrinter.Agent.Lib.Misc; +using VirtualPrinter.Utils; + +namespace VirtualPrinter.Agent.Autofac +{ + /// + /// All classes to be resolved with IoC are registered here + /// + public class VirtualPrinterModule : Module + { + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Enums/IntermediateFormat.cs b/Common/VirtualPrinter.Agent.Core/Enums/IntermediateFormat.cs new file mode 100644 index 0000000..d3eee6b --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Enums/IntermediateFormat.cs @@ -0,0 +1,8 @@ +namespace VirtualPrinter.Agent.Core.Enums +{ + public enum IntermediateFormat + { + Ps, + Xps + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IConfig.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IConfig.cs new file mode 100644 index 0000000..8da8973 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IConfig.cs @@ -0,0 +1,20 @@ +using JetBrains.Annotations; + +namespace VirtualPrinter.Agent.Core +{ + public interface IConfig + { + /// + /// The mask for the filename. + /// + /// The mask can be look like {yyyy}{MM}{DD}{hh}{mm}{ss}{job05}{page03} + [NotNull] + string FileNameMask { get; } + + /// + /// The port of the printer. + /// + /// E.g. 9101 + short PrinterPort { get; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IDirectoryHelper.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IDirectoryHelper.cs new file mode 100644 index 0000000..1bcd8e4 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IDirectoryHelper.cs @@ -0,0 +1,7 @@ +namespace VirtualPrinter.Agent.Core +{ + public interface IDirectoryHelper + { + string GetOutputDirectory(IExConfig config); + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IExConfig.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IExConfig.cs new file mode 100644 index 0000000..af6c3d8 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IExConfig.cs @@ -0,0 +1,36 @@ +using System; + +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core.Enums; + +namespace VirtualPrinter.Agent.Core +{ + public interface IExConfig : IConfig + { + /// + /// Splits a preconverter into two strings. + /// + /// e.g. "C:\Program Files (x86)\MySoftware\MySoftware.exe PRINT" now becomes: string 1 = "C:\Program Files (x86)\MySoftware\MySoftware.exe" and string 2 = "PRINT" + [NotNull] + Tuple ResolvedPreconverter { get; } + + /// + /// Splits a postconverter into two strings. + /// + /// e.g. "C:\Program Files (x86)\MySoftware\MySoftware.exe PRINTCOMPLETE" now becomes: string 1 = "C:\Program Files (x86)\MySoftware\MySoftware.exe" and string 2 = "PRINTCOMPLETE" + [NotNull] + Tuple ResolvedPostconverter { get; } + + /// + /// The full path of the output directory. + /// + [NotNull] + string ResolvedOutputDirectory { get; } + + /// + /// An intermediate format which is read by the printer or similar. + /// + IntermediateFormat IntermediateFormat { get; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IJob.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IJob.cs new file mode 100644 index 0000000..5a99448 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IJob.cs @@ -0,0 +1,34 @@ +using JetBrains.Annotations; + +namespace VirtualPrinter.Agent.Core +{ + /// + /// The information of the job. + /// + public interface IJob + { + /// + /// The path to the file containing the data. + /// + [NotNull] + string RawDataPath { get; } + + /// + /// The path to the ini file. + /// + [NotNull] + string IniDataPath { get; } + + /// + /// Several job infos. + /// + [NotNull] + IJobInfo JobInfo { get; } + + /// + /// Information about the session. + /// + [NotNull] + ISessionInfo SessionInfo { get; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IJobFactory.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IJobFactory.cs new file mode 100644 index 0000000..6acebf0 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IJobFactory.cs @@ -0,0 +1,15 @@ +using System.IO; + +using JetBrains.Annotations; + +namespace VirtualPrinter.Agent.Core +{ + public interface IJobFactory + { + [CanBeNull] + IJob Create([NotNull]string printerName, [NotNull]Stream stream); + + [NotNull] + IJob Create([NotNull]string iniPath, [NotNull]string rawPath, IJobInfo jobInfo, ISessionInfo sessionInfo); + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IJobInfo.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IJobInfo.cs new file mode 100644 index 0000000..63fe7ba --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IJobInfo.cs @@ -0,0 +1,15 @@ +using System.Printing; + +namespace VirtualPrinter.Agent.Core +{ + public interface IJobInfo + { + int JobId { get; set; } + string Name { get; set; } + string DomainName { get; set; } + string MachineName { get; set; } + string UserName { get; set; } + PrintJobStatus Status { get; set; } + string DeviceName { get; set; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IJobProcessor.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IJobProcessor.cs new file mode 100644 index 0000000..ab19f99 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IJobProcessor.cs @@ -0,0 +1,18 @@ +using System; + +using JetBrains.Annotations; + +namespace VirtualPrinter.Agent.Core +{ + public interface IJobProcessor + { + /// + /// Processes an passed to it with the information from the . + /// + /// + /// + /// Throws when the job or the is null. + /// The job cannot be converted. There is no redirect to a printer. Will not be thrown. + void Process([NotNull]IJob job, [NotNull]IUserConfig userConfig); + } +} diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IJobRedirector.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IJobRedirector.cs new file mode 100644 index 0000000..0017b34 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IJobRedirector.cs @@ -0,0 +1,17 @@ +using System; + +using JetBrains.Annotations; + +namespace VirtualPrinter.Agent.Core +{ + public interface IJobRedirector + { + /// + /// Redirects the information from the job and the config to an Process to be executed. + /// + /// + /// + /// Throws when the or the is null. + void Redirect([NotNull]IJob job, [NotNull]IUserConfig userConfig); + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IJobService.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IJobService.cs new file mode 100644 index 0000000..e214922 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IJobService.cs @@ -0,0 +1,47 @@ +using System; + +using JetBrains.Annotations; + +namespace VirtualPrinter.Agent.Core +{ + public interface IJobService + { + /// + /// Starts the in a new Process. + /// + /// + /// Throws when the is null. + void Start([NotNull]IJob job); + + /// + /// Creates an new from the ini file and the raw path. + /// + /// + /// + /// An new object. + /// Throws when the or the is null or empty. + [NotNull] + IJob CreateJob([NotNull]string iniPath, [NotNull]string rawPath); + + /// + /// Reads the from the + /// + /// + /// A + /// Throws when the is null or empty. + PrintStatus ReadStatus([NotNull]string iniPath); + + /// + /// Starts a new process to finish the . + /// + /// + void Finish([NotNull]IJob job); + + /// + /// Gets the from the ini file. + /// + /// The path to the ini file + /// + JobStatus ReadJobStatus(string iniPath); + } +} diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IPostScriptConverter.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IPostScriptConverter.cs new file mode 100644 index 0000000..25a5dcf --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IPostScriptConverter.cs @@ -0,0 +1,15 @@ +using System; + +using VirtualPrinter.Agent.Lib.Model; + +namespace VirtualPrinter.Agent.Core +{ + public interface IPostScriptConverter + { + event EventHandler ProgressInitialized; + event EventHandler ProgressFinished; + event EventHandler ProgressUpdate; + + void Convert(IJob job, string target, PostScriptRenderOptions options); + } +} diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IRegistryRepository.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IRegistryRepository.cs new file mode 100644 index 0000000..712afd4 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IRegistryRepository.cs @@ -0,0 +1,29 @@ +using JetBrains.Annotations; + +namespace VirtualPrinter.Agent.Core +{ + public interface IRegistryRepository + { + /// + /// Try to get the ghostscript path from. + /// + /// True if the path exists. + [ContractAnnotation("=>true,path:notnull; =>false,path:null")] + bool TryGetGhostscriptPath(out string path); + + /// + /// Get the from the registry. + /// + /// The configuration that was read from the registry in HKEY_LOCAL_MACHINE\SOFTWARE. + [NotNull] + IExConfig GetRegistryConfig(); + + /// + /// Get the from the registry. + /// + /// The security identifier with which each Windows user can be clearly identified in the network. + /// The configuration that was read from the registry in HKEY_USERS + [NotNull] + IUserConfig GetUserRegistryConfig([NotNull]string sid); + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/ISessionInfo.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/ISessionInfo.cs new file mode 100644 index 0000000..1125890 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/ISessionInfo.cs @@ -0,0 +1,11 @@ +namespace VirtualPrinter.Agent.Core +{ + public interface ISessionInfo + { + int Id { get; set; } + + string Desktop { get; set; } + + string Sid { get; set; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IShell.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IShell.cs new file mode 100644 index 0000000..d341f1d --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IShell.cs @@ -0,0 +1,16 @@ +using JetBrains.Annotations; + +namespace VirtualPrinter.Agent.Core +{ + public interface IShell + { + void WriteIniEntry(string section, string key, string value, string iniFilePath); + + [NotNull] + T ReadIniEntry(string section, string key, string iniFilePath); + + void Execute(IJobInfo job, ISessionInfo session, string exe, string args); + + bool FileExists([NotNull]string path); + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IUserConfig.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IUserConfig.cs new file mode 100644 index 0000000..c775f69 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IUserConfig.cs @@ -0,0 +1,26 @@ +using JetBrains.Annotations; + +namespace VirtualPrinter.Agent.Core +{ + public interface IUserConfig + { + /// + /// The printer stored in the registry. + /// + [CanBeNull] + string RedirectPrinter { get; } + + /// + /// The DPI value stored in the registry. + /// + /// Initial value is null. + double? UserRenderDpi { get; } + + /// + /// The format that you choose on your client side stored in the registry. + /// + /// Intital value is PDF + [NotNull] + string Format { get; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IVirtualPrinter.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IVirtualPrinter.cs new file mode 100644 index 0000000..60aae3f --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IVirtualPrinter.cs @@ -0,0 +1,12 @@ +using System; + +namespace VirtualPrinter.Agent.Core +{ + public interface IVirtualPrinter : IDisposable + { + /// + /// Initialize the virtual printer. + /// + void Init(); + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/IVirtualPrinterService.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/IVirtualPrinterService.cs new file mode 100644 index 0000000..e2af660 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/IVirtualPrinterService.cs @@ -0,0 +1,8 @@ +namespace VirtualPrinter.Agent.Core +{ + public interface IVirtualPrinterService + { + void Start(); + void Stop(); + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Interfaces/JobStatus.cs b/Common/VirtualPrinter.Agent.Core/Interfaces/JobStatus.cs new file mode 100644 index 0000000..e0fc3c4 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Interfaces/JobStatus.cs @@ -0,0 +1,9 @@ +namespace VirtualPrinter.Agent.Core +{ + public enum JobStatus + { + Completed, + Failed, + InProgress + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Model/JobInfo.cs b/Common/VirtualPrinter.Agent.Core/Model/JobInfo.cs new file mode 100644 index 0000000..ea17406 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Model/JobInfo.cs @@ -0,0 +1,15 @@ +using System.Printing; + +namespace VirtualPrinter.Agent.Core +{ + public struct JobInfo : IJobInfo + { + public int JobId { get; set; } + public string Name { get; set; } + public string DomainName { get; set; } + public string MachineName { get; set; } + public string UserName { get; set; } + public PrintJobStatus Status { get; set; } + public string DeviceName { get; set; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Model/PostScriptConversionException.cs b/Common/VirtualPrinter.Agent.Core/Model/PostScriptConversionException.cs new file mode 100644 index 0000000..f09876b --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Model/PostScriptConversionException.cs @@ -0,0 +1,19 @@ +using System; + +namespace VirtualPrinter.Agent.Core +{ + public class PostScriptConversionException : Exception + { + public PostScriptConversionException() + { + } + + public PostScriptConversionException(string message) : base(message) + { + } + + public PostScriptConversionException(string message, Exception inner) : base(message, inner) + { + } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderOptions.cs b/Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderOptions.cs new file mode 100644 index 0000000..c88763f --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderOptions.cs @@ -0,0 +1,9 @@ +namespace VirtualPrinter.Agent.Core +{ + public struct PostScriptRenderOptions + { + public double? UserRenderDpi { get; set; } + public PostScriptRenderPdfOptions PdfOptions { get; set; } + public PostScriptRenderTiffOptions TiffOptions { get; set; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderPdfOptions.cs b/Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderPdfOptions.cs new file mode 100644 index 0000000..6d47410 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderPdfOptions.cs @@ -0,0 +1,8 @@ +namespace VirtualPrinter.Agent.Core +{ + public struct PostScriptRenderPdfOptions + { + public bool Enabled { set; get; } + public bool Archivable { get; set; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderTiffOptions.cs b/Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderTiffOptions.cs new file mode 100644 index 0000000..f391638 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Model/PostScriptRenderTiffOptions.cs @@ -0,0 +1,7 @@ +namespace VirtualPrinter.Agent.Core +{ + public struct PostScriptRenderTiffOptions + { + public bool Enabled { set; get; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Model/PrintExts.cs b/Common/VirtualPrinter.Agent.Core/Model/PrintExts.cs new file mode 100644 index 0000000..50cddaa --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Model/PrintExts.cs @@ -0,0 +1,13 @@ +using JetBrains.Annotations; + +namespace VirtualPrinter.Agent.Core +{ + public static class PrintExts + { + [NotNull] + public static string ToIni(this PrintStatus status) + { + return status.ToString().ToLowerInvariant(); + } + } +} diff --git a/Common/VirtualPrinter.Agent.Core/Model/PrintStatus.cs b/Common/VirtualPrinter.Agent.Core/Model/PrintStatus.cs new file mode 100644 index 0000000..6d9166a --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Model/PrintStatus.cs @@ -0,0 +1,15 @@ +namespace VirtualPrinter.Agent.Core +{ + public enum PrintStatus + { + Undefined = 0, + + Paused, + + Resumed, + + Complete, + + Canceled + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Model/ProgressUpdateArgs.cs b/Common/VirtualPrinter.Agent.Core/Model/ProgressUpdateArgs.cs new file mode 100644 index 0000000..e5c0511 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Model/ProgressUpdateArgs.cs @@ -0,0 +1,22 @@ +using System; + +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core; + +namespace VirtualPrinter.Agent.Lib.Model +{ + public class ProgressUpdateArgs : EventArgs + { + public ProgressUpdateArgs([NotNull] IJob job, uint val) + { + Job = job; + Value = val; + } + + [NotNull] + public IJob Job { get; } + + public uint Value { get; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Model/RegistryConfig.cs b/Common/VirtualPrinter.Agent.Core/Model/RegistryConfig.cs new file mode 100644 index 0000000..c5869b2 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Model/RegistryConfig.cs @@ -0,0 +1,49 @@ +using System; +using System.IO; +using System.Linq; + +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core.Enums; + +namespace VirtualPrinter.Agent.Core +{ + public class RegistryConfig : IExConfig + { + public string Postconverter { get; set; } + + public string Preconverter { get; set; } + + public string OutputDirectory { get; set; } + + public string FileNameMask { get; set; } + + public short PrinterPort { get; set; } + + public Tuple ResolvedPreconverter + { + get { return GetResolvedArgs(Preconverter); } + } + + public Tuple ResolvedPostconverter + { + get { return GetResolvedArgs(Postconverter); } + } + + public string ResolvedOutputDirectory + { + get { return string.IsNullOrWhiteSpace(OutputDirectory) ? "" : Path.GetFullPath(OutputDirectory); } + } + + public IntermediateFormat IntermediateFormat { get; set; } + + [NotNull] + private static Tuple GetResolvedArgs([NotNull]string text) + { + const string ending = ".exe"; + var parts = text.Split(new[] { ending }, StringSplitOptions.RemoveEmptyEntries); + + return Tuple.Create(Path.GetFullPath(parts.First() + ending), parts.Last().Trim()); + } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Model/SessionInfo.cs b/Common/VirtualPrinter.Agent.Core/Model/SessionInfo.cs new file mode 100644 index 0000000..e299ed1 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Model/SessionInfo.cs @@ -0,0 +1,11 @@ +namespace VirtualPrinter.Agent.Core +{ + public struct SessionInfo : ISessionInfo + { + public int Id { get; set; } + + public string Desktop { get; set; } + + public string Sid { get; set; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Model/UserRegistryConfig.cs b/Common/VirtualPrinter.Agent.Core/Model/UserRegistryConfig.cs new file mode 100644 index 0000000..549733b --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Model/UserRegistryConfig.cs @@ -0,0 +1,13 @@ +namespace VirtualPrinter.Agent.Core +{ + public class UserRegistryConfig : IUserConfig + { + public bool RedirectEnabled { get; set; } + + public string RedirectPrinter { get; set; } + + public double? UserRenderDpi { get; set; } + + public string Format { get; set; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/Properties/AssemblyInfo.cs b/Common/VirtualPrinter.Agent.Core/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5f7ca49 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("VirtualPrinter.Agent.Core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("135c85eb-2116-4cc4-8ccb-b6804b9d6467")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// indem Sie "*" wie unten gezeigt eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Core/VirtualPrinter.Agent.Core.csproj b/Common/VirtualPrinter.Agent.Core/VirtualPrinter.Agent.Core.csproj new file mode 100644 index 0000000..af62dcc --- /dev/null +++ b/Common/VirtualPrinter.Agent.Core/VirtualPrinter.Agent.Core.csproj @@ -0,0 +1,77 @@ + + + + + Debug + AnyCPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467} + Library + Properties + VirtualPrinter.Agent.Core + VirtualPrinter.Agent.Core + v4.6.1 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + none + true + ..\..\Files\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Lib/Misc/GhostScriptConverter.cs b/Common/VirtualPrinter.Agent.Lib/Misc/GhostScriptConverter.cs new file mode 100644 index 0000000..6522e71 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Lib/Misc/GhostScriptConverter.cs @@ -0,0 +1,218 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Text.RegularExpressions; + +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core; +using VirtualPrinter.Agent.Lib.Model; +using VirtualPrinter.Logging; + +namespace VirtualPrinter.Agent.Lib.Misc +{ + public class GhostScriptConverter : IPostScriptConverter + { + private const string GsWin64 = "gswin64c.exe"; + private const string GsWin32 = "gswin32c.exe"; + + [NotNull] + private readonly IVirtualPrinterLogger _logger; + + [NotNull] + private readonly IRegistryRepository _registryRepository; + + [NotNull] + private readonly IShell _shell; + + public event EventHandler ProgressInitialized; + public event EventHandler ProgressFinished; + public event EventHandler ProgressUpdate; + + public GhostScriptConverter + ( + [NotNull]IVirtualPrinterLogger logger, + [NotNull]IRegistryRepository registryRepository, + [NotNull]IShell shell + ) + { + if (logger == null) + { + throw new ArgumentNullException(nameof(logger)); + } + + if (registryRepository == null) + { + throw new ArgumentNullException(nameof(registryRepository)); + } + + if (shell == null) + { + throw new ArgumentNullException(nameof(shell)); + } + + _logger = logger; + _registryRepository = registryRepository; + _shell = shell; + } + + public void Convert(IJob job, string target, PostScriptRenderOptions options) + { + var ghostScriptExe = GetGhostScriptPath(); + + if (ghostScriptExe == null) + { + throw new PostScriptConversionException("GhostScript not found. Please place local variable."); + } + + ProgressInitialized?.Invoke(this, job); + + var pdfTarget = target + ".pdf"; + if (options.PdfOptions.Enabled) + { + Convert(job, ghostScriptExe, GetArgumentsForPdfConversion(job.RawDataPath, pdfTarget, options)); + + if (!_shell.FileExists(pdfTarget)) + { + throw new PostScriptConversionException("Postscript conversion failed after output."); + } + } + + if (options.TiffOptions.Enabled) + { + var tiffTarget = target + ".tif"; + + Convert(job, ghostScriptExe, GetArgumentsForTiffConversion(job.RawDataPath, tiffTarget, options)); + Convert(job, ghostScriptExe, GetArgumentsForPdfConversion(job.RawDataPath, pdfTarget, options)); + + if (!_shell.FileExists(tiffTarget)) + { + throw new PostScriptConversionException("Postscript conversion failed after output."); + } + } + + ProgressFinished?.Invoke(this, job); + } + + [CanBeNull] + private string GetGhostScriptPath() + { + return GetGhostScriptPath(GsWin64) ?? GetGhostScriptPath(GsWin32); + } + + [CanBeNull] + private string GetGhostScriptPath(string execName) + { + if (!_registryRepository.TryGetGhostscriptPath(out var path)) + { + return null; + } + + var ghostScriptBinPath = Path.Combine(path, "bin"); + var fullPath = Path.Combine(ghostScriptBinPath, execName); + + return _shell.FileExists(fullPath) ? fullPath : null; + } + + [NotNull] + private static string GetArgumentsForPdfConversion(string source, string target, PostScriptRenderOptions options) + { + const string initialArguments = "-q -P- -dSAFER -dNOPAUSE -dBATCH -dNoCancel -sDEVICE=pdfwrite"; + var finalArguments = $"-sOutputFile=\"{target}\" \"{source}\""; + + var optionalArguments = ""; + + if (options.PdfOptions.Archivable) + { + optionalArguments += "-sColorConversionStrategy=/RGB -dUseCIEColor -dPDFACompatibilityPolicy=2"; + } + + if (options.UserRenderDpi != null && options.UserRenderDpi > 0) + { + optionalArguments += "-r" + options.UserRenderDpi.Value; + } + + return $"{initialArguments} {optionalArguments} {finalArguments}"; + } + + [NotNull] + private static string GetArgumentsForTiffConversion(string source, string target, PostScriptRenderOptions options) + { + const string initialArguments = "-q -P- -dSAFER -dNOPAUSE -dBATCH -sDEVICE=tiff12nc -sCompression=lzw"; + var finalArguments = $"-sOutputFile=\"{target}\" \"{source}\""; + + var optionalArguments = "-dTextAlphaBits=4 "; + + if (options.UserRenderDpi != null && options.UserRenderDpi > 0) + { + optionalArguments += "-r" + options.UserRenderDpi.Value; + } + else + { + optionalArguments += "-r300"; + } + + return $"{initialArguments} {optionalArguments} {finalArguments}"; + } + + private void Convert(IJob job, string gsExe, string gsArguments) + { + LogDebug("Starting ps conversion ...\n"+gsExe + " " + gsArguments); + + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = gsExe, + Arguments = gsArguments, + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + } + }; + + process.Start(); + + while (!process.StandardOutput.EndOfStream) + { + var readLine = process.StandardOutput.ReadLine(); + var progress = ParseProgress(readLine); + + if (progress == null) + { + continue; + } + + ProgressUpdate?.Invoke(this, new ProgressUpdateArgs(job, progress.Value)); + } + } + + private static uint? ParseProgress([CanBeNull]string line) + { + // Example output: + // %%[Page: 49]%% + if (line == null) + { + return null; + } + + var groups = Regex.Match(line, @"%%\[Page:(.*)\]%%").Groups; + if (groups.Count < 2) + { + return null; + } + + if (!uint.TryParse(groups[1].Value, out var result)) + { + return null; + } + + return result; + } + + private void LogDebug(string message, params object[] args) + { + _logger.Debug(message, args); + } + } +} diff --git a/Common/VirtualPrinter.Agent.Lib/Misc/Job.cs b/Common/VirtualPrinter.Agent.Lib/Misc/Job.cs new file mode 100644 index 0000000..a68a004 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Lib/Misc/Job.cs @@ -0,0 +1,15 @@ +using VirtualPrinter.Agent.Core; + +namespace VirtualPrinter.Agent.Lib.Misc +{ + public class Job : IJob + { + public string RawDataPath { get; set; } + + public string IniDataPath { get; set; } + + public IJobInfo JobInfo { get; set; } + + public ISessionInfo SessionInfo { get; set; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Lib/Misc/JobFactory.cs b/Common/VirtualPrinter.Agent.Lib/Misc/JobFactory.cs new file mode 100644 index 0000000..191600f --- /dev/null +++ b/Common/VirtualPrinter.Agent.Lib/Misc/JobFactory.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Printing; +using System.Security.Principal; + +using Cassia; + +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core; +using VirtualPrinter.Agent.Core.Enums; +using VirtualPrinter.Logging; + +namespace VirtualPrinter.Agent.Lib.Misc +{ + public class JobFactory : IJobFactory + { + [NotNull] + private readonly IVirtualPrinterLogger _logger; + private readonly IDirectoryHelper _directoryHelper; + [NotNull] + private readonly IRegistryRepository _registryRepository; + + public JobFactory + ( + [NotNull]IRegistryRepository registryRepository, + [NotNull]IVirtualPrinterLogger logger, + [NotNull]IDirectoryHelper directoryHelper + ) + { + if (registryRepository == null) + { + throw new ArgumentNullException(nameof(registryRepository)); + } + + if (logger == null) + { + throw new ArgumentNullException(nameof(logger)); + } + + if (directoryHelper == null) + { + throw new ArgumentNullException(nameof(logger)); + } + + _registryRepository = registryRepository; + _logger = logger; + _directoryHelper = directoryHelper; + } + + public IJob Create(string printerName, Stream stream) + { + if (printerName == null) + { + throw new ArgumentNullException(nameof(printerName)); + } + + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + try + { + var now = DateTime.Now; + var config = _registryRepository.GetRegistryConfig(); + var root = _directoryHelper.GetOutputDirectory(config); + var jobInfo = GetCurrentPrintJobs(printerName).FirstOrDefault(); + if (jobInfo == null) + { + throw new InvalidOperationException(); + } + + var session = GetCurrentSessions(jobInfo).FirstOrDefault(); + var iniName = GenerateFileName(now, jobInfo.JobId, 0, config.FileNameMask, "ini"); + var iniPath = Path.Combine(root, iniName); + var extension = GetRawFileExtension(config.IntermediateFormat); + var rawName = $"{Path.GetFileNameWithoutExtension(iniName)}.{extension}"; + var rawPath = Path.Combine(root, rawName); + using (var output = File.Create(rawPath)) + { + stream.CopyTo(output); + } + + return new Job + { + RawDataPath = rawPath, + IniDataPath = iniPath, + JobInfo = jobInfo, + SessionInfo = session + }; + } + catch (Exception exception) + { + LogError(exception, "Failed to create job."); + return null; + } + } + + public IJob Create(string iniPath, string rawPath, IJobInfo jobInfo, ISessionInfo sessionInfo) + { + if (string.IsNullOrWhiteSpace(iniPath)) + { + throw new ArgumentException("Value cannot be null or whitespace.", nameof(iniPath)); + } + + if (string.IsNullOrWhiteSpace(rawPath)) + { + throw new ArgumentException("Value cannot be null or whitespace.", nameof(rawPath)); + } + + return new Job + { + IniDataPath = iniPath, + RawDataPath = rawPath, + JobInfo = jobInfo, + SessionInfo = sessionInfo + }; + } + + [NotNull] + private string GenerateFileName(DateTime time, int job, int page, [NotNull]string pattern, [NotNull]string ending) + { + var fileName = pattern; + fileName = fileName.Replace("{yyyy}", $"{time.Year:0000}"); + fileName = fileName.Replace("{MM}", $"{time.Month:00}"); + fileName = fileName.Replace("{DD}", $"{time.Day:00}"); + fileName = fileName.Replace("{hh}", $"{time.Hour:00}"); + fileName = fileName.Replace("{mm}", $"{time.Minute:00}"); + fileName = fileName.Replace("{ss}", $"{time.Second:00}"); + fileName = fileName.Replace("{fff}", $"{time.Millisecond:000}"); + fileName = fileName.Replace("{job05}", $"{job:00000}"); + fileName = fileName.Replace("{page03}", $"{page:000}"); + + return $"{fileName}.{ending}"; + } + + private IEnumerable GetCurrentSessions([NotNull]IJobInfo job) + { + var domain = job.DomainName; + var machine = job.MachineName?.TrimStart('\\'); + var user = job.UserName; + + LogDebug($"Searching for session of {domain}\\{user} on {machine} !"); + + if (domain == null || machine == null || user == null) + { + yield break; + } + + const StringComparison cmp = StringComparison.OrdinalIgnoreCase; + using (var server = new TerminalServicesManager().GetLocalServer()) + { + var sessions = server.GetSessions().Where(s => s.UserName != null && s.DomainName != null); + foreach (var session in sessions) + { + if (!session.UserName.Equals(user, cmp)) + { + continue; + } + + var isSingleUser = session.DomainName.Equals(machine, cmp); + var isDomainUser = session.DomainName.Equals(domain, cmp); + if (!isSingleUser && !isDomainUser) + { + continue; + } + + var sessionId = session.SessionId; + var desktopName = session.WindowStationName; + var account = session.UserAccount; + yield return new SessionInfo + { + Id = sessionId, + Desktop = desktopName, + Sid = account.Translate(typeof(SecurityIdentifier)).Value + }; + } + } + } + + [ItemNotNull] + private IEnumerable GetCurrentPrintJobs(string printerName) + { + using (var server = new LocalPrintServer()) + { + using (var queue = server.GetPrintQueue(printerName)) + { + using (var jobs = queue.GetPrintJobInfoCollection()) + { + foreach (var job in jobs) + { + using (job) + { + var id = job.JobIdentifier; + var machine = server.Name; + var domain = Environment.UserDomainName; + var user = job.Submitter; + var name = job.Name; + yield return new JobInfo + { + JobId = id, + Name = name, + DomainName = domain, + MachineName = machine, + UserName = user, + Status = job.JobStatus, + DeviceName = queue.Name + }; + } + } + } + } + } + } + + [NotNull] + private string GetRawFileExtension(IntermediateFormat format) + { + switch (format) + { + case IntermediateFormat.Xps: + return "xps"; + case IntermediateFormat.Ps: + return "ps"; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void LogDebug(string message) + { + _logger.Debug(message); + } + + private void LogError(Exception exception, string message, params object[] args) + { + _logger.Error(exception, message, args); + } + } +} diff --git a/Common/VirtualPrinter.Agent.Lib/Misc/JobProcessor.cs b/Common/VirtualPrinter.Agent.Lib/Misc/JobProcessor.cs new file mode 100644 index 0000000..819597c --- /dev/null +++ b/Common/VirtualPrinter.Agent.Lib/Misc/JobProcessor.cs @@ -0,0 +1,150 @@ +using System; +using System.IO; + +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core; +using VirtualPrinter.Agent.Lib.Model; +using VirtualPrinter.Logging; +using VirtualPrinter.ProgressInfo.Core; + +namespace VirtualPrinter.Agent.Lib.Misc +{ + public class JobProcessor : IJobProcessor + { + [NotNull] + private readonly IRegistryRepository _registryRepository; + + [NotNull] + private readonly IJobRedirector _jobRedirector; + + [NotNull] + private readonly IVirtualPrinterLogger _logger; + + [NotNull] + private readonly IPostScriptConverter _postScriptConverter; + + [NotNull] + private readonly IProgressInfo _progressInfo; + private readonly IDirectoryHelper _directoryHelper; + + public JobProcessor + ( + [NotNull]IRegistryRepository registryRepository, + [NotNull]IVirtualPrinterLogger logger, + [NotNull]IPostScriptConverter postScriptConverter, + [NotNull]IJobRedirector redirector, + [NotNull]IProgressInfo progressInfo, + [NotNull]IDirectoryHelper directoryHelper + ) + { + if (registryRepository == null) + { + throw new ArgumentNullException(nameof(registryRepository)); + } + + if (logger == null) + { + throw new ArgumentNullException(nameof(logger)); + } + + if (postScriptConverter == null) + { + throw new ArgumentNullException(nameof(postScriptConverter)); + } + + if (redirector == null) + { + throw new ArgumentNullException(nameof(redirector)); + } + + if (progressInfo == null) + { + throw new ArgumentNullException(nameof(progressInfo)); + } + + if (directoryHelper == null) + { + throw new ArgumentNullException(nameof(directoryHelper)); + } + + _registryRepository = registryRepository; + _logger = logger; + _postScriptConverter = postScriptConverter; + _jobRedirector = redirector; + _progressInfo = progressInfo; + _directoryHelper = directoryHelper; + _postScriptConverter.ProgressInitialized += OnProgressInitialized; + _postScriptConverter.ProgressFinished += OnProgressFinished; + _postScriptConverter.ProgressUpdate += OnProgressUpdate; + } + + public void Process(IJob job, IUserConfig userConfig) + { + if (job == null) + { + throw new ArgumentNullException(nameof(job)); + } + + if (userConfig == null) + { + throw new ArgumentNullException(nameof(userConfig)); + } + + var targetFile = $"{Path.GetFileNameWithoutExtension(job.RawDataPath)}"; + var config = _registryRepository.GetRegistryConfig(); + var dir = _directoryHelper.GetOutputDirectory(config); + targetFile = Path.Combine(dir, targetFile); + + var options = new PostScriptRenderOptions + { + UserRenderDpi = userConfig.UserRenderDpi, + PdfOptions = new PostScriptRenderPdfOptions + { + Enabled = userConfig.Format == "PDF" || string.IsNullOrEmpty(userConfig.Format) + }, + TiffOptions = new PostScriptRenderTiffOptions + { + Enabled = userConfig.Format == "TIFF" + } + }; + + try + { + _postScriptConverter.Convert(job, targetFile, options); + } + catch (PostScriptConversionException exception) + { + LogError(exception, "Error processing PS file."); + return; + } + + _jobRedirector.Redirect(job, userConfig); + } + + private void OnProgressUpdate(object sender, [NotNull]ProgressUpdateArgs args) + { + if (args == null) + { + throw new ArgumentNullException(nameof(args)); + } + + _progressInfo.Progress(args.Job, args.Value); + } + + private void OnProgressFinished(object sender, IJob job) + { + _progressInfo.Finish(job); + } + + private void OnProgressInitialized(object sender, IJob job) + { + _progressInfo.Initialize(job); + } + + private void LogError(Exception exception, string message, params object[] args) + { + _logger.Error(exception, message, args); + } + } +} diff --git a/Common/VirtualPrinter.Agent.Lib/Misc/JobRedirector.cs b/Common/VirtualPrinter.Agent.Lib/Misc/JobRedirector.cs new file mode 100644 index 0000000..fbcfa86 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Lib/Misc/JobRedirector.cs @@ -0,0 +1,106 @@ +using System; +using System.IO; + +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core; +using VirtualPrinter.Delivery; +using VirtualPrinter.Logging; +using VirtualPrinter.Utils; + +namespace VirtualPrinter.Agent.Lib.Misc +{ + public class JobRedirector : IJobRedirector + { + [NotNull] + private readonly IVirtualPrinterLogger _logger; + + [NotNull] + private readonly IShell _shell; + + public JobRedirector([NotNull]IVirtualPrinterLogger logger, [NotNull]IShell shell) + { + if (logger == null) + { + throw new ArgumentNullException(nameof(logger)); + } + + if (shell == null) + { + throw new ArgumentNullException(nameof(shell)); + } + + _logger = logger; + _shell = shell; + } + + public void Redirect(IJob job, IUserConfig userConfig) + { + if (job == null) + { + throw new ArgumentNullException(nameof(job)); + } + + if (userConfig == null) + { + throw new ArgumentNullException(nameof(userConfig)); + } + + var printer = userConfig.RedirectPrinter; + if (string.IsNullOrWhiteSpace(printer)) + { + LogWarn("Can not redirect to empty printer."); + return; + } + + try + { + var pdfToRedirect = GetPdfPath(job.RawDataPath); + + LogDebug($"Redirecting '{pdfToRedirect}' to '{printer}'..."); + + var redirectExe = Path.GetFullPath(typeof(Redirector).Assembly.Location); + var redirectArgs = $@"redirect ""{pdfToRedirect}"" ""{printer}"""; + + _shell.Execute(job.JobInfo, job.SessionInfo, redirectExe, redirectArgs); + } + catch (Exception exception) + { + LogError(exception, $"{exception.GetType()}: {exception.Message}"); + } + } + + [NotNull] + private static string GetPdfPath([NotNull]string rawFilePath) + { + if (string.IsNullOrWhiteSpace(rawFilePath)) + { + throw new ArgumentException(nameof(rawFilePath)); + } + + var directoryName = Path.GetDirectoryName(rawFilePath); + if (string.IsNullOrWhiteSpace(directoryName)) + { + throw new ArgumentException(nameof(directoryName)); + } + + var file = Path.GetFileNameWithoutExtension(rawFilePath); + return Path.Combine(directoryName, file) + ".pdf"; + } + + private void LogDebug(string message, params object[] args) + { + _logger.Debug(message, args); + } + + private void LogWarn(string message, params object[] args) + { + _logger.Warn(message, args); + } + + private void LogError(Exception exception, string message, params object[] args) + { + _logger.Error(exception, message, args); + } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Lib/Misc/JobService.cs b/Common/VirtualPrinter.Agent.Lib/Misc/JobService.cs new file mode 100644 index 0000000..5a2d2ee --- /dev/null +++ b/Common/VirtualPrinter.Agent.Lib/Misc/JobService.cs @@ -0,0 +1,170 @@ +using System; +using System.IO; +using System.Printing; + +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core; + +namespace VirtualPrinter.Agent.Lib.Misc +{ + public class JobService : IJobService + { + [NotNull] + private readonly IRegistryRepository _registryRepository; + + [NotNull] + private readonly IJobFactory _jobFactory; + + [NotNull] + private readonly IShell _shell; + private IDirectoryHelper _directoryHelper; + + public JobService + ( + [NotNull]IRegistryRepository registryRepository, + [NotNull]IJobFactory jobFactory, + [NotNull]IShell shell, + [NotNull]IDirectoryHelper directoryHelper + ) + { + if (registryRepository == null) + { + throw new ArgumentNullException(nameof(registryRepository)); + } + + if (jobFactory == null) + { + throw new ArgumentNullException(nameof(jobFactory)); + } + + if (shell == null) + { + throw new ArgumentNullException(nameof(shell)); + } + + if (directoryHelper == null) + { + throw new ArgumentNullException(nameof(directoryHelper)); + } + + _registryRepository = registryRepository; + _jobFactory = jobFactory; + _shell = shell; + _directoryHelper = directoryHelper; + } + + public void Start(IJob job) + { + if (job == null) + { + throw new ArgumentNullException(nameof(job)); + } + + const PrintStatus status = PrintStatus.Paused; + + var iniFile = Path.GetFullPath(job.IniDataPath); + var config = _registryRepository.GetRegistryConfig(); + var pre = config.ResolvedPreconverter; + WriteJobStartIni(job, status); + + _shell.Execute(job.JobInfo, job.SessionInfo, pre.Item1, $"{pre.Item2} \"{iniFile}\""); + } + + public IJob CreateJob(string iniFile, string rawFile) + { + var jobInfo = GetJobInfo(iniFile); + + var sessionInfo = GetSessionInfo(iniFile); + + return _jobFactory.Create(iniFile, rawFile, jobInfo, sessionInfo); + } + + public PrintStatus ReadStatus(string iniPath) + { + var txt = _shell.ReadIniEntry("Preconverting", "Status", iniPath); + Enum.TryParse(txt, true, out PrintStatus result); + + return result; + } + + public JobStatus ReadJobStatus(string iniPath) + { + var status = _shell.ReadIniEntry("Job", "Status", iniPath); + Enum.TryParse(status, true, out JobStatus result); + return result; + } + + public void Finish(IJob job) + { + var config = _registryRepository.GetRegistryConfig(); + WriteJobFinishIni(job.IniDataPath, config); + var iniFile = Path.GetFullPath(job.IniDataPath); + var post = config.ResolvedPostconverter; + + _shell.Execute(job.JobInfo, job.SessionInfo, post.Item1, $"{post.Item2} \"{iniFile}\""); + } + + private void WriteJobStartIni([NotNull]IJob job, PrintStatus status) + { + _shell.WriteIniEntry("Job", "Status", JobStatus.InProgress.ToString().ToLowerInvariant(), job.IniDataPath); + _shell.WriteIniEntry("Device", "DeviceName", job.JobInfo.DeviceName, job.IniDataPath); + _shell.WriteIniEntry("Document", "Name", job.JobInfo.Name.Normalize(), job.IniDataPath); + _shell.WriteIniEntry("Document", "JobID", $"{job.JobInfo.JobId}", job.IniDataPath); + _shell.WriteIniEntry("Document", "DomainName", job.JobInfo.DomainName, job.IniDataPath); + _shell.WriteIniEntry("Document", "MachineName", job.JobInfo.MachineName, job.IniDataPath); + _shell.WriteIniEntry("Document", "UserName", job.JobInfo.UserName, job.IniDataPath); + _shell.WriteIniEntry("Document", "SessionID", $"{job.SessionInfo.Id}", job.IniDataPath); + _shell.WriteIniEntry("Document", "Desktop", $"{job.SessionInfo.Desktop}", job.IniDataPath); + _shell.WriteIniEntry("Document", "SID", $"{job.SessionInfo.Sid}", job.IniDataPath); + _shell.WriteIniEntry("Document", "Status", job.JobInfo.Status.ToString(), job.IniDataPath); + _shell.WriteIniEntry("Preconverting", "Status", status.ToIni(), job.IniDataPath); + } + + private SessionInfo GetSessionInfo(string iniFile) + { + var sessionInfo = new SessionInfo + { + Id = _shell.ReadIniEntry("Document", + "SessionID", + iniFile), + Sid = _shell.ReadIniEntry("Document", "SID", iniFile), + Desktop = _shell.ReadIniEntry("Document", "Desktop", iniFile) + }; + return sessionInfo; + } + + private JobInfo GetJobInfo(string iniFile) + { + var jobInfo = new JobInfo + { + DomainName = _shell.ReadIniEntry("Document", + "DomainName", + iniFile), + MachineName = _shell.ReadIniEntry("Document", + "MachineName", + iniFile), + UserName = _shell.ReadIniEntry("Document", + "UserName", + iniFile) + }; + return jobInfo; + } + + private void WriteJobFinishIni(string iniPath, [NotNull]IExConfig config) + { + const PrintStatus status = PrintStatus.Complete; + const PrintJobStatus spoolerState = PrintJobStatus.Printed; + + _shell.WriteIniEntry("Preconverting", "Status", status.ToIni(), iniPath); + var pdfFile = Path.GetFileNameWithoutExtension(iniPath) + ".pdf"; + var tiffFile = Path.GetFileNameWithoutExtension(iniPath) + ".tif"; + var dir = _directoryHelper.GetOutputDirectory(config); + pdfFile = Path.Combine(dir, pdfFile); + tiffFile = Path.Combine(dir, tiffFile); + _shell.WriteIniEntry("PDF", "File0", pdfFile, iniPath); + _shell.WriteIniEntry("TIFF", "File0", tiffFile, iniPath); + _shell.WriteIniEntry("Document", "Status", spoolerState.ToString(), iniPath); + } + } +} diff --git a/Common/VirtualPrinter.Agent.Lib/Misc/VirtualTcpInputPrinter.cs b/Common/VirtualPrinter.Agent.Lib/Misc/VirtualTcpInputPrinter.cs new file mode 100644 index 0000000..3171753 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Lib/Misc/VirtualTcpInputPrinter.cs @@ -0,0 +1,276 @@ +using JetBrains.Annotations; +using System; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +using VirtualPrinter.Agent.Core; +using VirtualPrinter.Logging; +using VirtualPrinter.SetupDriver; + +namespace VirtualPrinter.Agent.Lib.Misc +{ + public class VirtualTcpInputPrinter : IVirtualPrinter + { + [NotNull] + private readonly IRegistryRepository _registryRepository; + + [NotNull] + private readonly IJobFactory _jobFactory; + + [NotNull] + private readonly IJobService _jobService; + + [NotNull] + private readonly IVirtualPrinterLogger _logger; + + [NotNull] + private readonly IJobProcessor _jobProcessor; + private IDirectoryHelper _directoryHelper; + private TcpListener _socket; + + private FileSystemWatcher _watcher; + + public VirtualTcpInputPrinter + ( + [NotNull]IRegistryRepository registryRepository, + [NotNull]IVirtualPrinterLogger logger, + [NotNull]IJobFactory jobFactory, + [NotNull]IJobService jobService, + [NotNull]IJobProcessor jobProcessor, + [NotNull]IDirectoryHelper directoryHelper + ) + { + _registryRepository = registryRepository; + _logger = logger; + _jobFactory = jobFactory; + _jobService = jobService; + _jobProcessor = jobProcessor; + _directoryHelper = directoryHelper; + } + + public void Dispose() + { + _watcher.Dispose(); + _socket.Stop(); + } + + public void Init() + { + var config = GetRegistryConfig(); + + var dir = _directoryHelper.GetOutputDirectory(config); + _watcher = new FileSystemWatcher(dir, "*.ini") + { + IncludeSubdirectories = false, + NotifyFilter = NotifyFilters.LastWrite, + EnableRaisingEvents = true + }; + _watcher.Changed += IniFileChanged; + _socket = new TcpListener(IPAddress.Loopback, config.PrinterPort); + _socket.Start(); + _socket.BeginAcceptTcpClient(HandleClient, _socket); + + LogDebug($"Waiting on {_socket.LocalEndpoint}..."); + } + + private void HandleClient([NotNull]IAsyncResult ar) + { + const string printer = Defaults.PrinterName; + IJob job; + + var socket = (TcpListener) ar.AsyncState; + using (var client = socket.EndAcceptTcpClient(ar)) + { + var local = client.Client.LocalEndPoint; + var remote = client.Client.RemoteEndPoint; + + LogDebug($"{remote} --> {local}"); + job = _jobFactory.Create(printer, client.GetStream()); + if (job == null) + { + LogError("Job could not be created."); + return; + } + } + + LogDebug($"Temporarily printed '{job.RawDataPath}'!"); + socket.BeginAcceptTcpClient(HandleClient, ar.AsyncState); + + _jobService.Start(job); + } + + private void IniFileChanged(object sender, [NotNull]FileSystemEventArgs e) + { + var ini = e.FullPath; + if (!ini.ToLowerInvariant().EndsWith(".ini")) + { + return; + } + + var rawName = $"{Path.GetFileNameWithoutExtension(ini)}.ps"; + var config = GetRegistryConfig(); + var dir = _directoryHelper.GetOutputDirectory(config); + var rawFile = Path.Combine(dir, rawName); + var status = _jobService.ReadStatus(ini); + + if (status == PrintStatus.Resumed) + { + var job = _jobService.CreateJob(ini, rawFile); + var isJobValid = IsJobValid(job); + + if (!isJobValid) + { + return; + } + + ProcessFile(rawFile, ini); + } + if (status == PrintStatus.Canceled) + { + DeleteFiles(ini, dir, rawFile); + } + + var jobStatus = _jobService.ReadJobStatus(ini); + if (jobStatus == JobStatus.Completed || jobStatus == JobStatus.Failed) + { + DeleteFiles(ini, dir, rawFile); + } + } + + private void DeleteFiles([NotNull]string ini, [NotNull]string outputDir, [NotNull]string rawFile) + { + if (string.IsNullOrWhiteSpace(ini)) + { + throw new ArgumentException("Value cannot be null or whitespace.", nameof(ini)); + } + + if (string.IsNullOrWhiteSpace(outputDir)) + { + throw new ArgumentException("Value cannot be null or whitespace.", nameof(outputDir)); + } + + if (string.IsNullOrWhiteSpace(rawFile)) + { + throw new ArgumentException("Value cannot be null or whitespace.", nameof(rawFile)); + } + + var pdfFile = Path.Combine(outputDir, $"{Path.GetFileNameWithoutExtension(ini)}.pdf"); + var tiffFile = Path.Combine(outputDir, $"{Path.GetFileNameWithoutExtension(ini)}.tif"); + + if (File.Exists(pdfFile) && !IsFileLocked(pdfFile)) + { + File.Delete(pdfFile); + } + + if (File.Exists(tiffFile) && !IsFileLocked(tiffFile)) + { + File.Delete(tiffFile); + } + + File.Delete(ini); + File.Delete(rawFile); + } + + private bool IsFileLocked(string filePath) + { + try + { + using(var stream = File.Open(filePath, FileMode.Open, FileAccess.Read)) + { + stream.Close(); + } + + return false; + } + catch (IOException) + { + return true; + } + } + + [NotNull] + private IExConfig GetRegistryConfig() + { + return _registryRepository.GetRegistryConfig(); + } + + private bool IsJobValid([CanBeNull]IJob job) + { + if (job == null) + { + return false; + } + + if (string.IsNullOrWhiteSpace(job.JobInfo.DomainName)) + { + return false; + } + + if (string.IsNullOrWhiteSpace(job.JobInfo.MachineName)) + { + return false; + } + + if (string.IsNullOrWhiteSpace(job.JobInfo.UserName)) + { + return false; + } + + if (string.IsNullOrWhiteSpace(job.SessionInfo.Sid)) + { + return false; + } + + return true; + } + + private void ProcessFile(string filePath, string iniFile) + { + var thread = new Thread(obj => + { + var tuple = (Tuple) obj; + var rawFile = tuple.Item1; + var ini = tuple.Item2; + + var job = _jobService.CreateJob(ini, + rawFile); + + try + { + var userConfig = _registryRepository.GetUserRegistryConfig(job.SessionInfo.Sid); + _jobProcessor.Process(job, userConfig); + + LogDebug($"Converted '{rawFile}'!"); + _jobService.Finish(job); + } + catch (Exception exception) + { + LogError(exception, + "Failed to process file. Job: {@job}", + job); + } + }); + + thread.SetApartmentState(ApartmentState.STA); + thread.Start(Tuple.Create(filePath, iniFile)); + } + + private void LogError(Exception exception, string message, params object[] args) + { + _logger.Error(exception, message, args); + } + + private void LogError(string message, params object[] args) + { + _logger.Error(message, args); + } + + private void LogDebug(string message, params object[] args) + { + _logger.Debug(message, args); + } + } +} diff --git a/Common/VirtualPrinter.Agent.Lib/Model/ProgressUpdateArgs.cs b/Common/VirtualPrinter.Agent.Lib/Model/ProgressUpdateArgs.cs new file mode 100644 index 0000000..8873d5d --- /dev/null +++ b/Common/VirtualPrinter.Agent.Lib/Model/ProgressUpdateArgs.cs @@ -0,0 +1,22 @@ +using System; + +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core.Interfaces; + +namespace VirtualPrinter.Agent.Lib.Model +{ + public class ProgressUpdateArgs : EventArgs + { + public ProgressUpdateArgs([NotNull] IJob job, uint val) + { + Job = job; + Value = val; + } + + [NotNull] + public IJob Job { get; } + + public uint Value { get; } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Lib/Properties/AssemblyInfo.cs b/Common/VirtualPrinter.Agent.Lib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..32c0d6b --- /dev/null +++ b/Common/VirtualPrinter.Agent.Lib/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; +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("VirtualPrinter.Agent.Lib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[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("3d3f946d-c8dc-4518-b464-75e73cbad734")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Common/VirtualPrinter.Agent.Lib/VirtualPrinter.Agent.Lib.csproj b/Common/VirtualPrinter.Agent.Lib/VirtualPrinter.Agent.Lib.csproj new file mode 100644 index 0000000..b9d426b --- /dev/null +++ b/Common/VirtualPrinter.Agent.Lib/VirtualPrinter.Agent.Lib.csproj @@ -0,0 +1,100 @@ + + + + + Debug + AnyCPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65} + Library + VirtualPrinter.Agent.Lib + VirtualPrinter.Agent.Lib + v4.6.1 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + none + true + ..\..\Files\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {74fa80b3-7cf1-4b68-8aa3-4c3d37bbe855} + VirtualPrinter.Delivery + + + {12402f90-a2ae-4549-9142-f90650e2082a} + VirtualPrinter.SetupDriver + + + {24d28558-c825-43e6-85d2-7c59f4a97698} + VirtualPrinter.ProgressInfo.Core + + + {135c85eb-2116-4cc4-8ccb-b6804b9d6467} + VirtualPrinter.Agent.Core + + + {AA25364D-22D5-44B0-86A5-6FB14C686308} + VirtualPrinter.Logging + + + {cd1c8e9d-5335-41ac-b0c0-88fd7c7c55f3} + VirtualPrinter.Utils + + + + + + + + + + + + \ No newline at end of file diff --git a/Common/VirtualPrinter.Agent.Lib/VirtualPrinterService.cs b/Common/VirtualPrinter.Agent.Lib/VirtualPrinterService.cs new file mode 100644 index 0000000..ba6f454 --- /dev/null +++ b/Common/VirtualPrinter.Agent.Lib/VirtualPrinterService.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core; + +namespace VirtualPrinter.Agent.Lib +{ + public class VirtualPrinterService : IVirtualPrinterService + { + [NotNull] + private readonly IVirtualPrinter _printer; + + public VirtualPrinterService([NotNull]IVirtualPrinter printer) + { + _printer = printer; + } + + public void Start() + { + _printer.Init(); + } + + public void Stop() + { + _printer.Dispose(); + } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Logging/IVirtualPrinterLogger.cs b/Common/VirtualPrinter.Logging/IVirtualPrinterLogger.cs new file mode 100644 index 0000000..586df3b --- /dev/null +++ b/Common/VirtualPrinter.Logging/IVirtualPrinterLogger.cs @@ -0,0 +1,81 @@ +using System; + +using JetBrains.Annotations; + +namespace VirtualPrinter.Logging +{ + // ReSharper disable once UnusedTypeParameter + public interface IVirtualPrinterLogger : IVirtualPrinterLogger + { } + + public interface IVirtualPrinterLogger + { + /// + /// Gets the name of the logger. + /// + string Name { get; } + + /// + /// A value of true if logging is enabled for the Debug level, otherwise it returns false. + /// + bool IsDebugEnabled { get; } + + /// + /// A value of true if logging is enabled for the Trace level, otherwise it returns false. + /// + bool IsTraceEnabled { get; } + + /// + /// Writes the exception at the Error level. + /// + /// An exception to be logged. + void Error([CanBeNull]Exception exception); + + /// + /// Writes the diagnostic message and exception at the Error level. + /// + /// An exception to be logged. + /// A to be written. + /// Arguments to format. + void Error([CanBeNull]Exception exception, [CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args); + + /// + /// Something failed; application may or may not continue + /// Writes the diagnostic message and exception at the Error level. + /// + /// A to be written. + /// Arguments to format. + void Error([CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args); + + /// + /// Something unexpected; application will continue + /// Writes the diagnostic message at the Warn level using the specified parameters. + /// + /// A containing format items. + /// Arguments to format. + void Warn([CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args); + + /// + /// Normal behavior like mail sent, user updated profile etc. + /// Writes the diagnostic message at the Info level using the specified parameters. + /// + /// A containing format items. + /// Arguments to format. + void Info([CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args); + + /// + /// For debugging; executed query, user authenticated, session expired + /// Writes the diagnostic message at the Debug level using the specified parameters. + /// + /// A containing format items. + /// Arguments to format. + void Debug([CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args); + + /// + /// Writes the diagnostic message at the Trace level using the specified parameters. + /// + /// A containing format items. + /// Arguments to format. + void Trace([CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args); + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Logging/LoggerModule.cs b/Common/VirtualPrinter.Logging/LoggerModule.cs new file mode 100644 index 0000000..7d1a8d8 --- /dev/null +++ b/Common/VirtualPrinter.Logging/LoggerModule.cs @@ -0,0 +1,17 @@ +using Autofac; +using Autofac.Extras.NLog; + +namespace VirtualPrinter.Logging +{ + public class LoggerModule : Module + { + protected override void Load(ContainerBuilder builder) + { + builder.RegisterModule(); + builder.RegisterInstance(NLog.LogManager.GetCurrentClassLogger()).As().SingleInstance(); + builder.RegisterGeneric(typeof(VirtualPrinterLogger<>)) + .As(typeof(IVirtualPrinterLogger<>)) + .SingleInstance(); + } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Logging/NLog.config b/Common/VirtualPrinter.Logging/NLog.config new file mode 100644 index 0000000..03668bc --- /dev/null +++ b/Common/VirtualPrinter.Logging/NLog.config @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Common/VirtualPrinter.Logging/Properties/AssemblyInfo.cs b/Common/VirtualPrinter.Logging/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..920390a --- /dev/null +++ b/Common/VirtualPrinter.Logging/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +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("VirtualPrinter.Logging")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[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("aa25364d-22d5-44b0-86a5-6fb14c686308")] + +// 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.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Common/VirtualPrinter.Logging/VirtualPrinter.Logging.csproj b/Common/VirtualPrinter.Logging/VirtualPrinter.Logging.csproj new file mode 100644 index 0000000..de82b49 --- /dev/null +++ b/Common/VirtualPrinter.Logging/VirtualPrinter.Logging.csproj @@ -0,0 +1,71 @@ + + + + + Debug + AnyCPU + {AA25364D-22D5-44B0-86A5-6FB14C686308} + Library + Properties + VirtualPrinter.Logging + VirtualPrinter.Logging + v4.6.1 + 512 + true + + + + true + full + false + bin\Debug + DEBUG;TRACE + prompt + 4 + + + none + true + ..\..\Files + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + + + + + + + + + \ No newline at end of file diff --git a/Common/VirtualPrinter.Logging/VirtualPrinterLogger.cs b/Common/VirtualPrinter.Logging/VirtualPrinterLogger.cs new file mode 100644 index 0000000..e5f8b33 --- /dev/null +++ b/Common/VirtualPrinter.Logging/VirtualPrinterLogger.cs @@ -0,0 +1,103 @@ +using System; +using System.CodeDom; +using System.CodeDom.Compiler; +using System.IO; + +using JetBrains.Annotations; + +using NLog; + +namespace VirtualPrinter.Logging +{ + public class VirtualPrinterLogger : VirtualPrinterLogger, IVirtualPrinterLogger + { + public VirtualPrinterLogger() : base(ReadableTypeName.Generate(typeof(T))) + { + } + } + + public static class ReadableTypeName + { + [NotNull] + public static string Generate([NotNull]Type type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + var provider = CodeDomProvider.CreateProvider("C#"); + var typeReferenceExpression = new CodeTypeReferenceExpression(type); + using (var writer = new StringWriter()) + { + provider.GenerateCodeFromExpression(typeReferenceExpression, writer, new CodeGeneratorOptions()); + return writer.GetStringBuilder().ToString(); + } + } + } + + public class VirtualPrinterLogger : IVirtualPrinterLogger + { + private readonly ILogger _logger; + + public VirtualPrinterLogger([NotNull]string loggerName) + { + if (string.IsNullOrWhiteSpace(loggerName)) + { + throw new ArgumentNullException(nameof(loggerName)); + } + + _logger = LogManager.GetLogger(loggerName); + } + + public string Name + { + get { return _logger.Name; } + } + + public bool IsDebugEnabled + { + get { return _logger.IsDebugEnabled; } + } + + public bool IsTraceEnabled + { + get { return _logger.IsTraceEnabled; } + } + + public void Error(Exception exception) + { + _logger.Error(exception); + } + + public void Error(Exception exception, string message, params object[] args) + { + _logger.Error(exception, message, args); + } + + public void Error(string message, params object[] args) + { + _logger.Error(message, args); + } + + public void Warn(string message, params object[] args) + { + _logger.Warn(message, args); + } + + public void Info(string message, params object[] args) + { + _logger.Info(message, args); + } + + public void Debug(string message, params object[] args) + { + _logger.Debug(message, args); + } + + public void Trace(string message, params object[] args) + { + _logger.Trace(message, args); + } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Utils/Consts.cs b/Common/VirtualPrinter.Utils/Consts.cs new file mode 100644 index 0000000..87b3d8d --- /dev/null +++ b/Common/VirtualPrinter.Utils/Consts.cs @@ -0,0 +1,51 @@ +namespace VirtualPrinter.Utils +{ + public struct Files + { + public const string FILES = @"Files"; + public const string PRINTER_SERVICE_EXE = "VPDAgent.exe"; + public const string SETUP_DRIVER_EXE = "setupdrv.exe"; + public const string AGENT_PROGRESS_EXE = "VPDAgentProgress.exe"; + public const string DILIVERY_EXE = "delivery.exe"; + public const string LICENCE_FILE = ""; + public const string PRE_CONVERTER = @"C:\Program Files (x86)\MyPreConverter.exe ARG"; + public const string POST_CONVERTER = @"C:\Program Files (x86)\MyPostConverter.exe ARG"; + } + + public struct Keys + { + public const string PRINTER_DRIVER_KEY32 = @"SOFTWARE\vpd\PrinterDriver"; + public const string PRINTER_DRIVER_KEY64 = @"SOFTWARE\Wow6432Node\vpd\PrinterDriver"; + public const string POSTCONVERTER_KEY = @"Application\Postconverter"; + public const string PRECONVERTER_KEY = @"Application\Preconverter"; + public const string CONVERTER_KEY = @"Converter"; + public const string CONVERTER_PDF_KEY = CONVERTER_KEY + @"\PDF"; + public const string CONVERTER_TIFF_KEY = CONVERTER_KEY + @"\TIFF"; + public const string CONVERTER_REDIRECT_KEY = CONVERTER_KEY + @"\Redirect"; + } + + public struct KeyNames + { + public const string EXECUTABLE_FILE = "Executable File"; + public const string INSTALLATION_DIR = "Installation Directory"; + public const string THREADS = "Threads"; + public const string SHOW_PROGRESS = "Show Progress"; + public const string PAGES_PER_SHEET = "Pages per Sheet"; + public const string FILE_NAME_MASK = "File name mask"; + public const string OUTPUT_DIR = "Output Directory"; + public const string ENABLED = "Enabled"; + public const string MULTIPAGE = "Multipage"; + public const string PRODUCE_PDFA = "Produce PDFA"; + public const string ALLOW_PRINTING = "Allow printing"; + public const string ALLOW_COPYING = "Allow printing"; + public const string SUBSETTING = "Subsetting"; + public const string QUALITY = "Image Quality"; + public const string BITS_PIXEL = "Bits per pixel"; + public const string COMPRESSION = "Compression"; + public const string SERVER_PORT = "Server port"; + public const string RENDER_DPI = "RENDER: DPI"; + public const string FORMAT = "Intermediate Format"; + public const string PRINT_FORMAT = "Format"; + public const string PRINTER = "Printer"; + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Utils/DirectoryHelper.cs b/Common/VirtualPrinter.Utils/DirectoryHelper.cs new file mode 100644 index 0000000..8923acb --- /dev/null +++ b/Common/VirtualPrinter.Utils/DirectoryHelper.cs @@ -0,0 +1,24 @@ +using System.IO; + +using VirtualPrinter.Agent.Core; + +namespace VirtualPrinter.Utils +{ + public class DirectoryHelper : IDirectoryHelper + { + public string GetOutputDirectory(IExConfig config) + { + if (string.IsNullOrWhiteSpace(config.ResolvedOutputDirectory)) + { + var outputDir = Path.Combine(Path.GetTempPath(), "PrinterOutput"); + if (!Directory.Exists(outputDir)) + { + Directory.CreateDirectory(outputDir); + } + return outputDir; + } + + return config.ResolvedOutputDirectory; + } + } +} diff --git a/Common/VirtualPrinter.Utils/Properties/AssemblyInfo.cs b/Common/VirtualPrinter.Utils/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f703c65 --- /dev/null +++ b/Common/VirtualPrinter.Utils/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +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("VirtualPrinter.Utils")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[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("cd1c8e9d-5335-41ac-b0c0-88fd7c7c55f3")] + +// 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.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Common/VirtualPrinter.Utils/RegistryRepository.cs b/Common/VirtualPrinter.Utils/RegistryRepository.cs new file mode 100644 index 0000000..0997146 --- /dev/null +++ b/Common/VirtualPrinter.Utils/RegistryRepository.cs @@ -0,0 +1,170 @@ +using System; +using System.IO; +using System.Linq; + +using JetBrains.Annotations; + +using Microsoft.Win32; + +using VirtualPrinter.Agent.Core; +using VirtualPrinter.Agent.Core.Enums; + +namespace VirtualPrinter.Utils +{ + public class RegistryRepository : IRegistryRepository + { + private const short DefaultServerPort = 9101; + + public bool TryGetGhostscriptPath(out string path) + { + path = null; + + try + { + var regView = GetRegistryView(); + + using(var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, regView)) + { + const string gsSubKey = @"SOFTWARE\GPL Ghostscript"; + using(var ghostscript = baseKey.OpenSubKey(gsSubKey)) + { + CheckForNull(ghostscript, gsSubKey); + var subKeys = ghostscript.GetSubKeyNames(); + + var lastSubKey = subKeys.Last(); + using(var subKey = ghostscript.OpenSubKey(lastSubKey)) + { + CheckForNull(subKey, lastSubKey); + path = subKey.GetValue("GS_LIB").ToString().Split(';').FirstOrDefault(); + + if (string.IsNullOrWhiteSpace(path)) + { + return false; + } + + path = Directory.GetParent(path).FullName; + return true; + } + } + } + } + catch (Exception exception) + { + Console.WriteLine(exception); + } + + return false; + } + + public IExConfig GetRegistryConfig() + { + var regView = GetRegistryView(); + var subKey = GetSubKey(); + var registryConfig = new RegistryConfig(); + + using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, regView)) + { + using (var driver = baseKey.OpenSubKey(subKey)) + { + CheckForNull(driver, subKey); + + using(var key = driver.OpenSubKey(Keys.POSTCONVERTER_KEY)) + { + CheckForNull(key, Keys.POSTCONVERTER_KEY); + registryConfig.Postconverter = key.GetValue(KeyNames.EXECUTABLE_FILE).ToString(); + } + + using(var key = driver.OpenSubKey(Keys.PRECONVERTER_KEY)) + { + CheckForNull(key, Keys.PRECONVERTER_KEY); + registryConfig.Preconverter = key.GetValue(KeyNames.EXECUTABLE_FILE).ToString(); + } + + using (var key = driver.OpenSubKey(Keys.CONVERTER_KEY)) + { + CheckForNull(key, Keys.CONVERTER_KEY); + registryConfig.OutputDirectory = key.GetValue(KeyNames.OUTPUT_DIR).ToString(); + registryConfig.FileNameMask = key.GetValue(KeyNames.FILE_NAME_MASK).ToString(); + var portStr = key.GetValue(KeyNames.SERVER_PORT).ToString(); + registryConfig.PrinterPort = short.TryParse(portStr, out var portVal) ? portVal : DefaultServerPort; + registryConfig.IntermediateFormat = key.GetValue(KeyNames.FORMAT)?.ToString().ToLower() == "ps" ? IntermediateFormat.Ps : IntermediateFormat.Xps; + } + } + } + + return registryConfig; + } + + [ContractAnnotation("key:null => void")] + private void CheckForNull(RegistryKey key, string keyName) + { + if (key == null) + { + throw new NullReferenceException(keyName); + } + } + + public IUserConfig GetUserRegistryConfig(string sid) + { + var regView = GetRegistryView(); + var userConfig = new UserRegistryConfig(); + + using (var users = RegistryKey.OpenBaseKey(RegistryHive.Users, regView)) + { + var subKey = $@"{sid}\{Keys.PRINTER_DRIVER_KEY32}"; + using (var driver = users.OpenSubKey(subKey)) + { + CheckForNull(driver, subKey); + + using (var converter = driver.OpenSubKey(Keys.CONVERTER_KEY)) + { + CheckForNull(converter, Keys.CONVERTER_KEY); + + subKey = "Redirect"; + using (var redirect = converter.OpenSubKey(subKey)) + { + CheckForNull(redirect, subKey); + + userConfig.RedirectEnabled = (int?) redirect.GetValue("Enabled") == 1; + userConfig.RedirectPrinter = redirect.GetValue("Printer").ToString(); + userConfig.Format = converter.GetValue("Format").ToString(); + + var dpiStr = (string)driver.GetValue("RENDER: DPI"); + if (dpiStr == null) + { + userConfig.UserRenderDpi = null; + } + else + { + userConfig.UserRenderDpi = double.TryParse(dpiStr, out var dpiVal) ? dpiVal : (double?) null; + } + } + } + } + } + + return userConfig; + } + + private RegistryView GetRegistryView() + { + if (Environment.Is64BitOperatingSystem) + { + return RegistryView.Registry64; + } + + return RegistryView.Registry32; + } + + [NotNull] + private string GetSubKey() + { + if (Environment.Is64BitOperatingSystem) + { + return Keys.PRINTER_DRIVER_KEY64; + } + + return Keys.PRINTER_DRIVER_KEY32; + } + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Utils/Shell.cs b/Common/VirtualPrinter.Utils/Shell.cs new file mode 100644 index 0000000..2c382fa --- /dev/null +++ b/Common/VirtualPrinter.Utils/Shell.cs @@ -0,0 +1,95 @@ +using System; +using System.IO; +using System.Text; +using System.Threading; + +using JetBrains.Annotations; + +using VirtualPrinter.Agent.Core; +using VirtualPrinter.Logging; + +namespace VirtualPrinter.Utils +{ + public class Shell : IShell + { + private readonly IVirtualPrinterLogger _logger = new VirtualPrinterLogger(); + + public void WriteIniEntry(string section, string key, string value, string iniFilePath) + { + Win32Sys.WritePrivateProfileString(section, key, value, iniFilePath); + } + + public T ReadIniEntry(string section, string key, string iniFilePath) + { + var buffer = new StringBuilder(64 * 1024); + Win32Sys.GetPrivateProfileString(section, key, string.Empty, buffer, buffer.Capacity, iniFilePath); + var value = buffer.ToString().Trim(); + return (T)Convert.ChangeType(value, typeof(T)); + } + + public void Execute(IJobInfo job, ISessionInfo session, string exe, string args) + { + var thr = new Thread + ( + () => + { + try + { + if (!File.Exists(exe)) + throw new FileNotFoundException(exe); +#if DEBUG + System.Diagnostics.Process.Start(exe, args); +#else + StartProcessAsUser(job, session, exe, args); +#endif + } + catch (Exception exception) + { + LogError(exception, "Failed to create process"); + } + } + ); + + thr.Start(); + } + + public bool FileExists(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + throw new ArgumentException("The path may not be null or empty."); + } + + return File.Exists(path); + } + + private void StartProcessAsUser([NotNull]IJobInfo job, [NotNull]ISessionInfo session, string exe, string args) + { + if (job == null) + { + throw new ArgumentNullException(nameof(job)); + } + + if (session == null) + { + throw new ArgumentNullException(nameof(session)); + } + + var cmd = $@"""{exe}"" {args}"; + var id = session.Id; + var user = job.MachineName.TrimStart('\\') + '\\' + job.UserName; + LogDebug($"Executing '{cmd}' for '{user}' ({id})..."); + Win32Sys.CreateProcessAsUser(id, user, cmd); + } + + private void LogDebug(string message, params object[] args) + { + _logger.Debug(message, args); + } + + private void LogError(Exception exception, string message, params object[] args) + { + _logger.Error(exception, message, args); + } + } +} diff --git a/Common/VirtualPrinter.Utils/VirtualPrinter.Utils.csproj b/Common/VirtualPrinter.Utils/VirtualPrinter.Utils.csproj new file mode 100644 index 0000000..de789fc --- /dev/null +++ b/Common/VirtualPrinter.Utils/VirtualPrinter.Utils.csproj @@ -0,0 +1,69 @@ + + + + + Debug + AnyCPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3} + Library + Properties + VirtualPrinter.Utils + VirtualPrinter.Utils + v4.6.1 + 512 + true + + + true + full + false + bin\Debug + DEBUG;TRACE + prompt + 4 + + + none + true + ..\..\Files\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + {135C85EB-2116-4CC4-8CCB-B6804B9D6467} + VirtualPrinter.Agent.Core + + + {AA25364D-22D5-44B0-86A5-6FB14C686308} + VirtualPrinter.Logging + + + + + + + + + \ No newline at end of file diff --git a/Common/VirtualPrinter.Utils/Win32Sys.cs b/Common/VirtualPrinter.Utils/Win32Sys.cs new file mode 100644 index 0000000..07573af --- /dev/null +++ b/Common/VirtualPrinter.Utils/Win32Sys.cs @@ -0,0 +1,239 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; + +using JetBrains.Annotations; + +using Microsoft.Win32.SafeHandles; + +namespace VirtualPrinter.Utils +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + [SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Global")] + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] + internal static class Win32Sys + { + /// + /// Creates process with given command line via Win32 API. + /// Use this method to start a process as a service. + /// + /// + /// + /// + internal static void CreateProcessAsUser(int sessId, string user, string commandLine) + { + WTSQueryUserToken((uint) sessId, out var userToken); + if (userToken.IsInvalid) + { + throw new InvalidOperationException($"Could not query user token for session {sessId}! (" + GetLastError() + ")", + Windows.LastError); + } + + CreateProcessAsUser(userToken, user, commandLine); + } + + private static void CreateProcessAsUser([NotNull]SafeTokenHandle token, string user, string commandLine) + { + var processInformation = new PROCESS_INFORMATION(); + try + { + var securityAttributes = new SECURITY_ATTRIBUTES(); + securityAttributes.Length = Marshal.SizeOf(securityAttributes); + + var startupInfo = new STARTUPINFO(); + startupInfo.cb = Marshal.SizeOf(startupInfo); + startupInfo.lpDesktop = "winsta0\\default"; + + var info = new ProfileInfo(); + info.dwSize = Marshal.SizeOf(info); + info.lpUserName = user; + info.dwFlags = 1; + + var result = LoadUserProfile(token, ref info); + if (!result) + { + throw Windows.LastError; + } + + result = CreateEnvironmentBlock(out var lpEnvironment, token, false); + if (!result) + { + throw Windows.LastError; + } + + result = CreateProcessAsUser + ( + token, + null, + commandLine, + ref securityAttributes, + ref securityAttributes, + false, + 0x00000400, + lpEnvironment, + null, + ref startupInfo, + ref processInformation + ); + + if (!result) + { + throw Windows.LastError; + } + } + finally + { + if (processInformation.hProcess != IntPtr.Zero) + { + CloseMyHandle(processInformation.hProcess); + } + + if (processInformation.hThread != IntPtr.Zero) + { + CloseMyHandle(processInformation.hThread); + } + + if (!token.IsInvalid) + { + token.Dispose(); + } + } + } + + #region Classes + + public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid + { + private SafeTokenHandle() : base(true) + { + } + + [DllImport("kernel32.dll")] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [SuppressUnmanagedCodeSecurity] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool CloseHandle(IntPtr handle); + + protected override bool ReleaseHandle() + { + return CloseHandle(handle); + } + + public override string ToString() + { + return $"{handle}"; + } + } + + #endregion + + #region Structures + + [StructLayout(LayoutKind.Sequential)] + public struct PROCESS_INFORMATION + { + public IntPtr hProcess; + public IntPtr hThread; + public int dwProcessID; + public int dwThreadID; + } + + [StructLayout(LayoutKind.Sequential)] + public struct STARTUPINFO + { + public int cb; + public string lpReserved; + public string lpDesktop; + public string lpTitle; + public int dwX; + public int dwY; + public int dwXSize; + public int dwXCountChars; + public int dwYCountChars; + public int dwFillAttribute; + public int dwFlags; + public short wShowWindow; + public short cbReserved2; + public IntPtr lpReserved2; + public IntPtr hStdInput; + public IntPtr hStdOutput; + public IntPtr hStdError; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ProfileInfo + { + public int dwSize; + public int dwFlags; + public string lpUserName; + public string lpProfilePath; + public string lpDefaultPath; + public string lpServerName; + public string lpPolicyPath; + public IntPtr hProfile; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SECURITY_ATTRIBUTES + { + public int Length; + public IntPtr lpSecurityDescriptor; + public bool bInheritHandle; + } + + #endregion + + #region Windows interop + + [DllImport("userenv.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern bool LoadUserProfile(SafeTokenHandle hToken, ref ProfileInfo lpProfileInfo); + + [DllImport("userenv.dll", SetLastError = true)] + private static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, + SafeTokenHandle hToken, bool bInherit); + + [DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true, + CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] + private static extern bool CloseMyHandle(IntPtr handle); + + [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, + CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + private static extern bool CreateProcessAsUser(SafeTokenHandle hToken, + string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, + ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, + int dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, + ref STARTUPINFO lpStartupInfo, ref PROCESS_INFORMATION lpProcessInformation); + + [DllImport("wtsapi32.dll", SetLastError = true)] + private static extern bool WTSQueryUserToken(uint sessionId, out SafeTokenHandle Token); + + [DllImport("kernel32.dll")] + public static extern uint GetLastError(); + + [DllImport("kernel32")] + public static extern int GetPrivateProfileString + ( + string section, + string key, + string def, + StringBuilder retVal, + int size, + string filePath + ); + + [DllImport("kernel32")] + public static extern long WritePrivateProfileString + ( + string section, + string key, + string val, + string filePath + ); + + #endregion + } +} \ No newline at end of file diff --git a/Common/VirtualPrinter.Utils/Windows.cs b/Common/VirtualPrinter.Utils/Windows.cs new file mode 100644 index 0000000..8a6e6b3 --- /dev/null +++ b/Common/VirtualPrinter.Utils/Windows.cs @@ -0,0 +1,14 @@ +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +using JetBrains.Annotations; + +namespace VirtualPrinter.Utils +{ + public class Windows + { + [NotNull] + public static Exception LastError => new Win32Exception(Marshal.GetLastWin32Error()); + } +} diff --git a/Installer/VirtualPrinter.SetupDriver/Defaults.cs b/Installer/VirtualPrinter.SetupDriver/Defaults.cs new file mode 100644 index 0000000..6db7cab --- /dev/null +++ b/Installer/VirtualPrinter.SetupDriver/Defaults.cs @@ -0,0 +1,15 @@ +namespace VirtualPrinter.SetupDriver +{ + public static class Defaults + { + /// + /// The name that appears in the Windows "Printer & Scanner" menu. + /// + public const string PrinterName = "AMAGNO"; + + /// + /// The printer port. + /// + public const string PrinterPort = "IP_VIRT_PRINTER"; + } +} \ No newline at end of file diff --git a/Installer/VirtualPrinter.SetupDriver/Program.cs b/Installer/VirtualPrinter.SetupDriver/Program.cs new file mode 100644 index 0000000..6feeb22 --- /dev/null +++ b/Installer/VirtualPrinter.SetupDriver/Program.cs @@ -0,0 +1,125 @@ +using System; +using System.IO; + +using JetBrains.Annotations; + +using VirtualPrinter.Logging; +using VirtualPrinter.Utils; + +using static VirtualPrinter.SetupDriver.Windows; +using static VirtualPrinter.SetupDriver.Defaults; + +namespace VirtualPrinter.SetupDriver +{ + internal class Program + { + private const string InstallCmd = "install"; + private const string TestCmd = "test"; + private const string ConfigCmd = "config"; + private const string UninstallCmd = "uninstall"; + + private static readonly IVirtualPrinterLogger Logger = new VirtualPrinterLogger(); + + private static void Main([CanBeNull]string[] args) + { + if (args == null || args.Length < 1) + { + NotUseful(); + return; + } + + switch (args[0]) + { + case InstallCmd: + { + if (args.Length < 2) + { + NotUseful(); + return; + } + + switch (args[1].ToLower()) + { + case "xps": + try + { + AddPrinterPort(PrinterPort, "127.0.0.1", 9101); + var isWin7 = Environment.OSVersion.VersionString.Contains("NT 6.1."); + AddPrinter(PrinterName, "Microsoft XPS Document Writer" + (isWin7 ? string.Empty : " v4"), PrinterPort); + } + catch (Exception exception) + { + LogError(exception, "Failed to add xps printer."); + } + break; + case "ps": + try + { + AddPrinterPort(PrinterPort, "127.0.0.1", 9101); + new RegistryRepository().TryGetGhostscriptPath(out var ghostScriptPath); + if (ghostScriptPath == null) + { + throw new ArgumentNullException(nameof(ghostScriptPath), "Ghostscript path could not be found."); + } + + AddPrinter(PrinterName, "Ghostscript PDF", PrinterPort, Path.Combine(ghostScriptPath, @"lib\ghostpdf.inf")); + } + catch (Exception exception) + { + LogError(exception, "Failed to add ps printer."); + } + break; + default: + NotUseful(); + return; + } + + break; + } + case TestCmd: { + TestPrinter(PrinterName); + break; + } + case ConfigCmd: { + try + { + ConfigPrinter(PrinterName); + } + catch (Exception exception) + { + LogError(exception, "Failed to configurate printer {printerName}.", PrinterName); + } + break; + } + case UninstallCmd: { + try + { + DelPrinter(PrinterName); + DelPrinterPort(PrinterPort); + } + catch (Exception exception) + { + LogError(exception, "Failed to uninstall {printerName} on port {printerPort}.", PrinterName, PrinterPort); + } + break; + } + default: { + NotUseful(); + break; + } + } + } + + private static void NotUseful() + { + var exception = new ArgumentNullException($"Use '{InstallCmd} [PS|XPS]', '{TestCmd}' or '{UninstallCmd}'!"); + LogError(exception, "Failed to handle the arguments."); + throw exception; + } + + private static void LogError(Exception exception, string message, params object[] args) + { + Logger.Error(exception, message, args); + } + } +} \ No newline at end of file diff --git a/Installer/VirtualPrinter.SetupDriver/Properties/AssemblyInfo.cs b/Installer/VirtualPrinter.SetupDriver/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f1ec056 --- /dev/null +++ b/Installer/VirtualPrinter.SetupDriver/Properties/AssemblyInfo.cs @@ -0,0 +1,21 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("VirtualPrinter.SetupDriver")] +[assembly: AssemblyDescription("The setup for the virtual printer driver")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("12402f90-a2ae-4549-9142-f90650e2082a")] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("properties")] \ No newline at end of file diff --git a/Installer/VirtualPrinter.SetupDriver/Shell.cs b/Installer/VirtualPrinter.SetupDriver/Shell.cs new file mode 100644 index 0000000..00b3f04 --- /dev/null +++ b/Installer/VirtualPrinter.SetupDriver/Shell.cs @@ -0,0 +1,84 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; + +using JetBrains.Annotations; + +using VirtualPrinter.Logging; + +namespace VirtualPrinter.SetupDriver +{ + internal class Shell + { + private static readonly string WinFolder; + + private static readonly IVirtualPrinterLogger Logger = new VirtualPrinterLogger(); + + static Shell() + { + WinFolder = Environment.GetEnvironmentVariable("windir") ?? @"C:\Windows"; + } + + [NotNull] + internal static string GetPrintInf() + { + try + { + var winFolder = Environment.GetEnvironmentVariable("windir") ?? @"C:\Windows"; + return Path.Combine(winFolder, "inf", "ntprint.inf"); + } + catch (Exception exception) + { + LogError(exception, "Cannot get PrintInf"); + throw; + } + } + + [NotNull] + internal static string GetPrintVbs() + { + try + { + var printScripts = Path.Combine(WinFolder, "System32", "Printing_Admin_Scripts"); + return Directory.GetFiles(printScripts, "*port.vbs", SearchOption.AllDirectories).First(); + } + catch (Exception exception) + { + LogError(exception, "Cannot get PrintVbs"); + throw; + } + } + + internal static void Execute([NotNull]string exe, [NotNull]string args) + { + if (exe == null) + { + throw new ArgumentNullException(nameof(exe)); + } + + if (args == null) + { + throw new ArgumentNullException(nameof(args)); + } + + try + { + Console.WriteLine(exe + " " + args); + using(var proc = Process.Start(exe, args)) + { + proc?.WaitForExit(); + } + } + catch (Exception exception) + { + LogError(exception, "Cannot execute {exe} with the following args: {args}", exe, args); + } + } + + private static void LogError(Exception exception, string message, params object[] args) + { + Logger.Error(exception, message, args); + } + } +} \ No newline at end of file diff --git a/Installer/VirtualPrinter.SetupDriver/VirtualPrinter.SetupDriver.csproj b/Installer/VirtualPrinter.SetupDriver/VirtualPrinter.SetupDriver.csproj new file mode 100644 index 0000000..6d6c303 --- /dev/null +++ b/Installer/VirtualPrinter.SetupDriver/VirtualPrinter.SetupDriver.csproj @@ -0,0 +1,62 @@ + + + + + Debug + AnyCPU + {12402F90-A2AE-4549-9142-F90650E2082A} + Exe + VirtualPrinter.SetupDriver + setupdrv + v4.6.1 + 512 + true + + + AnyCPU + true + full + false + bin\Debug + DEBUG;TRACE + prompt + 4 + + + AnyCPU + none + true + ..\..\Files\ + TRACE + prompt + 4 + + + VirtualPrinter.SetupDriver.Program + + + + + + + + + + + + + + + {aa25364d-22d5-44b0-86a5-6fb14c686308} + VirtualPrinter.Logging + + + {cd1c8e9d-5335-41ac-b0c0-88fd7c7c55f3} + VirtualPrinter.Utils + + + + + + + \ No newline at end of file diff --git a/Installer/VirtualPrinter.SetupDriver/Windows.cs b/Installer/VirtualPrinter.SetupDriver/Windows.cs new file mode 100644 index 0000000..e710c95 --- /dev/null +++ b/Installer/VirtualPrinter.SetupDriver/Windows.cs @@ -0,0 +1,93 @@ +using System; + +using JetBrains.Annotations; + +namespace VirtualPrinter.SetupDriver +{ + internal static class Windows + { + public static void AddPrinter([NotNull]string name, [NotNull]string model, [NotNull]string port, [CanBeNull]string driver = null) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + + if (port == null) + { + throw new ArgumentNullException(nameof(port)); + } + + driver = driver ?? Shell.GetPrintInf(); + var args = $@"printui.dll,PrintUIEntry /if /b ""{name}"" /f ""{driver}"" /r ""{port}"" /m ""{model}"" /u"; + Shell.Execute("rundll32", args); + } + + public static void TestPrinter([NotNull]string name) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + var args = $@"printui.dll,PrintUIEntry /k /n ""{name}"""; + Shell.Execute("rundll32", args); + } + + public static void ConfigPrinter([NotNull]string name) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + var args = $@"printui.dll,PrintUIEntry /e /n ""{name}"""; + Shell.Execute("rundll32", args); + } + + public static void DelPrinter([NotNull]string name) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + var args = $@"printui.dll,PrintUIEntry /dl /n ""{name}"""; + Shell.Execute("rundll32", args); + } + + public static void AddPrinterPort([NotNull]string name, [NotNull]string ip, int port, [CanBeNull]string vbs = null) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + if (ip == null) + { + throw new ArgumentNullException(nameof(ip)); + } + + vbs = vbs ?? Shell.GetPrintVbs(); + var args = $@"""{vbs}"" -a -r {name} -h {ip} -o raw -n {port}"; + Shell.Execute("cscript", args); + } + + public static void DelPrinterPort([NotNull]string name, [CanBeNull]string vbs = null) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + vbs = vbs ?? Shell.GetPrintVbs(); + var args = $@"""{vbs}"" -d -r {name}"; + Shell.Execute("cscript", args); + } + } +} \ No newline at end of file diff --git a/Installer/VirtualPrinter.WixSharpInstaller/Properties/AssemblyInfo.cs b/Installer/VirtualPrinter.WixSharpInstaller/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..160acef --- /dev/null +++ b/Installer/VirtualPrinter.WixSharpInstaller/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +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("VirtualPrinter.WixSharpInstaller")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[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("a668846e-54c7-483d-9cf7-48f77ea398ca")] + +// 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.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Installer/VirtualPrinter.WixSharpInstaller/Script.cs b/Installer/VirtualPrinter.WixSharpInstaller/Script.cs new file mode 100644 index 0000000..9c5f609 --- /dev/null +++ b/Installer/VirtualPrinter.WixSharpInstaller/Script.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +// ReSharper disable once RedundantUsingDirective +using System.Diagnostics; +using System.IO; +using System.Linq; + +using JetBrains.Annotations; + +using VirtualPrinter.Utils; + +using WixSharp; + +using Action = WixSharp.Action; +using File = WixSharp.File; +using Files = VirtualPrinter.Utils.Files; +using RegistryHive = WixSharp.RegistryHive; + +namespace VirtualPrinter.WixSharpInstaller +{ + public class Script + { + private static string _filesDir; + const string SetupDriverId = "setupdrv_exe"; + + public static void Main([NotNull]string[] args) + { + var workingDir = ""; + if (args.Length > 0) + { + foreach(var cmd in args) + { + if (cmd.Contains(@"/p:")) + { + workingDir = cmd.Remove(0, 3); + Console.WriteLine(workingDir); + } + } + } + + if (workingDir.IsNullOrEmpty()) + { + throw new ArgumentException("Argument for working directory (/p) not set."); + } + + _filesDir = Path.Combine(workingDir, Files.FILES); + var feature = new Feature("VPD"); + var printerServiceFile = new File(feature, Path.Combine(_filesDir, Files.PRINTER_SERVICE_EXE)) + { + ServiceInstaller = new ServiceInstaller + { + Name = "VirtualPrinterService", + StartOn = SvcEvent.Install_Wait, + StopOn = SvcEvent.InstallUninstall_Wait, + RemoveOn = SvcEvent.Uninstall_Wait, + ErrorControl = SvcErrorControl.normal, + ConfigureServiceTrigger = ConfigureServiceTrigger.None + } + }; + + var project = new ManagedProject("VPDInstaller") + { + Name = "Virtual Printer Driver", + GUID = new Guid("8712D2CD-A9F6-456F-99C8-92C2BB070596"), + UpgradeCode = new Guid("0B37A935-EDEC-4ACA-9307-6D8299496C1D"), + UI = WUI.WixUI_InstallDir, + Version = Version.Parse(FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).FileVersion), + LicenceFile = Files.LICENCE_FILE, + Dirs = CreateProjectDirs(feature, printerServiceFile), + Actions = CreateActions(), + RegValues = CreateRegValues(feature).ToArray(), + InstallPrivileges = InstallPrivileges.elevated + }; + + project.BuildMsi(); + } + + [NotNull, ItemNotNull] + private static Dir[] CreateProjectDirs + ( + Feature feature, + File printerServiceFile + ) + { + return new[] + { + new Dir + ( + @"%ProgramFiles%\MyPrinterDriver\", + new DirFiles(feature, _filesDir + @"\*", s => !s.EndsWith(".exe")), + new File(new Id(SetupDriverId), feature, Path.Combine(_filesDir, Files.SETUP_DRIVER_EXE)), + new File(feature, Path.Combine(_filesDir, Files.DILIVERY_EXE)), + new File(feature, Path.Combine(_filesDir, Files.AGENT_PROGRESS_EXE)), + printerServiceFile + ) + }; + } + + [NotNull, ItemNotNull] + private static Action[] CreateActions() + { + return new Action[] + { + new InstalledFileAction(SetupDriverId, "install ps", Return.check, When.After, Step.InstallFinalize, Condition.NOT_Installed), + new InstalledFileAction(SetupDriverId, "uninstall", Return.check, When.Before, Step.RemoveFiles, Condition.BeingUninstalled) + }; + } + + [NotNull] + private static IEnumerable CreateRegValues(Feature feature) + { + var converterKey = $@"{Keys.PRINTER_DRIVER_KEY32}\{Keys.CONVERTER_KEY}"; + + var regValues = new List(); + regValues.AddRange(CreateLocalMachineValues(feature, converterKey)); + regValues.AddRange(CreateCurrentUserValues(feature, converterKey)); + + return regValues; + } + + [NotNull] + private static IEnumerable CreateLocalMachineValues(Feature feature, string converterKey) + { + var postConverterKey = $@"{Keys.PRINTER_DRIVER_KEY32}\{Keys.POSTCONVERTER_KEY}"; + var preConverterKey = $@"{Keys.PRINTER_DRIVER_KEY32}\{Keys.PRECONVERTER_KEY}"; + var converterPdfKey = $@"{Keys.PRINTER_DRIVER_KEY32}\{Keys.CONVERTER_PDF_KEY}"; + var converterTiffKey = $@"{Keys.PRINTER_DRIVER_KEY32}\{Keys.CONVERTER_TIFF_KEY}"; + var registryHive = RegistryHive.LocalMachine; + + return new List + { + new RegValue(feature, registryHive, Keys.PRINTER_DRIVER_KEY32, KeyNames.INSTALLATION_DIR, "[INSTALLDIR]"), + new RegValue(feature, registryHive, postConverterKey, KeyNames.EXECUTABLE_FILE, Files.POST_CONVERTER), + new RegValue(feature, registryHive, preConverterKey, KeyNames.EXECUTABLE_FILE, Files.PRE_CONVERTER), + new RegValue(feature, registryHive, converterKey, KeyNames.SERVER_PORT, 9101) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, converterKey, KeyNames.THREADS, 2), + new RegValue(feature, registryHive, converterKey, KeyNames.SHOW_PROGRESS, 1) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, converterKey, KeyNames.PAGES_PER_SHEET, 1), + new RegValue(feature, registryHive, converterKey, KeyNames.FILE_NAME_MASK, "{yyyy}{MM}{DD}{hh}{mm}{ss}{job05}{page03}"), + new RegValue(feature, registryHive, converterKey, KeyNames.OUTPUT_DIR, string.Empty), + new RegValue(feature, registryHive, converterKey, KeyNames.FORMAT, "ps"), + new RegValue(feature, registryHive, converterPdfKey, KeyNames.ENABLED, 1) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, converterPdfKey, KeyNames.MULTIPAGE, 1) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, converterPdfKey, KeyNames.PRODUCE_PDFA, 1) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, converterPdfKey, KeyNames.ALLOW_COPYING, 1) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, converterPdfKey, KeyNames.ALLOW_PRINTING, 1) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, converterPdfKey, KeyNames.SUBSETTING, 1) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, converterPdfKey,KeyNames.QUALITY , 80), + new RegValue(feature, registryHive, converterTiffKey, KeyNames.ENABLED, 1) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, converterTiffKey, KeyNames.BITS_PIXEL, 24), + new RegValue(feature, registryHive, converterTiffKey, KeyNames.MULTIPAGE, 1) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, converterTiffKey, KeyNames.COMPRESSION, 8) + }; + } + + [NotNull] + private static IEnumerable CreateCurrentUserValues(Feature feature, string converterKey) + { + var redirectKey = $@"{Keys.PRINTER_DRIVER_KEY32}\{Keys.CONVERTER_REDIRECT_KEY}"; + var registryHive = RegistryHive.CurrentUser; + + return new List + { + new RegValue(feature, registryHive, converterKey, KeyNames.PRINT_FORMAT, "PDF"), + new RegValue(feature, registryHive, converterKey, KeyNames.RENDER_DPI, 300) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, redirectKey, KeyNames.ENABLED, 1) {AttributesDefinition = "Type=integer"}, + new RegValue(feature, registryHive, redirectKey, KeyNames.PRINTER, "") + }; + } + } +} diff --git a/Installer/VirtualPrinter.WixSharpInstaller/VirtualPrinter.WixSharpInstaller.csproj b/Installer/VirtualPrinter.WixSharpInstaller/VirtualPrinter.WixSharpInstaller.csproj new file mode 100644 index 0000000..422a157 --- /dev/null +++ b/Installer/VirtualPrinter.WixSharpInstaller/VirtualPrinter.WixSharpInstaller.csproj @@ -0,0 +1,69 @@ + + + + + Debug + AnyCPU + {A668846E-54C7-483D-9CF7-48F77EA398CA} + Exe + Properties + VirtualPrinter.WixSharpInstaller + VPDInstaller + 512 + true + + + v4.6.1 + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + none + true + ..\..\Files\ + TRACE + prompt + 4 + + + VirtualPrinter.WixSharpInstaller.Script + + + true + + + + + + + + + {cd1c8e9d-5335-41ac-b0c0-88fd7c7c55f3} + VirtualPrinter.Utils + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Installer/VirtualPrinter.WixSharpInstaller/app.config b/Installer/VirtualPrinter.WixSharpInstaller/app.config new file mode 100644 index 0000000..3dbff35 --- /dev/null +++ b/Installer/VirtualPrinter.WixSharpInstaller/app.config @@ -0,0 +1,3 @@ + + + diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000..8ba0e1f --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Autofac/ProgressInfoModule.cs b/UI/VirtualPrinter.ProgressInfo.Autofac/ProgressInfoModule.cs new file mode 100644 index 0000000..4bd0e0a --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Autofac/ProgressInfoModule.cs @@ -0,0 +1,23 @@ +using Autofac; + +using VirtualPrinter.ProgressInfo.Core; +using VirtualPrinter.ProgressInfo.Core.Message; +using VirtualPrinter.ProgressInfo.Lib; +using VirtualPrinter.ProgressInfo.Lib.Interfaces; +using VirtualPrinter.ProgressInfo.Lib.Message; + +namespace VirtualPrinter.ProgressInfo.Autofac +{ + public class ProgressInfoModule : Module + { + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); + builder.RegisterType(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + } + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Autofac/Properties/AssemblyInfo.cs b/UI/VirtualPrinter.ProgressInfo.Autofac/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..789d2f6 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Autofac/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("VirtualPrinter.ProgressInfo.Autofac")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("17e2cf8a-462c-4130-9faf-f1ca5fc4e06d")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// indem Sie "*" wie unten gezeigt eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Autofac/VirtualPrinter.ProgressInfo.Autofac.csproj b/UI/VirtualPrinter.ProgressInfo.Autofac/VirtualPrinter.ProgressInfo.Autofac.csproj new file mode 100644 index 0000000..2699df6 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Autofac/VirtualPrinter.ProgressInfo.Autofac.csproj @@ -0,0 +1,65 @@ + + + + + Debug + AnyCPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D} + Library + Properties + VirtualPrinter.ProgressInfo.Autofac + VirtualPrinter.ProgressInfo.Autofac + v4.6.1 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + none + true + ..\..\Files\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + {24D28558-C825-43E6-85D2-7C59F4A97698} + VirtualPrinter.ProgressInfo.Core + + + {d66f55e5-b3f7-4c61-a4f2-b55c4d412e01} + VirtualPrinter.ProgressInfo.Lib + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Core/IProgressInfo.cs b/UI/VirtualPrinter.ProgressInfo.Core/IProgressInfo.cs new file mode 100644 index 0000000..56badf6 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Core/IProgressInfo.cs @@ -0,0 +1,11 @@ +using VirtualPrinter.Agent.Core; + +namespace VirtualPrinter.ProgressInfo.Core +{ + public interface IProgressInfo + { + void Progress(IJob job, uint val); + void Initialize(IJob job); + void Finish(IJob job); + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Core/Message/IFinal.cs b/UI/VirtualPrinter.ProgressInfo.Core/Message/IFinal.cs new file mode 100644 index 0000000..23ea47a --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Core/Message/IFinal.cs @@ -0,0 +1,6 @@ +namespace VirtualPrinter.ProgressInfo.Core.Message +{ + public interface IFinal : IMessage + { + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Core/Message/IMessage.cs b/UI/VirtualPrinter.ProgressInfo.Core/Message/IMessage.cs new file mode 100644 index 0000000..0330376 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Core/Message/IMessage.cs @@ -0,0 +1,6 @@ +namespace VirtualPrinter.ProgressInfo.Core.Message +{ + public interface IMessage + { + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Core/Message/IMessageFactory.cs b/UI/VirtualPrinter.ProgressInfo.Core/Message/IMessageFactory.cs new file mode 100644 index 0000000..4980332 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Core/Message/IMessageFactory.cs @@ -0,0 +1,16 @@ +using JetBrains.Annotations; + +namespace VirtualPrinter.ProgressInfo.Core.Message +{ + public interface IMessageFactory + { + [NotNull] + Message CreateStart(); + + [NotNull] + Message CreateStep(uint val); + + [NotNull] + Message CreateFinal(); + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Core/Message/IStart.cs b/UI/VirtualPrinter.ProgressInfo.Core/Message/IStart.cs new file mode 100644 index 0000000..648e2c8 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Core/Message/IStart.cs @@ -0,0 +1,6 @@ +namespace VirtualPrinter.ProgressInfo.Core.Message +{ + public interface IStart : IMessage + { + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Core/Message/IStep.cs b/UI/VirtualPrinter.ProgressInfo.Core/Message/IStep.cs new file mode 100644 index 0000000..27c0190 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Core/Message/IStep.cs @@ -0,0 +1,7 @@ +namespace VirtualPrinter.ProgressInfo.Core.Message +{ + public interface IStep : IMessage + { + uint Value { get; set; } + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Core/Message/Message.cs b/UI/VirtualPrinter.ProgressInfo.Core/Message/Message.cs new file mode 100644 index 0000000..a562b34 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Core/Message/Message.cs @@ -0,0 +1,17 @@ +using System; + +namespace VirtualPrinter.ProgressInfo.Core.Message +{ + [Serializable] + public class Message + { + public Message(MessageType type, uint val) + { + Type = type; + Value = val; + } + + public MessageType Type { get; } + public uint Value { get; } + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Core/Message/MessageType.cs b/UI/VirtualPrinter.ProgressInfo.Core/Message/MessageType.cs new file mode 100644 index 0000000..36c0b6d --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Core/Message/MessageType.cs @@ -0,0 +1,11 @@ +namespace VirtualPrinter.ProgressInfo.Core.Message +{ + public enum MessageType : uint + { + None, + Initialize, + Finalize, + Step, + Close + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Core/Properties/AssemblyInfo.cs b/UI/VirtualPrinter.ProgressInfo.Core/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b535c0b --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("VirtualPrinter.ProgressInfo.Core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("24d28558-c825-43e6-85d2-7c59f4a97698")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// indem Sie "*" wie unten gezeigt eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Core/VirtualPrinter.ProgressInfo.Core.csproj b/UI/VirtualPrinter.ProgressInfo.Core/VirtualPrinter.ProgressInfo.Core.csproj new file mode 100644 index 0000000..5baf6c3 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Core/VirtualPrinter.ProgressInfo.Core.csproj @@ -0,0 +1,57 @@ + + + + + Debug + AnyCPU + {24D28558-C825-43E6-85D2-7C59F4A97698} + Library + Properties + VirtualPrinter.ProgressInfo.Core + VirtualPrinter.ProgressInfo.Core + v4.6.1 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + none + true + ..\..\Files\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + {135c85eb-2116-4cc4-8ccb-b6804b9d6467} + VirtualPrinter.Agent.Core + + + + + + + \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoProcessManager.cs b/UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoProcessManager.cs new file mode 100644 index 0000000..6b4abce --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoProcessManager.cs @@ -0,0 +1,13 @@ +using VirtualPrinter.Agent.Core; + +namespace VirtualPrinter.ProgressInfo.Lib.Interfaces +{ + public interface IProgressInfoProcessManager + { + bool IsRunning(); + + void Run(IJob job); + + void Stop(); + } +} diff --git a/UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoServer.cs b/UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoServer.cs new file mode 100644 index 0000000..257a87a --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoServer.cs @@ -0,0 +1,18 @@ +using JetBrains.Annotations; + +using NamedPipeWrapper; + +namespace VirtualPrinter.ProgressInfo.Lib.Interfaces +{ + public interface IProgressInfoServer + { + [CanBeNull] + event ConnectionEventHandler ClientConnected; + + void PushMessage([NotNull] Core.Message.Message message); + + void Start(); + + void Stop(); + } +} diff --git a/UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoServerFactory.cs b/UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoServerFactory.cs new file mode 100644 index 0000000..90696d0 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Lib/Interfaces/IProgressInfoServerFactory.cs @@ -0,0 +1,7 @@ +namespace VirtualPrinter.ProgressInfo.Lib.Interfaces +{ + public interface IProgressInfoServerFactory + { + IProgressInfoServer Create(); + } +} diff --git a/UI/VirtualPrinter.ProgressInfo.Lib/Message/MessageFactory.cs b/UI/VirtualPrinter.ProgressInfo.Lib/Message/MessageFactory.cs new file mode 100644 index 0000000..4b0cf13 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Lib/Message/MessageFactory.cs @@ -0,0 +1,37 @@ +using System; +using JetBrains.Annotations; +using VirtualPrinter.ProgressInfo.Core.Message; + +namespace VirtualPrinter.ProgressInfo.Lib.Message +{ + public class MessageFactory : IMessageFactory + { + [NotNull] + private readonly Func _factory; + + public MessageFactory([NotNull]Func factory) + { + _factory = factory; + } + + public Core.Message.Message CreateStart() + { + return _factory(MessageType.Initialize, 0); + } + + public Core.Message.Message CreateStep(uint val) + { + return _factory(MessageType.Step, val); + } + + public Core.Message.Message CreateFinal() + { + return _factory(MessageType.Finalize, 0); + } + + public Core.Message.Message CreateClose() + { + return _factory(MessageType.Close, 0); + } + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoBroker.cs b/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoBroker.cs new file mode 100644 index 0000000..875e13b --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoBroker.cs @@ -0,0 +1,88 @@ +using System; + +using JetBrains.Annotations; + +using NamedPipeWrapper; + +using VirtualPrinter.Agent.Core; +using VirtualPrinter.Logging; +using VirtualPrinter.ProgressInfo.Core; +using VirtualPrinter.ProgressInfo.Core.Message; +using VirtualPrinter.ProgressInfo.Lib.Interfaces; + +namespace VirtualPrinter.ProgressInfo.Lib +{ + public class ProgressInfoBroker : IProgressInfo, IDisposable + { + [NotNull] + private readonly IVirtualPrinterLogger _logger; + + [NotNull] + private readonly IMessageFactory _messageFactory; + + [NotNull] + private readonly IProgressInfoServer _progressInfoServer; + + [NotNull] + private readonly IProgressInfoProcessManager _progressInfoProcessManager; + + public ProgressInfoBroker + ( + [NotNull]IVirtualPrinterLogger logger, + [NotNull]IMessageFactory messageFactory, + [NotNull]IProgressInfoServerFactory progressInfoServerFactory, + [NotNull]IProgressInfoProcessManager progressProcessManager + ) + { + _logger = logger; + _messageFactory = messageFactory; + _progressInfoProcessManager = progressProcessManager; + + _progressInfoServer = progressInfoServerFactory.Create(); + _progressInfoServer.ClientConnected += ServerOnClientConnected; + _progressInfoServer.Start(); + } + + public void Dispose() + { + _progressInfoProcessManager.Stop(); + _progressInfoServer.Stop(); + } + + public void Progress(IJob job, uint val) + { + StartProgressAgentIfNotRunning(job); + _progressInfoServer.PushMessage(_messageFactory.CreateStep(val)); + } + + public void Initialize(IJob job) + { + StartProgressAgentIfNotRunning(job); + _progressInfoServer.PushMessage(_messageFactory.CreateStart()); + } + + public void Finish(IJob job) + { + _progressInfoServer.PushMessage(_messageFactory.CreateFinal()); + Dispose(); + } + + private void ServerOnClientConnected(NamedPipeConnection connection) + { + LogDebug("New Progress Client connected"); + } + + private void StartProgressAgentIfNotRunning(IJob job) + { + if(!_progressInfoProcessManager.IsRunning()) + { + _progressInfoProcessManager.Run(job); + } + } + + private void LogDebug(string message, params object[] args) + { + _logger.Debug(message, args); + } + } +} diff --git a/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoProcessManager.cs b/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoProcessManager.cs new file mode 100644 index 0000000..d19aca3 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoProcessManager.cs @@ -0,0 +1,47 @@ +using JetBrains.Annotations; + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; + +using VirtualPrinter.Agent.Core; +using VirtualPrinter.ProgressInfo.Lib.Interfaces; +using VirtualPrinter.Utils; + +namespace VirtualPrinter.ProgressInfo.Lib +{ + [ExcludeFromCodeCoverage] + public class ProgressInfoProcessManager : IProgressInfoProcessManager + { + private const string ProcessName = "VPDAgentProgress"; + + public bool IsRunning() + { + return Process.GetProcesses().Any(pList => pList.ProcessName.Contains(ProcessName)); + } + + public void Run([NotNull]IJob job) + { + if (job == null) + { + throw new ArgumentNullException(nameof(job)); + } + + var path = Path.GetDirectoryName(typeof(ProgressInfoProcessManager).Assembly.Location); + var file = Path.Combine(path, ProcessName + ".exe"); + new Shell().Execute(job.JobInfo, job.SessionInfo, file, null); + } + + public void Stop() + { + var processes = Process.GetProcesses().Where(pList => pList.ProcessName.Contains(ProcessName)); + + foreach(var process in processes) + { + process.Kill(); + } + } + } +} diff --git a/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoServer.cs b/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoServer.cs new file mode 100644 index 0000000..3e525ab --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoServer.cs @@ -0,0 +1,42 @@ +using System.Diagnostics.CodeAnalysis; + +using JetBrains.Annotations; + +using NamedPipeWrapper; + +using VirtualPrinter.ProgressInfo.Lib.Interfaces; + +namespace VirtualPrinter.ProgressInfo.Lib +{ + [ExcludeFromCodeCoverage] + public class ProgressInfoServer : IProgressInfoServer + { + [NotNull] + private readonly NamedPipeServer _server; + + public ProgressInfoServer([NotNull] NamedPipeServer server) + { + _server = server; + _server.ClientConnected += ServerOnClientConnected; + } + + public event ConnectionEventHandler ClientConnected; + + private void ServerOnClientConnected([CanBeNull] NamedPipeConnection connection) => ClientConnected?.Invoke(connection); + + public void PushMessage([CanBeNull] Core.Message.Message message) + { + _server.PushMessage(message); + } + + public void Start() + { + _server.Start(); + } + + public void Stop() + { + _server.Stop(); + } + } +} diff --git a/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoServerFactory.cs b/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoServerFactory.cs new file mode 100644 index 0000000..ea7a88d --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Lib/ProgressInfoServerFactory.cs @@ -0,0 +1,46 @@ +using System; +using System.IO.Pipes; +using System.Security.AccessControl; +using System.Security.Principal; +using JetBrains.Annotations; + +using NamedPipeWrapper; + +using VirtualPrinter.ProgressInfo.Lib.Interfaces; + +namespace VirtualPrinter.ProgressInfo.Lib +{ + public class ProgressInfoServerFactory : IProgressInfoServerFactory + { + private const string PipeName = "vdpagent"; + + [NotNull] + private readonly Func, IProgressInfoServer> _factorInfoServer; + + public ProgressInfoServerFactory + ( + [NotNull]Func, IProgressInfoServer> factorInfoServer + ) + { + _factorInfoServer = factorInfoServer; + } + + public IProgressInfoServer Create() + { + var namedPipeServer = new NamedPipeServer(PipeName, GetPipeSecurity()); + + return _factorInfoServer(namedPipeServer); + } + + [NotNull] + private static PipeSecurity GetPipeSecurity() + { + var security = new PipeSecurity(); + + security.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), PipeAccessRights.ReadWrite, AccessControlType.Allow)); + security.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null), PipeAccessRights.FullControl, AccessControlType.Allow)); + + return security; + } + } +} diff --git a/UI/VirtualPrinter.ProgressInfo.Lib/Properties/AssemblyInfo.cs b/UI/VirtualPrinter.ProgressInfo.Lib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..be34a31 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Lib/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("VirtualPrinter.ProgressInfo.Lib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("d66f55e5-b3f7-4c61-a4f2-b55c4d412e01")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// indem Sie "*" wie unten gezeigt eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo.Lib/VirtualPrinter.ProgressInfo.Lib.csproj b/UI/VirtualPrinter.ProgressInfo.Lib/VirtualPrinter.ProgressInfo.Lib.csproj new file mode 100644 index 0000000..e2b905d --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo.Lib/VirtualPrinter.ProgressInfo.Lib.csproj @@ -0,0 +1,74 @@ + + + + + Debug + AnyCPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01} + Library + Properties + VirtualPrinter.ProgressInfo.Lib + VirtualPrinter.ProgressInfo.Lib + v4.6.1 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + none + true + ..\..\Files\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + {135c85eb-2116-4cc4-8ccb-b6804b9d6467} + VirtualPrinter.Agent.Core + + + {94e8105f-5001-403b-b9f1-b0b0b236ad65} + VirtualPrinter.Agent.Lib + + + {aa25364d-22d5-44b0-86a5-6fb14c686308} + VirtualPrinter.Logging + + + {cd1c8e9d-5335-41ac-b0c0-88fd7c7c55f3} + VirtualPrinter.Utils + + + {24d28558-c825-43e6-85d2-7c59f4a97698} + VirtualPrinter.ProgressInfo.Core + + + + + + + + \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo/Program.cs b/UI/VirtualPrinter.ProgressInfo/Program.cs new file mode 100644 index 0000000..391d3be --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo/Program.cs @@ -0,0 +1,19 @@ +using System; +using System.Windows.Forms; + +namespace VirtualPrinter.ProgressInfo +{ + internal static class Program + { + /// + /// Der Haupteinstiegspunkt für die Anwendung. + /// + [STAThread] + private static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new ProgressForm()); + } + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo/ProgressForm.Designer.cs b/UI/VirtualPrinter.ProgressInfo/ProgressForm.Designer.cs new file mode 100644 index 0000000..39c1924 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo/ProgressForm.Designer.cs @@ -0,0 +1,84 @@ +namespace VirtualPrinter.ProgressInfo +{ + partial class ProgressForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProgressForm)); + this.lbProgress = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // lbProgress + // + this.lbProgress.AutoSize = true; + this.lbProgress.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lbProgress.Location = new System.Drawing.Point(12, 60); + this.lbProgress.Name = "lbProgress"; + this.lbProgress.Size = new System.Drawing.Size(113, 16); + this.lbProgress.TabIndex = 1; + this.lbProgress.Text = "0 pages converted"; + // + // pictureBox1 + // + this.pictureBox1.Image = global::VirtualPrinter.ProgressInfo.Properties.Resources.waiting; + this.pictureBox1.Location = new System.Drawing.Point(50, 12); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 35); + this.pictureBox1.TabIndex = 2; + this.pictureBox1.TabStop = false; + // + // ProgressForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(135, 83); + this.ControlBox = false; + this.Controls.Add(this.pictureBox1); + this.Controls.Add(this.lbProgress); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ProgressForm"; + this.Opacity = 0.82D; + this.ShowInTaskbar = false; + this.Text = "AMAGNO Virtual Printer Progress"; + this.TopMost = true; + this.Load += new System.EventHandler(this.ProgressForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.Label lbProgress; + private System.Windows.Forms.PictureBox pictureBox1; + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo/ProgressForm.cs b/UI/VirtualPrinter.ProgressInfo/ProgressForm.cs new file mode 100644 index 0000000..0e91d1f --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo/ProgressForm.cs @@ -0,0 +1,84 @@ +using NamedPipeWrapper; +using System; +using System.Windows.Forms; + +using JetBrains.Annotations; + +using VirtualPrinter.ProgressInfo.Core.Message; + +namespace VirtualPrinter.ProgressInfo +{ + public partial class ProgressForm : Form + { + private const string PipeName = "vdpagent"; + + public ProgressForm() + { + InitializeComponent(); + + var client = new NamedPipeClient(PipeName) + { + AutoReconnect = true + }; + + client.ServerMessage += ServerMessage; + client.Start(new TimeSpan(TimeSpan.TicksPerMinute)); + } + + private void ServerMessage(NamedPipeConnection connection, [NotNull]Core.Message.Message message) + { + if (message == null) + { + throw new ArgumentNullException(nameof(message)); + } + + switch (message.Type) { + case MessageType.Finalize: + Invoke((Action) Finish); + break; + case MessageType.Initialize: + Invoke((Action) Initialize); + break; + case MessageType.Step: + Invoke((Action) (() => Progress(message.Value))); + break; + case MessageType.Close: + Invoke((Action) Dispose); + break; + case MessageType.None: + throw new ArgumentException("'None' is not a valid MessageType"); + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void Progress(uint val) + { + lbProgress.Text = $@"{val} pages converted"; + } + + private void Initialize() + { + PlaceToBottomRight(); + Show(); + BringToFront(); + } + + private void Finish() + { + Hide(); + } + + private void PlaceToBottomRight() + { + var desktopWorkingArea = Screen.PrimaryScreen.WorkingArea; + Left = desktopWorkingArea.Right - Width - 12; + Top = desktopWorkingArea.Bottom - Height - 12; + } + + private void ProgressForm_Load(object sender, EventArgs e) + { + Initialize(); + } + } +} \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo/ProgressForm.resx b/UI/VirtualPrinter.ProgressInfo/ProgressForm.resx new file mode 100644 index 0000000..036aafa --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo/ProgressForm.resx @@ -0,0 +1,1373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + AAABAA8AEBAQAAEABAAoAQAA9gAAABAQAAABAAgAaAUAAB4CAAAQEAAAAQAgAGgEAACGBwAAGBgQAAEA + BADoAQAA7gsAABgYAAABAAgAyAYAANYNAAAYGAAAAQAgAIgJAACeFAAAICAQAAEABADoAgAAJh4AACAg + AAABAAgAqAgAAA4hAAAgIAAAAQAgAKgQAAC2KQAAQEAQAAEABABoCgAAXjoAAEBAAAABAAgAKBYAAMZE + AABAQAAAAQAgAChCAADuWgAAAAAQAAEABABXQgAAFp0AAAAAAAABAAgAZR0AAG3fAAAAAAAAAQAgAHUn + AADS/AAAKAAAABAAAAAgAAAAAQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAD/AICA + gACAAIAAAICAAMDAwAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCQRAAAAAB + RRJSRSAAACEiFBEhRQABM2MlI2YhQAEmdkFCdzIQERZjIlFmMjESRTMRQjMhIRUmdyEldzIxFCN3ExR3 + MRISE3cRIXdiExMTdzIRd2EhASV3dmd3MkABFCZ3d3YVEAASMTNjJCEAAAESMkJREAAAAAERERAAAPgf + AADgBwAAwAMAAIABAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAEAAIABAADAAwAA4AcAAPgf + AAAoAAAAEAAAACAAAAABAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwZoQAdGqEAVlS4AIqJ + zgCVlNMAhYPMAEVDsQAzMKoAzMzqAP///wD+/v8AnpzWAM7N6gD+/v4AysnpALq54gDp6fYAamjBAE5M + tQB2dMYAKyinAOzs9wCrqtwAbGrBADAuqQDW1e0AfXvIACMgowDk5PMAmpnVAI2MzwD09PoA9fX6AI2L + zwBIRrMAb23DAGZkwABBPrAAi4rOAMjI6ACnptoALSqoAFdVuQC9veMAw8PmAEI/sABcWrsAk5LSALm4 + 4gCGhMwAQD6vAD48rwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAAAA + AAAAAAABAQEBAQEBAQEBAAAAAAABAQEBAQEBAQEBAQEAAAABATAxMgEBATMxMTQBAQAAAQEsCi0BAQEu + CgovAQEAAQEBJygpAQEBKigoKwEBAQEBASMkJQEBAQIkJCYBAQEBAQEfCiABAQEBIQoiAQEBAQEBGwoL + HAEBAR0KHgEBAQEBARgKChkBAQEaChcBAQEBAQETCgoUAQEVFgoXAQEBAAEBAg0KDg8QEQoKEgEBAAAB + AQEICQoKCgoLDAIBAQAAAAEBAQIDBAUGBwEBAQAAAAAAAQEBAQEBAQEBAQAAAAAAAAAAAQEBAQEBAAAA + AAD4HwAA4AcAAMADAACAAQAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIABAACAAQAAwAMAAOAH + AAD4HwAAKAAAABAAAAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAcGaExHBmhlxwZodkcGaH5HBmh+hwZodocGaGYHBmhMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwZ + oQkcGaGaHBmh/hwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof4cGaGbHBmgCQAAAAAAAAAAAAAAABwZ + oQkcGaHBHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZocIcGaAJAAAAAAAA + AAAcGaGaHBmh/5OS0v+5uOL/hoTM/xwZof8cGaH/HBmh/0A+r/+5uOL/ubji/z48r/8cGaH/HBmhmwAA + AAAcGaExHBmh/hwZof+9veP//////8PD5v8cGaH/HBmh/xwZof9CP7D///////////9cWrv/HBmh/xwZ + of4cGaExHBmhmBwZof8cGaH/i4rO/8jI6P+nptr/HBmh/xwZof8cGaH/LSqo/8jI6P/IyOj/V1W5/xwZ + of8cGaH/HBmhmBwZodocGaH/HBmh/0hGs/9vbcP/ZmTA/xwZof8cGaH/HBmh/x0aof9vbcP/b23D/0E+ + sP8cGaH/HBmh/xwZodkcGaH6HBmh/xwZof+NjM////////T0+v8cGaH/HBmh/xwZof8cGaH/9fX6//// + //+Ni8//HBmh/xwZof8cGaH5HBmh+hwZof8cGaH/fXvI///////+/v//IyCj/xwZof8cGaH/HBmh/+Tk + 8///////mpnV/xwZof8cGaH/HBmh+RwZodocGaH/HBmh/2xqwf///////////zAuqf8cGaH/HBmh/xwZ + of/W1e3//////6uq3P8cGaH/HBmh/xwZodkcGaGYHBmh/xwZof9OTLX///////////92dMb/HBmh/xwZ + of8rKKf/7Oz3//////+rqtz/HBmh/xwZof8cGaGYHBmhMRwZof4cGaH/HRqh/87N6v///////v7+/8rJ + 6f+6ueL/6en2////////////amjB/xwZof8cGaH+HBmhMQAAAAAcGaGaHBmh/xwZof8zMKr/zMzq//// + ///////////////////+/v//npzW/x0aof8cGaH/HBmhmwAAAAAAAAAAHBihCRwZocEcGaH/HBmh/x0a + of9WVLj/ionO/5WU0/+Fg8z/RUOx/xwZof8cGaH/HBmhwhwZoQkAAAAAAAAAAAAAAAAcGaEJHBmhmhwZ + of4cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH+HBmhmxwZoAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAcGaExHBmhlxwZodkcGaH5HBmh+RwZodocGaGYHBmhMgAAAAAAAAAAAAAAAAAAAADwDwAAwAMAAIAB + AACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAAgAEAAMADAADwDwAAKAAAABgA + AAAwAAAAAQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAD/AICAgACAAIAAAICAAMDA + wAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASETEAAAAAAAAAAUEhMSEkUA + AAAAAAESUUEhRSQQAAAAABIxQlITElEjAAAAAVESERMSEUIRIAAAFCd3YhISN3cyEwABJUd3MTExN3cx + EhABFCd3YhEhJ3diRRABJRZmYSFBNmYxIUATFCVBITJSERISMhISEhZ3cRQRN3dhETEUUTZ3cSUhJ3di + MhISEhZ3cUFFF3dhFBUTFCZ3clISRndxJSESElN3cUExJndxQUEBMUN3cyESF3dxJSABEhJ3dzITN3dx + FBABIxVnd3d3d3cyUhAAEUIWd3d3d3YUEQAAASMVNnd3dzJSEAAAABFCEyMyMlFBAAAAAAEjERFRQkIQ + AAAAAAAREjJCUREAAAAAAAAAAREREAAAAAD/gf8A/AA/APgAHwDwAA8A4AAHAMAAAwCAAAEAgAABAIAA + AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAEAgAABAIAAAQDAAAMA4AAHAPAADwD4AB8A/AA/AP+B + /wAoAAAAGAAAADAAAAABAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwZoQA1MqoAV1W5AGFf + vQBbWboAQD2vAB0aoQBoZsAA09LsAP7+/gD///8A4eHyAHl3xwAeG6IAIB2iAKuq3ACvrt0AlZTTAHd2 + xgA0MqoA+vr9APT0+gAvLagAJCGkADk2rAChn9cA1NTsAHd1xgDU0+wA9/f7AJCO0AA9O64Avr3jAPX1 + +gAxLqkAysnoAObm8wCysd4A/f3+ACMgowDb2u8A1tXtAMPC5QDz8/kA7Oz2AM7N6gD+/v8A4eDxAB4b + oQD7+/0AuLfgACYjpQAoJaYApKPYAK2s3ACFhMsALyyoACIfowD8/P0As7LeAEhFsgCJiM0AoaDXAFlX + uQB4d8YAOzmtAGpowABnZb8AJSKkAB8dogAfHKIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + 6v/+/v///v7//+Hg8f8cGaH/HBmh/xwZof8cGaH/HBmh/x4bof/7+/3//v7///7+//+4t+D/HBmh/xwZ + of8cGaH/HBmh/xwZoeUcGaH8HBmh/xwZof8cGaH/HBmh/8PC5f////////////Pz+f8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof/s7Pb////////////Kyej/HBmh/xwZof8cGaH/HBmh/xwZofscGaH8HBmh/xwZ + of8cGaH/HBmh/7Kx3v////////////39/v8jIKP/HBmh/xwZof8cGaH/HBmh/xwZof/b2u////////// + ///W1e3/HBmh/xwZof8cGaH/HBmh/xwZofocGaHmHBmh/xwZof8cGaH/HBmh/6Gf1/////////////// + //8xLqn/HBmh/xwZof8cGaH/HBmh/xwZof/Kyej////////////m5vP/HBmh/xwZof8cGaH/HBmh/xwZ + oeUcGaG8HBmh/xwZof8cGaH/HBmh/5CO0P////////////////89O67/HBmh/xwZof8cGaH/HBmh/xwZ + of++veP////////////19fr/Hhui/xwZof8cGaH/HBmh/xwZobscGaF5HBmh/xwZof8cGaH/HBmh/3d1 + xv////////////////93dcb/HBmh/xwZof8cGaH/HBmh/x0aof/U0+z////////////39/v/IB2i/xwZ + of8cGaH/HBmh/xwZoXkcGaEiHBmh/BwZof8cGaH/HBmh/zQyqv/6+v3////////////09Pr/eXfH/y8t + qP8kIaT/OTas/6Gf1//////////////////U1Oz/HBmh/xwZof8cGaH/HBmh/BwZoSIAAAAAHBmhqRwZ + of8cGaH/HBmh/xwZof+VlNP///////////////////////////////////////////////////////// + //93dsb/HBmh/xwZof8cGaH/HBmhqQAAAAAAAAAAHBmhIRwZofMcGaH/HBmh/xwZof8gHaL/q6rc//// + /////////////////////////////////////////////6+u3f8eG6L/HBmh/xwZof8cGaHzHBmgIQAA + AAAAAAAAAAAAABwZoVscGaH+HBmh/xwZof8cGaH/HRqh/2hmwP/T0uz//v7+//////////////////// + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEB + AQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEB + AQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAA + AAEBAV1RUVFRXgEBAQEBAQFfUVFRUWABAQEBAAAAAAABAQEBWQsLCwtaAQEBAQEBAVsLCwsLXAEBAQEB + AAAAAAEBAQFVCwsLC1YBAQEBAQEBVwsLCwtYAQEBAQEAAAABAQEBAVELCwsLUgEBAQEBAQFTCwsLC1QB + AQEBAQEAAAEBAQEBIgsLCwtOAQEBAQEBAU8LCwsLUAEBAQEBAQAAAQEBAQFJSkpKSksBAQEBAQEBTEpK + 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 + /////////////4OByv8cGaH/HBmh/xwZof8cGaH/HBmhjQAAAAAAAAAAAAAAABwZoCccGaH6HBmh/xwZ + of8cGaH/hILL//////////////////////9/fcn/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/3Bu + wv//////////////////////lJPR/xwZof8cGaH/HBmh/xwZof8cGaH7HBigJwAAAAAAAAAAHBmhnhwZ + of8cGaH/HBmh/xwZof90csT//////////////////////5GP0P8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/X127//////////////////////+lpNj/HBmh/xwZof8cGaH/HBmh/xwZof8cGaGeAAAAABwY + oA8cGaH2HBmh/xwZof8cGaH/HBmh/2Jgvf//////////////////////oqHX/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof9NS7T//////////////////////7W03/8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + ofYbGKAPHBmhWhwZof8cGaH/HBmh/xwZof8cGaH/Ojes/5KQ0f+SkNH/kpDR/5KQ0f9oZr//HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/y8tqP+SkNH/kpDR/5KQ0f+SkNH/b23C/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZoVocGaGdHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmhnBwZocwcGaH/HBmh/xwZof8cGaH/HBmh/yglpf/Cweb/wsHm/8LB + 5v/Cweb/oJ/X/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8gHaL/wcDl/8LB5v/Cweb/wsHm/7Cv + 3f8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaHLHBmh7RwZof8cGaH/HBmh/xwZof8cGaH/IR+i//// + ///////////////////g4PH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof/09Pn///////// + ////////9PT5/x0aof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZoescGaH9HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/+Pj7//////////////////Hx+P8dGqH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/+Pj + 8v/////////////////9/f7/JSKk/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh+xwZof0cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof/n5/P//////////////////Pz9/yMgo/8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/0tHr//////////////////////8uLKf/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH7HBmh7BwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/9XV7P//////////////////////Mi+p/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof/Av+P//////////////////////z07rf8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + oescGaHMHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/xMPl//////////////////////8+O67/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/7Kx3v//////////////////////T020/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmhyxwZoZ0cGaH/HBmh/xwZof8cGaH/HBmh/xwZof+0s9///////////////////////0tJ + s/8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/p6XZ//////////////////////9gXrz/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaGcHBmhWhwZof8cGaH/HBmh/xwZof8cGaH/HBmh/5+d1v////////////// + ////////gH7J/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof+2teD//////////////////////2Vj + vv8cGaH/HBmh/xwZof8cGaH/HBmh/xwZoVobGKEPHBmh9hwZof8cGaH/HBmh/xwZof8cGaH/YmC9//// + ///////////////////x8fn/SUez/xwZof8cGaH/HBmh/xwZof8cGaH/VlS4//v7/f////////////// + ////////Skiz/xwZof8cGaH/HBmh/xwZof8cGaH2HBigDwAAAAAcGaGeHBmh/xwZof8cGaH/HBmh/xwZ + of8hHqP/4eDy///////////////////////6+v3/r67d/3t5x/9ycMT/eXjH/62s3P/7+/3///////// + /////////////+vq9v8hHqP/HBmh/xwZof8cGaH/HBmh/xwZoZ4AAAAAAAAAABwZoCccGaH6HBmh/xwZ + of8cGaH/HBmh/xwZof9bWbr//f3+//////////////////////////////////////////////////// + ////////////////////////goDK/xwZof8cGaH/HBmh/xwZof8cGaH7HBigJwAAAAAAAAAAAAAAABwZ + oY0cGaH/HBmh/xwZof8cGaH/HBmh/xwZof93dcb//f3+//////////////////////////////////// + /////////////////////////////7u64v8fHKL/HBmh/xwZof8cGaH/HBmh/xwZoY0AAAAAAAAAAAAA + AAAAAAAAGxmhChwZodMcGaH/HBmh/xwZof8cGaH/HBmh/xwZof9WVLj/3t7x//////////////////// + //////////////////////////////z8/v+cm9X/IR6j/xwZof8cGaH/HBmh/xwZof8cGaHUHBmgCgAA + AAAAAAAAAAAAAAAAAAAAAAAAHBihJBwZoescGaH/HBmh/xwZof8cGaH/HBmh/xwZof8gHqP/a2nB/7W1 + 3//s7Pb//v7//////////////Pz+/9zb7/+bmtT/QT+w/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh6xwZ + oSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBmhMRwZoescGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8iIKP/LSqn/ysopv8fHKL/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + oescGaExAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBmhJBwZodMcGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaHUHBmgJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGxigCRwZ + oYwcGaH6HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH7HBmhjhsYoAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAABwZoSYcGaGdHBmh9hwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH2HBmhnxwYoScAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGKAOHBmhWRwZoZscGaHKHBmh6xwZofscGaH7HBmh7BwZ + oc0cGaGeHBmhXBsYoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AD//8A + AP/8AAA/+AAAH/AAAA/gAAAHwAAAA8AAAAOAAAABgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAGAAAABwAAAA8AAAAPgAAAH8AAAD/gAAB/8AAA//wAA///A + A/8oAAAAQAAAAIAAAAABAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAP8AgICAAIAA + gAAAgIAA////AMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU + ISFBJSEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVJREVRSFBExRSAAAAAAAAAAAAAAAAAAAAAAAAAAAA + EUJBIyEhRSMhISEhAAAAAAAAAAAAAAAAAAAAAAAAATEyFRIRFFEhERExMTESEAAAAAAAAAAAAAAAAAAA + AAASEhJCExMhJFJCMhISEkFUAAAAAAAAAAAAAAAAAAAAEhExFRMSEhMSQVERFFFFIRISAAAAAAAAAAAA + AAAAAAEhMhJBISQTESURJCMhISETJBVAAAAAAAAAAAAAAAABIxERRSVBFSEhQTIVEVRUEyEVISEgAAAA + AAAAAAAAABMRIyEhQSMhQUUhIUEkISEhFCFBQTEAAAAAAAAAAAABISQRMTElERJSEkVFElFRRRMlRSUh + ISAAAAAAAAAAABVBUlISEhFCMUFREhJBQkISEhISEUUTFQAAAAAAAAABQhJBQUVBMlESUkJRQVIVETEx + RUEyEhISEAAAAAAAAAEjFRJSEhISQhQRFBJSFBJCEhISEhExRUEwAAAAAAAAEREkJ3d3d3cyUjJSMRQl + JRd3d3d3chEhISEAAAAAAAFSMhVGZmZmZnFBEUEkJRQUJmZmZmZhITETFFAAAAAAAkERQRZmZmZmclJF + IVEUJSFWZmZmZmExJCEhIAAAAAARUkJSFmZmZmZxQSEUJCERQSdmZmZmYRIVFRMRAAAAASFBURQmZmZm + ZmElEyFRUTJSR2ZmZmZhIxQkEhJAAAABMSEkJRZmZmZmYRQhQSQhIUEXZmZmZmMRJRJRRRAAAAISMVFB + JmZmZmZhJRJSUUVBJSdmZmZmYkIUJCEhIAAAFFESQlIXZmZmZmMSQUFCESUUF2ZmZmZjFRURVFFCAAAR + JCFRFBdmZmZmYkFSUhUhQSEjZmZmZmMkISQhJSUAASMVEUISV2ZmZmZjEhQRQkUlRUNmZmZmYyETFRQU + FCABESQlIxQSQlITIUUjESUlEUISElQlQlQhVCEkJSElEAEyFUERJSRRQTETIREjFBQhJRRRRRRRQVQh + VBERRRQgAhFBJCMRERIiIiITJBElIVQUEhIiIiIiIRQhUjISElAVQlIVEkIyczMzMzIVIRQUJSUkVDMz + MzMzJRJBETFBERIRRRQlERFmZmZmZyQTElIRQRElZmZmZmchRRJCElJCFFISEhQjI2ZmZmZnESEhQTEj + JRRmZmZmZhISRRUUEVQSFFQTERESZmZmZmYlExUSEhFBIWZmZmZmExUhJCUkEhMSEhJSMkVmZmZmZxQh + JCVBMSMRZmZmZmYSQkFRFFIREhMUUUERIWZmZmZmElQVQSEhEhJ2ZmZmZhEVISQhIUUTISEhJSRRZmZm + ZmYUEhISUTJBMXZmZmZmMSQTFUVFIRIRVFQUEkJ2ZmZmZhUlQTFCEVISdmZmZmYhMRISEhJBFFQhISUh + UXZmZmZmIUEhISEyFBM2ZmZmZjISExQVQVISElFFQVFCdmZmZmYxITFUURElEjZmZmZmMhVCUhISFBMR + QhISQhF2ZmZmZiMRISEkIxQhNmZmZmYxQhEUUUUhEhJRMRUTIXZmZmZmMSMUVBUSEhE2ZmZmZjJRJFJC + EjEBMUISQhIRNmZmZmYyESEhJCExMjZmZmZmMhRRIRMREAEhIUUVQTI2ZmZmZjIxRRMRURIRNmZmZmZx + ISFFEhIwAUUTEkISETZmZmZmcRIRISQkJUI2ZmZmZnIxMSQhMRABISEhUUUkJmZmZmZiEyMUUVERITZm + ZmZmcRISUTESEAATFFFCEhVHZmZmZmcREhISQSMTZmZmZmYyFFQRISMAABISEhVFQSdmZmZmZnIRMTEj + ESdmZmZmZjEhISRUEQAAATFFQhISFWZmZmZmZjISEhEjZmZmZmZmIxUUUhIQAAABJSElFFFBdmZmZmZm + Znd3dmZmZmZmZmcRJCEkFUAAAAEUFBQhJSQmZmZmZmZmZmZmZmZmZmZmYyFFExUSEAAAABJSElQUFUVm + ZmZmZmZmZmZmZmZmZmZxMhISEkEAAAAAAUUUElISEjZmZmZmZmZmZmZmZmZmZyEhExQVIAAAAAABISUh + QTFFQ2ZmZmZmZmZmZmZmZmZkFRMhJSQQAAAAAAATFBUSEhISN2ZmZmZmZmZmZmZmZ1JBIRQUEQAAAAAA + AAElJCUTFBUUNmZmZmZmZmZmZmYyRSRUJSUgAAAAAAAAARQRFCElJCUkdmZmZmZmZmZmdFEhESERQRAA + AAAAAAAAEjJSFRRRFFElM2ZmZmZmZzISEjEyEyUhAAAAAAAAAAABFBQUISQlIUFCETEyMjESExFBEhER + FBAAAAAAAAAAAAASUlITERFCUhExISFBEkUSUlJUEyMhAAAAAAAAAAAAAAEUFBElQlFFQhJUFRJFEkFB + QSEhERAAAAAAAAAAAAAAAAElJUIRQhIVFBIUJRJBUhJSQTIQAAAAAAAAAAAAAAAAABFBITIVEyQlIyUU + JRIUUUFSEQAAAAAAAAAAAAAAAAAAABIxESQhERQRFCEUIyESUkEAAAAAAAAAAAAAAAAAAAAAAREjERUj + ISMhIyEREyQREAAAAAAAAAAAAAAAAAAAAAAAABEjJBEVERUREyMhEQAAAAAAAAAAAAAAAAAAAAAAAAAA + ABERIyQjJCMhEREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREREREREAAAAAAAAAAAAAAAAA////wAP/ + //////wAAD//////8AAAD/////+AAAAB/////wAAAAD////8AAAAAD////gAAAAAH///4AAAAAAH///A + AAAAAAP//4AAAAAAAf//AAAAAAAA//4AAAAAAAB//gAAAAAAAH/8AAAAAAAAP/gAAAAAAAAf+AAAAAAA + AB/wAAAAAAAAD+AAAAAAAAAH4AAAAAAAAAfgAAAAAAAAB8AAAAAAAAADwAAAAAAAAAOAAAAAAAAAAYAA + AAAAAAABgAAAAAAAAAGAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA + AAAAAAABgAAAAAAAAAGAAAAAAAAAAYAAAAAAAAABwAAAAAAAAAPAAAAAAAAAA+AAAAAAAAAH4AAAAAAA + AAfgAAAAAAAAB/AAAAAAAAAP+AAAAAAAAB/4AAAAAAAAH/wAAAAAAAA//gAAAAAAAH/+AAAAAAAAf/8A + AAAAAAD//4AAAAAAAf//wAAAAAAD///gAAAAAAf///gAAAAAH////AAAAAA/////AAAAAP////+AAAAB + //////AAAA///////AAAP///////wAP///8oAAAAQAAAAIAAAAABAAgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAABwZoQAhHqEAMS+nADw5qwA/PK0ANDGoACckowAeG6IATUuzAIuJzADFxOQA7e32AP39 + /QD///8A9fX6ANTT6gCdnNQAW1i5ACQhowAcGKEALiunAI2MzgDj4/IA7u73AJqY0wAzMakAJiOkAIuJ + zQDx8fgA8/P5AIqIzQAhHqIAQ0GwANTU7ADIx+cAMC6pAGFfvAD39/sA4uLzADUyqwBmZL4A+vr9ACgl + pQBMSrMA9vb7AKKh1wAcGaAAJySlAN3d8AD9/f4ATEq0AJGQzwDk5PEAz87qAMjI5gDIyOcAzc3pAODg + 8AD+/v4As7LeADEuqAD09PkA7Oz2AISDygA6N6sANjOqAIKByQD5+fwAgoDJALu74QAuK6gANDKqANPT + 7ABgXrsAzc3oACAdogA1MqoAkI7OAC8spwD6+vwAiYjMAKuq2gBSULUAtLPdAFFPtQCxsNsAYmC8AIOB + yABHRbAArKvZAHBuwQByccIAVVO3AJyb0wCAfscAZGK8AF9duwCKiMsAk5HPAFtZugBqaL8AeXjFAKOi + 1gBPTbQAeXfFAGhmvQC0tN0APz2tAFZUtgDGxeQAMC2nAEZEsADY1+wA9fX5ACUjowCtrNoAOjisAOrp + 8wDr6/UAHhyhAL++4gAyMKkAHRqhAPj4+gDc3O4Az8/oAPn5+wApJqUAIyCjAMvK5gDi4vAA8fD3ACsp + pQC5uN8A8vL3AOPj8QA6N6oAqafYACMhogDT0uoAhILMAFZUtwBqaMAAKiemACIfowCNi80AXly6AGVj + vAB4dsUAoJ/UAE5MswB1dMMAcG7DALKx3ACIh8sAZGK9AMTD5AArKKQAmZjSAFRStgDV1OsA+vr7AB8c + oQCrqtkAREGuAOXl8gDq6vQAvLvhADIvpwDy8vgA2dnsAM3M5wAjIKIAHBqhAN7e7wAlIqMAt7beAOHh + 8AAuLKYAy8voAIiGygCop9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAA + AAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEvAAAAAAAAAAAA + AAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAA + AAAAAAAAAAABAQEBAQGztLS0tLS0tLS0tQEBAQEBAQEBAQEBAQEBAROdtLS0tLS0tLS2AQEBAQEBAQEB + AAAAAAAAAAAAAAABAQEBAQEBsA4ODg4ODg4ODrEBAQEBAQEBAQEBAQEBAQGjDA4ODg4ODg4OsgEBAQEB + AQEBAQEAAAAAAAAAAAAAAQEBAQEBAa5QDg4ODg4ODg43AQEBAQEBAQEBAQEBAQEBAa8ODg4ODg4ODocB + AQEBAQEBAQEBAAAAAAAAAAAAAQEBAQEBAQEBqg4ODg4ODg4OqwEBAQEBAQEBAQEBAQEBAQGsDg4ODg4O + Dg4yrQEBAQEBAQEBAQEAAAAAAAAALwEBAQEBAQEBAaYODg4ODg4ODqcBAQEBAQEBAQEBAQEBAQEBqA4O + Dg4ODg4ODqkBAQEBAQEBAQEBLwAAAAAAAAEBAQEBAQEBAQGhDg4ODg4ODg6iowEBAQEBAQEBAQEBAQEB + AaQODg4ODg4ODg6lAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBnQ4ODg4ODg4ODp4BAQEBAQEBAQEB + AQEBAQGfDg4ODg4ODg4OoAEBAQEBAQEBAQEBAAAAAAABAQEBAQEBAQEBAZoODg4ODg4ODg4EAQEBAQEB + AQEBAQEBAQEBmw4ODg4ODg4ODpwBAQEBAQEBAQEBAQEAAAAAAQEBAQEBAQEBAQGWDg4ODg4ODg4OlwEB + AQEBAQEBAQEBAQEBAZgODg4ODg4ODg6ZAQEBAQEBAQEBAQEBAAAAAQEBAQEBAQEBAQEBklBQUFBQUFBQ + UJMBAQEBAQEBAQEBAQEBAQGUUFBQUFBQUFBQlQEBAQEBAQEBAQEBAQEAAAEBAQEBAQEBAQEBAYGQkJCQ + kJCQkJAgAQEBAQEBAQEBAQEBAQEBTJCQkJCQkJCQkJEBAQEBAQEBAQEBAQEBAAABAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEB + AQEBAQEBAU+NjY2NjY2NjY2OAQEBAQEBAQEBAQEBAQEBE42NjY2NjY2NjY8BAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQGJDg4ODg4ODg4OigEBAQEBAQEBAQEBAQEBAYsNDg4ODg4ODg6MAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBhQ4ODg4ODg4ODoYBAQEBAQEBAQEBAQEBAQEBhw4ODg4ODg4OiAEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAYEODg4ODg4ODg6CAQEBAQEBAQEBAQEBAQEBAYMODg4ODg4ODoQgAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQF7fA4ODg4ODg4OfQEBAQEBAQEBAQEBAQEBAQF+Dg4ODg4ODg5/ + gAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAXYODg4ODg4ODnd4AQEBAQEBAQEBAQEBAQEBeQ4ODg4O + Dg4OO3oBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQFxDg4ODg4ODg5ycwEBAQEBAQEBAQEBAQEBAXQO + Dg4ODg4ODg51AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBbg4ODg4ODg4ODW8BAQEBAQEBAQEBAQEB + AQFeDg4ODg4ODg4OcAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAWsODg4ODg4ODg5sAQEBAQEBAQEB + AQEBAQEBYg4ODg4ODg4ODm0BAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQFnDg4ODg4ODg4OaAEBAQEB + AQEBAQEBAQEBAWkODg4ODg4ODg5qAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBYw4ODg4ODg4ODmQB + AQEBAQEBAQEBAQEBAQFlDg4ODg4ODg4OZgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAV8ODg4ODg4O + Dg5gAQEBAQEBAQEBAQEBAQEBYQ4ODg4ODg4ODmIBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQFbDg4O + Dg4ODg4OXAEBAQEBAQEBAQEBAQEBAV0ODg4ODg4ODg5eAQEBAQEBAQEBAQEBAAABAQEBAQEBAQEBAQEB + Vw4ODg4ODg4ODlgBAQEBAQEBAQEBAQEBAQFZDg4ODg4ODg4OWgEBAQEBAQEBAQEBAQAAAQEBAQEBAQEB + AQEBAVMODg4ODg4ODg5UAQEBAQEBAQEBAQEBAQEBVQ4ODg4ODg4ODlYBAQEBAQEBAQEBAQEAAAEBAQEB + AQEBAQEBAQFPUA4ODg4ODg4OUEgBAQEBAQEBAQEBAQEBAVEODg4ODg4ODg5SAQEBAQEBAQEBAQEBAAAA + AQEBAQEBAQEBAQEBAUsODg4ODg4ODg44TAEBAQEBAQEBAQEBAU0dDg4ODg4ODg4OTgEBAQEBAQEBAQEB + AAAAAAEBAQEBAQEBAQEBAQFFDg4ODg4ODg4ODkZHAQEBAQEBAQEBAUhJDg4ODg4ODg4ODkoBAQEBAQEB + AQEBAQAAAAAAAQEBAQEBAQEBAQEBPT4ODg4ODg4ODg4OP0BBAQEBAQEBQkMYDg4ODg4ODg4ODkQVAQEB + AQEBAQEBAQAAAAAAAAEBAQEBAQEBAQEBAQE0Dg4ODg4ODg4ODg4ODjU2Nzg5OjsODg4ODg4ODg4ODg48 + AQEBAQEBAQEBAQEAAAAAAAAvAQEBAQEBAQEBAQEBMDEODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4O + Dg4yMwEBAQEBAQEBAQEvAAAAAAAAAAEBAQEBAQEBAQEBAQEsLQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4O + Dg4ODg4OLgEBAQEBAQEBAQEBAAAAAAAAAAAAAQEBAQEBAQEBAQEBASkqDg4ODg4ODg4ODg4ODg4ODg4O + Dg4ODg4ODg4OIisBAQEBAQEBAQEBAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBJSYODg4ODg4ODg4ODg4O + Dg4ODg4ODg4ODg4OJygBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEhIg4ODg4ODg4O + Dg4ODg4ODg4ODg4ODg4OIyQBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBARscHQ4O + Dg4ODg4ODg4ODg4ODg4ODg4eHyABAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAFAEBAQEBAQEBAQEBAQEB + ARUWFw4ODg4ODg4ODg4ODg4ODhgZGgEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEB + AQEBAQEBAQgJCgsMDQ4ODg4ODg8QERITAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAEBAQEB + AQEBAQEBAQEBAQEBAQEBAQIDBAUFBgcBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAA + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAA + AAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEB + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEB + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD////AA////////AAAP//////wAAAP/////4AAAAH///// + AAAAAP////wAAAAAP///+AAAAAAf///gAAAAAAf//8AAAAAAA///gAAAAAAB//8AAAAAAAD//gAAAAAA + AH/+AAAAAAAAf/wAAAAAAAA/+AAAAAAAAB/4AAAAAAAAH/AAAAAAAAAP4AAAAAAAAAfgAAAAAAAAB+AA + AAAAAAAHwAAAAAAAAAPAAAAAAAAAA4AAAAAAAAABgAAAAAAAAAGAAAAAAAAAAYAAAAAAAAABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAAYAAAAAAAAABgAAAAAAA + AAHAAAAAAAAAA8AAAAAAAAAD4AAAAAAAAAfgAAAAAAAAB+AAAAAAAAAH8AAAAAAAAA/4AAAAAAAAH/gA + AAAAAAAf/AAAAAAAAD/+AAAAAAAAf/4AAAAAAAB//wAAAAAAAP//gAAAAAAB///AAAAAAAP//+AAAAAA + B///+AAAAAAf///8AAAAAD////8AAAAA/////4AAAAH/////8AAAD//////8AAA////////AA////ygA + AABAAAAAgAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAbGKEbHBmgVBwZoYIcGaGpHBmhyxwZoeUcGaH2HBmh/RwZof0cGaH2HBmh5RwZ + oc8cGaGvHBmhhxwZoVkbGKAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAREZkBHBmgORwZoY0cGaHYHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZod0cGaGSHBigPhQUmQIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAABsYoBAcGaFyHBmh2RwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaHdHBmgdxwYoBMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGxigEhwZoYccGaHyHBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH0HBmhihwXoBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcFZ8CHBmhaBwZoewcGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaHuHBmhbRoa + ngMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbGKAmHBmhxhwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaHJGxigKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAbGaFbHBmh8xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZofUcGKFfAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAABsUmgIcGaGNHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + oZEcF58DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAABsYngccGaGuHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmhrxsZnwcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsXnwccGaG1HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaG2HRieBwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwXnwMcGaGuHBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + oa8bFZ8DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAcGaGOHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmgkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAcGaFdHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaFfAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbGaEmHBmh8xwZof8cGaH/HBmh/xwZof8cGaH/Liym/8vL + 6P/Ly+j/y8vo/8vL6P/Ly+j/y8vo/8vL6P/Ly+j/y8vo/4iGyv8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8kIaP/xMPk/8vL6P/Ly+j/y8vo/8vL + 6P/Ly+j/y8vo/8vL6P/Ly+j/qKfY/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh9BwZ + oCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbFJoCHBmhxxwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/yUio/////////////////////////////////////////////////+3tt7/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/Hxyh/+3t + 9v///////////////////////////////////////////+Hh8P8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaHJGRmbAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBmgahwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGqH/+vr8//////////////////////////////////// + ////////yMjm/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof/e3u/////////////////////////////////////////////y8vf/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZoWsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAGxigExwZoe0cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh//Ly+P////////////// + /////////////////////////////9nZ7P8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/zczn//////////////////////////////////// + /////////f3+/yMgov8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaHtHBefEwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAABwZoIgcGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of/l5fL////////////////////////////////////////////q6vT/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/7y74f////////////// + //////////////////////////////////8yL6f/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZoIgAAAAAAAAAAAAAAAAAAAAAAAAAABwZoREcGaHzHBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/1dTr////////////////////////////////////////////+vr7/x8c + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of+rqtn/////////////////////////////////////////////////REGu/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaHzHBmhEQAAAAAAAAAAAAAAAAAAAAAcGaB1HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/8TD5P////////////////////////////// + //////////////////8rKKT/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/mZjS/////////////////////////////////////////////////1RS + tv8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZoHUAAAAAAAAAAAAA + AAAcDpwBHBmh2xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof+ysdz///////// + ////////////////////////////////////////PDmr/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/4iHy/////////////////////////////// + //////////////////9kYr3/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaHbFxeXAQAAAAAAAAAAHBihOxwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/oJ/U/////////////////////////////////////////////////05Ms/8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof91dMP///////// + ////////////////////////////////////////cG7D/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwYoTsAAAAAAAAAABwZoY8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/42Lzf/6+vz/+vr8//r6/P/6+vz/+vr8//r6/P/6+vz/+vr8//r6 + /P9eXLr/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/ZWO8//r6/P/6+vz/+vr8//r6/P/6+vz/+vr8//r6/P/6+vz/+vr8/3h2xf8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaGPAAAAAAAAAAAcGaHaHBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8jIKP/Kiem/yonpv8qJ6b/Kiem/yon + pv8qJ6b/Kiem/yonpv8qJ6b/IR6i/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/yAdov8qJ6b/Kiem/yonpv8qJ6b/Kiem/yonpv8qJ6b/Kiem/yon + pv8iH6P/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh2gAA + AAAbGZ8eHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8bGaAdHBmhVxwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmgVhwZoYUcGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8vLKf/hILM/4SCzP+Egsz/hILM/4SCzP+Egsz/hILM/4SC + zP+Egsz/VlS3/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/yQho/+Egsz/hILM/4SCzP+Egsz/hILM/4SCzP+Egsz/hILM/4SCzP9qaMD/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZoYMcGaGsHBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/Ojeq//////////////////// + /////////////////////////////6mn2P8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8jIaL//f39//////////////////////////////////// + ////////09Lq/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaGqHBmhzhwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/ysp + pf////////////////////////////////////////////////+5uN//HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh//Ly9/////////////// + /////////////////////////////+Pj8f8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmhzBwZoeYcGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8jIKP/////////////////////////////////////////////////y8rm/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of/i4vD////////////////////////////////////////////x8Pf/IR6i/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZoeIcGaH3HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HRqh//j4+v////////////////////////////// + /////////////9zc7v8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/z8/o////////////////////////////////////////////+fn7/ykm + pf8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaHzHBmh/hwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof/q6fP///////// + ///////////////////////////////////r6/X/Hhyh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/7++4v////////////////////////////// + //////////////7+/v8yMKn/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/RwZof4cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/2Nfs////////////////////////////////////////////9fX5/yUjo/8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof+trNr///////// + ////////////////////////////////////////Ojis/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof0cGaH3HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/8bF5P////////////////////////////////////////////39 + /f8wLaf/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/nJvT/////////////////////////////////////////////////0ZEsP8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaHyHBmh5RwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof+0tN3///////////////////////// + ////////////////////////Pz2t/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/4qIy/////////////////////////////////////////////// + //9WVLb/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh4hwZ + oc4cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/o6LW//// + /////////////////////////////////////////////09NtP8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof95d8X///////////////////////// + ////////////////////////aGa9/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZocscGaGsHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/5ORz/////////////////////////////////////////////////9bWbr/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/ami///// + /////////////////////////////////////////////3l4xf8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaGqHBmhhRwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof+Afsf///////////////////////////////////////// + ////////ZGK8/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/19du/////////////////////////////////////////////////+KiMv/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmhgxwZoVccGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/cG7B//////////////////// + /////////////////////////////3Jxwv8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof9VU7f///////////////////////////////////////// + ////////nJvT/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + oFYbGaAdHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/2Jg + vP////////////////////////////////////////////////+Dgcj/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/R0Ww//////////////////// + /////////////////////////////6yr2f8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8bGaAdAAAAABwZodocGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof9SULX/////////////////////////////////////////////////tLPd/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/1FP + tf////////////////////////////////////////////////+xsNv/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaHaAAAAAAAAAAAcGaGPHBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/Lyyn//r6/P////////////////////////////// + //////////////r6/P80Mqr/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof+JiMz/////////////////////////////////////////////////q6ra/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmhjwAAAAAAAAAAGxmhOxwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof/Nzej///////// + ////////////////////////////////////////yMjn/yAdov8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof81Mqr/8fH4//////////////////////////////////// + /////////////5COzv8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwY + oTsAAAAAAAAAABwOnAEcGaHaHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/goDJ//////////////////////////////////////////////////////+7u+H/Liuo/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof80Mqr/09Ps//////////////////// + //////////////////////////////////9gXrv/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZodocDpwBAAAAAAAAAAAAAAAAHBmgdRwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/zEuqP/09Pn///////////////////////////////////////// + /////////////+zs9v+Eg8r/Ojer/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/zYzqv+Cgcn/7u73//// + ///////////////////////////////////////////////////5+fz/Liun/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaB1AAAAAAAAAAAAAAAAAAAAABwZoBAcGaHzHBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/kZDP//////////////////// + ///////////////////////////////////////////////////k5PH/z87q/8jI5v/IyOf/zc3p/+Dg + 8P/+/v7/////////////////////////////////////////////////////////////////s7Le/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaHzHBmgEAAAAAAAAAAAAAAAAAAA + AAAAAAAAHBmgiBwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/yck + pf/d3fD///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////f3+/0xKtP8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmgiAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAABsYoBIcGaHtHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/TEqz//b2+/////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////6Kh1/8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh7RwXnxMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBmgahwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof9mZL7/+vr9//////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////9TU7P8oJaX/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZoGsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsU + mgIcGaHHHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/2Ff + vP/39/v///////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////+Li8/81Mqv/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZockZGZsDAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAGxmhJhwZofMcGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/Q0Gw/9TU7P////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////8jH + 5/8wLqn/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZofQcGaAoAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGaBcHBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8mI6T/i4nN//Hx+P////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////8/P5/4qIzf8hHqL/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaBeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwY + oY0cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8uK6f/jYzO/+Pj8v////////////////////////////////////////////////////////////// + ///////////////////u7vf/mpjT/zMxqf8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaGPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAbFJoCHBmhrhwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8eG6L/TUuz/4uJzP/FxOT/7e32//39/f////////////// + ///////////////////19fr/1NPq/52c1P9bWLn/JCGj/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaGvGRmbAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsXnwccGaG1HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8hHqH/MS+n/zw5q/8/PK3/Pzyt/zQxqP8nJKP/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaG2HRieBwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGxieBxwZ + oa4cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaGvGxmfBwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAbFJoCHBmhjRwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaGRHBefAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGaBaHBmh8xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZofUcGaBfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsY + oCYcGaHGHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZockbGKAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAHBWfAhwZoWgcGaHsHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh7hwZoW0aGp4DAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGxigEhwZoYYcGaHyHBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH0HBmhiRwXoBQAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAGxmfDxwZoXIcGaHZHBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZod0cGaB3GxmgEgAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAERGZARwZoDkcGaGNHBmh2BwZof8cGaH/HBmh/xwZ + of8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaH/HBmh/xwZof8cGaHdHBmhkhwY + oD4UFJkCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAbGKEbHBmgVBwZoYIcGaGpHBmhyhwZoeQcGaH0HBmh+xwZofscGaH0HBmh5BwZoc4cGaGvHBmhhxwZ + oVkbGKAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAD///////AAAA////// + wAAAA/////8AAAAA/////AAAAAA////4AAAAAB////AAAAAAD///wAAAAAAD//+AAAAAAAH//wAAAAAA + AP/+AAAAAAAAf/4AAAAAAAB//AAAAAAAAD/4AAAAAAAAH/AAAAAAAAAP8AAAAAAAAA/gAAAAAAAAB+AA + AAAAAAAHwAAAAAAAAAPAAAAAAAAAA4AAAAAAAAABgAAAAAAAAAGAAAAAAAAAAYAAAAAAAAABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACAAAAAAAAAAYAAAAAAAAABgAAAAAAAAAGAAAAAAAAAAcAAAAAAAAADwAAAAAAAAAPgAAAAAAAAB+AA + AAAAAAAH8AAAAAAAAA/wAAAAAAAAD/gAAAAAAAAf/AAAAAAAAD/+AAAAAAAAf/4AAAAAAAB//wAAAAAA + AP//gAAAAAAB///AAAAAAAP///AAAAAAD///+AAAAAAf///8AAAAAD////8AAAAA/////8AAAAP///// + 8AAAD///////AAD///+JUE5HDQoaCgAAAA1JSERSAAABAAAAAQAIBgAAAFxyqGYAACAASURBVHja7V1p + VuQ6s8z+NvZ6ZwQ767syvR9QhYeMQTTQJbDP4QA1uFy2JeUQw6+6tm+3oWp80n5/XWf3e23/u07BmgNc + /TxVVQH19Prqj/nff+5nTTzX9nnbNaMvuJI/VdUzUE9APRfqqfD2P1AF7HZSqA/4//Vzjp93+v+KHq7t + 2j5kVR9VA8DL78L9/93r0Lzn/hv7/4G550//N6v+8bHmeMcVKVzbtekBfxzs54GVDXAc34/X/3ef9/L8 + aJ7vP/9tv7f3tJ+/+d9ODNeEcG0/edCfBrxdxbEfsM0AH+r9zaDdve+w3/a9OEwIOAxu1GkiOR7T+T3n + CeG6U67tBwz6/eq+W8HbQV77VbgZpPuVG/37cPhMsk80A96u+kWOe5e29BHA6fiuyeDavtOgpyH4KfxO + IoDzANepQT/Yz6nAcXIgNQA0E4yrL9Q5imDRBUsVrjvr2pYc9H0o3kwE2Ofbu9eKwd5OCjjn7/0gb3L8 + bUoSRQHb48Qp98ehPjHI8Z3ThCsyuLZFBj4b9HxA1m6FUyv2eRJJo4bz/kYz0E+fiRJpRlNcbI7nHBF0 + 3xciQjmnFt3j1x14bQ+z2h9Xwahij669hzZkPkUBzep6DMtpFEC7BJCTlw7vcRrox0niXOtw6Qia9OMq + Hl7bA632tEDXtuW6QdKt1tiHwCTMjiKAZt8yP4eOJk5RAMSE2EQT++/fFQWb79w+dk0E1/aPBn4X6nZV + bx4Gq/y/u9H9ZHBaWbvOQPEIYcg6wDGHd92A4z7QRxMgHZK2LdnUEhqcwTURXNsXrPgsRz2vUJCpQR9K + 01waM52DoqF6GxkAeSegPCZgqFoAVPsPtNA5iqUlXXHzmgjcdpGBxMC/kWKeX38fyTK7x+/4e9Qz9q97 + en3m6fU1z4ffu/du910bfP39d9XTKzNn+1n334f3P2/3f9xXVT2/7uv5cKzVfO5zoZ5ed/W0PZaq18fR + vO98LMfzRj97ey63329zHNvv9rQ5zpdje3ngmgiu7WMr+iykb1FvCNB6Z0DQIK0/tx9eXSdVelZzQAmY + L0SBz0QbJPIBgQv356cBLTUdhisiuLYPHfjtAEC1cFoe9h7yfSh03Ln1N2gLDrSI56r07WCrvs1n6xq0 + Y3Euho4O79DhD06gKX5O6ARx1Qiu7a8HPs2tRftLVPO7ldWt4GpFbYt46ElH58o/+iiEtPqOsOUYb0A6 + IEdIMz2/4Ku9ngiuGsG1HQb/zMA/secIKacfCGHVnqDvekoteqy9Yg2KQmaXykC1+mgIjqZVWBzlCF5M + ZVFPArKikQI5p9eI+GGrvqLA9q26kHXXhc6YzN1ZBBCv/v3kMijxBhO5e1PTQNm6AcMjoByjsGu9hozH + Ng3ROIJrhPyIVZ+tKsHAh8iPYXLktgYAi+OnUQRAI5RBVkH+OqJDIODHLd9A6RGckImiMIgeMn1OcSBE + SkDrEzz9uiaCH7DqQ3PUZe7Jw/xusKUkGi2sAYkjYOF7v+pBroIqAunC6b7yn+IRGJkJHPgDFwX0uAlG + xIKosfyEsfHrJwz+Fw29l171/XfVS+94q2t3fxM2/eU6aOId9n7rOd/3Wfce9Jte3us+b/371/29fM7m + 8w6vu+3zZV9vv3fvff1799rNfm7Hsd8nNu8j33v3/d4evx9D99r7YzhcBOz69Vvcw+2cnr/j4bH2OhzP + aXNtDn92n7k9D7tz/PomXHqG32fVB4OtwvfUYZF5fQU+W/VZcQ2+vUhXz6ZwxlZ2iREozUIUHQNZA2hW + /rM4CjQCECQCgNFTQA8nZt2Ca0Qtnuv3pBdRuHPAny4chxjIgMzfI1BNdR2Ipo/OimGdBgDI5CFTJpV/ + Cy4B0tYgZO4/WOUfHKI8WG0ASuVof26vkbX4qk+LfvDYeVSvmYeuzYR+tZ393ZFp1GtlLcBoANAKuyiY + DiV1JuoAcmJgnQ+lfmxrDrAD/wzO4q3Oa6Qtuupb7nqD0IPqe0OvXHS1FTd/hy6UCkCssk8IPuh68qK6 + Pma6IOQcQfT++bki+AAQ9STWaWk0BiwZq/ms8QMLhN9g5Rc3imgJKbHNro/d4veBrLZAlHLa7wNxfJab + EObjKNMahJ2YnHQ4BF6CtwV1N8FKlZ3amTCgrpLw7GsSeLiV36PwJNQ0FNsEk9MOVjRQpBxJG6CAM1of + cAjxTlRfHKST2mH/XWQzVPpFUiImFsKwAyzF6vetJs8ckNXVUy4o8UOu+gYmy3I+vCP3J0Cd442b9vqH + hdhCoOjQ56zBRMhNSCD74yARCJu0eL0CEyjH0Byl4JGHTCgFoqDI0q4rGnikfB8RsMbr2YsKtQKaVE/e + gdT6h9X9G9ahR/AaglRomH0OIl3mIiQ4hd+oy8E6CxC1GxXteOr0FIz56hI8UKUfxSGy1beN7CoMvgKe + Zbs/cPUHMw9hslsghCOe8w8i1UUnCeiCIZ88BOFnRi8h0BhIHIlgYc9lJ85B2o3XCP2n+b7Wqx/Shw/t + SjISIo2IFiAINK6nzym1IINZ4RD8jcxkwlhBTq/gwQTGzEcbwZEhUhMYPcSZe0NSt6FET68OwT/K+aGL + XcyowgpcMKCOqcQjxL8n/X/0hTOLd3C4AZCiHiVHidW/VC0FfhJTLVRkuolJdwWGV4ESyEBpoNrfX9eI + /ZeV/pR003HzD71jOTmASFtRKCuEi04A9Y1JOEq9iKP9onQGXMZ8WHYj0UBAD6tWBUcomzX0SkDWywCm + IKk6Ps17rpH75Ss/LM7cVv5ZFR59BXikIBdHG+4kwtFzEaAARuz7ISlm5g5F/WB8z6QcIBRDJqYWYuEp + ylB+DY0MOW2xNhHRNYI/ZeXPWmjRAKfAkDwKYBJX7Eajny8LYLCr/bAhKugNPpKiF0w4Dq9UFGEiHBXY + hPGgJC0FDOKKQSpFklTkKxL4pD7/zM2EkoW4YQYdRP9YwVfVjZbUB/qioRAUASxjD5IfrzoGIHoH6jsh + bLcFtuNWaEUU5UAEW8GLl6rbM1TbUUQN14j+0JUfmaSWtLcCBXpk+TVPJbq8Ug1GV3nOhUS4eKec4ExU + Eg1Egrxrz20zoQ6ClRgSBQjtTEzZhYhl4Fy7Uq7+eHzo8K9HHPz3v3YqD9iIZtRBSONV0GH33OE99fae + nSAE3kQy3sQ7Np+/E7l4e+wuANIIe2xFJV4+CyexjJ1gyOEEbD/v/vzu+9bhOG7HVc1n3PaL07n+/ft3 + /fnz5/73bfvz58/u/+22ff3t76raGJgczuf2ODaXlH3/vTDI5g2vfx6FQ16u4f683x673RNbAZij0Mv9 + c46iKttrdnquzvfc9jwDJ0GY2/txiYt8RLUfGigSIgKVqYSLAhy6jBFLaDpA7bo8yWUXqgPjz58/419v + f/78uf/cjsu6DjdRxKDAoV7lmLVJXaHXm78YlqK5xo9aGPy1zsrfr+Z32atOxguH97KV5D6bH6KM0/Fs + P+8mMbZZ2TfHd17hmucPK/bh4ItKa21W89tK/X//939LTPL//fdf/fnz536+t5HD/bqgmsimixDY7/PK + e7ontqv+SfLsELEd7pldtHKKNg8RGOocWbzYlV2RwPur/axAhKmWU1TEUoy8BMYLL04xDANwnx/jvrKu + vm0jhFHcHVkjNiE8FjJBVjjJs87FCQgjAN6xuEZ+Wu0HD8GoC05XhBKKsrxPzMPSjlHXW2yT1qKS1X79 + rt9lsKcTwqmbAUTFTzd5Q6H7CJsSorUH6qyESBr+6g78VbX/3PYaszUAK9mlhS80QCbByfftyEfK4x9m + MjCoTZRQVwpxI0N2ABgmAVF7shcgfYzuwK9/Ofhttf9YFT9JUW9zsS7fb/K9bXX+UHHv8r7jMR1lo/d5 + YFe9birUzef/3lTUV8nnv7xmQGXEm47DqQvS3Udd3ebcAerkyff1gHN3putYdDL0t+d+VE0grvYHctM8 + b/Nw0TiUlIo73K2W9/73K8tPX+3nogKe1oFSwSfo1zB+jvJaK5Vp55f4g9IBOBtqKMKHMbY0ORmqt6eW + BSWA2mAPhgYrriQ8qq5B/xfbmeCDwC+BQ5U5QIhLv0MQqbLFrOdi/JDBjzlhh67wpowtW0EIaIWbGTUh + KJ15aJLPteJ/aAdh0IIvpuzXGNoRhAo92vdhHqtw2Pe3rgFgY9N1bn2D2l2d9tIh3draQVVv6XX4jFOr + nyHQ9j36Y465O95jvQKo379/X/n9p9YIGIKQ1JBen7ujNamV2qHnf6gPMXszjU04I1I3h/zrm678ZrWU + ai2gtNnUCiqp4g/J3GOUWuF2c634X1cfKERS4Y7p1wqvlru/IFWe+/ufuB59YSTw62tX/k2FFN3qLar9 + W8TVMQIgq/a5Kr+PBk5ovANa7FxR3nYUcKgwn6OZ37//XCv+F2/Pz88H7oaKBreV/nMEcTSVZR2i2Qjg + dCwkAv02kQCoaUXaBYDXZqve8x1Mxy7EDxwLgkrccvvea9V/gCIhQoPXYkAxiKIzOMioQSsqTUl2D36r + ol9vW1Va0VYpuobkGxjfPCddJUFAjQnHNfAfKyWg91krVS5SPtJ2TCXowDQOIe7B1ScBCHlneTFcBCB0 + 8EdxOS0pGFGwfgGDeeldg/+howE+ENFiQroagBI5ZV0I0IkFZvXH92gNQijRQBZkWBRAsNvQWv/SQ+Ck + 6mpMOTpFmavQtwy/YEjbMkhfQjAx03qnqxHjnzQRy7dY/UejQTectDQSXH95qWrnIgRjr936873y3K9t + kZQgNRjpgEBesoypEUM4O6fKVWu2/OD962DNNLVlFIRum3TaZTr4ECq9h31fq/6qxUFhMMLag+CWZFKk + Bub+BHe2WlZmHJXp6WtRx1RMUrjxCJnpISuyXqH3Gvyrw4iZEtO8vRsf7PDeicbk9DgxffRY/d9nDP66 + 9Tu3v6vuvfWtZlrVi55c3XECb48f33vv9Vb/uqfDZ+xf+/LY9ve2D/u0fX6zr9v/z3eEYtXvPxeib9Xt + 6enp5T6rwz1x6+VvmKTHa9/fQ9t77uWeut+bG6xIe4+e7s23+/npMDbe3rPkym/87ZG5t7qZWRE4ZPjF + ZK+bz7hW/m9KKOo0GDFjHpNZpEllYaVAtEJrEEZxRYffqo1CTjggLbt7gobW54eQ774G/3ftDnD5cAhB + Ej5hgBqjMHcmbg57/oxFVn8ETjUTai3GrQcmd7e6beC6cNfg/+6dgWwgDoH+5Mi+HqGqqe08UnjIKAAl + rKCYMQWZ/VQXYBDdvHMFH9Y/0EqLb477GvzfexLg8uugSL3BtAQpQagMKImYzYoJaaHVv0c/JZX9wdIB + aGvn2E8AWvP9Gvw/qzMA6YKEtp8f17GYII3bN4kMHhLrb/H0UKo52oNvSNvoTuVHqAUry6wtcuzafsYk + IOjdFmkKnlYq8BElqrEFqln8HrrnrzXVcolnihUAd73NPAP5jHvBe39qPaCkO1DnFaixI7BOQUxLkMKG + H8VvsK9mIrTEghRSGM7+uTWuhGZYOR1/XIP/SgXEfSRac8N4UQy3AJL9tnBkPIjBCJyHvRFXTP3+tsU9 + hpVOIwAPR74G/49PBZI8HhXl7FLLsvrwHo1qdmtY87rPh+L5Q3mtg6zgDb6aUTbbWRid0GjTdlStvk0k + cm1XV6DN5eHk30rWDORC2AiPIpCv/2epAPvyDNHkLJssvpoUUfqwiVEvIW2artD/2o5dAY1K1W3lQVd4 + CPBRLzQDJnX/L6KANveXFVO0uvnM18+F+yCz7kgNHNG3I6/Bf223CUBiWwLzmbN+hCCYETGcKWj9V04C + CtLYHeAgeXxfiIMogpR1ZmXIQQhJsKvld22nbcpdmrWsBZoPIJGFoMGzFjm+MA1A54yrQDVwEYCYHck+ + BhVhMNBgatpx5f3XRtqCyLAAHXJwCDn6IbECE5ZmX40OhPDak9BaBtsV2uxgAooBh5q3H3vv9mu7trYY + SFZ1p/ADkfrqFjmMpRnabsGXpAGRjh9gjTiGC4VIyDWKq7K0EQCM6MIPyP1vFlonNRwamRW9acdGBu0n + FEw7TslQtQCwXn/Xv59pkQudy4Yt+4W5P/dI57kPw/NDt1EQ6qi1wAlQ7bbvdhOfBnwnclkwCknCjen1 + PScVpm84IXRRQLvyQpnFOh1A3hmg8HbomteX5f6WUIOidk2I0ohe3qtH+REmlpkwvk2+ehMoZTRpgWpj + 2PXO9bhrwZ5C2W80GUh5b9kKZ1L2AokqBHEp6A79/1+S+2sUH3i/XRXsoIwZYNGDcnI6nLDvcJPebhLG + bUh47f7mQ7/iEeLX+EaKycxHkKMAFSUYuggICFl80K5WN44+Te1nGEeeM+wR1FBzVnxxsJXpVNTTFuO3 + /1eeAG5V6hFYpEMxJCXcVIG8uLw6vpGMWheCUzn60C2IG9oY3QxjTrp97xfk/hnvmX0RX0QEtQUbhlRB + XVuOE9HC4T6FWLfaCZl1lXRXakVVdMp1LB6ue76r5fNTuC8qMx4BMaphEw3AhUOafX6K1l8P2ukjgcH0 + 1ptQJ5ZgBnP2gSy0HCeHFVclLyXlRCv7whXVb0wKiEL8pUshljzv1swWcxFskLoO4qYlAXGH4/o01F/E + mEJxwo2iCQsYpiuuDCcLtvl/tRuxdZpBeM6CCEDqNwqxF4hr24tfYN2JF72QTStEC04Tbq9dLFAKCmXv + CrqfUP0XKD3KsUeGgAoIFWwlixlUWOsmPIX8U/bmEIUkmHOZ5/wSdPUN6gL7egtpYZf2pFTFO60tUAHY + DhRJ+PHVf8e6owo7ih0ImgcpLgG37tYurUut/pb5SHJOpPUZY84q0zzO2bCmr4tNwoNEk21kgKw92DFd + IV2IuTQ5E9z5gNy/o/GCqqYyzX+1Mg23YjNIJVlx7Mq12MrThYfO2nyIYt0QrbwxU5MBvKoNQFuMK03E + s8g/Gp2CS4q3hXZUFH2o13yo4o821eBCiF0qIeXAxY3DHX+ECQjWWnl6UA/LRYsqzii1pSRdYGQYiEGu + 6K3Hn1UmgbYm0lXhbVEUbVQggXYtShDSxPZDPAS6wsWIwCYQJhvzq00PrURGSjqc0BVuuLMqjTGfaEE7 + RcE6jM46tfon1X8kjMxFJmSB1uvrYux8lMFviFSCcQpMO/zDtP4xM1Ah+sGlrMLZfqAlvM1suZLcVyeZ + prosjMATdU1Yl0eaq5R1UtKCsOsZryjAlEpre+wK5/wPUdUfjKDFkLR/Aw1WoBLIXj48IYiixmAEGNig + T4BBa6w22xutlToTxB0lutLDTBVMNbPGYrqOIzLL3Fy7xTAYFAHIiEHGI4BGCeD0+xm4919X/63rDkiR + Q85s5L0U8QRjrkjC24XCTaVt4PUPQR+PogAIufamzmB1HZlZZnOPPHoUcCrIkuiUFghlm/Rcs6E1HpU6 + MFMSTKYBeId/n5TkYn1NIKvcg+fAGZ56DfTf202m3IrIao/SbSHSYpUqt4adebppwclf3vAVD39taEsW + Rh4cPC1SyL9hlIilpsDfRAFe778sAQSCLcVDqZ7UwwkQSjnlfNyPPgGciVK6f+/MU0cYBcCiCsFTKxgA + EpxV9hqqTCcMg6z6h/h/cr0o7gMKY6HwL++YAGh4rbT/wRh+DRJKaawhgRYjYg3uKrULrTAj4HxLkVVo + oNA0Lt1JYFHtB2+vtQI+Q4mDwArVis4Neo3LYSzH34PcfDfyL4XpSuRXDFntddQ520r1oPf7WnOFyZyQ + OpHVhGjSpgZswkDutaCk4ul3XCE9a1iSQ4jVUgFbhx0oZbgDws+BrY3NM/+a0MJXfWEUfksafir8v+NY + K+mmh4f8EprvkKEkR12mtN0xU4cRKk1Zu5FbZT9yiiYjAJPmegk2YgwKj5DN+Alv+3t39T/lj7c8dUeC + gKh6AtZ8YchceI0WIGz4r0Lv6jn8cOrJHGc+BPOz02lEFe8eMB/Gw4T36BMAjDI1K3QPI1zDTD/7Dgra + 6yH5CTN6gTBKPwkxZCR1AEBaeA1BeGGh7FAOQw88AezYZvAF0LY6jKLOsu/NGRVJxVa0xarXTWqPHgFw + u+4iKcE8R4WlTY6yzY6rWzgn0X+59t7o5L5CGCtEi0MZL/BQq4tGsMDqEqwsFdQBULpXjf5cMiWbLuRV + g1nBj2U7cKUODQv3YSY9oXil8TXgdS9ZK0NuJ27JHwJokKHVhDgIPMQx0k1jedCDTwB9ldfgwIVQ5Hv1 + 6vjkA8FAQ6ZnLzEkePgIAMTYlhJ4pmotxSXdqiY0A3XaPNwE8DERgFi5oHDjPaKKqZ0oqPGZebhABEAF + Tnz7rfWYg+dr9D17B9oRRC26+sBoQa4aAXRQdaF12XFVjLemk29zrcJjlJzn/1S2WIBHiKABE+yk4WVT + GJQVVCUOitUiAM1u5DO/J2np/FwVIJVvPWzvvwNrnV67CBdgyNB9AlmJ4u08vLNLA/T3BwweIJGXypBl + igQB6rFmhUJUp6CEDsACKECaWjW5Y4ebGERuHYmEeylzEFFTALjzMtLUY3+zLtGlYajXNmXWq7iMjGTh + He/z51CtQCgLLQhwD5ARUdDkLWAINqUozHJ8nR8tVWE2WPzBiDmOr86uCeZ6/xELkwqNMC9HrBUBsCp8 + YTLnd5TgEKGpLMkQoAKzDxLFB5TnPAt4JKtsd4IXbeHQ8KRXmQCcEo/MQ1HWWYZ60LWtVLS9fwdioSAv + c/OugdOAcLYuiqwcDGvhuATvQmgqbgapA3B/OMjcov8AhVVHm/v3xSv0mnXI8tjtc2ukACEbrwFcOXuv + GRswaoNltO1sBAAtaPnoE4By+LWMVBXqg8uBZehMEaWhX7QzBCBTjWlAK4Pg0TOxENAJZRgePJe52k8u + D80EdKs0OMIrqYE4lV8W4VmjFQHuUvcG69o8fgQAjcMwqtaJBHvUekeQzpHuC9QEIA0Qykh6JVVoiCpq + KzyBuCdu9euWyi9nXGXwvigARHgEsI62HK1YQX7KNSbXQGpWqNAc8CRo5f99OA3asWnkx+f4/yhpNKlc + ZZIWiSx2laotsDypmXQWqzAzBxkFQnEuPSzyGkRT0Ml5OX/CiI+wGFDLegIoQhthfA6rjwmqSizHKrhu + R8AAbAYbygoRaMopo0smsuGkGxBGAatVmEcC+aUYCaO4BKHgAwdGOQ92u/obc5gVcBoMt5LhXAz9He9D + Dg6WKpCawPH972AAuvwlW/2HcBeCCHUH45uznHgRLwCUI1k1leSWkQfq0pOQgZJrPBJPCCCv/i8VAcAU + vqHTH7i2tcf/RzJgUBM+zp0ABp3lORvnpGfgiAbAIvTQpCU5tEXYmhVmjaAcLlWT/oG9tqPCUnALckSq + wa76/+iTdBf9DEO0ctFpL/s2GQUwOneo9hyoAAmjw1YaCQE9lPPcBzOTEGxA2r5cTgtAMyhBLzzp6VeP + 0JtZ/d9LYIETAlnMLJT7MjDVXqNSLXAEI/JmRNTSZb6cJ3UgWwNoMfsT1FV4hlufDiSqp8Upyav2mAE7 + 4zvHmEFC8chkUlmtwUnFQdYOWLF3iQkARuU4rOTze3terYnVyZRGoY4AhMrrMDrnLnxloWFX5R/txAP+ + N4kcXp5bRwuAcroT7LkwTI1qO20rqTI1YeEMxT3u15BsP/Ew0DMAqeISrY0UZW9yRCiCicjUAI6cABgl + Hm0bzcw9SpobdDMniAb9lF99J8i4SgRQqoXjbb8jXD8C3HkoFe5IYrRT0CwKjw/UShx4JlOtGOtRwihW + 6HaY6JnjANDLFOkvFbIESaV7sP6z6onCRS61hNgkRTUWbHV5EP29EfPF52GtFP8OxhsQHIUHV2z+8+eP + 8J+Ex2QI6S4q3w6N4nSOTMOYk9z2s+8AMJQfysI9R9gnhln9pX1YwpAj4c5qarMM2plYrLlqNKvdUL27 + KP9ntG4YZ6A1rMES8I4jsamWbeq+PBid2KhzKR5CReIEQV8+Q4sREwvm5JsoqsB0L7BKBABZ0Wch5JCC + LFzCS9qGV1iMRCBIAlOsenCodhsBkFSYqSkr6nq/sHLtRp4qIugGnNuDFRd/oBV6nY6gFe/ErB05WzHP + OepaWgCwBVDtN8e1Eq2ABErfwEhSvKQCjWWYgDsYMBC1RbUfRnhuAkaoRFoacd27T4AN9c1Fj4wPpIBl + Xx0ertoPrQC0y0dXgAEDAlUGSXVucRFBbYZBvu1KYp2fEnuy/fdYqwYgFH6grkFxpyCWQgfdlSELrQQd + u00Bkp6hQoD11keEuy7BQgEZKFJIxXJqs1Go3Tk2qQ5Ct+q7a43AUwAwBV7YfvmSEUDYGmURqUPmjWgx + ddRv313bHldZiqJcBcLcv7ng0k0GzCTDk5RakYVFiEAp8EnhAtQEijLdFTY4rRZD3ntmuIU1ujRK21/4 + WyYQXoB7C0rRVx2pSUr+rgaAhAoME8Yoh9P5lT1Snu1w8od8dA0xkBDnLVqfVJI6qR3Q9Iy4LCkK66y8 + /CJEoGl1JQbpDQhZg+huDgF+Yy1KLryLJgKIwnlE/UfXiqKVaNXmUCEQ1mOZ8d6/AH+Esl2uqMo6K1rb + 0RSY0JONlGLOOp6A4rupnN92UWBtwZHodcBZup8X9VJiEZG3G0qKVyqnFF9zmNW461amNSKAQXN34kgD + gUADNwt1nQPqNAzwLkWqg78gUCvXVdTUW0+TL2L6qdy1mVJzFqUBNAIA1fT3gAXtlcZ00gbzNytT6IAx + nlgwAtDimuCFJxFFMPFViTqkHnRCGcex1xo8wCpMwK4rNaYmQJ4yD4XGhDLd4TZ8iclIafkn1ZcuofTT + Vy0TwhGUwCHmcNNYqMI8Il13odVvuQO++j+ExNgI6kMRdbjJmZeRbBcktSHbd4h8E9S9wCzIOS4HFtU5 + jl0AGnYaV1TJ90e/Ug3ptKKMKJx9+WEFe/gKs8GKF3jdBU5gotqbFxJQwtq32ireCYioltgapqDKG1AV + p7miFo1ii0DsHUwYTDyHR5WVmRMyAoN2qB0ETGa7IQAAIABJREFU+ddCgaFXMkcxZu9ZigeAQN8dCdKL + 21INCyghasHBzTS9+i/i2cC7LKo/TyjuLC0TGhlD1ICUMhOPFtBwARj6D7yFwC2oGs1505JgNEdl++1O + xFoVZhg4rxEADbXiIEU7wHUaTSXf3pgdG3QpwVZtnuIs0QY11wFVeNJ1HUiwXqoTUM6kgNl/qRXJAVSY + BJKUCqNca+2FvlqFuZ8Ui/s1gFWPOSc8dlSeigBSA5BmBV0Cqs3dq1PchZbC5+14JsDTjkdLWRY4gIT+ + mQB1IPLTYRyA/P4wlJHpcaCsVWEmBTwhvjpCmCnj+icrDKywCCeCsRbZSpLtbHEb0hwFgjujLPe076PG + 908ai94jAKfvjs48ErStQ51sm8HbqwlBGixMuecscnMNYWzKxTuF8AP6iYF5LQ7h3TgmC0tZVPPmB/Co + k3SHAuzaf9rABRrCK7AvLs3r8TbcMKeLSEpTen04x4oPHpmWAiPQ2IrDVKbfTs4a4aWT+/Z68hnMVHkz + IFCC5r70SXGqtx3DGpM0NKuO8WloB4BYgkEVzq3xaiJHvp8Iyru7MMinZ4CpyiV3WtXONnOr0DqegIoS + OgK4tHKuZdeCgk2EMCurNDvbsEFVohfCabQpak8DTox2lTEI7aoBLbBLRYiKaFbSCryToILjfxN2GdVU + By10cFtxSNWU5TwBLZ8iKBa5tiBzYIZ3cAbxHnRdGU0/xlpITQgQnGBZ2oEJh3uBScGQTTRE8aucYMQQ + AhOZUUFJjoBKLVJ33OU9AcnN1ZNyYI1YNEIQVptRojELFF7cRRTDeQMuxQSEkcY3UngBfkVFdO466VSj + /9zSds++5eCcZeiKIv3SXGFFix+u5glIhTWj1R+eBCLycSvXrtq3FObtwERriLW8RADFTW8oV4Ln9RqY + Q9yewPEwORS7X7BLvdD50iGRIkIFVtEkP6xAnhyalvz4E0BgqwVwTX8WAYCEoUicat11g1YtVmpQh1Rt + DaRmAMNGSTyKKuLGPoJMk4OmxJqHIM1B0wiAyxOBowjRu94OIXHNaK4yClghvJTUadebZ9VonTohEGRV + UVvC1szQiyt5NiTCJxCRAbJIWZnyArqjEjl7E29AthIPkZ/HAoWVeqWrkBaSUbai0ox1TiJoy9Ey9CDt + ukag1JS44PqVTUBgmzbXaqagWrNRtcS9spVt9bnQXkKxz+PvZA6qdMQH8TajaDCqLxi2msDNFqCUgg6z + 5HoRgBHWRO8i7IVRuF6ck+7mrVvS/oKwJz+yQ1cq0pquhvK9ZB0XBnenLVZwLEaWQrwdBzEHRTALBeEH + 3oMUc4M+1CtYyRSU3hyVXXBVROradfB+gdKtWXVoYFB/XWt4CaQmMvAVDJuW+PlJurwpBlOsPyAkw9DU + AKIqsVD3RXEfO+V5Ji2wQNlUjCBzEq9cBmTiON39ahIVRJGj/yzxBLrf7fHrh++2ClALhqtSwjh3BnNB + 9fsgoPKqlc81HUkNABHpAIkRIeZWf6pGKzDxChSzhtAEJ4AMYwzB6LxDaMZRtxrwgcvagqwFrDzsVwEB + HScAJmirO2ACsw+jjoXEHQvCeAXWj5F3ARKAjyDxDKXgY62pDUOOtcaaXvpSBSY6yIUykOEFWMxAkDeO + YFVStQGZj2IRpKasuHNXJoWUpOhYGJ8O+LRD6g9uqcCqC6AcgTxHHB71VFqaivVStTnC/jXLac2ZYlDP + 6ILB9sNo1/uqsarm28igNc+sb8LV8B6VXB6spA4nHDaAtN2HUxo6YgBYJyAjCRlGHlOQgQdFsBbUENrs + xy+6jCWYIXgM4QnA5L6pWq9DF9J2H2R70lb/WxzCikhNUtCDnxg741rODPREHt2GFZ6DIBNA6ypbJUEL + HngC4/6LXkBSWFHZlGSjN3+bBG5/H/+/F+TI70/724aLkEhBWmQDhAQbu3lBVmhTeyDClaqgeZQ7+9Rz + LK5zdK1llT3vyyvvxmEp9RXpPUAoF0sU4KkOQAEnxisOXDmG5n9GGKHTOo+ISMitxT/j7+iz0PswOPsz + rzRbGnlpogCZVrR1mUDQUkjEv/f6/M31TB+LIgBbOHXAOpMCJy7dBnDVTRYkBdAFI6ZSy3JPXlAyua6w + ROKtJUj8gLTBYuEb5v9WXOzcvgvGIBJWHFSjz7h/3QjbV7JToVqWEKQucizeb0+/3kmnU+w8owJ3smel + VbMkLoBoAliXbrXYvScCkIAeaMinlLZihKLwRMyo4OrimoFfEiCMhUQnIg+0oAmT+7MWmkkT2u+RMAAD + 0RBRlFUqR3M2YmUhsDJ6qbL1LC3VBcnUlE68JWzT4ABb3OwzWv3B6w7bSY6nAELwgIsPuIuOYSMMIkDK + dc74Babfpa01BIIVjhAlVv6hBCUVAUiAnXJGpIFwi4mCXQMq5gpWIGYLCGlvsWvEWlqsgAbojhZr45FK + f/93j6wc4volg3jICSvxG5xc/RkgaDhrMIJKc9VsXWPgK56GWZaenOiKIaiVdmXJqNAaeFN0gNiqP1Ke + eShPBXAKd8vOFKrOEEKVEzdringbUqVqhnyTe19GojZAP27YpNPW1tzEoVrHggXIooBWpcZYgsOYiCi9 + Px26uQIWMakkBIjOsMJ6vTPVXHDXVcltKEVrhs71kuNVfX+rGqMiAFOoYrWYEqs/hEwWBOINxL8AEGE1 + jMYe10NIZOiyFnbZKMCRshjyMyV36QkAmuCDBLlUJXn+MAUqhpZi/dcRY+NBnXLcyjmjZizdeIDYmssq + vNDVgxS7gvaTknHrBvB78tJZktgIowBMC9qWwStgSoqedrzY+VBRQIrbgKEEN+lZkAJgUm5agByUKCVK + y1nRL+XaLYwd5yidZjY2hCmNmeCRS1s3MAov/ljLhOCgcFEFPFJ6eJEOPkTrEqa+ovrynZUdlCiHHoCD + uADZwq4R0p1ardVkj7mUFB0LUEUBkv0HLQyRiFt4bAEs2WgkkMyJFRpCZw9qIhBikcpdR/HkrVowS6OU + NBfCc8Sgx9B2Vz5CQQTgimzMRTSnaOZp0RQB6pINfC0P3uliEi6OtBVnxUbIon25DdJpxLOS/oap1hbM + YDTuCgEIguEFECmy8iJPz1PowrlEPDUldDiAFld1FlLUVIsRpnAKrvjbtgfrLx1twcFnqggd7INNzLwV + pyv9eqGCXO15RwtSmn1I6nY4AchQigIxeu65naWh8jIEZCMetllueqDJ3p4HdYMbqLJbiW2NQEQnLgVJ + pahpThsWtZQ2HgUiBV2bkZiTABRt56KeIZGV3DjFuQWfazEJSnOCTi/bn/uFJY4AnNAHD3Uh/OwVWtDV + B8wKbCyulWhjP2s6oAkoCYdV2LXhBkKuRHojV6D9F1qEMQk45kFIlYhnbK54G8utyLrtB253XkXxEqqb + 0hdGIfAfeQGYw6/Bj5MpFyUpwDEKGJJZ5gQL+SQhK+T2pjbtNSgxiqQFBznjS2omvLrOCBR2IhEIpY1o + 81+V33cTaojeM4CuIaDZczbk2oBTTXbehQlSR4FFbcNRcwFKr0+Qmtp8hKe5Q4T/v9gEUEAVcHrmqVDP + VfVUtfn9+vjtPff33v7e7/z2/+29t9fc9vm2j9tr8faz2d9T1dtn7p573R9ejun2e7t1z6nHuuPv3qM+ + a/f/9ju9/hzP7f48vPz9hM15R2X/396/O49vj90/j13fbj/HY7vv520ftTme+9+37/F67brz1Z5osrHz + nlyX47U5vRY4nYfjeXw7d3U/L/fvfDindRo35PftGA73wPZcbq/D/n6q5phf/v5FxrtEBEoBiQl+Ocv9 + nGkFb2toWfJOC+BIAZ3W8Gv+Tl5/fEwpIif98jPYCbzS7BSEiA4EJU6F2AHuLNxLtnfXJqFrJ+d99j7Y + 6jXSCMIIf9CoWQHHYCTvCt5WXPh71syWoLp6Nhg4BDbC8GdkiSFMSZbxBCzjOkMk0IeBEKtcVgmo2EIm + dBFLtueaItsKhiC6wyPSx4mJc4i2XYyAlG3LycHPogBd2TWY/4Z8MQwISFY8oTDyj+s5t19dUhZieeKK + afFpP4dMw9FLwav2HJYyBYWTtoObiBUHwOA9poFDCgofgH9kNwBB+wEqlNGrV8TWIio1NJ1YQG02gpoq + wFXQzmNMw/f5OSiWJaQwyFgsAvC6CNCWeJbuDm+CqxiQrDMkfDLqPZsSIhjmBnbW1B2IQvO1QUU8OrTV + ChFA27eGwrXr1Vl5yzMNAtdilf6NwoHIMQCXMAVFGUPaAKNgz7tRZK4JgBqJ5Oq9Gw/Pob3fjPpNR48d + tD8NWijjedKDh5fS3gsNNReRysvOEGWCyZk6OtEajcPDN4SiJTwbmA4fq3VJdeWAdNRpCIB7cnDmIDL+ + /3QEIMQguZS0Uq413HxoogOEG8rjOwKBg6gofwAagGOwEco2WhNlMo6FNB49rFireDbMaBF6jT5h4BF0 + AHhnjkQACNF/STdgCOptSw4RAAoIxxjKKBRMvo4T/vAFpikocw6IaYE2DraLkI0mbmSWtjGwzhITAEp0 + udCq+FD0JzIAkobez0il4e9Wf2UbpjXqFbPL97d7rb4JbsEq+WXH2YdSlIHpKSsILKyMlWo3ZSxLLhTa + Xed1TFsQrfyK6diF+oPWuLLisGy//037T3UDeMvHOPqASUlx+S1Jb4TAWQOL9ZidVmASgoKu1ImIRiR1 + BaElCN3C6jpBa3RplBY/0VqET+WG09gEjyhyKbP6mAiA2YdLcQhKUkhntpqqvK4aXtL0pgVSEQyA1V9g + wiiQCrXOnEIVCKVBLPDwNYAxxclQvAtIcRYt3OJ4C1yI5UNyf8YQVMiwkbCk1E1MpKX73JOnGkuZgiYk + lZkIAPlNlD7O5dIgSU1ypVsJqYmcSQqldwlIYd1h2JN6Qjpfx/rILZPUAvkioSwyC33h5aV2OdUi4SWT + K2fuSBqrb6rQUtaasNZCuTRGfe29IR4fp+EGGkNcpkKtqhXYd8ggAWJdxFYfvck8EtpAg5JFoAgR4HJd + EMorCznOzkQAXtoMGrwy+XnDEViioiyhBT+8KSgfaMNIjHGlKx6u97RsCIi1N179lAlAmTIMqhAETRax + HIJEL/6gMPTIm4R5QiryQoqFEh4704e30YXJ/+EFTbnQ5wI4DRgmJhnow6liV2USYJRJCypVvr2W9Rnb + jCmDjBQCLTmqgw6DE3j4CCBTgdVecjA95Tm3mCjvR3lzT+iJfFfsXQKpqYw5uWDuqEApivllKkUnZFTh + +qwNUktfK5vOuJs47PMQ/gUPX2AqrqnYzujS5AQaU46SNuwsNJ1S4mGGMCgZFT4+TsMrPyHg6HNejLHA + g7Os45T6+swtK+AlzqaCaSjkrrlmwNu+HnsCSFdmTqjK8k9kbdSE9deCkFLy1vn+eHSgFpSwhp1o5/kU + EdgNyrvh7TjqszdahUbZVl86s6aGFxQjvdrNBXifeTMpWgxABYo0SeQl0oTeG/K8Yq6B1DTANwSKVSoC + ol6ACDwBuZR7fcWWoNGoRBLhAMgTV84jbvPYg1eY49WfwaKFUConbYWAHutfEEzm5Yk0S0QAqSQaawci + bXH74rjtRqC+bvAnUQDTj6eVVRshIHaJXebmCow/T200cKNOyRJz9NWCtmijeSt8BwNnIMxaRCCRwqat + QAS8D4EJGQZabV1/v6YWQGitTCYaMJhxSEvw7u+xyARg8fnWeAJzMumBNbr00sNEVJG4Ci2B00AkCzYr + m67k8p35B97j+Gu2//3NJPD8KsF9ky++SRHf5JJvEsl3+eSNfPRNcrlwkwaveqo3efA3eWXcP+vpJnuM + 7Wfc3oeNFPNjb7fve5d9vp/PN3nq7eueNq9/2pzr+3s3/9/Of3dt3s4RDvvZHtNtH2/HsT/f532xz3q6 + X7vttar677//Hvz6bL5vbe7Dw/k6nhc2Jrpztb3+/Xl8u/dv13/3ms1rn/CPTpTWsQtdWYtr10GZTZKw + eRWaqXbgFSQRJF2TytR9qew7IZukBK1iRS4sFAEElXc4taUQtx9oBShbtH82U8qbDyHphDrmgOoLqALU + Gvkl4wN0/XRvdS0hwTSnZDyCiXYXzXNF1RuP36ZFYFumMRGsxiNEPqt3YFaCLOMr+v5xLQBFihvgYhOs + 0kkmFJji1lguAshnfEU5jYhBEqWpXHlFKxYhkvH43AoRAJS6LwwmImVcQtKrO/n4437/eb4UKZjE6D9l + kpgRMVYRm6SsPyKGwvv7jhp8njw1aQje9VeYYLRIxsOgWiEC0NJdzq+By3erKr42XOkL3w9RNJGrETwC + kLquSIchUn1dDQOA3tue2kkXQqeevAPQw7qJOAjmkIydtfYSSE2Ap2ZEB2MWcRmlygKH8DBV0xmJolk5 + Kqkn0Dm0rkAyob1kzqfPFJGVBz0I1Tq/bn3OD6kkdK47rOEIxFIkjQ0wsuFGNJRhPdhk/1CtE1gNM1Db + bnpTUQFLcDHGh48AVC9ZhX3gvXVAAq34yqzpwLwGgKgg22IXVkBqUr+DgBuACWWngPDD3vuQ/dN4FcFk + rYAaTjRh0hIRgIloDD10uPNIKvK88+BNQ1jHh4bE4M7DKyA1BxP1pCQdRPl8n+KJ2kDTxXlYAAWkk6kw + jWDURmGb3OIE8NgpQKSPUMItmbDsQC3FEP/uI7GZ3DVAAC4D1UbrtQjhrDxm0ykkKk/9/h4aRRUXnwqy + 4s/EFGju/+ApwLEGkMirnQ1ZuNFG2z1A6d+zrD/R5h2GEbqKZHue+6tJkyv10okbrB2Ox6v6z8uH8QIU + JIUU0oihE19YKgII0WRO5Te3kzarNpwdeKAhYIQwlzEEMU69cyks06+cjAA+AfX3v8+aBJ4O2PQ3XP8Z + Q739/Xx47MQzOODdt/svPPbE+HzE/G8x8ye8+Ru3YceR2GHFz/wJhc9/Ko5NfzrxMXDiCJzw6w0HQV23 + FbgazwcexPP2/jp+P8aDuN2IqN3rtte7w/TvuAKHc/ZcKKB+1SobiJrJEB5nUmxB2ZMv4grsv48JvztK + LiY8AIBAXMIbYjjaNo3asBhUG31a5fr9HXbAm7eCS95hkdDfdwWOQBZoSCm4Sk6f/+Khby4FHmH0Zijn + 5TJmEmCuwyCQYyfMAu4l2Oo37AfSCpZgDn/CFZZAVapBDW9EZ+Xw/LITAHdFYaQSVkmGEF94/Aig66VD + Duhevmsof4QEMo0yYiDz6kEpaevRI4BRyq0nZ0IiLG5rleGvQfz975MngF9Pp3wGPZ//mONvOPH7GgF2 + udWNC/1UVb9//15iWnzuvufp+55z/+337zjiUX66qQdszz2ru7Sc9ub/J5yv8zPe8tdH3/7777/7NTid + C1kH2WtWqOswq6fw/DqGPvN7//qqSOAmCPK0OXGFW+Xupfh1L5BsConP9+Ie7hdiK9Bw38dMEfD+vuZI + gcN+uv0Hn7l57m3gvg3o5833vxU/d9939922P2/f4WlTZNuds81n3gpOT2g+o/aff35/nY7tCUX293bt + 3DGczv/p/+29IU6sO/Hxc8djf3vd7nu787P5rm/XeXPP2/P7+trXz/tVCxX9Yphw4PajBUZhxSiPegJa + dhk6xEUo3gD0Io8t7htSCm3KPxHg0t0oLXCJjvgCilwDqQ+MClyHlXuuU4AGt89+3/PokaTMxNaZpRit + RiitRirmglHfadNFItbXJ1h59IWsHjXYQyt7bgGIWYMSwxRdDTnouRGHck5CIBmdcc61dv8MMo1V/4dU + HQK9RswwQ9YuJJLSIxQdZn+K2QdtDApC3noIlZ+v7gp0KDar+08GZaukYwYA035n2PqRQG2P/HejuKsA + NMMU9vqqf+8jMIpNnILH3nkLwHkVKKNMdj1hroFxjAaJIkl7jflZypWdTswwEQDxYkQPlqrvvKE1FXUn + WnmuV2vmiJRfD+ViaxxzQDzcaIuOQ2gHM/0Ap9jKFIh51wcw13T1x8wqCQQYkNKej8SFB8qJmBrZhvqJ + samtT2tgPSDwvQf/KRJACRfUPKSlqxtZMae8CS2DEaEuP4lekDvyuNZot8pBkH6Y2CoTIhlMXchNXoy4 + JSIABYumExI0x4SF4dqIVnsc0EgH4LJ24KSuHzMB9BJYpamlbKUQq5uvIaBRyGF0Vi18mSDy4AwfCMiE + 8tSJeGQfFuerP02PZP5a3lAEZViDOh0ZSkizy//b+wl57YLUBihuAsgRkl9h6b0EVNgyCDl9la8ennWo + xRmaCy9sulFC7CSQlT5XsEMxz2JuPDws5toB8DRlIj8GJggj5N+HEh0hohhQBU0IjcVyMHRwZR4oRqrw + daQR3zl6rJ+4oYoXYqgWoLZI4kq5mBRnMKg5qmGQiHSqwQyjl6DUg7nU1BCyU1HqhcrrDkzEFFoQVrUw + R2dpBkQKy1ATPGYZlBX5AEro9eH61U/e5iIA42E/XdgJwttWEBPvUMw1fXxV1S6CMSCmlHrlJ8VJTBRI + QdKlFjfAo5ZZdWKwUBz+XPfCq6q1qzUVNVZAtQHxfXv9H5UOMEmsUz4OEVZBCViSm5SJW7AVGYYhJlpZ + ke8hSW1A9eLRFzzBNeiQ6NiDR0Qpn/18riDUiRXeI2gZAzz/r0m7eSPaMpyRSDeB4AeH/R4jwAEjI0QS + zskyF23RdUU4fcEFsInVMmyNICGZQLQ8g7w70LGX1u9QxVXknYxUm5BEPE4U1avulI9whNV9xrK8Vv4w + EkgccDKoak9pha3KS9UboVswHPIQXB4N4uYdZrAPgX0Y1GwiV7IZRKMwiwKaKj4SMBKrZZS28aLGK6mK + LyRTz0YAQsfhGulTGIHQGxAe+uporXqScf1nI2UGMakxdBq0CKoVqxT5eN8WRKsfOChFlkcaHAPAMBzB + 6g8V7gd0ZNqLh6/+d10VaF2E8VP7/B+KE4BysOlnWhArpVxJJyj2Qa9+SCrd5Tjj4PoHbDUnphNq4I+g + ug/j+OMmWYraA2/jsbaezMOJKeqsDP2I8BSJRRiunP9vugN4l/wy19SHFNVUK6GA7oKBfCARiF3ffQjv + OIpBQAm5MfSIScNFgBycZ2ANza1nfSGtN4FyQUK2+lvHJOHQQ23q9b15jeh3bBoj0F0MhSsP/O5TCm47 + YLhCDitY+dyzaO2gLxCq9wp/RTDCkg/PtXcAd3amAxOaI9AqQau+PxJCmZmMoBYQBgh6+32N5A/pDsxa + MHsRR+7uwjX2qL8hq1mAo+Eosk62ryC0EdXq74E/oGQqCJl3Vk3XKZbjVwx2DYzseML1ADkG697bSdyb + 1f8awR/WHRDOw62HW9aim8N/I3I6HkHRbwQDcjgGYpvLg3cDQuCPBj0piLSrXYBfG6GvwHvsqstCioNw + TkYIi8vgCs3Xyv8VkYDzHQS9SWGZXT73T5SMYOXM4Xn8gf+fV0s2PndlEG5gkVA/uTJh1zb3RyZl7izK + o5Ysw17AWYIrheX+PF4j9tMjgTKrShf6IaSIiry/udlVzz5TzoWW+XbMRwN35WhEsgIHNRGXXjkEIl/N + S9ZoWLpB9RTkcYKmaCOUaO8mqWuk/qOagAK8KOz6EIIRUqtOmWsoEhO14watLyiIrmQzAuHqzwBXIs0x + BVaoOgnS74dIDQiG4ANLIhImrablfFX7/2UkAMjw0vXdk8kD5AaBW/GTCr9EzEEUpkihTUw60tY60vXj + n6nVcTQhCUl/v51cmMoPeMGQKCslqEnH8rxG5le3CCXHHLmjq8z7YKIAUAkyybGHDkGt+jF6cQtn023t + vTp1Yacl4CYrVIjaQ2jGyeTOYHUCkdCWi4uwMNTfNSL/aTQgOObAfAsRnIbKKLizLrE6/O4r6MPCg3sm + IE0H4AFFyolpSpU4SjecerFyMObwZ/m5QcF4GFfmaxQ+BGpQy24xsJAToEAZbfpSuvyQCDTlE8BlqCCo + xuDSVZamDN7qLIFUVFRrlMZVBN6RUQfG1AnouYGYgFmUdgl5PPIkQBR2IxUbIUFVQvZ5mn4MiitvGXKE + S05zZiVfBdBWlvOltzWMmMqbiJHyTkeXaqiCHysqMl5IGsldI+7hIwHQCjGtyJfSfjO+BNCOukyXD4FY + 5gj690jlq0SLThfRoGscjlPfFDc9ms91C4rrKoh8HWXs52md6GL0LVUXQE2q4jKZayLx7avgHPrKlYGL + gnGYs9IgRUYb5s9EKwHUdm5S4hMDZtuNpC8vRV/f4bJ0jawFowHIdhSkhvvsjQ7Sj1erD+sKTFmJq0HG + cmMoZhuEShIza4HG14P5AeguRQQ4Ei3E3r9Qw6a7OtE1ohZvF7LQ0EYA0iIrAadwRp5VIILpxaNoq0oS + iGbUj5ALq3JyEUNVGlZnC62GvobMuJSKeXhhkmsUfYuUAEYLIKHDig5ApQy+QL7cCJiMcsq71Sr7tOkA + QyJCkKAYnDgS/0Tcko3zf2hxE0nnbQBS18D/7mkBODXXCX1QDACEhyAT0bS6Axy/zjj/MGjHKPeXWIdQ + BbixTJtJKWTfXsh/RYU/QJiWXIP/208CVOMu1akDaU9NOBgPMRCGsSQbQtgkWtVbF5wejMN76AQNaL0a + EAiQhjp/jb7fkFgOjoe4KLw/fiKAdLNhLTGlAgQpMR1YfRnYcUqFHTOVf5lWCD1AKDkyB8JCjLqTqz+0 + wjKYnPq14v/sdiErUKXqtJx6m0pMN1x3FqYq7L9xuaVsv7ilWC1Ccn71N6o9SFyghCiLE2E5TBTXSLgm + gl7xxdhOwbSi6M1oTDOZrTkExXaG5JNEANR8RKAIKU4f0L6LCIFOifQ3Kz425/a686+tmQiMXp30jGOr + vBecUNp0vFXplYwiCzJovH9b7Dxg+5XQitRsLK3yyyr3COzh2Pe47vS37dd1CvqJ4Kmqnm//AVV4e/7l + OdRToZ43/7+8bvt61O2N+9e8PHd6f+G07yLHUKh6QtXz60dsj7fb7+24nurlPU+ozWsOr919z/33KPea + +9PH87F//nYcx8cnCkElAAACBklEQVTrdEy3j73to3/N/rXnfb0+fN3v1/aeQmEJhWAvja2lvhHKhvMV + 9EyBVi08zmAcM/370AtvriAJ6jugjUaYH8OF3b+2DysWwt7EShCT89grcMuBtRJn0l0gyjlSgViRpaC6 + Fyl1uG/jeaddX8fYHu91517b59cIYNRvkQh/hkCbxAjE4BcgDTRz1x5QjIFvO1JOQzLZmTrGRdq5ti9N + DbRJZ7OKQUCDmWQZIH3pnByXVrYVGANhkzZCpSQQJt6crVeWalx35rX9w6hAGYhwX4J3oeUiIU9400xC + Ux6VRQCD6CZQTUbh+NwblcAKg1534LU9cJ0g85wH6ZcP4ZvXW14zIk6G3afOSgiw/dRaDJHpR2rqefXw + r22ZyQAM/GIGj+6TzxXOqAU3U78FjPU3Igtzz3kgPgNCF+G6s65tuU1W2RnpxkUFxck6Z209WPVjJMw5 + BPJZ5SDSWsH3stW+tp9RPITj86OF+UK0/CxlV0Gau9UbXMQz4eWDmX/AwIivQX9tP20y4KtqgH0XEt6Q + hqFGMYfoD4B48HlegXYNuu6Ia7smBOuPB++ua3D5p5AdIBJmkM7LveOyYSBeq/y1XdvfTArcyBLUpgxW + 5gxUrIRIlkPXMy6+/bVd21dODMix+LSOgPJgo2Aiuq7OtV3bA0wQZxQfJNAIlHv/FgFcZ/b7bf8PKMR8 + PBr03lwAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAABAAAAAQAIBgAAAFxyqGYAAB0sSURBVHja + 7V1plF1Vlf7ufffNQ1VqnpJASJEEk0AQGgmz2kivVmzUblm0vQKiLdoOYLeNU9txAqc/LcpytUNIu1yO + uFi6mERtVATBSINCIAkhhFRSqdT0xvvuve/ee/rHe1VUKlVJTa/evufsby0WlUrl1bn3nP2db++zz94a + GNJhZ3evADT4tT/rAHwAOgQArfZdAV/U/l7D8d+HNvlvJv49ILBt8LDGb1cu8IQG1MCrRipOMoWiDtM7 + 82dOJYptgwO8ppgAGEtm6ALQtSBOU01haFWiYvXABMA4qbH3ianye+ruqkvwfP4UV8IXwA1HmRCYANjg + lZ8CXwhA03ADuw5MACpI+umvXJYdfsnIAKwOmAAkwo7uPgEhAurHNz6OwLEDJgA2epVVAfgYkgkgCEbf + 1SuqEW9GPckAHDNgAqDl1/cJfgvsIjAB8G7PaJQy4OAhE8By+fY6H92xKmACYJnPoA9OS2YCWLTU50g+ + EwETAO/4DAniBBwjYAJgw2ciYCJgAphu+Cem6DJkBwcLlSeAuzp7haaz4ausBnQNShOBsg/Ocp8xSQSA + spmFyj109SyfweD4gHIEwLs+g4lAQQLgIB9j/lAjSCj9A3IyD2MxJCB7+TJpH4x3fcaSuAOQu9qxlA/F + gT5GPSAjCUj1QBzkY3BsYH7Q5TH+XjZ+xrLsmXd1yrPWpCCAHV3s7zOWkQJ0rVr3kV0AKjs/Gz+DYwNK + EQAf7zGoIMiJQ4EcNO/6DFYCisYAqpF+Nn4GPQQxOBgoS+LzfQZ5dwDBulkYmIGyz89gd0BRF2BnNxs/ + g90BJRUAB/wYwQX9rEGNtvFzai+D3QElCYCNn8EkoCgBsPEvs1ANhea+YDwX7JLJQwIaG7/c8AHo0SiM + 5mYY7W2It7fDSCaR6GhHOJ6AaVlo7V8LYy5LQdeQGxhAuVBEMpHA6IEDiMXjKBw8iNKRI0ChCN80oXke + v/iAkIBGy/g54LdQI4+uXoXmTZuwYu0ZyPT3o3n1aoTTKcSamhBOpRCORBAyjLqOo+I4qJhlWONjsHJ5 + lI8NYeyF/Rh+5lmMPf00/CODgG2rrbZ8geuH6AQGNTb+4Bl7vLMTsc4OpDdtQtfWC5FZtw7dZ/bX3cAX + i/FDhzD4f09h6NFHUX7xAHJ79sIeHlawzTqd0wESg+AknzkgHEb6nLPRddmlWH3JxYh3dSHT3U3e6GeC + 57ow83nk9+7Dy48+iuFHH0P2j7uASoWVgGoEwD7/7Ij39+O0t70V7eedi44NZyHR3CTts5rj4zjypydx + 5NHHcPje+2AfOqSEMmh0TKChv5x3/mnyXggk16xB2yUXYfWVV2L1pZcEcodfLJxyGfsf/AUO/ORujP3p + Sbi5nLRk0Ggl0LBfzDv/K4j2dKPtvPPQsnEjel97BVasPQPhSET592KOj+NoLWZw9JHfI//sbmlPGBql + BBryS7kp54TlR9Fy4QU45+ab0XnO2Wz0J4kZjA8cxuEHHsD+H/4YxT17ZNQCDQkMNsQKVd/9jZYVaL74 + Ymx5303o3ryZLXweqDgOHtn+aRy9935UhofZHQgaAajq9/sAIp2dWH3l69F1xRXovmgrEuk0W/QCYwRH + d+3C8GOP4+C996G4bx+7AkEgAJULevS8+Wqc+Y/Xofc1FygZ2KsXju1+Do/cfAvyf3kGsmwsy0kCy/aL + VN35oz3dOONdN+K8m97D1lonmNkcXrj7bjz3tTthDw2xK0CNAFT0+Y1MBud8ZjvWvumNiMTjbKXLALtQ + wK/e/wGM/PaRwKccL1dpMS6xVweE29ux5XOfwVn/8Pds/MupttJpXPLlL2H9e98zrxuOFLFchll3hlFq + 9w+HsfKtb8E5t3wIK1auZItsIPY/8CCe+vxtKO1/McjOQN2PBrX6Gr86F3yinZ245NvfRM+5W9j6iGDs + wAH8aftnMPjQLzke0BiloYbxp/r7cd7tn2fjJ4aW00/HBbffhratrwnsM2i6VlcVXTcLVSHqb2Qy6H/X + jdj0vpsQSyTY4ojCMk288LOf48kP/xu7AsuhAHZ290lv/KFEHK+6+YM49+YPsvETRyyRwMZr3471NwU1 + OFg/FcCnAAvE+ve9F/3XXstJPQHC2bd8CD1vuDKw469Hr4Elp0PZo/7Rnm6c/5UvY9P12xCOxdiqguSy + RaPou+JywDAw/IfHg+gJ4J5S4dNkYwCy+/1Gywq85vbbsOZNb2RrCjjufcvbMBpAEljqBKEldQFkNv5w + ezvO374dfa9/HVuPBDh/+3+iafOmwI1bp/p51TN/SXf+1lZs+tit6H/bWzizTxJ0bN6ELZ/8BJKrVwVu + 7Etpa0uyZU9Ifx8SRhXDYWz9+h1Y+8a/ZauREPt/8Qv8/t03Ba4g6VK5AkvrAki2OHwhsPYd1+H0q97A + liIpVl1+Odbf+M4AugJLIwIWzSAy3/Fv3nohrvyfu/icX3KY2Rx+euFF8HO5wG1QNxxdXILQom1XWuM/ + dwu2fukLbPwKINHchHNu/XeEEsGK7yxF0H1R9itr4C9++um44jvfQtuaNWwdimDddddizfXbAARrSS82 + 72aRG3g18CcbNt7yIaQ7OtgqFEI4EsH6d94ALZ0JHAk0hAB2dFV3f9lcgNSGDVh79ZvYIhTEip4ebPzA + +4FwsMqzL0YFLNh+ZUz6SW3YgEu+fgfX51cYZ237J3RffhkrgLns/rJh7XXXomXtGWwFCiOaTqMjgHUd + FmqTCyIAGXf/lde+HZtvfCff7mNg9VVXIbVuXbB28gXa5LwJQMbd3wew5T3/zCufAQBIn7EGPX8TvOSv + hdjmvAlAxt2/afMmpM9Q88jPc92T/qciQoaBM66+OnAnXAuxzXn9Cxmz/ozOTmy98w6cduGF0i1kyzQx + vH8/Rp7+M7K7d6N48GW4Y2NwSyX4lgXfdmCXSsBJFk5I1xHKZKAZIRjxOKItLQg3N6P57M1o37ABrWdt + wIqeHimJ4IGbb8HRH/0kUCdd870jMC+HV8asv/arrkTvq18txbM45TJyAwMYfuZZvHTPPcg9sxv24OBJ + 502vLZrZfkYAcAoF6AAqAMq17w/fdz/2+gIilUTHRRei79JL0bZlC1r71yIqSc/D/quuwui998MrlYKj + AuqlAGQs9qG1teGqH/0A7evXBfYZKo6D7MGDGPjVrzH21NPI7dmL4ksvTemMI1Df6sxVt9MPGYh3dyG9 + YT1WXfFatGzehPaNrwr0ker4kSN4+L3/gsIfdwVq3PO5IzB3BSCZ8fsA1lzz5kAbvzk+jme++S0MPPgQ + Cnv3QvM8AAI+tCk7Qb2vaVfXhe65sAcOozxwGMO/fhjxnh70XPNmnH399Uh3dQby/WY6OtB21lmBI4D5 + bNRzJgDZ5H9i5UqsveaaQI7dLhQw8Nhj2HXrxyebYWpTdnu9IXOnvfK7PA/WoUN48atfw/Bvfotz/vXD + WHX5ZYE7Yg0ZBpokzwuZ09rYIWGhz44L/gpt684MnI//8v8+jEdv/Rie+MhHYQ8NTYtU01Nphaf/jCc+ + ciue+MIXMfJi8Np0NZ/ZD6O1NXDjnqvNGkvGEgGT/y1nbw5cea8XfnoPnv7Sl1EZHp70v/UAdF+yh4aw + 785voLjvBVxw+23I9HQHSCmuQrK3B7nRUfl29rn8nIxlvuN9vWjbEpx0T8918eQdX8NTn/1czfgF2R3/ + ZBh86Jd45OZbYE4SGH2kOtoRD6gbMBfbPSUByHjdt/2yy9C+8VWBGOvw83vw4HXvwDO3fxFOPo/6R/Xr + i5FHfo/7r/47vPy73wVivLFEAj0XXwzhy3lFWF/0DwTR/3/1uYE5nnp8+6cx/NgfpkTyg1+DoXTwZeza + /lk45XIgxps87TRouqYeAchY8cdPJrH6yr8OxFh3f/d7GH34t9A877gikDKQcvG557Dnx3cHYqwrzuyH + H9DScKey4VOsJflYr+N1r0W6pYW8z7/7e9/Hrls/Wtt5JmS/XHz85Cc+icMB6M7T3NKC6Mq+gL5lTTmF + PytEKIS+888jP87Rvfvw/H9/EycG+yTLxPQ87P7Wt2GOj9OPBXR2SmkTukryP9LTQz76bxYKePhd70Zx + 396qyyI5KQ8+9Es8+/0f0FcBp60OrAI7mS3rKsn/VG8P0n29pMf49H99FdZLB2vvX5NfolUqeP47O8gH + BGMdHQG2CY1dAKDa2pv6TbXBh34l/a5/gmt2ZBBHd9HOtzdiMYhQSA0XQNZ6/z1bt5LO/tv9s5+juG/v + krV9ChL27PwubQJY0RzoWZnNpmckAB9ynnkmCTf6MMfH8dIPfjgp/VVDfs8e0uPzKi7gefBFUGlAm7sC + kNEvEKEQmletJDu+Y395Brlndwd4gS0OpaNDsEyTvhlJVjRWV0X+a7EYMoS7/bz88G+mXPJRD36xiMLh + w4QtRQdCIQjPC2xa8Ey2rasi/8MtLaTvow898UR1QjRNSQLQNQ3Zo0fJji+RyQCxWHUz0eU5DdBVkP8A + YCTppnKa2RxKz+8BoKb8n0CoQrcKsW+aEI4jnX0ocwwYJZzLPXbkCFAqSau+ZEA+X4Dm+9KRtK6C/w9g + Ur5RhG3WSnMLtRWARpikw2UTuuch6LeCp9u4roL/DwBGJkPXBRg6Bh1CWf+/uvaAaCvdS1rFWvm1oM/R + dBvXVfEH9AzdDMAQy39ooRDiySRhlWbKaReqLLBkczPZsWWzOeV9bM0wSKdpO2PjUhjLrBWjZW35PRkC + aG0jOzZvZFitSxkzLcxYDAnCBFAaGZEySWty3emSK1A9TjcI6EkqL+cDEQ6THp9RMqWJ0UwtGa7PFhyQ + DXHCWYDF4RHlbgCeYGCEL2lVHAdWqSjNHOkqxgC0JrqnACjklVcABuFj2lKxCC+bk+aW5lRXRleDCQSS + mSayo3MsR/kcAIOwi+aYZYhKRRqVPNWVUUIB+NCQWLGCrjoxS0rnAABAhHASUGl8DJrjSPnedUD+EwAk + kzAI5wEI24HqcAj3adCKRWl3y1qvCbl3n0gqhRjlVGCrrHwQMJZKkR1bOZuVTqFNtA2rEoDk/qefiJPu + BCQsW/k8gChhF83KZqV97/r0oICUiyuVJlsLwHNdOJalbCWgCSTaCSdq5eQ7pZlYb0psPAbhSyYVx4Hu + usoHAale1vJcF+WxMflctNp6U4IAooTvAfhOBXBdqI4Q4RiAm89LWwhECQJItND1L7PDx+DbNgcBiaq0 + iuOgLPFlLekJwAcQaqKbBOQWS4CEDSfmi3ATTZVWsSy4I/KmahsqLK445Vtm42PQvQkXQM04gC8EQmmi + LoDrwvPl1We61GXAAOjhMEKE7wGI4kQxEIWDgIaBFFGVZptluCVTSqm8s7tP6D40qf1PPxJBqqWV7Pjs + bFb5HACkUggTDQL6pgmUZb2uLaDrkgcCItEIooRLTVk5rgYUCoeRJEoAlm3DtR1J8zQ06NInoMQTAGEC + cEdHuRbAimaymZpauQxYlrR5GtKrz3Akglg0SnJsTrmM4tgYNF/xq8CUYzSeC9d1IWPTFl8I6NJnoEUj + 0MIG2QmAWYZQvB8I6VoNuTyErBWBNU1+BWAkEmQbTvi2Da9YlP425illNuFELcc04bsuZD2lkZ4AookE + okTrzZmmiXLtrrnKaGpvJzs2yzQBz+NEoMAilUKYai0A20ZIwoaT81JBADTCQVrNsuRumCP7Aos3N5O9 + ClyxbdglEyp3BdZCIUQIt20TlQqExKna0hOAlklD12k+pihb0E0TKmcBaoaBeCvdRC2nXIbmyXkKoEYM + IJOhWwzEsuA4jtJ5AEY0Svquhm/bUhO0/ATQQrcYiFUoAK6rdAxAi0YRIVwLwDPLtd1fzpR5+ROBCNea + cwsFCMdROgYgIhFoRLMAPdeFXy5P9gOQ0VikPwVId9A9YioeO3bcGbOKSiAcj5HtClRxHNiWVesIxHkA + wXzAGN2ec26pesYMIZR1A0KxGHSqiVqeB7csd5BW6nXnAzBSdM+YC6Oj0CGULghqRCIIRWh2BvYqFaBs + QUh8V0Pq24BaKIQ04SMmN5+H7PUYTkkAmQyiCZokbRWLKOXyELqcBO0DMHSJNx8tEkGIct/5UlFq/3JO + u2wiAYRoClHNdYGKvJmatVog8u5AWiyGBOEz5tzQMeUVQKy5CWGi17UrxSJEyZT6/eu+xIGAEOF2YJ7r + ArkcZK/IdEoCaGkhWwzEs2y4UidqCei6xGfQGmECmDhiUh0GYYUmXFfypi2a3C5AlHDPecuygEIRKicB + AUCa8FXgwsgInHIZsm6S2wYHNH3b4IAmqwTVooQVQLEImOZklpmqEIQVgJ3PA3wXIMAxAMI55kWuBgwA + iFNuCz4+Dt3zpH7/UhOARjS6DABuNltNAlKcAKJpwk1BCwWpawFITwDRFXS7ApfGxqF4MWB44TDxvo1F + CM+DzHEaqQkgTLjSjJvLcTHQcBgJwm5aeWy8ZiDyzZM/lQBkTQc2CPuXgouBIpRIIEa1XiOqTVtk3/lr + BCfnTpQiGmH2XBfFsTHoih8BxpqbECN8VFsqFKSfgyoBSKoA9LY2mvLL9+EOj0Ao3hMs1Ew3RlNxHLgj + I9L6/9sGB7RJArjh6GEpJUCS6AKr2DYsswRNVzwGQLkUmOsCjiN9oFbqikCF4WPI7tk7fwMVAuE6ukVm + Pgd38Chkvocxp8WnaQuan+XA+Pg43EJR+jStyefb0d0nZFyMU41s4uvjDU/AhzbFH9eO+z5EtWCHX3OV + ji/eMfFva40Wa39X/fxXPu+4iGvt30HxDMDpc4QT3q84bi6qX7/yToUvJhXU9PfrCzEZ19KnzeMJa0LM + XJBl6ufL7AJIXxNQn+FrfRoH6lMMVZ/+fW1Kvb4TFsorzRWnLqLpR0f67LzLmPp+jnu/M339yveqximO + mwPMMBfT5/GENaFpMxLy1M+XD+LEd6F6RBqKy/GAC9g6fY4m/XubXPM+2z+DoQQm5P9xBCDrSQCDwWDV + y2AwTkUAPr8PBkNdAuBAIIMhO8TsBLBtkOMADIbMmG7jHANgMNgF4DgAg6Ga/J+RADgOwGAorAA4DsBg + qOH/A7PcBQj8LbVoFE3rzkRoga3BNV2ra0fYwoEDqAwPK70YQ8kkmjdtrArT2rsWugZtju+9nnPk5HIo + vvgiUKlIPw/GzLIg2JcgYt1dOPdT/4HmNWsAYje6XNfFHz61HcP33QeVLwXFN6zHpd+4k+TYBh9/Ao9/ + 9OMQ42PSz5Exm1TY2d0X2GCAp+kwUkmkuzrJjc0yTRiVClS/EWg0NyPd0UGTACBfzcap+f8njQHIgFgm + jRjRgqBONofy6Kjypy0hne7Sc/MF+I6jBEmfZBYCfBoQicAg2hTEdivwPE/5BIxETzfZsdmFvGRvW8yf + AIJ8GhCKRACDaK0T24awbCgPwtWA4Qtohjy1ck5my3K6AJ0diBEtOGmPZ2Fls1C9K3Cmq4vs2CrFAjTJ + OwLNkQCC+QJcwtVNdMNAKKRD6SBgOAw9Qrdzs/AmIjQyzJFYOAEE1Q1I9/UiTHSB2WNjcHN5KA1dR4xy + 2zazpIT8n5MLEMRodYxwwwmrWITnq30GYKRSSBE9AvRcF2a+oMxc6Kf+geC5AfGWFrJjM0dGakdMKjOA + gVCYZpDN931o0syPWDwBBNENSBDdXQDAHB+veZbqBgGNeAxGlGZT0Iptw5GkJ+BcbHdOpwBB6h7sA7AJ + G1fE9aB5rtICQAtHoMWJdgV2XfiuOvMzJwIIWsXgdBfdJBNzeLjaqUbhU4BoOgWDaFtwu1yGL0Ea8Gyp + vwsigImdNRCMFg4j1kQ3wlzOZqE6jEQCRjJJUwCUSrBNU5lU7bknAgXEDfDDYSQIHzGVjh1TngB8IwSP + 8gA9P9AZcvNx2ef8nEFxA6KtrYjG42THVz52TPl7ANHWNiQJZ2q6AVdp87FV6dZiRfgIEc7jNkSwgqp1 + eQfJBHSitwGFq1aAdl6zMNfAQiOR7usjO7bC2BjsY8dm6DKsFpItLWRJ2ioUUCkWEdRj2vna6LxpmPru + ZRDOAnQti/Q9+OVCvKeH7NiKw8PwHad2UsMKIHCxgGiCrv9v5XLwbb4KXKEss2tp2kGk6YUo9AU9J2UV + kOlbSXZs2cFBMID0qlV0FcDAAHTPC1ycZqEFUhdEAJRVQCVEl7vDvoAObsdkUC4GUrsHoAcsTnP90MJs + csFrkSpDNnfSLTSRHxhQ/gQAAFKtdC9rlUdGELQA4GLW1IIJgKoKCKVTdCfKspQ/AUAyiVhrK12SHjwa + uADgYmxxUWqU4m6WInwK4IyOKS//fSFIZwGKihOoOVqsDS7qWSmqAI1oNeCK49RqAaoNPZMmmwUIAPbo + mDK7/6IJAKB3SYhqoQkAcMum8v0Awk1NZMu1OeUydLMcoLe5eAW+aAK4YXBAoxQ0CRN1AaxiEdYQ3wOg + 2rAFqF4FtrPZQARqfSGWpFiPvjSDIeQChIlWm3Vd6BVXeQUQJV6vEb6vVKB2SQig6ofQYIFQJEzT/m0b + FasM1WEQztSs2DY0JwhBQLFk8bcle1YKtQNFKIRogmihCcuCW7aUdwEyhLMAc4cOUWsmXXdbW9L12Gjf + ydd16EQVgChbEJalvAIQhGs1hGz61YCX2oVcUgJo9LFgtKWFbITZyudhF4tKxwB8ALGmJrLjKw4NkU4C + 8oWoBd2JEkBVnjSuZoBDOYVT+MpfBdajUdJBQM80lXPRpHreRHs72UITpdExuHnFW4IZBtmmrQBQGaed + qFUPhV0XAtg2OKA1Ih6QINwRyJKg1PRiEc5kECN6V8Mpl5E9fJioeBR1U9Z1UwCNiAcIwtdM3XweqFTU + PgWIhIEw3a7Ahu+D4k1ArY5HE3Vej8v7MtvWnE52cWUPHVJeAURjcYSTNEnaLpdhjY6SCwL6qG9cra4E + sJy5AT4Ayods0UhEeQLQYlFoVFWa60LzPFIKTfhLH/U/YU6W40F2dvctixTQ0ml4iThCnj8HVaLVvtZm + +Pvpfzfb15jlM2b4rYUCfNtW2wUIh6E1Nc3hHc91rhajTGuf5XlAKAR4HtxiEaFKhczrWo4TNUOm9SUK + BeiFAnxfTPpN/gwyxxcC0LTjvj/xc9P/P9NnzPQzE9+fLqtm+l3KolKBGBmZl6qrTqyYLNE127xM/xqz + zDFOMq/aPAh9ORTtsmyay/VAO7p6ha56NRwGg9Duv6wEsJyuAIPBxk+QAJgEGIyTuLC+WHB134Vi2V3T + ILQXYzAaQgANsAyOTTEYBOCjMclzDduN2RVgMKYYf4OUcUPl+F2dvULT2SNgKC38G1pMp6EuwHIHPBgM + Nn5CCmACnCPAUM70GxDxJ0sAHBNgsPErTgAcE2CoAkpH4aSOATkmwGDjV1gBsDvAYONnAmASYLDxq04A + TAIMNn7FCYBJgMHGrzgBAHw6wAgiBIl2eadCIC4D8ekAg41fYQIIgpRiMICJKr7B2bACZ1TsDjB4o1JQ + AbA7wGDjZwUwiZ3dvSLAw2fIJPuFaHhnbOUIgF0CBgVQutijJAGwGmCw5FecAJgEGCz5FSeAKglw1iCj + 7qI/UMd8ShHABHZ09wkud8xY0l0fjSvcyQTALgGDd30mAHYLGMtt+MKXO/dEiS2S1QCDd32FCYDVAGPO + Zu8LCA3SRPmZAJgEGHOETMd7TABMBIx5QNXbpko7xpxGzHJf06GEr88EwETAON78lTZ8JgB2C1juM5gA + mAjY8JkAGEwEbPhMAAwmAjZ8JgDGSYlA8GsjjKAX6GACCAB2dPUKXeNXR8js4Qsol8TDBMDugfKGz0d5 + TABEiIAvHC3bbg9Nyrv5TACyuAjdfQJCgN0E3u2ZAJgMmAwWCBUv5zABsJug9j7PUXwmADXIgIOHU8Fn + 9kwATAi1AJfcBU35yI4JgDFnl8EXCGj8oGro0DToHMBjAmAsMTEQUwo+qp1mWcozATDIKAdg4v9Tp1v4 + AkJ/hUCqxjvV/Tg+POHX/siyXT78P3GxDFBeUnQ8AAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAA + AQAAAAEACAYAAABccqhmAAAgAElEQVR42u19eZRU1bX3b59bc3VVD3RT1V3NJIOKqETUBIJTjIka4xRR + n0OkAUVNHjG+mMT3oraZNMvkSx6fiVFZgIkZDPneE8dogjGKIGpwYhARBKnu6qHooaq6plt19/cHaFRA + Gujh3HPPby2WLNei+9x99v6dvffZZ2+Chu2xuKZhlOGiRkvgcAbXGoQRgBhhASMJqCZGDRO8BPaCyQ2C + D8xuBvwAQEAORCYYeRCbDCoQo8CELga6BdABWDvLjJ0ESsLiHnbhvc5icfN3ksm03gH7grQI7IFF9fVj + XCymMGiyAI9losMIPA6g0dhtyMOEbga2AthGjK0MXlcma0OvYay/MR7P6Z3TBKBxAGgGPGNHNpwAEtMg + +CgwjiHQZBDCtvoQZmbQViasI/CbsPjlUk6snJeKd+ld1gSg8f7JHm6scfmtmURiJoinM+gEArzqfjFv + YsYqZl5plmnlNcmWt7UWaAJw0gnvGlNfP13AOJvBXyTQp5wsD2a0gvAYk/VkR7G4QucUNAEoh3sikZE+ + GOcIojNBdAaAKi2VvZKBCfBzDHrKLPFy7R1oArAt7m1oqHWXcb4QYhYYpxHBraVygIQAfhUWlpUsWjav + M/6OlogmALmNvrq60uMLXkzARdroB4cMCuXC0vnJZEJLRBOANFgcafy0IJ4PoksICGiJDGaYwGUmeoyY + 79/W1vJkM2BpqWgCGJbT3uf1Xw6I+SAcoyUyLHSwjZmWFEr5+7VXoAlgSLCornGCYWABEebq014erwDA + sjKJn81N7HhFS0QTwMC7+fX1XyQY1wnmc0Gk5SYvHaxk0K+3JeIPNQMlLQ9NAAeNZsA1Jhq7QoD+A4Qp + WiK2QtwC/yydaLlnAVDQ4tAEcCCGL8bUxy4nptuIMF5LxN5EwGzdmWprXaSJQBPA/g0/GvuKAN2qT3zV + 8gTYwuAfbm9reVCHBpoA9ozxIw2fN0j8XBu++kQApltmt+/4g5aGJoBdb+k99CsQnaPVwVFUsLLA5Wuv + aWtbrwnAgbgrEgnWwXUzCboRw/ueXmPYvAEug3B/gfiW+a2tSU0ADsHSaOyrRPQjAI3aDDQA9LCF27a1 + x+9udlhloaMIYEld40Ry4W4CvqB1XmMv+YEXLWF9bU5r61pNAAqhGXCNrY/9O4F+pN19jf2QgMmC7+wW + dIcTWpopTwBLYrGpwsJSgI7V6q3RbyIAb2ZYc5sSiec1Adjz1Bdjoo03EfAD/SxX4yDdAWbQXdva4rc0 + A0VNADbB4pqGUYaXfg/QTK3FGgPABK9bJZrV1BnfrNqXCeVc/mhslvCKV7XxawzgOXksufDakvrGq7UH + IK/L7xlX33g3gKu1wmoMYliwrINLTTe1t/dpApAE99bW1vvc3j8DNENrqMbgcwA2WGx+eU57+1YdAgx3 + vB9p+LzX5VurjV9jyE5NwmQh3K8sqW+80O7fYtg73m+8ySD8hohCWi01hth19hNwyQUV4eDUTGrFswDr + EGAI4/2x0dhviehirYoaww2L+dEkl/7NjnkB2xHAonBjjTvIj2qXX0MyvJY382fbrTmprQjgvtrYJK+L + /gLCOK1vGrKBGa3MOLOpPf6mXdZsmyTgkmjjqR43rdLGryHtaUpoIIEXH4g2nqUJYACxNBr7KgFPEzBC + q5mG5C51AODHl0Qa5mgCGIiTP9Iwh4Clup5fw0auAAmiRXYgAamvARdHY9cZRPfqPvwadiQBAs49LxTu + XZ5Jv6gJ4MBj/psMol9o49ewNwnQmedVhLPLM6lVmgD6ffI3fMsguktrkIYaPIAzzg+FSg9n0s9rAujf + ya+NfwjBQgBE+/8jBGBZ2ik7GBIAfU5GT0CqnVwSid0gBP1cq8vAwQIArxdGZRiekRH462rhCgYRHFkH + lz+AXD6P2gkTYBj7zwcTEbrf24F8JoNgMIDk1ncR8PuR2r4dmdZWcCYD7stClMta8PtAmemmOW07fqoJ + YA/jb5gjiBbp4+UglAqAb8xoVB99NKomTkB4wgRUjR4Fb7gSrsowvMEgPH4/hBi8Sx9mhlksopTPI9/V + jWKqF30dHdi5eQu61q1D1xuvw2xtA+XzDne3mC3meU3trYs1Abxv/PWxKwXjAW38/TjRieAdWYdAJIrQ + MVMQnTEd4UmHo/7wSTAMeS91LMtCT2srEmtfRcfq1cht2YreTW+jmEyCmJ1HAsCcpraWpY4ngKWx2Oko + 05P6nn8/8LgROvZYRE4+CWNOOgnBaAShhgYYLpf9PJZSCfneXvS+8w7eW/kC2l5YhZ61r0IUiw7iAJgW + 0ZfnJHY85VgCuK82NsnrpjUAqrSF7wnfxAkYd/EsRI47DiOOPAL+cHhQ3fjhRLanF4lXXkHLqtWIP/Y4 + zJYW9T0D5kyRrBOvTiQ2Oo4AFkejdQKu1Xr89of0AUDwsHGo/exnMfqsL2L0zJlw2fCEP1QU83m8+/Rf + seWhh9C19jWUe3vVbV/NvC1fcs2Yn9yecAwBNAOecdHG50D4tDZ7wBtrQO20aaiZMgWNp52K6okT4PJ4 + nE2GzOjr6kLy9TfQtmo1EitXIrVhI6ik3mRvBv7ZZeCk4RhEMiwEsDQS+y0JusLphi98PlR95kRMveEG + RI45Gm6fT7PhPnIGqZYWbHvyKWz/05+QemuTioy37Kq2louVJ4ClkdjNJOjHTlZoV00NqmfOwNTrr0Nk + yhRl4/rBgFko4Lnm76P9iSdQ6lRroK/FuL2pLd6sLAEsra8/GSyeISLDaYrLRHCPrMOYL5yB6OdOQ8P0 + 6fCHw9qiDwKFXA5tr7yC5Oo12P74E8hsVmReBzMTibO+OoQ3A0NGAEui0bFErrUEVDtRaevPOxcTL7sU + o6ZPt+XVnazo2LARK2/4JtLr1iuRKGSgu0zW9LmtrZuUIYC7IpFgHbn/ToQTHKWdRPDWRzFh7lxMu26+ + ttZBQj6VwlvL/h/e+r93o9jRoQILvNHB5oyhaDI6JATwQH3j7wBc5iSlNMJhfOr7zZj45XPg9uuJ5EMS + GqTTeOZr/46dK1+AZfOSYwtY3pSInz/oejr4rn9sFhF930mK6B45Ep9qvhVHXvQVGG5d4DhUcHm9qP/s + DFgeD5JrXgJsXEhEwBEXhMJbHs6k3rCtB7AkGh0ryPUqnFLp53Zh9IUXYuqNN6Bq1ChtkcOILX95Cq/9 + 6Mfo22Lj6V3MmZLg4wczHzBoHkAzIGpClY8BNNEJCueNRnHaH36Ho2dfBV9lpbbAYUbNhAloOO009O7Y + gcxWm5IAkYeYPj01k1ry7O6X3bYhgKb62M0AzXaCslVMmojjm2/F6Jl6IrlM8FVXoe7EE5Bcvw7ZHXGb + cgBi1aFK18OZ1DO2CQGWREedQLBWq37f7wqHMWnePBxz/Xx4AgFtcZLCzGax5ZFH8dK3vg1Ylv0+gJnZ + 4pNmd7S+IL0H0Ax4akLhR4ioQWWlMgJ+TLnxm5j69esdX7cv/V653aidMgWFTB+S/1xrRzeAiOjEk6vC + S59KpQb0McSA16COjTZ8F8BU1ZXqiOuvw+GXXqLLeG2EY29YgMazztzV39B2JIAp1SW+WWoP4L7a2CSX + IR4E1G3u4Wuox4k/vQtTZl8Fl368Y6+QzetF7PTPoSQMJF9cY8eMwIwvhYJ/fjSTGbBHEAN6fHlc+DUA + ZatePNXVOP62WzHhy+doa7LrHgaDOPHb38KIz9jvJToR3G4Yv5bSA3igvvEKIrpRWcWpq8Xxt92GMWd+ + AUIX99geVUceieQbbyDfbq/SYQLGnBcKty7PpNZKQwA/qa0NBQ3jCQIFVVQW94gaTP3Pm3H4xbO08SuC + YCSC4LixaFuzBqXelM1Wz585z2Xcvzx/6PXOAxICRFze2whUp6KikNuFE+74MY689BJtNYqh8bOfxXG3 + 3way2S0Ogergr2iWwgO4rzY2yRD4LREplw5nABOuuhJHzZsLYRjaYhREeMwYFHJZ7Hz5FZspJ5/wpVDF + skNNCB6y0Xrc9N+qFvzUTJ+O4//zZri0268sXG43jv3a9RChkL28ACLDDfHfw+oBLI3GvkREt6qoGFXH + H4eT/s9PURGJaCtRHG6/HxSqQOeq1WAbNR0l0PjzApWvL+9LvTXkBNAMuKpC4YcJVKuaQvjHjcUZf/w9 + KmMxbR0OwYjJk5HN9qHLbqEA4YSpmdSvnj3Ix0IHHQKMicauINARKirDMd+8AaHaWm0VTgoFPB5MbpoN + YbM+jUQYPyYaO+gO2wdFAM2Ai0DfU1ERKiYficN0oY8jURWLYfKCr9vxVuB7zYBryAhgTDR2hYoTfSqO + PAIn//JuuL1ebQ0OxZQrr0DDKac4xgs4YAJQ+fQ/7PLLUDNBTypzMjyhEGqPs99btoP1Ag6YAFQ9/Udd + egmObZqt7/s1MOqssxA6/HD7eQGRhq8OOgGoePozEY659hoQkdZ+DVRNGI/6M79gPy+AxH8OKgHsuvdX + 7/QPHT0FVYcd5khltyzrE/+w6iO692YUQmDsuefCslmvByKMXxqNfelA/o3rAH/DAtU22xWJYNqttyg5 + rSefzyO5eTOSr7+B7o0b0bdtO8o9PSim07DyeVhFE/lM5pP7wgmCv6oacBlwBQLwVFXBXV2NqilHoebo + o1E7+UjURKPKyS565BGIXXg+En/+H7u5AQsAPN5/j76fWFzbcJzhFv9UbaNjV12Jk5pvg0eBzH8xn0dq + xw4k163HtuWPoOvNdSgmWiEGs/u7z4faGdNR/7lTETl2KmoOnwRfRYUSuvHOU0/jxW/cACuVttW6y6Y1 + bU6ytV/Phft97JFLvdPfqK3FUbOvsrXxl00TPdu3Y8ffVmDnq6+h5+3N6Nu+DcgXdsd4g5zXyOeRfObv + 6HzuOfijUVRNPhKxU09DzbHHoPaoyXDbuF9i3dFHI3z44eixWXXgbludPWAewKJwY40riFYClLkgtwAc + dvVcnHx7s22/IdvVjQ2LFuG9p/+K9Ma3QJLE62QY8DTUI3bB+Th29myEovZ8T2FZFlb91y3Y+sBvbLVu + BgqlPjTMS8W79pvv6NdJGeTZKhk/AARGj8KkCy+wp6vf14ctT/8Nj5x+Bjb8YiEyGzZKY/wAwOUyCjvi + 2LrwbqyYPQfb/rYClg3bcQshEJ4wHmyz2yECvEaQ++UB9OvS+4JQ5SIClGr40XDGGZh06SW2mt1n5nJo + WfkCXv/FQmy6fxHMzk7p15xvb0f7qtXo25lEIFoP/4gRtiPb+DPPwMrlbKbhNOrhTOpXh+wBLIk2nkrA + ZJWM3wJQfczR8Nhoai8z453/XY5V3/gmdjy8HObOnXY5jVBob8fb99yLV+64A+lEwla6UjF6NIKxRtvp + OAGTl0QbTz1kAhCEuVAM/lgMI6cdZx/CKpex9u5f4tUf/ADFZNKeQmdG21N/xQsLbkDWBp7LB6HiyDp4 + x421pcj7Y7ufSACLwo01DMxSjQAip56CuilTbLHWzrc24cnLrsD6O35iw+aVe6LjhVV48tzzEX9+pS3W + 6/X7ETvlZHtyLjBrUbix5qAJwB2wLlUt+QcANdOOs0WbL7YsvNR8O3auWqWU/Pu2v4eXmr+P4qE3tR2a + MGCsPT0AArwuP644+BCA6N9UM34OBjH2jM/bYq0bf/cH7HzueaBsqbYNyGzciE0PLbPFWqsnTgBsOvyV + BM86KAK4t7a2HiDl5l2P/PzpCEueibZKJaz/3e/xyne+C5Wx9r++h/ga+Ud0VY0YAd/oUTaVMs3cZcsH + SABew6dc7A8hUH/8NOmX2bXpbWy6736oDrIsbLhvETJdXdKv1TfSvrfgn2TL4mBdBzvCE4shMk1uAsil + M3jm6vnIbH4HTkDb31Zgw0MPyZ8HGDfOvkT7CbYsnOT+B2MNCDbUy+0WL1yI/LZtcAxME5sXLUFR8kKb + Clu/eNx3GLBXAvC6PBeqqGvehnr4JO/62v70X+E0lBIJtLwi+UNTlwsQ9h1+tS+b3usXEdHZKipa/YwZ + 8Ph80q5vw6OPOcb1/4i+Adgs+YMbT3U1LBt3jNqXTe9BAAsBL4NOV1HRKiTu+tPX1Y13//BHOBW9mzbJ + 7aWUSrBs3B2JQacv3EtNzx4EUBFpOEnF4h82DFSOGS3t+jrfXIfUhg2OJYB8WxvyfX3y6g8zYGMCIMBb + EWk4ab8EYBh0gYoKRn4/wnXyXuW8949/wOxMOpYArL4seiV+KGS43SCbd4zem22LPZmOTlVRwdzVVXBJ + 2vePmdG5Zo2tT5iByAP0tMpLAP5QCMJj7ynRe7PtjxDAPZHISNWe/n5AAMGgvPF/b68jk3977JHEk3lL + 2SxgmnYn2cn3RCIj90kAPnKdoqpyeSQmgO72dljptOMJgCVOsqd7U2AF3mR83MY/QgBC4FRllUvixp+l + VApCDyVBWeIHN+5cFsKyPwF83MaFE+J/APBWylsAlO7ohNPN3wKkHsme7uhQ4yD8mI1/QAALAa+q8T8A + IBSSdmlGNuv40x9CSB2mmRJfUR4gxn+4HuADAghFG6errF8VVdXSrq2vp8fx9k9uN3wSE0DeBi8W+yVn + wPthW/9wCHCqygrmlbgHQNEmDT4H1QvyehGU2EvLJtXZIyLekwCE4MlKa1hQ3gRTKZNxPAGw5HfsaoVp + NHkPAmCmo5QOAerkTTBlHFwB+D5cErdoLxaLKCp1TctHfYQAdicFxiutYRI/A+ZUShOAT14CyPb1oaTU + Hn3MA/BFoxNUfAD0PiwwAiF5CcAsFDUBSPxMu9iXhaXQHhHgXVTXOOEDAnDDUDr+t0Dwj6iRd0Ny+hrQ + LXGOJtPVBVEylZK3S1iTP5QDUDv+p2AQHokzzKw9AJgSjxEXfZnBH7M+5B+1y+YFABCpHf+7gkH4JC4z + NbUHAG9FhbRry/X2qngsjv+XB8A8QW0PIAC3pJOAmBlWLq8JoFreQq1CV7d6NgE0fsgDoEaVlcsXCsGQ + tJkDM6Nk6hDAL/E7ADOt3i0NM3YlAXdfASpNAC6JT5disahzAADckl7TWpaFwk71PAAQGhcCXlFR23CU + 8spVIy8BlAoFsGk6ngAoVCEtAZgKvtUgwBuoaxwlhKH26Q8AwaoqadfWk9ypCQBAsFrOPTKLReQULdQS + VB4viAylCYABCIkJgFMpCGi4a+Ss0ygVCigp+ljLJURYMFmVqhNAQOIy4FRPt+ONv8QMQ9JrQDZLYIl7 + FR6abYg6AaBOZeUitxskMQGITJ/jCYCEQEjSfg3FbBZlVRu2CB4pAFKaAOD1IFQjbxmwinfMB0wA4TDc + YTkrNa1cTuE6Da4TpLgH4PJ45O40k+p1PAEYbhcCklZqmoUCigVVCUDUCWZWOgdA/gAMSR+aMDNKSd0N + yFVdLW+hVj4H5BUlAOaw8iGA2+uByyPnS+dioYB0tw4BjHAYQtLR21axCKuo5jUtg0cKIoSV1i6PZ9cf + GTfAsoA+nQT0V8rrhBb6srCKqlZqklf5K2gjEIA7IGe3mVKhgLImALgk7tVQSqdhFQrKyl55AvAGAvBI + 2m+umM3CdHhDUAYQlvghUD6bBRSYCLQP4XvVrwOoqIAh6Vgwq1BQ+nTpNyS+paFiUdmpTUQYr7wH4Kuu + gkvSHICZy8HM5pztAQgBl8T9Gq1CQemxbcoTgAiFpM0wc74AFJzdDES43aiolXdoi+oErX4OQOIrpnKh + gLLDewGQ1wt/WGYPIK8JwN4hQA1I0tHb+Uwa5aKzcwAurxdemYeC5jQB2FvBZG4Gks4ARWf3AmCPW9o6 + DcuywDn1Q4BOlT+wok7eS46u9naFi0z6SdD+AFyS1mmYxSIKCo9uZ8YW9XtRBOQdOSX6shDMziYAnxcu + r5xTgUqmiZLCBABCQWkCYAB+iQeCpPVYcJDHC/JKWqptmmDFPTTBDHUnU7oM+CVuB2bqp8DwhkPSPtfO + pTPK9gPcTXEFAWJ1v9DthiHxyCn9EAiwAn6wpE+BRcmEMEvKyl6AegWBOtSNL/0ISjxyKtXe4XgC8FZV + wSNpqXaxrw9FhUmaiToFK3wLQF6PtDUA5XIZ6NUhgF/iZiBWoQhL6ToNq1MArCwBCEnnAQK7JgIVs3oo + qKiokLdU2zQVn9lAnYKIlM0BuCWeCJzt6wPrjsAIR0ZKu7benUmUVK4EtKhDwFI3BwBJY0sA4FwOVNQz + AVnil4Cl3hSg8h5ZnBLM5biyHoDENeZ93d1AuaxzABJf0+Z6e8EK71EZ5U5hlaEsAcDnk3Zppk4A7nLS + wvIWahV7e5Wu1LTY2CIyydb1+nQZemS6upVuNNEvF9vlgiFxQ9ByWt12bQwUsp3xHWIBUADU9AKMSnnj + y7L2ACC8XgQkrtPIqdyynRFfgN1vAZhZSQJwV8v7FJjTaccTAAUD8PrlfaxV6u5SV/aEd4D3+wEQvaPi + RwbCcrqX5XIZfTu7HE8AvnAl/BITQF+Pul4a7/b6d3sA2KLiR8rab75cLsPULwFhVMkbohWLRZSU3iPe + 8i8PAKxkIjAoaRKwZJrIZXURkJD4qbZVLqteA7AeAFwAYKK8wbvrr0ohlexEz6a3pVtXLp1COZFwPAG4 + QVLuDwD0dHejnM4o2zOvZIkNAHbdRC0EvOH6xl4CvNDQ0FAaDBRmJ+K+D0KA3VeBW7RoNDQcQQEbPgjD + 3v8LEa/XgtHQcAJo/R4EYFm0QQtGQ8OhHgCAZ7VgNDQcYP5Mq/cggHRbfLUWjYaG4sYPFD5s6x8QwAKg + wIAOAzQ01MaW3Un/PUIAELEOAzQ0FMbHbfwjBGBZOg+goaEyPm7jHyGAbJFf1CLS0FAXeS79Y58E8LWu + 1h06D6ChoSp403XtHx1GIfYXI2hoaKiSAMCKj/+vPQigXOb/1ZLS0FAPe7PtPZ4AZtpbnw/XNxbs/DCI + fD6EJ06A4ZdxLgAjvfVdmMmko5XRCAZRNeUoyNhzs5hOIbP5HaCkzlxABgqZ9tbn90sAC4DCA+AVAJ1t + 14/1RSOYeustqJk4QUIWLmPNrc1of/wJRxOA/8gjcPK990i5tsSal7Dm298FK9S3kcArPnz/v08CAABm + foLIvgRQJoK7MozQSPmmzuT7+tRuNNFPuKqqpNwfAEgwg3NqjW1j5r2eOHvtd1AoFf/H1qdLZSUCkrab + LqRSKKjcbba/EPI2RTfTaVhFtWYC7sum90oA85PJBMArbfu1Hg+ExyOnd2KaKCs9cLJ/CDfEpF1bsa9P + sZkNvHKXTfeTAACALVpm23jH7QZccrY4s/IFWPm8o42fAcAv79QmKpWVIoBPsuV9EkChnLctAfgiEfgk + bTiZ7+1F3uFDQRhAKBKR1wNQbGbDJ9nyPgnAzmGAyRZY0pluLiHgEsLRBEAuF4TEcxvZshzh/n8iAdg5 + DAg3xOCVdDR4rqcHxZSzpwKxEPBKPBOwpFDL9v3Z8CcSQCmHB3kvd4fShwA18o4EK2QyYIUKTA4GnlAI + 4bo6KddWLpeRV4SgGSjkYP7xoAlgXireRcSP2O3DvRLPBOzbuRPlQsHRBACXCyRrktaywIrUaRDxIx9/ + /HNABLBLIPQru314QNICEwDIJpNKz5zvl/37fTAkvQUwCwUU0ykl5Nwf290vATS1xZ+10+xABmBCXgNz + lS3F7pgPHMLjhZA0R8OmCZTK9nf/GVua2uLPHjIBAADButdOHx+KRiX2ADrhdLiDAXgCASnXZuZyKPXZ + PwnYX5vtFwFkufyAXZKB5PHAJ3GGOd/d43gCMAIBuINBKddW7OtDweYEwEAhy+UHBowArmtv72DmP9rh + 48uGIW0REABkOzocTwCWYcCSNA8imCEse+domPmP+0v+HRABAACXeKEdPt5XV4ugpATAzMi2awLw1dVJ + S9KFnh4Ueu3tpR2IrfabAOYkW9eSDaYHmZJXcXkcXgUIAEYwACI5U6FWuQzY2AMg4Nk5yda1A04AAGAx + /1R2AYQaG6VVrnRvrw4BAARrauCStA6gkErDzGTsG14doI0eEAHMbmt5XPYrQZfECUAzm4Xb4TUAABCo + r5d2banOTlimPQuBmLFldlvL44NGAADA4B9K7WJXBKVdWyGVUqbK7FBQLMt7zy4sC2TTEIDZ+vEBf++B + /oPtbS0PyuwFVMYa5T1dEgnHFwEBQOWY0dKuLd3SArLha0BmbNne3vqbQSeAZqAksxdQkrjVlFG2HG/8 + DEAE5fXSUCjYkqQZ/MNmoDToBCC7F1AhcRVgb7xFH/8AKmpqpF1bNrnTnqd/W8uDBxXyHMw/ktkLcIcq + 5N2pfM7xxk+BAAIjRsgbAiQSjjn9D5oAZPYCKqrkfQpc3NnleAIwLQuypgCZGWSzG4BDOf0PiQB2MQ5/ + QzaByPrKzDRN5Hr0OwB3VSWCFfJ6acWd9mrZzhZ962BP/0MiAGB3XQDwF6lcTLdb2tOlnM1qAqislLYI + yCwWYdlojxj816aOHQ8f0oF5yIxp8jeYWRqvzlclZyFQPpNBXlcBwlNVJW2lZj6btc3QFmYum7AO2QM/ + ZAK4JtnyNoBfaA9gPyiVQGbJ8QTgq66Sdm35dBqGTSo1mejuqxOJjcNOAADQXirczmApOl0Ysk4EyudR + dvhAEGDXVGBZYeXzIBtMbWJwJ3KZ5oH4WQNCAN9JJtMEunHYBWMYcMvaaSafh6kJAFWj5a0C7N6xwybB + P9/e1DMwGeUBe5t6VSL+IDP/fVi9bEEQsiYB8wVwweEjwYhgeeUdCCKKdjj98dzsttZfDtg3D+TiiiVc + C2DYql181TXw+v1SblwhnUYh7eyBIBYB/qqwtOuT/ak2M0wT5WsHlPQG8oddk2x5m9m6c9jcbIK0I8FQ + LkM4/CmQ4fHCF5Z4IlBG7l6ADL5zIBJ/g0YAALCtrfVOAK8Nh4ACdXUwDEPKzevr7kbJxo0mBgQuF7xh + edu1mTIXajHWdbvojgEPewb6BzYDRYvpmuGoDfBJ/MikmE7b8pnpQMITqoAvLGcIUCwU0JtoleLnlaMA + AAcwSURBVNX3Z7asa2+Mx3PSEwAANLXteJkItw69CxCQVvnNVNrxMwHhdu/6I2mAbcg6EITEHbM7Wl8Y + jB89aB0q30203AnwqqGUU+1h46TV/e4d7zm+GYjbH5D3mjaXg7lTvqfAzHj53cSO2wbr5w8aATQDlsXl + ywEMSWDFAPIkr4l5PF44HcLvg/DJeQ3I5fKujsByWX+mLKwrmw/hsc9+nYvB/oYl0dgsQfSnIRFYKASS + 9DWglU6DnD4V2O0GhcOAhETN5TI4lQLJRQJXXpWIPziYv2BIduKB+sbfAbgMGhoa/TswgOVNifj5g+6V + DcXHdFjmNcx4WW+rhka/4tk3kpZ5+VD8qiHzxZZEo2MFuV4FUKV3WENj33F/SfDxc1tbNw3FrxuyOVVN + bW3bWPBFMvUO0NCQzPgZoIuHyviHlAAAYHZLywowbtE7raGxt7ifvn9VW/zJofydw5KO1UlBDY2PG//Q + JP2G1QN4Hx2WeQ0Ya/S2a2gADPxzqJJ+UngAALA4Gq0TcK0mwnitAhoOjvu35UuuGfOT24dlIMGwDauf + 09bWyYwLMESVghoaEhp/xirjguEy/mElAABoao+/uetmAKbWBg1n2T7MMomLmjpbXhvOdYjhFsTslpYV + TDxX3k4eGhoDbv3M4GvmJHY8NdxLETLIoynR8luLeZ4mAQ0nGL/FPK+prWWpDMuRpn3O8r70q+cFw71E + dKbWEg1VUYb49pz2ll/Ksh6p+mct70u/eF5FOEuEM7SqaKgGi/HtOW3xn8q0Juka6C3PpFadW1HRJ4i+ + oFVGQxnPH/y9praWO2Vbl5QdNJdn0qu0J6Ch0skvo/EDkLtL1eJo7DoD+KW00yQ1ND7x2Ge2CDc2JVp+ + IesSpTesJZGGOYJokSYBDdsZP/O8pvbWxTIvU8gux6b21sUMzNbFQhra+B3oAXzgCUQbTyXCnwkYoTVM + Q1rbB7LEuGion/UqTwAAcF9tbJLXRX8BYZxWNQ35Dn60MuPMpvb4m3ZZs+3i6kXhxhp3kB8FaIZWOQ2J + 8FrezJ89P5lM2GnRwm5SnpeKd72baDmNmf+kdU5DBljMj3ZY5ky7Gb8tPYCP5QVuEuCf6BsCjWEM+u96 + ty3+3WbAloMfbW84v6kf9UUL1m8JVKe1UWMIDT9lgec1tbUss/NnKHFy3ltbW+9ze/+s8wIaQ2L7jA0W + m1+e096+1e7fYqiwIY9ls5mpmfSD1aFwFMA0raIag2j9yzq5dM7X29s7VPgc5WLnJdHYLCK6R9cLaAys + x48sAzc0JeL3q/RdSibPFtc0jDK89HuAZmrV1RgA83/dKtGsps74ZtW+zFBxu5bn0qmpmfQDlRXhHIBT + iNT8To1Bd/eZQXdta2u57JvZVKeKn6j89dmSWGyqsLAUoGO1Rmv03+XnzQxrblMi8bzK36n8ybg8nW6b + mkkvqgqFegh0MgC3Vm+NfR/6MFnwj7sNuvz61tYtqn+vowpoltQ1TiQX7iZAdxvS2Jvxv2gJ62tzWlvX + OuWbHVlBtzQa+yoR/QhAo1Z7DQA9bOG2be3xu5ttWtGnCeAAcVckEqyD62YSdCMAv7YBJ574XAbh/gLx + LfNbW5NOlIHja+gX1zSMMjz0KxCdo03CUea/ssDla69pa1vvZCnoRzTvE0Gk4fMGiZ+DMEVLQ+k4fwuY + bpndvuMPWhqaAD6CZkCMica+QqBmIkzWElEKcYv5lu1tLQ82AyUtDk0An0QErjHR2BUE+p4eX25/w2e2 + 7ky1tS5aABS0ODQBHDARCNB/6NDAhic++GfpRMs92vA1ARx6jqC+/osGGwsAPks3IJE6xn8JhIXbEvGH + tKuvCWDAsaiucYJhYAER5hIQ0BKRwei5DGBZmcTP5iZ2vKIloglg0HFvdXWlz+u/HBDzQThGS2RYTH8b + My0plPL327EfnyYAVcKDSOOnBfF8EF2ivYLBP+2Z6DFivn9bW8uTzQ6r3NMEILlX4PEFLybgIjBOI9IP + jwbM8MGvwsKyQrmwVJ/2mgDkJ4OGhlp3GecLIWZpMjg0oy9ZtGxeZ/wdLRFNALbEPZHISB+McwTRmSA6 + A0CVlsre3HuYAD/HoKfMEi+/JtnytpaKJgCl0Ay4xtTXTxcwzgbjbKcnEJnRCsJjTNaTHcXiiu8kk2mt + JZoAHINF4cYal9+aSSRmgng6g04gwKuwyW9ixipmXlkSvPrqRGKj1gJNABr/8hA8Y0c2nAAS0yD4KDCO + IdBkEMI2O9qZQVuZsI7Ab8Lil0s5sXJeKt6ld1kTgMaBegr19WNcLKYwaLIAj2Wiwwg8DqDRGN5+Bt0M + bAWwjRhbGbyuTNaGXsNYf2M8ntM7pwlAYyjIAa4xDD6cwLVgjGCgVmDXf4lQDcALJi8TPMTsZSL3+6EG + AwViNpmoQIwiiAsACszoJiBpATsJSIKwk0FJlK1OduG9zmJxs47Z7Y3/D6O5kASavNINAAAAAElFTkSu + QmCC + + + \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo/Properties/AssemblyInfo.cs b/UI/VirtualPrinter.ProgressInfo/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..766dd0f --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("VirtualPrinter.ProgressInfo")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("6579d542-ef21-4cf7-a9ec-7360eceb3bbb")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo/Properties/Resources.Designer.cs b/UI/VirtualPrinter.ProgressInfo/Properties/Resources.Designer.cs new file mode 100644 index 0000000..956f92c --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// 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 VirtualPrinter.ProgressInfo.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "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 (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VirtualPrinter.ProgressInfo.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap waiting { + get { + object obj = ResourceManager.GetObject("waiting", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/UI/VirtualPrinter.ProgressInfo/Properties/Resources.resx b/UI/VirtualPrinter.ProgressInfo/Properties/Resources.resx new file mode 100644 index 0000000..62fcc35 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + ..\Resources\waiting.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo/Properties/Settings.Designer.cs b/UI/VirtualPrinter.ProgressInfo/Properties/Settings.Designer.cs new file mode 100644 index 0000000..7bd715c --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo/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 VirtualPrinter.ProgressInfo.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/UI/VirtualPrinter.ProgressInfo/Properties/Settings.settings b/UI/VirtualPrinter.ProgressInfo/Properties/Settings.settings new file mode 100644 index 0000000..e04fc63 --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo/Properties/Settings.settings @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/UI/VirtualPrinter.ProgressInfo/Resources/printer.ico b/UI/VirtualPrinter.ProgressInfo/Resources/printer.ico new file mode 100644 index 0000000000000000000000000000000000000000..5890db7348373ab6f69c9b0713e0b7597b583185 GIT binary patch literal 4286 zcmeHKu};H43^hwf#DtPe9gyHFT0W&8QtAGLnXh1B?Gh82o`{|ptfFTI^#0(v_uCe&Lcf+}`BGI?a}E$gXNk`W zKTDU0&m8>m73woww~znCZ|wuAiY0%xc~fu%r^K5o!OuVpjRXB1vze10YxB=mtVf`S z&D6Zbo_(YJ$Fbd1ez6~ubMZ@DtIVChl~?R?@pGJQB92OLnfIT$eV?YtbNGv*cudUu zR4>Gk{RpL{|3mxSQ0ol}+^?tKk?Y+d9=!9+4eE0Am_mWE&Q6m4A9q$iM(8#_3 literal 0 HcmV?d00001 diff --git a/UI/VirtualPrinter.ProgressInfo/Resources/waiting.gif b/UI/VirtualPrinter.ProgressInfo/Resources/waiting.gif new file mode 100644 index 0000000000000000000000000000000000000000..b3302ca6d464f43562bbac8e9c1beb936adec3e5 GIT binary patch literal 9559 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 literal 0 HcmV?d00001 diff --git a/UI/VirtualPrinter.ProgressInfo/VirtualPrinter.ProgressInfo.csproj b/UI/VirtualPrinter.ProgressInfo/VirtualPrinter.ProgressInfo.csproj new file mode 100644 index 0000000..816145b --- /dev/null +++ b/UI/VirtualPrinter.ProgressInfo/VirtualPrinter.ProgressInfo.csproj @@ -0,0 +1,90 @@ + + + + + Debug + AnyCPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB} + WinExe + VirtualPrinter.ProgressInfo + VPDAgentProgress + v4.6.1 + 512 + true + + + AnyCPU + true + full + false + bin\Debug + DEBUG;TRACE + prompt + 4 + + + AnyCPU + none + true + ..\..\Files\ + TRACE + prompt + 4 + + + Resources\printer.ico + + + + + + + + + + + Form + + + ProgressForm.cs + + + + ProgressForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + {24d28558-c825-43e6-85d2-7c59f4a97698} + VirtualPrinter.ProgressInfo.Core + + + + + + + + + + + + \ No newline at end of file diff --git a/VirtualPrinter.sln b/VirtualPrinter.sln new file mode 100644 index 0000000..bb145d2 --- /dev/null +++ b/VirtualPrinter.sln @@ -0,0 +1,306 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.SetupDriver", "Installer\VirtualPrinter.SetupDriver\VirtualPrinter.SetupDriver.csproj", "{12402F90-A2AE-4549-9142-F90650E2082A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.Agent.Service", "Agent\VirtualPrinter.Agent.Service\VirtualPrinter.Agent.Service.csproj", "{8C4F0640-4628-4CEA-8E31-143D68A3A70F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.IntegrationTests", "Tests\VirtualPrinter.IntegrationTests\VirtualPrinter.IntegrationTests.csproj", "{1A8B9166-7396-44BE-B03A-778C750EA253}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.Delivery", "Agent\VirtualPrinter.Delivery\VirtualPrinter.Delivery.csproj", "{74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.Agent.Console", "Agent\VirtualPrinter.Agent.Console\VirtualPrinter.Agent.Console.csproj", "{3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.Agent.Lib", "Common\VirtualPrinter.Agent.Lib\VirtualPrinter.Agent.Lib.csproj", "{94E8105F-5001-403B-B9F1-B0B0B236AD65}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.Agent.Autofac", "Common\VirtualPrinter.Agent.Autofac\VirtualPrinter.Agent.Autofac.csproj", "{1B2F0781-82D7-4576-B936-C6A26053D6ED}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Agent", "Agent", "{E801472E-AAD2-4255-AA2F-F48DC4445B0B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.ProgressInfo", "UI\VirtualPrinter.ProgressInfo\VirtualPrinter.ProgressInfo.csproj", "{6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UI", "UI", "{CE239FC1-5CD0-4F49-A7E3-28CFAD7A5DF4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.ProgressInfo.Lib", "UI\VirtualPrinter.ProgressInfo.Lib\VirtualPrinter.ProgressInfo.Lib.csproj", "{D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.ProgressInfo.Autofac", "UI\VirtualPrinter.ProgressInfo.Autofac\VirtualPrinter.ProgressInfo.Autofac.csproj", "{17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.ProgressInfo.Core", "UI\VirtualPrinter.ProgressInfo.Core\VirtualPrinter.ProgressInfo.Core.csproj", "{24D28558-C825-43E6-85D2-7C59F4A97698}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.Agent.Core", "Common\VirtualPrinter.Agent.Core\VirtualPrinter.Agent.Core.csproj", "{135C85EB-2116-4CC4-8CCB-B6804B9D6467}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.ProgressInfo.UnitTest", "Tests\VirtualPrinter.ProgressInfo.UnitTest\VirtualPrinter.ProgressInfo.UnitTest.csproj", "{2524D86F-9B55-4140-B932-00F8A1461704}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.Utils", "Common\VirtualPrinter.Utils\VirtualPrinter.Utils.csproj", "{CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.Agent.Lib.UnitTest", "Tests\VirtualPrinter.Agent.Lib.UnitTest\VirtualPrinter.Agent.Lib.UnitTest.csproj", "{3728EEF1-DEBF-4113-8310-301B0908D387}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.Logging.UnitTest", "Tests\VirtualPrinter.Logging.UnitTest\VirtualPrinter.Logging.UnitTest.csproj", "{1F6351AC-7885-4BEF-A309-3B39DAB59ABE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.Logging", "Common\VirtualPrinter.Logging\VirtualPrinter.Logging.csproj", "{AA25364D-22D5-44B0-86A5-6FB14C686308}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualPrinter.WixSharpInstaller", "Installer\VirtualPrinter.WixSharpInstaller\VirtualPrinter.WixSharpInstaller.csproj", "{A668846E-54C7-483D-9CF7-48F77EA398CA}" + +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Installer", "Installer", "{5EE0067B-1ED5-44FB-941D-8F4B039FDD2E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{1937EF74-F321-49FC-B37F-0E09DDECE94B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{95284260-12AD-4C69-BF4B-6B3A7BA5627C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {12402F90-A2AE-4549-9142-F90650E2082A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {12402F90-A2AE-4549-9142-F90650E2082A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {12402F90-A2AE-4549-9142-F90650E2082A}.Debug|x64.ActiveCfg = Debug|Any CPU + {12402F90-A2AE-4549-9142-F90650E2082A}.Debug|x64.Build.0 = Debug|Any CPU + {12402F90-A2AE-4549-9142-F90650E2082A}.Debug|x86.ActiveCfg = Debug|Any CPU + {12402F90-A2AE-4549-9142-F90650E2082A}.Debug|x86.Build.0 = Debug|Any CPU + {12402F90-A2AE-4549-9142-F90650E2082A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {12402F90-A2AE-4549-9142-F90650E2082A}.Release|Any CPU.Build.0 = Release|Any CPU + {12402F90-A2AE-4549-9142-F90650E2082A}.Release|x64.ActiveCfg = Release|Any CPU + {12402F90-A2AE-4549-9142-F90650E2082A}.Release|x64.Build.0 = Release|Any CPU + {12402F90-A2AE-4549-9142-F90650E2082A}.Release|x86.ActiveCfg = Release|Any CPU + {12402F90-A2AE-4549-9142-F90650E2082A}.Release|x86.Build.0 = Release|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Debug|x64.ActiveCfg = Debug|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Debug|x64.Build.0 = Debug|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Debug|x86.ActiveCfg = Debug|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Debug|x86.Build.0 = Debug|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Release|Any CPU.Build.0 = Release|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Release|x64.ActiveCfg = Release|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Release|x64.Build.0 = Release|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Release|x86.ActiveCfg = Release|Any CPU + {8C4F0640-4628-4CEA-8E31-143D68A3A70F}.Release|x86.Build.0 = Release|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Debug|x64.ActiveCfg = Debug|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Debug|x64.Build.0 = Debug|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Debug|x86.ActiveCfg = Debug|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Debug|x86.Build.0 = Debug|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Release|Any CPU.Build.0 = Release|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Release|x64.ActiveCfg = Release|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Release|x64.Build.0 = Release|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Release|x86.ActiveCfg = Release|Any CPU + {1A8B9166-7396-44BE-B03A-778C750EA253}.Release|x86.Build.0 = Release|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Debug|x64.ActiveCfg = Debug|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Debug|x64.Build.0 = Debug|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Debug|x86.ActiveCfg = Debug|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Debug|x86.Build.0 = Debug|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Release|Any CPU.ActiveCfg = Release|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Release|Any CPU.Build.0 = Release|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Release|x64.ActiveCfg = Release|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Release|x64.Build.0 = Release|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Release|x86.ActiveCfg = Release|Any CPU + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855}.Release|x86.Build.0 = Release|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Debug|x64.ActiveCfg = Debug|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Debug|x64.Build.0 = Debug|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Debug|x86.ActiveCfg = Debug|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Debug|x86.Build.0 = Debug|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Release|Any CPU.Build.0 = Release|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Release|x64.ActiveCfg = Release|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Release|x64.Build.0 = Release|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Release|x86.ActiveCfg = Release|Any CPU + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C}.Release|x86.Build.0 = Release|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Debug|x64.ActiveCfg = Debug|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Debug|x64.Build.0 = Debug|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Debug|x86.ActiveCfg = Debug|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Debug|x86.Build.0 = Debug|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Release|Any CPU.Build.0 = Release|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Release|x64.ActiveCfg = Release|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Release|x64.Build.0 = Release|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Release|x86.ActiveCfg = Release|Any CPU + {94E8105F-5001-403B-B9F1-B0B0B236AD65}.Release|x86.Build.0 = Release|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Debug|x64.ActiveCfg = Debug|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Debug|x64.Build.0 = Debug|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Debug|x86.ActiveCfg = Debug|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Debug|x86.Build.0 = Debug|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Release|Any CPU.Build.0 = Release|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Release|x64.ActiveCfg = Release|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Release|x64.Build.0 = Release|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Release|x86.ActiveCfg = Release|Any CPU + {1B2F0781-82D7-4576-B936-C6A26053D6ED}.Release|x86.Build.0 = Release|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Debug|x64.ActiveCfg = Debug|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Debug|x64.Build.0 = Debug|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Debug|x86.ActiveCfg = Debug|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Debug|x86.Build.0 = Debug|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Release|Any CPU.Build.0 = Release|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Release|x64.ActiveCfg = Release|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Release|x64.Build.0 = Release|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Release|x86.ActiveCfg = Release|Any CPU + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB}.Release|x86.Build.0 = Release|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Debug|x64.ActiveCfg = Debug|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Debug|x64.Build.0 = Debug|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Debug|x86.ActiveCfg = Debug|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Debug|x86.Build.0 = Debug|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Release|Any CPU.Build.0 = Release|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Release|x64.ActiveCfg = Release|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Release|x64.Build.0 = Release|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Release|x86.ActiveCfg = Release|Any CPU + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01}.Release|x86.Build.0 = Release|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Debug|x64.ActiveCfg = Debug|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Debug|x64.Build.0 = Debug|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Debug|x86.ActiveCfg = Debug|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Debug|x86.Build.0 = Debug|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Release|Any CPU.Build.0 = Release|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Release|x64.ActiveCfg = Release|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Release|x64.Build.0 = Release|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Release|x86.ActiveCfg = Release|Any CPU + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D}.Release|x86.Build.0 = Release|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Debug|Any CPU.Build.0 = Debug|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Debug|x64.ActiveCfg = Debug|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Debug|x64.Build.0 = Debug|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Debug|x86.ActiveCfg = Debug|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Debug|x86.Build.0 = Debug|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Release|Any CPU.ActiveCfg = Release|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Release|Any CPU.Build.0 = Release|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Release|x64.ActiveCfg = Release|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Release|x64.Build.0 = Release|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Release|x86.ActiveCfg = Release|Any CPU + {24D28558-C825-43E6-85D2-7C59F4A97698}.Release|x86.Build.0 = Release|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Debug|Any CPU.Build.0 = Debug|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Debug|x64.ActiveCfg = Debug|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Debug|x64.Build.0 = Debug|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Debug|x86.ActiveCfg = Debug|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Debug|x86.Build.0 = Debug|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Release|Any CPU.ActiveCfg = Release|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Release|Any CPU.Build.0 = Release|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Release|x64.ActiveCfg = Release|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Release|x64.Build.0 = Release|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Release|x86.ActiveCfg = Release|Any CPU + {135C85EB-2116-4CC4-8CCB-B6804B9D6467}.Release|x86.Build.0 = Release|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Debug|x64.ActiveCfg = Debug|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Debug|x64.Build.0 = Debug|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Debug|x86.ActiveCfg = Debug|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Debug|x86.Build.0 = Debug|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Release|Any CPU.Build.0 = Release|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Release|x64.ActiveCfg = Release|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Release|x64.Build.0 = Release|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Release|x86.ActiveCfg = Release|Any CPU + {2524D86F-9B55-4140-B932-00F8A1461704}.Release|x86.Build.0 = Release|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Debug|x64.ActiveCfg = Debug|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Debug|x64.Build.0 = Debug|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Debug|x86.ActiveCfg = Debug|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Debug|x86.Build.0 = Debug|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Release|Any CPU.Build.0 = Release|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Release|x64.ActiveCfg = Release|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Release|x64.Build.0 = Release|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Release|x86.ActiveCfg = Release|Any CPU + {A668846E-54C7-483D-9CF7-48F77EA398CA}.Release|x86.Build.0 = Release|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Debug|x64.ActiveCfg = Debug|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Debug|x64.Build.0 = Debug|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Debug|x86.ActiveCfg = Debug|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Debug|x86.Build.0 = Debug|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Release|Any CPU.Build.0 = Release|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Release|x64.ActiveCfg = Release|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Release|x64.Build.0 = Release|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Release|x86.ActiveCfg = Release|Any CPU + {AA25364D-22D5-44B0-86A5-6FB14C686308}.Release|x86.Build.0 = Release|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Debug|x64.ActiveCfg = Debug|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Debug|x64.Build.0 = Debug|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Debug|x86.ActiveCfg = Debug|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Debug|x86.Build.0 = Debug|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Release|Any CPU.Build.0 = Release|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Release|x64.ActiveCfg = Release|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Release|x64.Build.0 = Release|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Release|x86.ActiveCfg = Release|Any CPU + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}.Release|x86.Build.0 = Release|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Debug|x64.ActiveCfg = Debug|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Debug|x64.Build.0 = Debug|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Debug|x86.ActiveCfg = Debug|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Debug|x86.Build.0 = Debug|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Release|Any CPU.Build.0 = Release|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Release|x64.ActiveCfg = Release|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Release|x64.Build.0 = Release|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Release|x86.ActiveCfg = Release|Any CPU + {3728EEF1-DEBF-4113-8310-301B0908D387}.Release|x86.Build.0 = Release|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Debug|x64.ActiveCfg = Debug|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Debug|x64.Build.0 = Debug|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Debug|x86.ActiveCfg = Debug|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Debug|x86.Build.0 = Debug|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Release|Any CPU.Build.0 = Release|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Release|x64.ActiveCfg = Release|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Release|x64.Build.0 = Release|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Release|x86.ActiveCfg = Release|Any CPU + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {12402F90-A2AE-4549-9142-F90650E2082A} = {5EE0067B-1ED5-44FB-941D-8F4B039FDD2E} + {8C4F0640-4628-4CEA-8E31-143D68A3A70F} = {E801472E-AAD2-4255-AA2F-F48DC4445B0B} + {1A8B9166-7396-44BE-B03A-778C750EA253} = {1937EF74-F321-49FC-B37F-0E09DDECE94B} + {74FA80B3-7CF1-4B68-8AA3-4C3D37BBE855} = {E801472E-AAD2-4255-AA2F-F48DC4445B0B} + {3D3A379B-F9B8-466D-A04D-FD5EF948FF1C} = {E801472E-AAD2-4255-AA2F-F48DC4445B0B} + {94E8105F-5001-403B-B9F1-B0B0B236AD65} = {95284260-12AD-4C69-BF4B-6B3A7BA5627C} + {1B2F0781-82D7-4576-B936-C6A26053D6ED} = {95284260-12AD-4C69-BF4B-6B3A7BA5627C} + {6579D542-EF21-4CF7-A9EC-7360ECEB3BBB} = {CE239FC1-5CD0-4F49-A7E3-28CFAD7A5DF4} + {D66F55E5-B3F7-4C61-A4F2-B55C4D412E01} = {CE239FC1-5CD0-4F49-A7E3-28CFAD7A5DF4} + {17E2CF8A-462C-4130-9FAF-F1CA5FC4E06D} = {CE239FC1-5CD0-4F49-A7E3-28CFAD7A5DF4} + {24D28558-C825-43E6-85D2-7C59F4A97698} = {CE239FC1-5CD0-4F49-A7E3-28CFAD7A5DF4} + {135C85EB-2116-4CC4-8CCB-B6804B9D6467} = {95284260-12AD-4C69-BF4B-6B3A7BA5627C} + {2524D86F-9B55-4140-B932-00F8A1461704} = {1937EF74-F321-49FC-B37F-0E09DDECE94B} + {A668846E-54C7-483D-9CF7-48F77EA398CA} = {5EE0067B-1ED5-44FB-941D-8F4B039FDD2E} + {AA25364D-22D5-44B0-86A5-6FB14C686308} = {95284260-12AD-4C69-BF4B-6B3A7BA5627C} + {CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3} = {95284260-12AD-4C69-BF4B-6B3A7BA5627C} + {3728EEF1-DEBF-4113-8310-301B0908D387} = {1937EF74-F321-49FC-B37F-0E09DDECE94B} + {1F6351AC-7885-4BEF-A309-3B39DAB59ABE} = {1937EF74-F321-49FC-B37F-0E09DDECE94B} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {52642DB4-40BC-4C37-880C-73F24AE287ED} + EndGlobalSection +EndGlobal diff --git a/create_msi.ps1 b/create_msi.ps1 new file mode 100644 index 0000000..b51b524 --- /dev/null +++ b/create_msi.ps1 @@ -0,0 +1,2 @@ +$args = '/MSBUILD:..\Installer\VirtualPrinter.WixSharpInstaller', '/p:..\VirtualPrinterDriver' +Start-Process -FilePath '.Files\VPDInstaller.exe' -ArgumentList $args \ No newline at end of file