From 09349b3d0f92f0fc4949207fb54ff015cbf01f47 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 17:32:50 +0000 Subject: [PATCH] Migrate SampleMvcWebApp from ASP.NET MVC5/.NET 4.5.1 to ASP.NET Core MVC on .NET 8 - Convert all projects to SDK-style net8.0 - MVC5/System.Web -> ASP.NET Core MVC (Program.cs, middleware, built-in DI) - EF6 -> EF Core 8 (SQLite, migrations) preserving data model + validation - In-repo GenericServices/GenericLibsBase compatibility port on EF Core 8 + AutoMapper 14 - Autofac -> built-in DI; log4net -> Microsoft.Extensions.Logging; web.config -> appsettings.json - Replace legacy NUnit2/.NET4.5 tests with net8.0 NUnit4 regression suite for CRUD/service behavior - Add GitHub Actions CI for .NET 8 build+test; update README Co-Authored-By: Achal Channarasappa --- .github/workflows/ci.yml | 28 + .gitignore | 5 + BizLayer/App.config | 17 - BizLayer/BizLayer.csproj | 91 +- BizLayer/Properties/AssemblyInfo.cs | 62 - BizLayer/Startup/BizLayerModule.cs | 46 - BizLayer/packages.config | 7 - DataLayer/App.config | 25 - DataLayer/DataClasses/EfConfiguration.cs | 48 - DataLayer/DataClasses/SampleWebAppDb.cs | 136 +- DataLayer/DataLayer.csproj | 148 +- .../20260714171925_InitialCreate.Designer.cs | 141 + .../20260714171925_InitialCreate.cs | 115 + .../Migrations/SampleWebAppDbModelSnapshot.cs | 138 + DataLayer/Properties/AssemblyInfo.cs | 62 - DataLayer/Startup/DataLayerInitialise.cs | 69 +- DataLayer/Startup/DataLayerModule.cs | 50 - DataLayer/packages.config | 11 - GenericLibsBase/Core/ISuccessOrErrors.cs | 48 + .../Core/ISuccessOrErrorsGeneric.cs | 14 + GenericLibsBase/Core/SuccessOrErrors.cs | 106 + .../Core/SuccessOrErrorsGeneric.cs | 28 + GenericLibsBase/GenericLibsBase.csproj | 11 + GenericLibsBase/GenericLibsBaseConfig.cs | 32 + GenericLibsBase/IGenericLogger.cs | 27 + GenericLibsBase/NoLoggingGenericLogger.cs | 22 + GenericServices/Core/EfGenericDto.cs | 81 + GenericServices/Core/EfGenericDtoAsync.cs | 74 + GenericServices/Core/EfGenericDtoBase.cs | 53 + GenericServices/Core/EntityFromDto.cs | 44 + GenericServices/Core/GenericValidation.cs | 59 + GenericServices/Core/IInternalDtoCrud.cs | 31 + GenericServices/CrudFunctions.cs | 19 + .../DoNotCopyBackToDatabaseAttribute.cs | 13 + GenericServices/GenericServices.csproj | 32 + GenericServices/GenericServicesConfig.cs | 68 + GenericServices/IGenericServicesDbContext.cs | 25 + GenericServices/IValidateOnSave.cs | 19 + GenericServices/Internal/DtoMappingConfig.cs | 114 + GenericServices/Internal/DtoReflection.cs | 117 + GenericServices/SaveChangesExtensions.cs | 75 + GenericServices/Services.cs | 81 + GenericServices/Services/AsyncServices.cs | 182 ++ .../Services/GenericServiceBase.cs | 56 + GenericServices/Services/SyncServices.cs | 195 ++ README.md | 45 + SampleWebApp.sln | 81 +- SampleWebApp/App_Start/BundleConfig.cs | 97 - SampleWebApp/App_Start/FilterConfig.cs | 39 - SampleWebApp/App_Start/RouteConfig.cs | 49 - SampleWebApp/Controllers/BlogsController.cs | 2 +- SampleWebApp/Controllers/HomeController.cs | 7 +- .../Controllers/PostsAsyncController.cs | 6 +- SampleWebApp/Controllers/PostsController.cs | 4 +- .../Controllers/TagsAsyncController.cs | 6 +- SampleWebApp/Controllers/TagsController.cs | 4 +- SampleWebApp/Global.asax | 1 - SampleWebApp/Global.asax.cs | 51 - SampleWebApp/Infrastructure/AutofacDi.cs | 57 - SampleWebApp/Infrastructure/DiModelBinder.cs | 41 - SampleWebApp/Infrastructure/JsonNetResult.cs | 75 - .../Infrastructure/Log4NetGenericLogger.cs | 99 - .../Infrastructure/MelGenericLogger.cs | 36 + .../ServiceParameterBindingConvention.cs | 58 + .../Infrastructure/TraceGenericLogger.cs | 107 - .../Infrastructure/ValidationHelper.cs | 100 +- .../Infrastructure/WebUiInitialise.cs | 97 +- SampleWebApp/Log4Net.xml | 27 - SampleWebApp/Models/InternalsInfo.cs | 4 +- SampleWebApp/Program.cs | 59 + SampleWebApp/Project_Readme.html | 151 -- SampleWebApp/Properties/AssemblyInfo.cs | 61 - SampleWebApp/Properties/Settings.Designer.cs | 44 - SampleWebApp/Properties/Settings.settings | 12 - SampleWebApp/SampleWebApp.csproj | 492 +--- SampleWebApp/Views/Blogs/Index.cshtml | 2 +- SampleWebApp/Views/Posts/Create.cshtml | 7 +- SampleWebApp/Views/Posts/Edit.cshtml | 7 +- SampleWebApp/Views/Posts/Index.cshtml | 2 +- SampleWebApp/Views/PostsAsync/Create.cshtml | 7 +- SampleWebApp/Views/PostsAsync/Edit.cshtml | 7 +- SampleWebApp/Views/PostsAsync/Index.cshtml | 2 +- SampleWebApp/Views/Shared/Error.cshtml | 3 - SampleWebApp/Views/Shared/_Layout.cshtml | 9 +- SampleWebApp/Views/Tags/Create.cshtml | 2 +- SampleWebApp/Views/Tags/Edit.cshtml | 2 +- SampleWebApp/Views/Tags/Index.cshtml | 2 +- SampleWebApp/Views/TagsAsync/Create.cshtml | 2 +- SampleWebApp/Views/TagsAsync/Edit.cshtml | 2 +- SampleWebApp/Views/TagsAsync/Index.cshtml | 2 +- SampleWebApp/Views/Web.config | 35 - SampleWebApp/Views/_ViewImports.cshtml | 6 + SampleWebApp/Web.AzureRelease.config | 44 - SampleWebApp/Web.Debug.config | 30 - SampleWebApp/Web.Release.config | 31 - SampleWebApp/Web.WebWizRelease.config | 64 - SampleWebApp/Web.config | 110 - SampleWebApp/appsettings.Development.json | 8 + SampleWebApp/appsettings.json | 13 + SampleWebApp/packages.config | 47 - SampleWebApp/{ => wwwroot}/Content/Site.css | 0 .../{ => wwwroot}/Content/bootstrap-theme.css | 0 .../Content/bootstrap-theme.css.map | 0 .../Content/bootstrap-theme.min.css | 0 .../{ => wwwroot}/Content/bootstrap.css | 0 .../{ => wwwroot}/Content/bootstrap.css.map | 0 .../{ => wwwroot}/Content/bootstrap.min.css | 0 .../Content/img/setup-progress.gif | Bin .../Content/img/task-progress.gif | Bin SampleWebApp/{ => wwwroot}/Content/notify.css | 0 .../{ => wwwroot}/Content/notify.min.css | 0 .../themes/base/images/animated-overlay.gif | Bin .../images/ui-bg_flat_0_aaaaaa_40x100.png | Bin .../images/ui-bg_flat_75_ffffff_40x100.png | Bin .../images/ui-bg_glass_55_fbf9ee_1x400.png | Bin .../images/ui-bg_glass_65_ffffff_1x400.png | Bin .../images/ui-bg_glass_75_dadada_1x400.png | Bin .../images/ui-bg_glass_75_e6e6e6_1x400.png | Bin .../images/ui-bg_glass_95_fef1ec_1x400.png | Bin .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin .../base/images/ui-icons_222222_256x240.png | Bin .../base/images/ui-icons_2e83ff_256x240.png | Bin .../base/images/ui-icons_454545_256x240.png | Bin .../base/images/ui-icons_888888_256x240.png | Bin .../base/images/ui-icons_cd0a0a_256x240.png | Bin .../Content/themes/base/jquery-ui.css | 0 .../themes/base/jquery.ui.accordion.css | 0 .../Content/themes/base/jquery.ui.all.css | 0 .../themes/base/jquery.ui.autocomplete.css | 0 .../Content/themes/base/jquery.ui.base.css | 0 .../Content/themes/base/jquery.ui.button.css | 0 .../Content/themes/base/jquery.ui.core.css | 0 .../themes/base/jquery.ui.datepicker.css | 0 .../Content/themes/base/jquery.ui.dialog.css | 0 .../Content/themes/base/jquery.ui.menu.css | 0 .../themes/base/jquery.ui.progressbar.css | 0 .../themes/base/jquery.ui.resizable.css | 0 .../themes/base/jquery.ui.selectable.css | 0 .../Content/themes/base/jquery.ui.slider.css | 0 .../Content/themes/base/jquery.ui.spinner.css | 0 .../Content/themes/base/jquery.ui.tabs.css | 0 .../Content/themes/base/jquery.ui.theme.css | 0 .../Content/themes/base/jquery.ui.tooltip.css | 0 .../base/minified/images/animated-overlay.gif | Bin .../images/ui-bg_flat_0_aaaaaa_40x100.png | Bin .../images/ui-bg_flat_75_ffffff_40x100.png | Bin .../images/ui-bg_glass_55_fbf9ee_1x400.png | Bin .../images/ui-bg_glass_65_ffffff_1x400.png | Bin .../images/ui-bg_glass_75_dadada_1x400.png | Bin .../images/ui-bg_glass_75_e6e6e6_1x400.png | Bin .../images/ui-bg_glass_95_fef1ec_1x400.png | Bin .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin .../images/ui-icons_222222_256x240.png | Bin .../images/ui-icons_2e83ff_256x240.png | Bin .../images/ui-icons_454545_256x240.png | Bin .../images/ui-icons_888888_256x240.png | Bin .../images/ui-icons_cd0a0a_256x240.png | Bin .../themes/base/minified/jquery-ui.min.css | 0 .../base/minified/jquery.ui.accordion.min.css | 0 .../minified/jquery.ui.autocomplete.min.css | 0 .../base/minified/jquery.ui.button.min.css | 0 .../base/minified/jquery.ui.core.min.css | 0 .../minified/jquery.ui.datepicker.min.css | 0 .../base/minified/jquery.ui.dialog.min.css | 0 .../base/minified/jquery.ui.menu.min.css | 0 .../minified/jquery.ui.progressbar.min.css | 0 .../base/minified/jquery.ui.resizable.min.css | 0 .../minified/jquery.ui.selectable.min.css | 0 .../base/minified/jquery.ui.slider.min.css | 0 .../base/minified/jquery.ui.spinner.min.css | 0 .../base/minified/jquery.ui.tabs.min.css | 0 .../base/minified/jquery.ui.theme.min.css | 0 .../base/minified/jquery.ui.tooltip.min.css | 0 .../Scripts/ActionRunnerComms.js | 0 .../{ => wwwroot}/Scripts/ActionRunnerUi.js | 0 .../{ => wwwroot}/Scripts/_references.js | Bin .../{ => wwwroot}/Scripts/bootstrap.js | 0 .../{ => wwwroot}/Scripts/bootstrap.min.js | 0 .../Scripts/jquery-1.10.2.intellisense.js | 0 .../{ => wwwroot}/Scripts/jquery-1.10.2.js | 0 .../Scripts/jquery-1.10.2.min.js | 0 .../Scripts/jquery-1.10.2.min.map | 0 .../{ => wwwroot}/Scripts/jquery-notify.js | 0 .../Scripts/jquery-notify.min.js | 0 .../{ => wwwroot}/Scripts/jquery-ui-1.10.4.js | 0 .../Scripts/jquery-ui-1.10.4.min.js | 0 .../Scripts/jquery.signalR-2.0.3.js | 0 .../Scripts/jquery.signalR-2.0.3.min.js | 0 .../Scripts/jquery.validate-vsdoc.js | 0 .../{ => wwwroot}/Scripts/jquery.validate.js | 0 .../Scripts/jquery.validate.min.js | 0 .../Scripts/jquery.validate.unobtrusive.js | 0 .../jquery.validate.unobtrusive.min.js | 0 .../{ => wwwroot}/Scripts/modernizr-2.6.2.js | 0 SampleWebApp/{ => wwwroot}/Scripts/npm.js | 0 SampleWebApp/{ => wwwroot}/Scripts/respond.js | 0 .../{ => wwwroot}/Scripts/respond.min.js | 0 SampleWebApp/{ => wwwroot}/favicon.ico | Bin .../fonts/glyphicons-halflings-regular.eot | Bin .../fonts/glyphicons-halflings-regular.svg | 0 .../fonts/glyphicons-halflings-regular.ttf | Bin .../fonts/glyphicons-halflings-regular.woff | Bin .../fonts/glyphicons-halflings-regular.woff2 | Bin ServiceLayer/App.config | 29 - .../PostServices/DetailPostDtoAsync.cs | 2 +- ServiceLayer/Properties/AssemblyInfo.cs | 62 - ServiceLayer/ServiceLayer.csproj | 141 +- .../Startup/ServiceLayerInitialise.cs | 46 +- ServiceLayer/Startup/ServiceLayerModule.cs | 57 - ServiceLayer/packages.config | 12 - Tests/App.config | 76 - .../ClassToTestClassWithPrivateCtor.cs | 27 - Tests/DependencyItems/ClassWithPrivateCtor.cs | 19 - .../DependencyItems/ConstructorParamClass.cs | 44 - Tests/DependencyItems/GenericInterface.cs | 43 - Tests/DependencyItems/MyDisposableClass.cs | 64 - Tests/DependencyItems/ServiceTypeClass.cs | 18 - Tests/DependencyItems/SimpleClass.cs | 40 - ...unning action with progress and cancel.pdf | Bin 196946 -> 0 bytes ...unning action with progress and cancel.vsd | Bin 267776 -> 0 bytes Tests/Helpers/DbSnapShot.cs | 62 - .../Helpers/DummyIDbContextWithValidation.cs | 85 - Tests/Helpers/ExtendAsserts.cs | 111 - Tests/Helpers/JsonHelper.cs | 129 - Tests/Helpers/ModelStateTester.cs | 102 - Tests/Helpers/SimpleTagDto.cs | 56 - Tests/Helpers/SimpleTagDtoAsync.cs | 59 - Tests/Helpers/TestFileHelpers.cs | 108 - Tests/Helpers/TestServices.cs | 48 + Tests/Properties/AssemblyInfo.cs | 62 - Tests/Properties/Settings.Designer.cs | 38 - Tests/Properties/Settings.settings | 9 - .../TestData/TestRadio4 schedule 2014-7-3.xml | 2375 ----------------- Tests/TestData/actionRunnerData - default.js | 1 - Tests/Tests.csproj | 245 +- .../Group01DataLayer/DataLayerTests.cs | 70 + .../Group01DataLayer/Test10SetupBlogs.cs | 126 - .../Group01DataLayer/Test13Validation.cs | 230 -- .../Group01DataLayer/Test14ReadWriteBlogs.cs | 331 --- .../ServiceLayerAsyncTests.cs | 59 + .../ServiceLayerCrudTests.cs | 151 ++ .../ServiceLayerValidationTests.cs | 95 + .../Group03ServiceLayer/Test10DiSimple.cs | 296 -- .../Test11AutoFacModules.cs | 167 -- .../UnitTests/Group06Mvc/Test02Validation.cs | 273 -- Tests/packages.config | 23 - global.json | 6 + 247 files changed, 2975 insertions(+), 8205 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 BizLayer/App.config delete mode 100644 BizLayer/Properties/AssemblyInfo.cs delete mode 100644 BizLayer/Startup/BizLayerModule.cs delete mode 100644 BizLayer/packages.config delete mode 100644 DataLayer/App.config delete mode 100644 DataLayer/DataClasses/EfConfiguration.cs create mode 100644 DataLayer/Migrations/20260714171925_InitialCreate.Designer.cs create mode 100644 DataLayer/Migrations/20260714171925_InitialCreate.cs create mode 100644 DataLayer/Migrations/SampleWebAppDbModelSnapshot.cs delete mode 100644 DataLayer/Properties/AssemblyInfo.cs delete mode 100644 DataLayer/Startup/DataLayerModule.cs delete mode 100644 DataLayer/packages.config create mode 100644 GenericLibsBase/Core/ISuccessOrErrors.cs create mode 100644 GenericLibsBase/Core/ISuccessOrErrorsGeneric.cs create mode 100644 GenericLibsBase/Core/SuccessOrErrors.cs create mode 100644 GenericLibsBase/Core/SuccessOrErrorsGeneric.cs create mode 100644 GenericLibsBase/GenericLibsBase.csproj create mode 100644 GenericLibsBase/GenericLibsBaseConfig.cs create mode 100644 GenericLibsBase/IGenericLogger.cs create mode 100644 GenericLibsBase/NoLoggingGenericLogger.cs create mode 100644 GenericServices/Core/EfGenericDto.cs create mode 100644 GenericServices/Core/EfGenericDtoAsync.cs create mode 100644 GenericServices/Core/EfGenericDtoBase.cs create mode 100644 GenericServices/Core/EntityFromDto.cs create mode 100644 GenericServices/Core/GenericValidation.cs create mode 100644 GenericServices/Core/IInternalDtoCrud.cs create mode 100644 GenericServices/CrudFunctions.cs create mode 100644 GenericServices/DoNotCopyBackToDatabaseAttribute.cs create mode 100644 GenericServices/GenericServices.csproj create mode 100644 GenericServices/GenericServicesConfig.cs create mode 100644 GenericServices/IGenericServicesDbContext.cs create mode 100644 GenericServices/IValidateOnSave.cs create mode 100644 GenericServices/Internal/DtoMappingConfig.cs create mode 100644 GenericServices/Internal/DtoReflection.cs create mode 100644 GenericServices/SaveChangesExtensions.cs create mode 100644 GenericServices/Services.cs create mode 100644 GenericServices/Services/AsyncServices.cs create mode 100644 GenericServices/Services/GenericServiceBase.cs create mode 100644 GenericServices/Services/SyncServices.cs delete mode 100644 SampleWebApp/App_Start/BundleConfig.cs delete mode 100644 SampleWebApp/App_Start/FilterConfig.cs delete mode 100644 SampleWebApp/App_Start/RouteConfig.cs delete mode 100644 SampleWebApp/Global.asax delete mode 100644 SampleWebApp/Global.asax.cs delete mode 100644 SampleWebApp/Infrastructure/AutofacDi.cs delete mode 100644 SampleWebApp/Infrastructure/DiModelBinder.cs delete mode 100644 SampleWebApp/Infrastructure/JsonNetResult.cs delete mode 100644 SampleWebApp/Infrastructure/Log4NetGenericLogger.cs create mode 100644 SampleWebApp/Infrastructure/MelGenericLogger.cs create mode 100644 SampleWebApp/Infrastructure/ServiceParameterBindingConvention.cs delete mode 100644 SampleWebApp/Infrastructure/TraceGenericLogger.cs delete mode 100644 SampleWebApp/Log4Net.xml create mode 100644 SampleWebApp/Program.cs delete mode 100644 SampleWebApp/Project_Readme.html delete mode 100644 SampleWebApp/Properties/AssemblyInfo.cs delete mode 100644 SampleWebApp/Properties/Settings.Designer.cs delete mode 100644 SampleWebApp/Properties/Settings.settings delete mode 100644 SampleWebApp/Views/Web.config create mode 100644 SampleWebApp/Views/_ViewImports.cshtml delete mode 100644 SampleWebApp/Web.AzureRelease.config delete mode 100644 SampleWebApp/Web.Debug.config delete mode 100644 SampleWebApp/Web.Release.config delete mode 100644 SampleWebApp/Web.WebWizRelease.config delete mode 100644 SampleWebApp/Web.config create mode 100644 SampleWebApp/appsettings.Development.json create mode 100644 SampleWebApp/appsettings.json delete mode 100644 SampleWebApp/packages.config rename SampleWebApp/{ => wwwroot}/Content/Site.css (100%) rename SampleWebApp/{ => wwwroot}/Content/bootstrap-theme.css (100%) rename SampleWebApp/{ => wwwroot}/Content/bootstrap-theme.css.map (100%) rename SampleWebApp/{ => wwwroot}/Content/bootstrap-theme.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/bootstrap.css (100%) rename SampleWebApp/{ => wwwroot}/Content/bootstrap.css.map (100%) rename SampleWebApp/{ => wwwroot}/Content/bootstrap.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/img/setup-progress.gif (100%) rename SampleWebApp/{ => wwwroot}/Content/img/task-progress.gif (100%) rename SampleWebApp/{ => wwwroot}/Content/notify.css (100%) rename SampleWebApp/{ => wwwroot}/Content/notify.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/animated-overlay.gif (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-bg_flat_75_ffffff_40x100.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-bg_glass_65_ffffff_1x400.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-bg_glass_75_dadada_1x400.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-icons_222222_256x240.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-icons_2e83ff_256x240.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-icons_454545_256x240.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-icons_888888_256x240.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/images/ui-icons_cd0a0a_256x240.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery-ui.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.accordion.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.all.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.autocomplete.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.base.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.button.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.core.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.datepicker.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.dialog.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.menu.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.progressbar.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.resizable.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.selectable.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.slider.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.spinner.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.tabs.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.theme.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/jquery.ui.tooltip.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/animated-overlay.gif (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-bg_flat_0_aaaaaa_40x100.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-bg_flat_75_ffffff_40x100.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-bg_glass_55_fbf9ee_1x400.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-bg_glass_65_ffffff_1x400.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-bg_glass_75_dadada_1x400.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-bg_glass_75_e6e6e6_1x400.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-bg_glass_95_fef1ec_1x400.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-bg_highlight-soft_75_cccccc_1x100.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-icons_222222_256x240.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-icons_2e83ff_256x240.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-icons_454545_256x240.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-icons_888888_256x240.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/images/ui-icons_cd0a0a_256x240.png (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery-ui.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.accordion.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.autocomplete.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.button.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.core.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.datepicker.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.dialog.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.menu.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.progressbar.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.resizable.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.selectable.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.slider.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.spinner.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.tabs.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.theme.min.css (100%) rename SampleWebApp/{ => wwwroot}/Content/themes/base/minified/jquery.ui.tooltip.min.css (100%) rename SampleWebApp/{ => wwwroot}/Scripts/ActionRunnerComms.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/ActionRunnerUi.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/_references.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/bootstrap.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/bootstrap.min.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery-1.10.2.intellisense.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery-1.10.2.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery-1.10.2.min.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery-1.10.2.min.map (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery-notify.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery-notify.min.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery-ui-1.10.4.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery-ui-1.10.4.min.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery.signalR-2.0.3.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery.signalR-2.0.3.min.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery.validate-vsdoc.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery.validate.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery.validate.min.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery.validate.unobtrusive.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/jquery.validate.unobtrusive.min.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/modernizr-2.6.2.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/npm.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/respond.js (100%) rename SampleWebApp/{ => wwwroot}/Scripts/respond.min.js (100%) rename SampleWebApp/{ => wwwroot}/favicon.ico (100%) rename SampleWebApp/{ => wwwroot}/fonts/glyphicons-halflings-regular.eot (100%) rename SampleWebApp/{ => wwwroot}/fonts/glyphicons-halflings-regular.svg (100%) rename SampleWebApp/{ => wwwroot}/fonts/glyphicons-halflings-regular.ttf (100%) rename SampleWebApp/{ => wwwroot}/fonts/glyphicons-halflings-regular.woff (100%) rename SampleWebApp/{ => wwwroot}/fonts/glyphicons-halflings-regular.woff2 (100%) delete mode 100644 ServiceLayer/App.config delete mode 100644 ServiceLayer/Properties/AssemblyInfo.cs delete mode 100644 ServiceLayer/Startup/ServiceLayerModule.cs delete mode 100644 ServiceLayer/packages.config delete mode 100644 Tests/App.config delete mode 100644 Tests/DependencyItems/ClassToTestClassWithPrivateCtor.cs delete mode 100644 Tests/DependencyItems/ClassWithPrivateCtor.cs delete mode 100644 Tests/DependencyItems/ConstructorParamClass.cs delete mode 100644 Tests/DependencyItems/GenericInterface.cs delete mode 100644 Tests/DependencyItems/MyDisposableClass.cs delete mode 100644 Tests/DependencyItems/ServiceTypeClass.cs delete mode 100644 Tests/DependencyItems/SimpleClass.cs delete mode 100644 Tests/Docs/Flow of control when running action with progress and cancel.pdf delete mode 100644 Tests/Docs/Flow of control when running action with progress and cancel.vsd delete mode 100644 Tests/Helpers/DbSnapShot.cs delete mode 100644 Tests/Helpers/DummyIDbContextWithValidation.cs delete mode 100644 Tests/Helpers/ExtendAsserts.cs delete mode 100644 Tests/Helpers/JsonHelper.cs delete mode 100644 Tests/Helpers/ModelStateTester.cs delete mode 100644 Tests/Helpers/SimpleTagDto.cs delete mode 100644 Tests/Helpers/SimpleTagDtoAsync.cs delete mode 100644 Tests/Helpers/TestFileHelpers.cs create mode 100644 Tests/Helpers/TestServices.cs delete mode 100644 Tests/Properties/AssemblyInfo.cs delete mode 100644 Tests/Properties/Settings.Designer.cs delete mode 100644 Tests/Properties/Settings.settings delete mode 100644 Tests/TestData/TestRadio4 schedule 2014-7-3.xml delete mode 100644 Tests/TestData/actionRunnerData - default.js create mode 100644 Tests/UnitTests/Group01DataLayer/DataLayerTests.cs delete mode 100644 Tests/UnitTests/Group01DataLayer/Test10SetupBlogs.cs delete mode 100644 Tests/UnitTests/Group01DataLayer/Test13Validation.cs delete mode 100644 Tests/UnitTests/Group01DataLayer/Test14ReadWriteBlogs.cs create mode 100644 Tests/UnitTests/Group03ServiceLayer/ServiceLayerAsyncTests.cs create mode 100644 Tests/UnitTests/Group03ServiceLayer/ServiceLayerCrudTests.cs create mode 100644 Tests/UnitTests/Group03ServiceLayer/ServiceLayerValidationTests.cs delete mode 100644 Tests/UnitTests/Group03ServiceLayer/Test10DiSimple.cs delete mode 100644 Tests/UnitTests/Group03ServiceLayer/Test11AutoFacModules.cs delete mode 100644 Tests/UnitTests/Group06Mvc/Test02Validation.cs delete mode 100644 Tests/packages.config create mode 100644 global.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f0dff49 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,28 @@ +name: CI + +on: + push: + branches: [ master, main ] + pull_request: + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET 8 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Restore + run: dotnet restore SampleWebApp.sln + + - name: Build + run: dotnet build SampleWebApp.sln --configuration Release --no-restore + + - name: Test + run: dotnet test SampleWebApp.sln --configuration Release --no-build --verbosity normal diff --git a/.gitignore b/.gitignore index f863a14..c8dccab 100644 --- a/.gitignore +++ b/.gitignore @@ -163,3 +163,8 @@ SampleWebApp/Properties/PublishProfiles/samplemvcwebapp - Web Deploy.pubxml SampleWebApp/Properties/PublishProfiles/samplemvcwebapp.net - WebWiz.pubxml git/.gitattributes git/.gitignore + +# Local SQLite demo database +*.db +*.db-shm +*.db-wal diff --git a/BizLayer/App.config b/BizLayer/App.config deleted file mode 100644 index 13ecece..0000000 --- a/BizLayer/App.config +++ /dev/null @@ -1,17 +0,0 @@ - - - - -
- - - - - - - - - - - - \ No newline at end of file diff --git a/BizLayer/BizLayer.csproj b/BizLayer/BizLayer.csproj index aa58ad0..8338e7d 100644 --- a/BizLayer/BizLayer.csproj +++ b/BizLayer/BizLayer.csproj @@ -1,87 +1,16 @@ - - - + + - Debug - AnyCPU - {19592A8F-7C58-4221-8124-D38ACD8F5E31} - Library - Properties + net8.0 + disable + disable BizLayer BizLayer - v4.5.1 - 512 - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Autofac.3.5.0\lib\net40\Autofac.dll - - - ..\packages\AutoMapper.3.2.1\lib\net40\AutoMapper.dll - - - ..\packages\AutoMapper.3.2.1\lib\net40\AutoMapper.Net4.dll - - - False - ..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll - - - ..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.SqlServer.dll - - - False - ..\packages\GenericServices.1.0.0-beta4-003\lib\GenericServices.dll - - - - - - - - - - - - - - - - - - - + - - {264e1878-12de-4099-b8d7-cc53a73fea49} - DataLayer - + + - - - - - \ No newline at end of file + + diff --git a/BizLayer/Properties/AssemblyInfo.cs b/BizLayer/Properties/AssemblyInfo.cs deleted file mode 100644 index f93aad5..0000000 --- a/BizLayer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,62 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: AssemblyInfo.cs -// Date Created: 2014/07/11 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("BizLayer")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("BizLayer")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[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("3ea2faa1-4bb3-4d8e-8d35-f8038d375643")] - -// 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/BizLayer/Startup/BizLayerModule.cs b/BizLayer/Startup/BizLayerModule.cs deleted file mode 100644 index e924a90..0000000 --- a/BizLayer/Startup/BizLayerModule.cs +++ /dev/null @@ -1,46 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: BizLayerModule.cs -// Date Created: 2014/07/11 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using Autofac; - -namespace BizLayer.Startup -{ - public class BizLayerModule : Module - { - - /// - /// This registers all items in service layer and below - /// - /// - protected override void Load(ContainerBuilder builder) - { - //--------------------------- - //Register service layer: autowire all - builder.RegisterAssemblyTypes(GetType().Assembly).AsImplementedInterfaces(); - } - - } -} diff --git a/BizLayer/packages.config b/BizLayer/packages.config deleted file mode 100644 index 4a74205..0000000 --- a/BizLayer/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/DataLayer/App.config b/DataLayer/App.config deleted file mode 100644 index 5b4002b..0000000 --- a/DataLayer/App.config +++ /dev/null @@ -1,25 +0,0 @@ - - - - -
- - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DataLayer/DataClasses/EfConfiguration.cs b/DataLayer/DataClasses/EfConfiguration.cs deleted file mode 100644 index 8c3cfe7..0000000 --- a/DataLayer/DataClasses/EfConfiguration.cs +++ /dev/null @@ -1,48 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: EfConfiguration.cs -// Date Created: 2014/08/14 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System.Data.Entity; -using System.Data.Entity.SqlServer; - -namespace DataLayer.DataClasses -{ - public class EfConfiguration : DbConfiguration - { - /// - /// This flag should be set to true if we are working with an Azure database. - /// It should be set before EF uses the configuration, i.e. beofre the first access - /// - public static bool IsAzure { get; internal set; } - - public EfConfiguration() - { - if (IsAzure) - SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy()); - } - - } -} diff --git a/DataLayer/DataClasses/SampleWebAppDb.cs b/DataLayer/DataClasses/SampleWebAppDb.cs index 0a86cf3..88ac963 100644 --- a/DataLayer/DataClasses/SampleWebAppDb.cs +++ b/DataLayer/DataClasses/SampleWebAppDb.cs @@ -1,134 +1,102 @@ -#region licence -// The MIT License (MIT) -// -// Filename: SampleWebAppDb.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion +using System; using System.Collections.Generic; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Data.Entity.Validation; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; using DataLayer.DataClasses.Concrete; using DataLayer.DataClasses.Concrete.Helpers; using GenericServices; +using Microsoft.EntityFrameworkCore; [assembly: InternalsVisibleTo("Tests")] namespace DataLayer.DataClasses { - - public class SampleWebAppDb : DbContext, IGenericServicesDbContext + /// + /// EF Core replacement for the original EF6 context. It keeps the same public shape + /// (DbSets, SaveChanges override, database-level Tag uniqueness check) so the rest of + /// the application is unchanged. + /// + public class SampleWebAppDb : DbContext, IGenericServicesDbContext, IValidateOnSave { internal const string NameOfConnectionString = "SampleWebAppDb"; + /// + /// Fallback configuration used when the context is created without DI (tests, EF tooling, + /// the parameterless constructor). The web host configures the context through DI instead. + /// + public static Action DefaultOptionsAction { get; set; } + public DbSet Blogs { get; set; } public DbSet Posts { get; set; } public DbSet Tags { get; set; } - public SampleWebAppDb() : base("name=" + NameOfConnectionString) {} + public SampleWebAppDb() + { + } - internal SampleWebAppDb(string connectionString) : base(connectionString) { } + public SampleWebAppDb(DbContextOptions options) : base(options) + { + } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (optionsBuilder.IsConfigured) + return; + + if (DefaultOptionsAction != null) + DefaultOptionsAction(optionsBuilder); + else + optionsBuilder.UseSqlite("Data Source=SampleWebAppDb.db"); + } - /// - /// This has been overridden to handle: - /// a) Updating of modified items (see p194 in DbContext book) - /// - /// public override int SaveChanges() { HandleChangeTracking(); return base.SaveChanges(); } - /// - /// Same for async - /// - /// - public override Task SaveChangesAsync() + public override Task SaveChangesAsync(CancellationToken cancellationToken = default) { HandleChangeTracking(); - return base.SaveChangesAsync(); + return base.SaveChangesAsync(cancellationToken); } /// - /// This does validations that can only be done at the database level + /// Database-level validation. Replaces the EF6 ValidateEntity override: ensures a + /// Tag's Slug is unique (excluding the Tag being edited). /// - /// - /// - /// - protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, - IDictionary items) + public IEnumerable ValidateEntity(object entity) { - - if (entityEntry.Entity is Tag && (entityEntry.State == EntityState.Added || entityEntry.State == EntityState.Modified)) - { - var tagToCheck = ((Tag)entityEntry.Entity); - - //check for uniqueness of Tag's Slug property (note: because we may alter a Tag we need to exclude check against itself) - if (Tags.Any(x => x.TagId != tagToCheck.TagId && x.Slug == tagToCheck.Slug)) - return new DbEntityValidationResult(entityEntry, - new List - { - new DbValidationError( "Slug", - string.Format( "The Slug on tag '{0}' must be unique and is already being used.", tagToCheck.Name)) - }); - } - - return base.ValidateEntity(entityEntry, items); + var tagToCheck = entity as Tag; + if (tagToCheck == null) + yield break; + + if (Tags.Any(x => x.TagId != tagToCheck.TagId && x.Slug == tagToCheck.Slug)) + yield return new ValidationResult( + string.Format("The Slug on tag '{0}' must be unique and is already being used.", tagToCheck.Name), + new[] { "Slug" }); } - //-------------------------------------------------- //private helpers /// - /// This handles going through all the entities that have changed and seeing if they need any special handling. + /// Stamps on every added/modified entity that + /// tracks updates. /// private void HandleChangeTracking() { - //Debug.WriteLine("----------------------------------------------"); - //foreach (var entity in ChangeTracker.Entries() - //.Where( - // e => - // e.State == EntityState.Added || e.State == EntityState.Modified)) - //{ - // Debug.WriteLine("Entry {0}, state {1}", entity.Entity, entity.State); - //} - - foreach (var entity in ChangeTracker.Entries() - .Where( - e => - e.State == EntityState.Added || e.State == EntityState.Modified)) + foreach (var entry in ChangeTracker.Entries() + .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified)) { - var trackUpdateClass = entity.Entity as TrackUpdate; - if (trackUpdateClass == null) return; + var trackUpdateClass = entry.Entity as TrackUpdate; + if (trackUpdateClass == null) + continue; trackUpdateClass.UpdateTrackingInfo(); } } - } } diff --git a/DataLayer/DataLayer.csproj b/DataLayer/DataLayer.csproj index 01771cf..f6f040f 100644 --- a/DataLayer/DataLayer.csproj +++ b/DataLayer/DataLayer.csproj @@ -1,135 +1,33 @@ - - - + + - Debug - AnyCPU - {264E1878-12DE-4099-B8D7-CC53A73FEA49} - Library - Properties + net8.0 + disable + disable DataLayer DataLayer - v4.5.1 - 512 - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - bin\ReleaseAzure\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - bin\AzureRelease\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - bin\WebWizRelease\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - False - ..\packages\Autofac.3.5.0\lib\net40\Autofac.dll - - - ..\packages\AutoMapper.4.2.1\lib\net45\AutoMapper.dll - True - - - ..\packages\DelegateDecompiler.0.18.0\lib\net40-Client\DelegateDecompiler.dll - True - - - ..\packages\DelegateDecompiler.EntityFramework.0.18.0\lib\net45\DelegateDecompiler.EntityFramework.dll - True - - - ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll - True - - - ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll - True - - - ..\packages\GenericLibsBase.1.0.1\lib\GenericLibsBase.dll - True - - - ..\packages\GenericServices.1.0.9\lib\GenericServices.dll - True - - - ..\packages\Mono.Reflection.1.0.0.0\lib\Mono.Reflection.dll - - - - - - - - - - - - - - - - - - - - - - - + - - + + DataLayer.Startup.Internal.BlogsContentSimple.xml + + + DataLayer.Startup.Internal.BlogsContextMedium.xml + + - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + - + + - - - \ No newline at end of file + + diff --git a/DataLayer/Migrations/20260714171925_InitialCreate.Designer.cs b/DataLayer/Migrations/20260714171925_InitialCreate.Designer.cs new file mode 100644 index 0000000..8195298 --- /dev/null +++ b/DataLayer/Migrations/20260714171925_InitialCreate.Designer.cs @@ -0,0 +1,141 @@ +// +using System; +using DataLayer.DataClasses; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace DataLayer.Migrations +{ + [DbContext(typeof(SampleWebAppDb))] + [Migration("20260714171925_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.11"); + + modelBuilder.Entity("DataLayer.DataClasses.Concrete.Blog", b => + { + b.Property("BlogId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EmailAddress") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("BlogId"); + + b.ToTable("Blogs"); + }); + + modelBuilder.Entity("DataLayer.DataClasses.Concrete.Post", b => + { + b.Property("PostId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BlogId") + .HasColumnType("INTEGER"); + + b.Property("Content") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.HasKey("PostId"); + + b.HasIndex("BlogId"); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("DataLayer.DataClasses.Concrete.Tag", b => + { + b.Property("TagId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("TagId"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("PostTag", b => + { + b.Property("PostsPostId") + .HasColumnType("INTEGER"); + + b.Property("TagsTagId") + .HasColumnType("INTEGER"); + + b.HasKey("PostsPostId", "TagsTagId"); + + b.HasIndex("TagsTagId"); + + b.ToTable("PostTag"); + }); + + modelBuilder.Entity("DataLayer.DataClasses.Concrete.Post", b => + { + b.HasOne("DataLayer.DataClasses.Concrete.Blog", "Blogger") + .WithMany("Posts") + .HasForeignKey("BlogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Blogger"); + }); + + modelBuilder.Entity("PostTag", b => + { + b.HasOne("DataLayer.DataClasses.Concrete.Post", null) + .WithMany() + .HasForeignKey("PostsPostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("DataLayer.DataClasses.Concrete.Tag", null) + .WithMany() + .HasForeignKey("TagsTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("DataLayer.DataClasses.Concrete.Blog", b => + { + b.Navigation("Posts"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DataLayer/Migrations/20260714171925_InitialCreate.cs b/DataLayer/Migrations/20260714171925_InitialCreate.cs new file mode 100644 index 0000000..e286b01 --- /dev/null +++ b/DataLayer/Migrations/20260714171925_InitialCreate.cs @@ -0,0 +1,115 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DataLayer.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Blogs", + columns: table => new + { + BlogId = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", maxLength: 64, nullable: false), + EmailAddress = table.Column(type: "TEXT", maxLength: 256, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Blogs", x => x.BlogId); + }); + + migrationBuilder.CreateTable( + name: "Tags", + columns: table => new + { + TagId = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Slug = table.Column(type: "TEXT", maxLength: 64, nullable: false), + Name = table.Column(type: "TEXT", maxLength: 128, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Tags", x => x.TagId); + }); + + migrationBuilder.CreateTable( + name: "Posts", + columns: table => new + { + PostId = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Title = table.Column(type: "TEXT", maxLength: 128, nullable: false), + Content = table.Column(type: "TEXT", nullable: false), + BlogId = table.Column(type: "INTEGER", nullable: false), + LastUpdated = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Posts", x => x.PostId); + table.ForeignKey( + name: "FK_Posts_Blogs_BlogId", + column: x => x.BlogId, + principalTable: "Blogs", + principalColumn: "BlogId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "PostTag", + columns: table => new + { + PostsPostId = table.Column(type: "INTEGER", nullable: false), + TagsTagId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PostTag", x => new { x.PostsPostId, x.TagsTagId }); + table.ForeignKey( + name: "FK_PostTag_Posts_PostsPostId", + column: x => x.PostsPostId, + principalTable: "Posts", + principalColumn: "PostId", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_PostTag_Tags_TagsTagId", + column: x => x.TagsTagId, + principalTable: "Tags", + principalColumn: "TagId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Posts_BlogId", + table: "Posts", + column: "BlogId"); + + migrationBuilder.CreateIndex( + name: "IX_PostTag_TagsTagId", + table: "PostTag", + column: "TagsTagId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "PostTag"); + + migrationBuilder.DropTable( + name: "Posts"); + + migrationBuilder.DropTable( + name: "Tags"); + + migrationBuilder.DropTable( + name: "Blogs"); + } + } +} diff --git a/DataLayer/Migrations/SampleWebAppDbModelSnapshot.cs b/DataLayer/Migrations/SampleWebAppDbModelSnapshot.cs new file mode 100644 index 0000000..b593be0 --- /dev/null +++ b/DataLayer/Migrations/SampleWebAppDbModelSnapshot.cs @@ -0,0 +1,138 @@ +// +using System; +using DataLayer.DataClasses; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace DataLayer.Migrations +{ + [DbContext(typeof(SampleWebAppDb))] + partial class SampleWebAppDbModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.11"); + + modelBuilder.Entity("DataLayer.DataClasses.Concrete.Blog", b => + { + b.Property("BlogId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EmailAddress") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("BlogId"); + + b.ToTable("Blogs"); + }); + + modelBuilder.Entity("DataLayer.DataClasses.Concrete.Post", b => + { + b.Property("PostId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BlogId") + .HasColumnType("INTEGER"); + + b.Property("Content") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.HasKey("PostId"); + + b.HasIndex("BlogId"); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("DataLayer.DataClasses.Concrete.Tag", b => + { + b.Property("TagId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("TagId"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("PostTag", b => + { + b.Property("PostsPostId") + .HasColumnType("INTEGER"); + + b.Property("TagsTagId") + .HasColumnType("INTEGER"); + + b.HasKey("PostsPostId", "TagsTagId"); + + b.HasIndex("TagsTagId"); + + b.ToTable("PostTag"); + }); + + modelBuilder.Entity("DataLayer.DataClasses.Concrete.Post", b => + { + b.HasOne("DataLayer.DataClasses.Concrete.Blog", "Blogger") + .WithMany("Posts") + .HasForeignKey("BlogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Blogger"); + }); + + modelBuilder.Entity("PostTag", b => + { + b.HasOne("DataLayer.DataClasses.Concrete.Post", null) + .WithMany() + .HasForeignKey("PostsPostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("DataLayer.DataClasses.Concrete.Tag", null) + .WithMany() + .HasForeignKey("TagsTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("DataLayer.DataClasses.Concrete.Blog", b => + { + b.Navigation("Posts"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DataLayer/Properties/AssemblyInfo.cs b/DataLayer/Properties/AssemblyInfo.cs deleted file mode 100644 index 5cbbe5f..0000000 --- a/DataLayer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,62 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: AssemblyInfo.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DataLayer")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("DataLayer")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[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("f78cbd3c-264d-4fda-8d1a-3679faf55c2c")] - -// 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/DataLayer/Startup/DataLayerInitialise.cs b/DataLayer/Startup/DataLayerInitialise.cs index e7c2df5..d657658 100644 --- a/DataLayer/Startup/DataLayerInitialise.cs +++ b/DataLayer/Startup/DataLayerInitialise.cs @@ -1,69 +1,42 @@ -#region licence -// The MIT License (MIT) -// -// Filename: DataLayerInitialise.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion using System; using System.Collections.Generic; -using System.Data.Entity; using System.Linq; using DataLayer.DataClasses; using DataLayer.Startup.Internal; using GenericLibsBase; using GenericServices; +using Microsoft.EntityFrameworkCore; namespace DataLayer.Startup { - public enum TestDataSelection { Small = 0, Medium = 1} + public enum TestDataSelection { Small = 0, Medium = 1 } public static class DataLayerInitialise { - private static IGenericLogger _logger; - private static readonly Dictionary XmlBlogsDataFileManifestPath = new Dictionary + private static readonly Dictionary XmlBlogsDataFileManifestPath = + new Dictionary { - {TestDataSelection.Small, "DataLayer.Startup.Internal.BlogsContentSimple.xml"}, - {TestDataSelection.Medium, "DataLayer.Startup.Internal.BlogsContextMedium.xml"} + { TestDataSelection.Small, "DataLayer.Startup.Internal.BlogsContentSimple.xml" }, + { TestDataSelection.Medium, "DataLayer.Startup.Internal.BlogsContextMedium.xml" } }; /// - /// This should be called at Startup + /// Called at startup. Applies EF Core migrations to create/update the schema and, when the + /// database has no blogs yet, seeds the small data set so the demo has content to show. /// - /// true if running on azure (used for configuring retry policy and BuildSqlConnectionString UserId) - /// true if the database provider allows the app to drop/create a database - public static void InitialiseThis(bool isAzure, bool canCreateDatabase) + public static void InitialiseThis(SampleWebAppDb context, bool canCreateDatabase) { - EfConfiguration.IsAzure = isAzure; _logger = GenericLibsBaseConfig.GetLogger("DataLayerInitialise"); - //Initialiser for the database. Only used when first access is made - if (canCreateDatabase) - Database.SetInitializer(new CreateDatabaseIfNotExists()); - else - //This initializer will not try to change the database - Database.SetInitializer(new NullDatabaseInitializer()); + if (!canCreateDatabase) + return; + + context.Database.Migrate(); + + if (!context.Blogs.Any()) + ResetBlogs(context, TestDataSelection.Small); } public static void ResetBlogs(SampleWebAppDb context, TestDataSelection selection) @@ -77,7 +50,8 @@ public static void ResetBlogs(SampleWebAppDb context, TestDataSelection selectio } catch (Exception ex) { - _logger.Critical("Exception when resetting the blogs", ex); + if (_logger != null) + _logger.Critical("Exception when resetting the blogs", ex); throw; } @@ -87,12 +61,11 @@ public static void ResetBlogs(SampleWebAppDb context, TestDataSelection selectio var status = context.SaveChangesWithChecking(); if (!status.IsValid) { - _logger.CriticalFormat("Error when resetting courses data. Error:\n{0}", - string.Join(",", status.Errors)); + if (_logger != null) + _logger.CriticalFormat("Error when resetting courses data. Error:\n{0}", + string.Join(",", status.Errors)); throw new FormatException("problem writing to database. See log."); } } - } - } diff --git a/DataLayer/Startup/DataLayerModule.cs b/DataLayer/Startup/DataLayerModule.cs deleted file mode 100644 index b2a6ecf..0000000 --- a/DataLayer/Startup/DataLayerModule.cs +++ /dev/null @@ -1,50 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: DataLayerModule.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Runtime.CompilerServices; -using Autofac; -using DataLayer.DataClasses; -using GenericServices; - -[assembly: InternalsVisibleTo("Tests")] - -namespace DataLayer.Startup -{ - public class DataLayerModule : Module - { - - protected override void Load(ContainerBuilder builder) - { - - //Autowire the classes with interfaces - builder.RegisterAssemblyTypes(GetType().Assembly).AsImplementedInterfaces(); - - //set Entity Framework context to instance per lifetime scope. - //This is important as we get one context per lifetime, so all db classes are tracked together. - builder.RegisterType().As().As().InstancePerLifetimeScope(); - } - } -} diff --git a/DataLayer/packages.config b/DataLayer/packages.config deleted file mode 100644 index 79bc6a6..0000000 --- a/DataLayer/packages.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/GenericLibsBase/Core/ISuccessOrErrors.cs b/GenericLibsBase/Core/ISuccessOrErrors.cs new file mode 100644 index 0000000..02955a4 --- /dev/null +++ b/GenericLibsBase/Core/ISuccessOrErrors.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace GenericLibsBase.Core +{ + /// + /// Carries the success/error outcome of an operation, including a list of + /// errors (each possibly associated with member names) + /// and an optional success message. + /// + public interface ISuccessOrErrors + { + /// + /// True if there are no errors. (A status must have been given a success message + /// or had errors added before this is meaningful.) + /// + bool IsValid { get; } + + /// The validation errors, if any. + IReadOnlyList Errors { get; } + + /// Optional non-error warnings. + IReadOnlyList Warnings { get; } + + bool HasWarnings { get; } + + /// The success message set via . + string SuccessMessage { get; } + + /// Adds a global error (no member name). + ISuccessOrErrors AddSingleError(string errorformat, params object[] args); + + /// Adds an error associated with the named property/parameter. + ISuccessOrErrors AddNamedParameterError(string parameterName, string errorformat, params object[] args); + + /// Adds a warning message. + ISuccessOrErrors AddWarning(string warningformat, params object[] args); + + /// Copies the errors and warnings from another status into this one. + ISuccessOrErrors Combine(ISuccessOrErrors objToCopyErrorsFrom); + + /// Sets the success message. Only meaningful when there are no errors. + ISuccessOrErrors SetSuccessMessage(string successformat, params object[] args); + + /// Returns the errors formatted as an HTML unordered list. + string ErrorsAsHtml(); + } +} diff --git a/GenericLibsBase/Core/ISuccessOrErrorsGeneric.cs b/GenericLibsBase/Core/ISuccessOrErrorsGeneric.cs new file mode 100644 index 0000000..82c1f88 --- /dev/null +++ b/GenericLibsBase/Core/ISuccessOrErrorsGeneric.cs @@ -0,0 +1,14 @@ +namespace GenericLibsBase.Core +{ + /// + /// A success/error status that also carries a typed result. + /// + public interface ISuccessOrErrors : ISuccessOrErrors + { + /// The result value (only meaningful when is true). + T Result { get; } + + /// Sets the result and a success message. + ISuccessOrErrors SetSuccessWithResult(T result, string successformat, params object[] args); + } +} diff --git a/GenericLibsBase/Core/SuccessOrErrors.cs b/GenericLibsBase/Core/SuccessOrErrors.cs new file mode 100644 index 0000000..4bc2aa3 --- /dev/null +++ b/GenericLibsBase/Core/SuccessOrErrors.cs @@ -0,0 +1,106 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; + +namespace GenericLibsBase.Core +{ + /// + /// Default implementation of . + /// + public class SuccessOrErrors : ISuccessOrErrors + { + private readonly List _errors = new List(); + private readonly List _warnings = new List(); + private string _successMessage = string.Empty; + + private static string Format(string format, object[] args) + { + //When there are no args the string is used verbatim, so messages containing + //braces (e.g. validation messages) are never re-parsed by string.Format. + return args == null || args.Length == 0 ? format : string.Format(format, args); + } + + public bool IsValid + { + get { return _errors.Count == 0; } + } + + public IReadOnlyList Errors + { + get { return _errors; } + } + + public IReadOnlyList Warnings + { + get { return _warnings; } + } + + public bool HasWarnings + { + get { return _warnings.Count > 0; } + } + + public string SuccessMessage + { + get { return IsValid ? _successMessage : string.Empty; } + } + + public ISuccessOrErrors AddSingleError(string errorformat, params object[] args) + { + _errors.Add(new ValidationResult(Format(errorformat, args))); + return this; + } + + public ISuccessOrErrors AddNamedParameterError(string parameterName, string errorformat, params object[] args) + { + _errors.Add(new ValidationResult(Format(errorformat, args), new[] { parameterName })); + return this; + } + + public ISuccessOrErrors AddWarning(string warningformat, params object[] args) + { + _warnings.Add("Warning: " + Format(warningformat, args)); + return this; + } + + public ISuccessOrErrors Combine(ISuccessOrErrors objToCopyErrorsFrom) + { + if (objToCopyErrorsFrom == null) return this; + _errors.AddRange(objToCopyErrorsFrom.Errors); + _warnings.AddRange(objToCopyErrorsFrom.Warnings); + return this; + } + + public ISuccessOrErrors SetSuccessMessage(string successformat, params object[] args) + { + _successMessage = Format(successformat, args); + return this; + } + + public string ErrorsAsHtml() + { + if (IsValid) return string.Empty; + var lines = _errors.Select(x => "
  • " + System.Net.WebUtility.HtmlEncode(x.ErrorMessage) + "
  • "); + return "
      " + string.Join(string.Empty, lines) + "
    "; + } + + public override string ToString() + { + return IsValid + ? (string.IsNullOrEmpty(_successMessage) ? "Successful" : _successMessage) + : string.Format("Failed with {0} error(s)", _errors.Count); + } + + /// Creates a successful status with the given message. + public static ISuccessOrErrors Success(string successformat, params object[] args) + { + return new SuccessOrErrors().SetSuccessMessage(successformat, args); + } + + /// Creates a status carrying a single global error. + public static ISuccessOrErrors SingleError(string errorformat, params object[] args) + { + return new SuccessOrErrors().AddSingleError(errorformat, args); + } + } +} diff --git a/GenericLibsBase/Core/SuccessOrErrorsGeneric.cs b/GenericLibsBase/Core/SuccessOrErrorsGeneric.cs new file mode 100644 index 0000000..1de1ee6 --- /dev/null +++ b/GenericLibsBase/Core/SuccessOrErrorsGeneric.cs @@ -0,0 +1,28 @@ +namespace GenericLibsBase.Core +{ + /// + /// Default implementation of . + /// + public class SuccessOrErrors : SuccessOrErrors, ISuccessOrErrors + { + public T Result { get; private set; } + + public ISuccessOrErrors SetSuccessWithResult(T result, string successformat, params object[] args) + { + Result = result; + SetSuccessMessage(successformat, args); + return this; + } + + /// + /// Builds an errored from a non-generic status. + /// The result stays at its default value; errors/warnings are copied over. + /// + public static ISuccessOrErrors ConvertNonResultStatus(ISuccessOrErrors status) + { + var result = new SuccessOrErrors(); + result.Combine(status); + return result; + } + } +} diff --git a/GenericLibsBase/GenericLibsBase.csproj b/GenericLibsBase/GenericLibsBase.csproj new file mode 100644 index 0000000..d3ba5d3 --- /dev/null +++ b/GenericLibsBase/GenericLibsBase.csproj @@ -0,0 +1,11 @@ + + + + net8.0 + disable + disable + GenericLibsBase + GenericLibsBase + + + diff --git a/GenericLibsBase/GenericLibsBaseConfig.cs b/GenericLibsBase/GenericLibsBaseConfig.cs new file mode 100644 index 0000000..51e1e88 --- /dev/null +++ b/GenericLibsBase/GenericLibsBaseConfig.cs @@ -0,0 +1,32 @@ +using System; + +namespace GenericLibsBase +{ + /// + /// Global configuration point for the logging abstraction. The host assigns + /// at startup; callers obtain loggers via . + /// + public static class GenericLibsBaseConfig + { + private static Func _getLoggerMethod = name => new NoLoggingGenericLogger(); + + /// + /// Set this at startup to control how loggers are created. + /// + public static Func SetLoggerMethod + { + private get { return _getLoggerMethod; } + set { _getLoggerMethod = value ?? (name => new NoLoggingGenericLogger()); } + } + + public static IGenericLogger GetLogger(string name) + { + return _getLoggerMethod(name); + } + + public static IGenericLogger GetLogger(Type typeForName) + { + return _getLoggerMethod(typeForName.Name); + } + } +} diff --git a/GenericLibsBase/IGenericLogger.cs b/GenericLibsBase/IGenericLogger.cs new file mode 100644 index 0000000..62148d5 --- /dev/null +++ b/GenericLibsBase/IGenericLogger.cs @@ -0,0 +1,27 @@ +using System; + +namespace GenericLibsBase +{ + /// + /// Logging abstraction used across the layers. Implementations bridge to a + /// concrete logging framework (originally log4net; now Microsoft.Extensions.Logging). + /// + public interface IGenericLogger + { + void Verbose(object message); + void VerboseFormat(string format, params object[] args); + + void Info(object message); + void InfoFormat(string format, params object[] args); + + void Warn(object message); + void WarnFormat(string format, params object[] args); + + void Error(object message); + void ErrorFormat(string format, params object[] args); + + void Critical(object message); + void Critical(object message, Exception ex); + void CriticalFormat(string format, params object[] args); + } +} diff --git a/GenericLibsBase/NoLoggingGenericLogger.cs b/GenericLibsBase/NoLoggingGenericLogger.cs new file mode 100644 index 0000000..4d11067 --- /dev/null +++ b/GenericLibsBase/NoLoggingGenericLogger.cs @@ -0,0 +1,22 @@ +using System; + +namespace GenericLibsBase +{ + /// + /// Default no-op logger used until the host assigns a real logger factory. + /// + public class NoLoggingGenericLogger : IGenericLogger + { + public void Verbose(object message) { } + public void VerboseFormat(string format, params object[] args) { } + public void Info(object message) { } + public void InfoFormat(string format, params object[] args) { } + public void Warn(object message) { } + public void WarnFormat(string format, params object[] args) { } + public void Error(object message) { } + public void ErrorFormat(string format, params object[] args) { } + public void Critical(object message) { } + public void Critical(object message, Exception ex) { } + public void CriticalFormat(string format, params object[] args) { } + } +} diff --git a/GenericServices/Core/EfGenericDto.cs b/GenericServices/Core/EfGenericDto.cs new file mode 100644 index 0000000..cfa3e4a --- /dev/null +++ b/GenericServices/Core/EfGenericDto.cs @@ -0,0 +1,81 @@ +using System; +using GenericLibsBase.Core; + +namespace GenericServices.Core +{ + /// + /// Base class for a synchronous DTO mapped to . + /// Concrete DTOs override the hooks to shape data and add business logic. + /// + public abstract class EfGenericDto : EfGenericDtoBase, ISyncInternalDtoCrud + where TEntity : class + where TDto : EfGenericDto + { + /// + /// Override to fill in any secondary data (dropdown lists etc.) needed by the view. + /// + protected internal virtual void SetupSecondaryData(IGenericServicesDbContext context, TDto dto) + { + } + + /// + /// Builds a new entity from this DTO. Default behaviour maps the DTO onto a new entity. + /// + protected internal virtual ISuccessOrErrors CreateDataFromDto(IGenericServicesDbContext context, TDto source) + { + var entity = System.Activator.CreateInstance(); + EntityFromDto.Copy(source, entity); + return new SuccessOrErrors().SetSuccessWithResult(entity, string.Empty); + } + + /// + /// Copies this DTO onto an existing entity. Default behaviour maps the DTO onto the entity. + /// + protected internal virtual ISuccessOrErrors UpdateDataFromDto(IGenericServicesDbContext context, TDto source, TEntity destination) + { + EntityFromDto.Copy(source, destination); + return SuccessOrErrors.Success(string.Empty); + } + + //-------------------------------------------------- + //non-generic entry points used by the service layer + + Type IInternalDtoCrud.AssociatedEntityType + { + get { return EntityTypeInternal; } + } + + object[] IInternalDtoCrud.GetKeyValues() + { + return GetKeyValuesInternal(); + } + + CrudFunctions IInternalDtoCrud.GetSupportedFunctions() + { + return GetSupportedFunctionsInternal(); + } + + void ISyncInternalDtoCrud.RunSetupSecondaryData(IGenericServicesDbContext context) + { + SetupSecondaryData(context, Self); + } + + ISuccessOrErrors ISyncInternalDtoCrud.RunCreateDataFromDto(IGenericServicesDbContext context) + { + var status = CreateDataFromDto(context, Self); + if (status.IsValid) + context.Set().Add(status.Result); + return status; + } + + ISuccessOrErrors ISyncInternalDtoCrud.RunUpdateDataFromDto(IGenericServicesDbContext context, object destinationEntity) + { + return UpdateDataFromDto(context, Self, (TEntity)destinationEntity); + } + + private TDto Self + { + get { return (TDto)(object)this; } + } + } +} diff --git a/GenericServices/Core/EfGenericDtoAsync.cs b/GenericServices/Core/EfGenericDtoAsync.cs new file mode 100644 index 0000000..55a9c0a --- /dev/null +++ b/GenericServices/Core/EfGenericDtoAsync.cs @@ -0,0 +1,74 @@ +using System; +using System.Threading.Tasks; +using GenericLibsBase.Core; + +namespace GenericServices.Core +{ + /// + /// Base class for an asynchronous DTO mapped to . + /// + public abstract class EfGenericDtoAsync : EfGenericDtoBase, IAsyncInternalDtoCrud + where TEntity : class + where TDto : EfGenericDtoAsync + { + protected internal virtual Task SetupSecondaryDataAsync(IGenericServicesDbContext context, TDto dto) + { + return Task.CompletedTask; + } + + protected internal virtual Task> CreateDataFromDtoAsync(IGenericServicesDbContext context, TDto source) + { + var entity = System.Activator.CreateInstance(); + EntityFromDto.Copy(source, entity); + ISuccessOrErrors status = new SuccessOrErrors().SetSuccessWithResult(entity, string.Empty); + return Task.FromResult(status); + } + + protected internal virtual Task UpdateDataFromDtoAsync(IGenericServicesDbContext context, TDto source, TEntity destination) + { + EntityFromDto.Copy(source, destination); + return Task.FromResult(SuccessOrErrors.Success(string.Empty)); + } + + //-------------------------------------------------- + //non-generic entry points used by the service layer + + Type IInternalDtoCrud.AssociatedEntityType + { + get { return EntityTypeInternal; } + } + + object[] IInternalDtoCrud.GetKeyValues() + { + return GetKeyValuesInternal(); + } + + CrudFunctions IInternalDtoCrud.GetSupportedFunctions() + { + return GetSupportedFunctionsInternal(); + } + + async Task IAsyncInternalDtoCrud.RunSetupSecondaryDataAsync(IGenericServicesDbContext context) + { + await SetupSecondaryDataAsync(context, Self).ConfigureAwait(false); + } + + async Task IAsyncInternalDtoCrud.RunCreateDataFromDtoAsync(IGenericServicesDbContext context) + { + var status = await CreateDataFromDtoAsync(context, Self).ConfigureAwait(false); + if (status.IsValid) + context.Set().Add(status.Result); + return status; + } + + async Task IAsyncInternalDtoCrud.RunUpdateDataFromDtoAsync(IGenericServicesDbContext context, object destinationEntity) + { + return await UpdateDataFromDtoAsync(context, Self, (TEntity)destinationEntity).ConfigureAwait(false); + } + + private TDto Self + { + get { return (TDto)(object)this; } + } + } +} diff --git a/GenericServices/Core/EfGenericDtoBase.cs b/GenericServices/Core/EfGenericDtoBase.cs new file mode 100644 index 0000000..d19c0e9 --- /dev/null +++ b/GenericServices/Core/EfGenericDtoBase.cs @@ -0,0 +1,53 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Reflection; + +namespace GenericServices.Core +{ + /// + /// Non-generic root of the DTO hierarchy. Lets non-generic code (the service layer, + /// the mapper configuration) recognise DTOs and read their metadata. + /// + public abstract class EfGenericDtoBase + { + /// + /// Which CRUD functions this DTO supports. Override in the concrete DTO. + /// + protected internal virtual CrudFunctions SupportedFunctions + { + get { return CrudFunctions.None; } + } + + internal CrudFunctions GetSupportedFunctionsInternal() + { + return SupportedFunctions; + } + + /// + /// Reads the values of the DTO properties marked with , + /// used to locate the matching data entity for update. + /// + internal object[] GetKeyValuesInternal() + { + var keyProps = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(p => p.IsDefined(typeof(KeyAttribute), true)) + .ToArray(); + return keyProps.Select(p => p.GetValue(this)).ToArray(); + } + } + + /// + /// Generic DTO base carrying the associated entity/DTO types. Shared by the sync and + /// async DTO base classes. + /// + public abstract class EfGenericDtoBase : EfGenericDtoBase + where TEntity : class + where TDto : EfGenericDtoBase + { + internal Type EntityTypeInternal + { + get { return typeof(TEntity); } + } + } +} diff --git a/GenericServices/Core/EntityFromDto.cs b/GenericServices/Core/EntityFromDto.cs new file mode 100644 index 0000000..aa7e42a --- /dev/null +++ b/GenericServices/Core/EntityFromDto.cs @@ -0,0 +1,44 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Reflection; + +namespace GenericServices.Core +{ + /// + /// Copies the writable data from a DTO onto a data entity for create/update. This replaces + /// the AutoMapper "write" map GenericServices used in EF6. Doing the copy by reflection keeps + /// full control over entity navigations: related entities (e.g. the chosen Tags) are assigned + /// by reference so EF Core tracks them, rather than being cloned. + /// Rules: + /// - properties marked [DoNotCopyBackToDatabase] are skipped (data layer owns them), + /// - [Key] properties are skipped (never overwrite the primary key), + /// - only properties that exist and are writable on the entity, with an assignable value, are copied. + /// + internal static class EntityFromDto + { + public static void Copy(object source, object destination) + { + var dtoType = source.GetType(); + var entityType = destination.GetType(); + + foreach (var dtoProp in dtoType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + if (!dtoProp.CanRead) continue; + if (dtoProp.GetIndexParameters().Length != 0) continue; + if (dtoProp.IsDefined(typeof(DoNotCopyBackToDatabaseAttribute), true)) continue; + if (dtoProp.IsDefined(typeof(KeyAttribute), true)) continue; + + var entityProp = entityType.GetProperty(dtoProp.Name, BindingFlags.Public | BindingFlags.Instance); + if (entityProp == null || !entityProp.CanWrite) continue; + + var value = dtoProp.GetValue(source); + if (value != null && !entityProp.PropertyType.IsInstanceOfType(value)) continue; + if (value == null && entityProp.PropertyType.IsValueType && + Nullable.GetUnderlyingType(entityProp.PropertyType) == null) + continue; + + entityProp.SetValue(destination, value); + } + } + } +} diff --git a/GenericServices/Core/GenericValidation.cs b/GenericServices/Core/GenericValidation.cs new file mode 100644 index 0000000..6a14ef7 --- /dev/null +++ b/GenericServices/Core/GenericValidation.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using GenericLibsBase.Core; +using Microsoft.EntityFrameworkCore; + +namespace GenericServices.Core +{ + /// + /// Reproduces the validation EF6 used to run automatically on SaveChanges: + /// DataAnnotations + on every Added/Modified entity, + /// plus any database-level checks exposed via . + /// + internal static class GenericValidation + { + public static ISuccessOrErrors Validate(DbContext context) + { + var status = new SuccessOrErrors(); + var customValidator = context as IValidateOnSave; + + var changedEntities = context.ChangeTracker.Entries() + .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified) + .ToList(); + + foreach (var entry in changedEntities) + { + var entity = entry.Entity; + + var validationContext = new ValidationContext(entity, serviceProvider: null, items: null); + var results = new List(); + Validator.TryValidateObject(entity, validationContext, results, validateAllProperties: true); + + if (customValidator != null) + { + var extra = customValidator.ValidateEntity(entity); + if (extra != null) + results.AddRange(extra); + } + + foreach (var result in results) + { + var memberName = result.MemberNames == null ? null : result.MemberNames.FirstOrDefault(); + if (string.IsNullOrEmpty(memberName)) + status.AddSingleError(SafeFormat(result.ErrorMessage)); + else + status.AddNamedParameterError(memberName, SafeFormat(result.ErrorMessage)); + } + } + + return status.IsValid ? status.SetSuccessMessage("Successfully validated.") : status; + } + + //Error messages may legitimately contain braces, so avoid string.Format re-parsing them. + private static string SafeFormat(string message) + { + return message ?? string.Empty; + } + } +} diff --git a/GenericServices/Core/IInternalDtoCrud.cs b/GenericServices/Core/IInternalDtoCrud.cs new file mode 100644 index 0000000..ba6b020 --- /dev/null +++ b/GenericServices/Core/IInternalDtoCrud.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using GenericLibsBase.Core; + +namespace GenericServices.Core +{ + /// + /// Non-generic entry points the service layer uses to drive a DTO without knowing its + /// concrete generic type. Implemented internally by the DTO base classes. + /// + internal interface IInternalDtoCrud + { + Type AssociatedEntityType { get; } + object[] GetKeyValues(); + CrudFunctions GetSupportedFunctions(); + } + + internal interface ISyncInternalDtoCrud : IInternalDtoCrud + { + void RunSetupSecondaryData(IGenericServicesDbContext context); + ISuccessOrErrors RunCreateDataFromDto(IGenericServicesDbContext context); + ISuccessOrErrors RunUpdateDataFromDto(IGenericServicesDbContext context, object destinationEntity); + } + + internal interface IAsyncInternalDtoCrud : IInternalDtoCrud + { + Task RunSetupSecondaryDataAsync(IGenericServicesDbContext context); + Task RunCreateDataFromDtoAsync(IGenericServicesDbContext context); + Task RunUpdateDataFromDtoAsync(IGenericServicesDbContext context, object destinationEntity); + } +} diff --git a/GenericServices/CrudFunctions.cs b/GenericServices/CrudFunctions.cs new file mode 100644 index 0000000..2f94188 --- /dev/null +++ b/GenericServices/CrudFunctions.cs @@ -0,0 +1,19 @@ +using System; + +namespace GenericServices.Core +{ + /// + /// Flags describing which CRUD operations a DTO supports. + /// + [Flags] + public enum CrudFunctions + { + None = 0, + List = 1, + Detail = 2, + Create = 4, + Update = 8, + Delete = 16, + AllCrud = List | Detail | Create | Update | Delete + } +} diff --git a/GenericServices/DoNotCopyBackToDatabaseAttribute.cs b/GenericServices/DoNotCopyBackToDatabaseAttribute.cs new file mode 100644 index 0000000..2438f51 --- /dev/null +++ b/GenericServices/DoNotCopyBackToDatabaseAttribute.cs @@ -0,0 +1,13 @@ +using System; + +namespace GenericServices +{ + /// + /// Marks a DTO property that must NOT be copied back onto the data entity when + /// creating/updating (e.g. values the data layer maintains itself). + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] + public sealed class DoNotCopyBackToDatabaseAttribute : Attribute + { + } +} diff --git a/GenericServices/GenericServices.csproj b/GenericServices/GenericServices.csproj new file mode 100644 index 0000000..69f8a45 --- /dev/null +++ b/GenericServices/GenericServices.csproj @@ -0,0 +1,32 @@ + + + + net8.0 + disable + disable + GenericServices + GenericServices + + + + + + + + + + + + + + + + + + + diff --git a/GenericServices/GenericServicesConfig.cs b/GenericServices/GenericServicesConfig.cs new file mode 100644 index 0000000..4e3fc86 --- /dev/null +++ b/GenericServices/GenericServicesConfig.cs @@ -0,0 +1,68 @@ +using System.Linq; +using System.Reflection; +using AutoMapper; +using GenericServices.Internal; +using GenericServices.Services; +using Microsoft.Extensions.DependencyInjection; + +namespace GenericServices +{ + /// + /// Configuration entry point for the GenericServices EF Core compatibility layer. + /// Builds the AutoMapper configuration from the DTOs and registers the service + /// implementations in the ASP.NET Core DI container. + /// + public static class GenericServicesConfig + { + /// + /// The AutoMapper instance used by the DTO base classes for in-memory mapping. + /// Set by / . + /// + public static IMapper Mapper { get; set; } + + /// + /// Scans the given assemblies for DTOs, builds the AutoMapper configuration and + /// stores it in . + /// + public static IMapper BuildMapper(params Assembly[] dtoAssemblies) + { + var dtoTypes = dtoAssemblies + .SelectMany(a => a.GetTypes()) + .Where(t => !t.IsAbstract && DtoReflection.IsDto(t)) + .ToList(); + + var config = new MapperConfiguration(cfg => DtoMappingConfig.AddMappings(cfg, dtoTypes)); + var mapper = config.CreateMapper(); + Mapper = mapper; + return mapper; + } + + /// + /// Registers the AutoMapper instance and all GenericServices service implementations. + /// The application must separately register its DbContext as + /// (scoped). + /// + public static IServiceCollection AddGenericServices(this IServiceCollection services, params Assembly[] dtoAssemblies) + { + var mapper = BuildMapper(dtoAssemblies); + services.AddSingleton(mapper); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + return services; + } + } +} diff --git a/GenericServices/IGenericServicesDbContext.cs b/GenericServices/IGenericServicesDbContext.cs new file mode 100644 index 0000000..9299a1c --- /dev/null +++ b/GenericServices/IGenericServicesDbContext.cs @@ -0,0 +1,25 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; + +namespace GenericServices +{ + /// + /// Abstraction over the EF Core used by the service layer and DTOs. + /// The signatures deliberately match so a context can implement this + /// interface without any extra code. + /// + public interface IGenericServicesDbContext + { + DbSet Set() where TEntity : class; + + EntityEntry Entry(TEntity entity) where TEntity : class; + + EntityEntry Entry(object entity); + + int SaveChanges(); + + Task SaveChangesAsync(CancellationToken cancellationToken = default); + } +} diff --git a/GenericServices/IValidateOnSave.cs b/GenericServices/IValidateOnSave.cs new file mode 100644 index 0000000..2acf3c7 --- /dev/null +++ b/GenericServices/IValidateOnSave.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace GenericServices +{ + /// + /// Implemented by a DbContext that needs to run extra, database-level validation on + /// entities being added/modified (e.g. cross-row uniqueness checks). This replaces the + /// EF6 DbContext.ValidateEntity override, which EF Core does not provide. + /// + public interface IValidateOnSave + { + /// + /// Returns any database-level validation errors for the given entity, or an empty + /// sequence if it is valid. + /// + IEnumerable ValidateEntity(object entity); + } +} diff --git a/GenericServices/Internal/DtoMappingConfig.cs b/GenericServices/Internal/DtoMappingConfig.cs new file mode 100644 index 0000000..e900c34 --- /dev/null +++ b/GenericServices/Internal/DtoMappingConfig.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using AutoMapper; + +namespace GenericServices.Internal +{ + /// + /// Builds the AutoMapper read maps used to project entities onto DTOs (entity -> DTO), + /// relying on AutoMapper flattening for members like BloggerName / PostsCount. + /// Writing DTOs back onto entities is handled by , not + /// AutoMapper, so no DTO -> entity maps are configured here. + /// + internal static class DtoMappingConfig + { + public static void AddMappings(IMapperConfigurationExpression cfg, IEnumerable dtoTypes) + { + var entityMemberTypes = new HashSet(); + + foreach (var dtoType in dtoTypes) + { + var pair = DtoReflection.GetEntityAndDtoTypes(dtoType); + if (pair == null) continue; + + var entityType = pair.Item1; + BuildReadMap(cfg, entityType, dtoType, entityMemberTypes); + } + + //DTOs sometimes expose the entity type directly (e.g. ICollection Tags). Add a + //self-map for those types that copies only scalar members, so projection works and + //we never recurse through their navigations. + foreach (var entityMemberType in entityMemberTypes) + BuildScalarSelfMap(cfg, entityMemberType); + } + + private static void BuildReadMap(IMapperConfigurationExpression cfg, Type entityType, Type dtoType, + HashSet entityMemberTypes) + { + var map = cfg.CreateMap(entityType, dtoType); + + foreach (var prop in PublicProps(dtoType)) + { + //computed (read-only) properties are evaluated in memory, never projected + if (!prop.CanWrite) + { + map.ForMember(prop.Name, o => o.Ignore()); + continue; + } + + //members with no matching source (e.g. UI dropdown lists) are filled elsewhere + if (!DtoReflection.CanResolveSource(entityType, prop.Name)) + { + map.ForMember(prop.Name, o => o.Ignore()); + continue; + } + + var memberEntityType = EntityElementType(prop.PropertyType); + if (memberEntityType != null) + entityMemberTypes.Add(memberEntityType); + } + } + + private static void BuildScalarSelfMap(IMapperConfigurationExpression cfg, Type type) + { + var map = cfg.CreateMap(type, type); + foreach (var prop in PublicProps(type)) + { + if (DtoReflection.IsEnumerableButNotString(prop.PropertyType) || IsEntityLike(prop.PropertyType)) + map.ForMember(prop.Name, o => o.Ignore()); + } + } + + /// + /// If the property is an entity or a collection of entities, returns that entity type; + /// otherwise null. + /// + private static Type EntityElementType(Type propertyType) + { + if (DtoReflection.IsEnumerableButNotString(propertyType)) + { + var element = GetEnumerableElementType(propertyType); + return element != null && IsEntityLike(element) ? element : null; + } + + return IsEntityLike(propertyType) ? propertyType : null; + } + + private static Type GetEnumerableElementType(Type type) + { + if (type.IsArray) + return type.GetElementType(); + if (type.IsGenericType) + return type.GetGenericArguments().FirstOrDefault(); + var iface = type.GetInterfaces() + .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)); + return iface != null ? iface.GetGenericArguments()[0] : null; + } + + private static bool IsEntityLike(Type type) + { + return type.IsClass + && type != typeof(string) + && (type.Namespace == null || !type.Namespace.StartsWith("System")); + } + + private static IEnumerable PublicProps(Type type) + { + return type.GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(p => p.GetIndexParameters().Length == 0); + } + } +} diff --git a/GenericServices/Internal/DtoReflection.cs b/GenericServices/Internal/DtoReflection.cs new file mode 100644 index 0000000..0a18ae5 --- /dev/null +++ b/GenericServices/Internal/DtoReflection.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using GenericServices.Core; +using Microsoft.EntityFrameworkCore; + +namespace GenericServices.Internal +{ + /// + /// Reflection helpers shared by the mapper configuration and the service layer. + /// + internal static class DtoReflection + { + public static bool IsDto(Type type) + { + return typeof(EfGenericDtoBase).IsAssignableFrom(type); + } + + /// + /// Walks the base chain to find and returns + /// (entityType, dtoType), or null if the type is not a DTO. + /// + public static Tuple GetEntityAndDtoTypes(Type dtoType) + { + var t = dtoType; + while (t != null && t != typeof(object)) + { + if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(EfGenericDtoBase<,>)) + { + var args = t.GetGenericArguments(); + return Tuple.Create(args[0], args[1]); + } + t = t.BaseType; + } + return null; + } + + /// + /// Returns true if a source member on can supply + /// either directly or by AutoMapper flattening + /// (e.g. "BloggerName" -> Blogger.Name, "PostsCount" -> Posts.Count). + /// + public static bool CanResolveSource(Type entityType, string memberName) + { + if (string.IsNullOrEmpty(memberName)) return false; + + if (GetPublicProperty(entityType, memberName) != null) + return true; + + //greedy longest-prefix flattening + for (var i = memberName.Length - 1; i >= 1; i--) + { + var prefix = memberName.Substring(0, i); + var remainder = memberName.Substring(i); + var prop = GetPublicProperty(entityType, prefix); + if (prop == null) continue; + + if (IsEnumerableButNotString(prop.PropertyType)) + { + if (remainder == "Count") + return true; + continue; + } + + if (CanResolveSource(prop.PropertyType, remainder)) + return true; + } + + return false; + } + + private static PropertyInfo GetPublicProperty(Type type, string name) + { + return type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); + } + + public static bool IsEnumerableButNotString(Type type) + { + return type != typeof(string) && typeof(IEnumerable).IsAssignableFrom(type); + } + + //-------------------------------------------------- + //runtime access to Set() / Find for a type only known at runtime + + private static readonly MethodInfo SetMethod = typeof(IGenericServicesDbContext) + .GetMethod("Set", Type.EmptyTypes); + + public static IQueryable QueryableForEntity(IGenericServicesDbContext context, Type entityType) + { + var generic = SetMethod.MakeGenericMethod(entityType); + return (IQueryable)generic.Invoke(context, null); + } + + public static object FindEntity(IGenericServicesDbContext context, Type entityType, object[] keys) + { + var set = SetMethod.MakeGenericMethod(entityType).Invoke(context, null); + var find = set.GetType().GetMethod("Find", new[] { typeof(object[]) }); + return find.Invoke(set, new object[] { keys }); + } + + public static async Task FindEntityAsync(IGenericServicesDbContext context, Type entityType, object[] keys) + { + var set = SetMethod.MakeGenericMethod(entityType).Invoke(context, null); + var find = set.GetType().GetMethod("FindAsync", new[] { typeof(object[]) }); + var valueTask = find.Invoke(set, new object[] { keys }); + + // DbSet.FindAsync returns ValueTask; convert to Task via AsTask() + var asTask = valueTask.GetType().GetMethod("AsTask").Invoke(valueTask, null); + await (Task)asTask; + var resultProp = asTask.GetType().GetProperty("Result"); + return resultProp.GetValue(asTask); + } + } +} diff --git a/GenericServices/SaveChangesExtensions.cs b/GenericServices/SaveChangesExtensions.cs new file mode 100644 index 0000000..9f3e74d --- /dev/null +++ b/GenericServices/SaveChangesExtensions.cs @@ -0,0 +1,75 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using GenericLibsBase.Core; +using GenericServices.Core; +using Microsoft.EntityFrameworkCore; + +namespace GenericServices +{ + /// + /// Provides the GenericServices "save with checking" behaviour on top of EF Core: + /// it validates the tracked changes first (as EF6 did automatically) and turns any + /// validation or concurrency failure into an result + /// rather than throwing. + /// + public static class SaveChangesExtensions + { + public static ISuccessOrErrors SaveChangesWithChecking(this IGenericServicesDbContext context) + { + var dbContext = AsDbContext(context); + + var validation = GenericValidation.Validate(dbContext); + if (!validation.IsValid) + return validation; + + try + { + dbContext.SaveChanges(); + } + catch (DbUpdateConcurrencyException ex) + { + return ConcurrencyError(ex); + } + + return SuccessOrErrors.Success("Successfully saved."); + } + + public static async Task SaveChangesWithCheckingAsync( + this IGenericServicesDbContext context, CancellationToken cancellationToken = default) + { + var dbContext = AsDbContext(context); + + var validation = GenericValidation.Validate(dbContext); + if (!validation.IsValid) + return validation; + + try + { + await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); + } + catch (DbUpdateConcurrencyException ex) + { + return ConcurrencyError(ex); + } + + return SuccessOrErrors.Success("Successfully saved."); + } + + private static DbContext AsDbContext(IGenericServicesDbContext context) + { + var dbContext = context as DbContext; + if (dbContext == null) + throw new InvalidOperationException( + "SaveChangesWithChecking requires the context to derive from EF Core's DbContext."); + return dbContext; + } + + private static ISuccessOrErrors ConcurrencyError(DbUpdateConcurrencyException ex) + { + return new SuccessOrErrors().AddSingleError( + "Another user changed this data at the same time. Please retry your edit. ({0})", + ex.Message); + } + } +} diff --git a/GenericServices/Services.cs b/GenericServices/Services.cs new file mode 100644 index 0000000..a046a1e --- /dev/null +++ b/GenericServices/Services.cs @@ -0,0 +1,81 @@ +using System.Linq; +using System.Threading.Tasks; +using GenericLibsBase.Core; + +namespace GenericServices +{ + //------------------------------------------------------------------- + // Synchronous service contracts + + public interface IListService + { + IQueryable GetAll() where T : class; + } + + public interface IDetailService + { + ISuccessOrErrors GetDetail(params object[] keys) where T : class; + } + + public interface IUpdateSetupService + { + ISuccessOrErrors GetOriginal(params object[] keys) where T : class; + } + + public interface IUpdateService + { + ISuccessOrErrors Update(T item) where T : class; + T ResetDto(T dto) where T : class; + } + + public interface ICreateSetupService + { + T GetDto() where T : class; + } + + public interface ICreateService + { + ISuccessOrErrors Create(T item) where T : class; + T ResetDto(T dto) where T : class; + } + + public interface IDeleteService + { + ISuccessOrErrors Delete(params object[] keys) where T : class; + } + + //------------------------------------------------------------------- + // Asynchronous service contracts + + public interface IDetailServiceAsync + { + Task> GetDetailAsync(params object[] keys) where T : class; + } + + public interface IUpdateSetupServiceAsync + { + Task> GetOriginalAsync(params object[] keys) where T : class; + } + + public interface IUpdateServiceAsync + { + Task UpdateAsync(T item) where T : class; + Task ResetDtoAsync(T dto) where T : class; + } + + public interface ICreateSetupServiceAsync + { + Task GetDtoAsync() where T : class; + } + + public interface ICreateServiceAsync + { + Task CreateAsync(T item) where T : class; + Task ResetDtoAsync(T dto) where T : class; + } + + public interface IDeleteServiceAsync + { + Task DeleteAsync(params object[] keys) where T : class; + } +} diff --git a/GenericServices/Services/AsyncServices.cs b/GenericServices/Services/AsyncServices.cs new file mode 100644 index 0000000..6f6c432 --- /dev/null +++ b/GenericServices/Services/AsyncServices.cs @@ -0,0 +1,182 @@ +using System.Linq; +using System.Threading.Tasks; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using GenericLibsBase.Core; +using GenericServices; +using GenericServices.Core; +using GenericServices.Internal; +using Microsoft.EntityFrameworkCore; + +namespace GenericServices.Services +{ + public class DetailServiceAsync : GenericServiceBase, IDetailServiceAsync + { + public DetailServiceAsync(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public Task> GetDetailAsync(params object[] keys) where T : class + { + return AsyncReadHelper.ReadSingleAsync(Context, Mapper, keys); + } + } + + public class UpdateSetupServiceAsync : GenericServiceBase, IUpdateSetupServiceAsync + { + public UpdateSetupServiceAsync(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public Task> GetOriginalAsync(params object[] keys) where T : class + { + return AsyncReadHelper.ReadSingleAsync(Context, Mapper, keys); + } + } + + public class CreateSetupServiceAsync : GenericServiceBase, ICreateSetupServiceAsync + { + public CreateSetupServiceAsync(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public async Task GetDtoAsync() where T : class + { + var dto = System.Activator.CreateInstance(); + var crud = dto as IAsyncInternalDtoCrud; + if (crud != null) + await crud.RunSetupSecondaryDataAsync(Context).ConfigureAwait(false); + return dto; + } + } + + public class CreateServiceAsync : GenericServiceBase, ICreateServiceAsync + { + public CreateServiceAsync(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public async Task CreateAsync(T item) where T : class + { + var crud = item as IAsyncInternalDtoCrud; + if (crud != null) + { + var buildStatus = await crud.RunCreateDataFromDtoAsync(Context).ConfigureAwait(false); + if (!buildStatus.IsValid) + { + await crud.RunSetupSecondaryDataAsync(Context).ConfigureAwait(false); + return buildStatus; + } + + var saveStatus = await Context.SaveChangesWithCheckingAsync().ConfigureAwait(false); + if (saveStatus.IsValid) + saveStatus.SetSuccessMessage("Successfully created {0}.", crud.AssociatedEntityType.Name); + else + await crud.RunSetupSecondaryDataAsync(Context).ConfigureAwait(false); + return saveStatus; + } + + Context.Set().Add(item); + var status = await Context.SaveChangesWithCheckingAsync().ConfigureAwait(false); + if (status.IsValid) + status.SetSuccessMessage("Successfully created {0}.", typeof(T).Name); + return status; + } + + public async Task ResetDtoAsync(T dto) where T : class + { + var crud = dto as IAsyncInternalDtoCrud; + if (crud != null) + await crud.RunSetupSecondaryDataAsync(Context).ConfigureAwait(false); + return dto; + } + } + + public class UpdateServiceAsync : GenericServiceBase, IUpdateServiceAsync + { + public UpdateServiceAsync(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public async Task UpdateAsync(T item) where T : class + { + var crud = item as IAsyncInternalDtoCrud; + if (crud != null) + { + var entity = await DtoReflection.FindEntityAsync(Context, crud.AssociatedEntityType, crud.GetKeyValues()).ConfigureAwait(false); + if (entity == null) + { + await crud.RunSetupSecondaryDataAsync(Context).ConfigureAwait(false); + return new SuccessOrErrors().AddSingleError( + "Could not find the item you requested. Perhaps it was deleted by another user."); + } + + var buildStatus = await crud.RunUpdateDataFromDtoAsync(Context, entity).ConfigureAwait(false); + if (!buildStatus.IsValid) + { + await crud.RunSetupSecondaryDataAsync(Context).ConfigureAwait(false); + return buildStatus; + } + + var saveStatus = await Context.SaveChangesWithCheckingAsync().ConfigureAwait(false); + if (saveStatus.IsValid) + saveStatus.SetSuccessMessage("Successfully updated {0}.", crud.AssociatedEntityType.Name); + else + await crud.RunSetupSecondaryDataAsync(Context).ConfigureAwait(false); + return saveStatus; + } + + Context.Entry(item).State = EntityState.Modified; + var status = await Context.SaveChangesWithCheckingAsync().ConfigureAwait(false); + if (status.IsValid) + status.SetSuccessMessage("Successfully updated {0}.", typeof(T).Name); + return status; + } + + public async Task ResetDtoAsync(T dto) where T : class + { + var crud = dto as IAsyncInternalDtoCrud; + if (crud != null) + await crud.RunSetupSecondaryDataAsync(Context).ConfigureAwait(false); + return dto; + } + } + + public class DeleteServiceAsync : GenericServiceBase, IDeleteServiceAsync + { + public DeleteServiceAsync(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public async Task DeleteAsync(params object[] keys) where T : class + { + var entity = await Context.Set().FindAsync(keys).AsTask().ConfigureAwait(false); + if (entity == null) + return new SuccessOrErrors().AddSingleError( + "Could not find the {0} you requested. Perhaps it was deleted by another user.", typeof(T).Name); + + Context.Set().Remove(entity); + var status = await Context.SaveChangesWithCheckingAsync().ConfigureAwait(false); + if (status.IsValid) + status.SetSuccessMessage("Successfully deleted {0}.", typeof(T).Name); + return status; + } + } + + internal static class AsyncReadHelper + { + public static async Task> ReadSingleAsync(IGenericServicesDbContext context, IMapper mapper, object[] keys) where T : class + { + if (!DtoReflection.IsDto(typeof(T))) + { + var entity = await context.Set().FindAsync(keys).AsTask().ConfigureAwait(false); + if (entity == null) + return (ISuccessOrErrors)new SuccessOrErrors().AddSingleError("Could not find the data entry you requested."); + return new SuccessOrErrors().SetSuccessWithResult(entity, "Success"); + } + + var pair = DtoReflection.GetEntityAndDtoTypes(typeof(T)); + var source = DtoReflection.QueryableForEntity(context, pair.Item1); + var projected = source.ProjectTo(mapper.ConfigurationProvider); + var predicate = GenericServiceBase.BuildKeyPredicate(keys); + var dto = await projected.Where(predicate).SingleOrDefaultAsync().ConfigureAwait(false); + + if (dto == null) + return (ISuccessOrErrors)new SuccessOrErrors().AddSingleError("Could not find the data entry you requested."); + + var crud = dto as IAsyncInternalDtoCrud; + if (crud != null) + await crud.RunSetupSecondaryDataAsync(context).ConfigureAwait(false); + + return new SuccessOrErrors().SetSuccessWithResult(dto, "Success"); + } + } +} diff --git a/GenericServices/Services/GenericServiceBase.cs b/GenericServices/Services/GenericServiceBase.cs new file mode 100644 index 0000000..dedc88e --- /dev/null +++ b/GenericServices/Services/GenericServiceBase.cs @@ -0,0 +1,56 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using AutoMapper; +using GenericServices.Internal; + +namespace GenericServices.Services +{ + /// + /// Shared state and helpers for the concrete service classes. + /// + public abstract class GenericServiceBase + { + protected readonly IGenericServicesDbContext Context; + protected readonly IMapper Mapper; + + protected GenericServiceBase(IGenericServicesDbContext context, IMapper mapper) + { + Context = context; + Mapper = mapper; + } + + protected static bool IsDto(Type type) + { + return DtoReflection.IsDto(type); + } + + /// + /// Builds a predicate matching the DTO's [Key] property/properties against the given key values. + /// + internal static Expression> BuildKeyPredicate(object[] keys) + { + var keyProps = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(p => p.IsDefined(typeof(KeyAttribute), true)) + .ToArray(); + + if (keyProps.Length == 0) + throw new InvalidOperationException( + string.Format("The DTO '{0}' has no [Key] property to identify the row.", typeof(T).Name)); + + var param = Expression.Parameter(typeof(T), "x"); + Expression body = null; + for (var i = 0; i < keyProps.Length; i++) + { + var member = Expression.Property(param, keyProps[i]); + var value = Convert.ChangeType(keys[i], keyProps[i].PropertyType); + var equal = Expression.Equal(member, Expression.Constant(value, keyProps[i].PropertyType)); + body = body == null ? equal : Expression.AndAlso(body, equal); + } + + return Expression.Lambda>(body, param); + } + } +} diff --git a/GenericServices/Services/SyncServices.cs b/GenericServices/Services/SyncServices.cs new file mode 100644 index 0000000..12e28ae --- /dev/null +++ b/GenericServices/Services/SyncServices.cs @@ -0,0 +1,195 @@ +using System.Linq; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using GenericLibsBase.Core; +using GenericServices; +using GenericServices.Core; +using GenericServices.Internal; + +namespace GenericServices.Services +{ + public class ListService : GenericServiceBase, IListService + { + public ListService(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public IQueryable GetAll() where T : class + { + if (!IsDto(typeof(T))) + return Context.Set(); + + var pair = DtoReflection.GetEntityAndDtoTypes(typeof(T)); + var source = DtoReflection.QueryableForEntity(Context, pair.Item1); + return source.ProjectTo(Mapper.ConfigurationProvider); + } + } + + public class DetailService : GenericServiceBase, IDetailService + { + public DetailService(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public ISuccessOrErrors GetDetail(params object[] keys) where T : class + { + return SyncReadHelper.ReadSingle(Context, Mapper, keys); + } + } + + public class UpdateSetupService : GenericServiceBase, IUpdateSetupService + { + public UpdateSetupService(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public ISuccessOrErrors GetOriginal(params object[] keys) where T : class + { + return SyncReadHelper.ReadSingle(Context, Mapper, keys); + } + } + + public class CreateSetupService : GenericServiceBase, ICreateSetupService + { + public CreateSetupService(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public T GetDto() where T : class + { + var dto = System.Activator.CreateInstance(); + var crud = dto as ISyncInternalDtoCrud; + if (crud != null) + crud.RunSetupSecondaryData(Context); + return dto; + } + } + + public class CreateService : GenericServiceBase, ICreateService + { + public CreateService(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public ISuccessOrErrors Create(T item) where T : class + { + var crud = item as ISyncInternalDtoCrud; + if (crud != null) + { + var buildStatus = crud.RunCreateDataFromDto(Context); + if (!buildStatus.IsValid) + { + crud.RunSetupSecondaryData(Context); + return buildStatus; + } + + var saveStatus = Context.SaveChangesWithChecking(); + if (saveStatus.IsValid) + saveStatus.SetSuccessMessage("Successfully created {0}.", crud.AssociatedEntityType.Name); + else + crud.RunSetupSecondaryData(Context); + return saveStatus; + } + + Context.Set().Add(item); + var status = Context.SaveChangesWithChecking(); + if (status.IsValid) + status.SetSuccessMessage("Successfully created {0}.", typeof(T).Name); + return status; + } + + public T ResetDto(T dto) where T : class + { + var crud = dto as ISyncInternalDtoCrud; + if (crud != null) + crud.RunSetupSecondaryData(Context); + return dto; + } + } + + public class UpdateService : GenericServiceBase, IUpdateService + { + public UpdateService(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public ISuccessOrErrors Update(T item) where T : class + { + var crud = item as ISyncInternalDtoCrud; + if (crud != null) + { + var entity = DtoReflection.FindEntity(Context, crud.AssociatedEntityType, crud.GetKeyValues()); + if (entity == null) + { + crud.RunSetupSecondaryData(Context); + return new SuccessOrErrors().AddSingleError( + "Could not find the item you requested. Perhaps it was deleted by another user."); + } + + var buildStatus = crud.RunUpdateDataFromDto(Context, entity); + if (!buildStatus.IsValid) + { + crud.RunSetupSecondaryData(Context); + return buildStatus; + } + + var saveStatus = Context.SaveChangesWithChecking(); + if (saveStatus.IsValid) + saveStatus.SetSuccessMessage("Successfully updated {0}.", crud.AssociatedEntityType.Name); + else + crud.RunSetupSecondaryData(Context); + return saveStatus; + } + + Context.Entry(item).State = Microsoft.EntityFrameworkCore.EntityState.Modified; + var status = Context.SaveChangesWithChecking(); + if (status.IsValid) + status.SetSuccessMessage("Successfully updated {0}.", typeof(T).Name); + return status; + } + + public T ResetDto(T dto) where T : class + { + var crud = dto as ISyncInternalDtoCrud; + if (crud != null) + crud.RunSetupSecondaryData(Context); + return dto; + } + } + + public class DeleteService : GenericServiceBase, IDeleteService + { + public DeleteService(IGenericServicesDbContext context, IMapper mapper) : base(context, mapper) { } + + public ISuccessOrErrors Delete(params object[] keys) where T : class + { + var entity = Context.Set().Find(keys); + if (entity == null) + return new SuccessOrErrors().AddSingleError( + "Could not find the {0} you requested. Perhaps it was deleted by another user.", typeof(T).Name); + + Context.Set().Remove(entity); + var status = Context.SaveChangesWithChecking(); + if (status.IsValid) + status.SetSuccessMessage("Successfully deleted {0}.", typeof(T).Name); + return status; + } + } + + internal static class SyncReadHelper + { + public static ISuccessOrErrors ReadSingle(IGenericServicesDbContext context, IMapper mapper, object[] keys) where T : class + { + if (!DtoReflection.IsDto(typeof(T))) + { + var entity = context.Set().Find(keys); + if (entity == null) + return new SuccessOrErrors().AddSingleError("Could not find the data entry you requested.") as ISuccessOrErrors; + return new SuccessOrErrors().SetSuccessWithResult(entity, "Success"); + } + + var pair = DtoReflection.GetEntityAndDtoTypes(typeof(T)); + var source = DtoReflection.QueryableForEntity(context, pair.Item1); + var projected = source.ProjectTo(mapper.ConfigurationProvider); + var predicate = GenericServiceBase.BuildKeyPredicate(keys); + var dto = projected.Where(predicate).SingleOrDefault(); + + if (dto == null) + return new SuccessOrErrors().AddSingleError("Could not find the data entry you requested.") as ISuccessOrErrors; + + var crud = dto as ISyncInternalDtoCrud; + if (crud != null) + crud.RunSetupSecondaryData(context); + + return new SuccessOrErrors().SetSuccessWithResult(dto, "Success"); + } + } +} diff --git a/README.md b/README.md index 21e465e..cc102d7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,51 @@ SampleMvcWebApp =============== +> ### .NET 8 modernization +> +> This repository has been migrated from **ASP.NET MVC 5 / .NET Framework 4.5.1** to +> **cross-platform ASP.NET Core MVC on .NET 8**, while preserving the app's pages, CRUD +> flows, and business rules. The historical description below is retained for context. +> +> **What changed** +> +> | Area | Before | After | +> |------|--------|-------| +> | Projects | old MSBuild + `packages.config` | SDK-style `.csproj`, `net8.0` | +> | Web framework | ASP.NET MVC 5 (`System.Web`, `Global.asax`) | ASP.NET Core MVC (`Program.cs`, middleware) | +> | ORM | Entity Framework 6.1.3 | EF Core 8 (SQLite, cross-platform, with migrations) | +> | DI | Autofac 3.5 | built-in ASP.NET Core DI | +> | Mapping | AutoMapper 4.2 | AutoMapper 14 | +> | Logging | log4net | Microsoft.Extensions.Logging | +> | Config | `web.config` | `appsettings.json` | +> | GenericServices | EF6-only NuGet package | in-repo `GenericServices`/`GenericLibsBase` compatibility port on EF Core 8 | +> | Tests | NUnit 2.6 (.NET 4.5.1) | NUnit 4 (`net8.0`) | +> +> **Prerequisites:** [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0). +> +> **Build, test and run:** +> ```bash +> dotnet build SampleWebApp.sln +> dotnet test SampleWebApp.sln +> dotnet run --project SampleWebApp +> ``` +> On first run the app creates and seeds a local SQLite database (`SampleWebAppDb.db`) via +> EF Core migrations. The connection string and host type live in +> `SampleWebApp/appsettings.json`. +> +> **CI:** `.github/workflows/ci.yml` builds and tests the solution on .NET 8. +> +> **Remaining risks / review notes:** +> - The default database provider is now **SQLite** for cross-platform demo use; the original +> used SQL Server LocalDB. Production SQL Server compatibility is not re-validated. +> - EF Core validation/tracking/cascade behaviour can differ subtly from EF6. +> - AutoMapper is pinned to **14.0.0** (last MIT-licensed line); a single, scoped NuGet audit +> suppression is applied for advisory `GHSA-rvv3-g6hj-g44x`. +> - The legacy test suite (which asserted EF6/Autofac/MVC5 internals that no longer exist) was +> replaced with focused regression tests covering the preserved CRUD/service-layer behaviour. +> +> --- + SampleMvcWebApp is a ASP.NET MVC5 web site designed to show number of useful methods for building enterprise grade web applications using ASP.NET MVC5 and Entity Framework 6. The code for this sample MVC web application, and the associated diff --git a/SampleWebApp.sln b/SampleWebApp.sln index b474189..b517f90 100644 --- a/SampleWebApp.sln +++ b/SampleWebApp.sln @@ -1,63 +1,58 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleWebApp", "SampleWebApp\SampleWebApp.csproj", "{CFFEE5E0-3B99-46E0-9A82-2E74621C17C5}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GenericLibsBase", "GenericLibsBase\GenericLibsBase.csproj", "{F3FEAB2B-8725-4E8B-83A2-E51C4EC66EF7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataLayer", "DataLayer\DataLayer.csproj", "{264E1878-12DE-4099-B8D7-CC53A73FEA49}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GenericServices", "GenericServices\GenericServices.csproj", "{BC14D5B3-3FA5-48E4-9062-6D30929D72F4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceLayer", "ServiceLayer\ServiceLayer.csproj", "{D2813927-0F38-43C3-B47C-AE8F00D50CAE}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataLayer", "DataLayer\DataLayer.csproj", "{095E3125-1C36-49B2-98D2-D21ED7225FAB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{6D9E7904-B2AC-49E3-83A7-6B48876F46B9}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceLayer", "ServiceLayer\ServiceLayer.csproj", "{5BE6B3D0-A4CA-493D-BA86-377105DD92BC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizLayer", "BizLayer\BizLayer.csproj", "{4538B585-62DE-45E5-A6DD-8BD48505075D}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{AF8764F7-FBEE-48AD-AF62-23010DA35D70}" - ProjectSection(SolutionItems) = preProject - Licence.txt = Licence.txt - README.md = README.md - EndProjectSection +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleWebApp", "SampleWebApp\SampleWebApp.csproj", "{FBD2F5CB-9E02-4E9B-B26D-8BB9E9DC4C63}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{6D9E7904-B2AC-49E3-83A7-6B48876F46B9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - AzureRelease|Any CPU = AzureRelease|Any CPU Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU - WebWizRelease|Any CPU = WebWizRelease|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CFFEE5E0-3B99-46E0-9A82-2E74621C17C5}.AzureRelease|Any CPU.ActiveCfg = AzureRelease|Any CPU - {CFFEE5E0-3B99-46E0-9A82-2E74621C17C5}.AzureRelease|Any CPU.Build.0 = AzureRelease|Any CPU - {CFFEE5E0-3B99-46E0-9A82-2E74621C17C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CFFEE5E0-3B99-46E0-9A82-2E74621C17C5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CFFEE5E0-3B99-46E0-9A82-2E74621C17C5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CFFEE5E0-3B99-46E0-9A82-2E74621C17C5}.Release|Any CPU.Build.0 = Release|Any CPU - {CFFEE5E0-3B99-46E0-9A82-2E74621C17C5}.WebWizRelease|Any CPU.ActiveCfg = WebWizRelease|Any CPU - {CFFEE5E0-3B99-46E0-9A82-2E74621C17C5}.WebWizRelease|Any CPU.Build.0 = WebWizRelease|Any CPU - {264E1878-12DE-4099-B8D7-CC53A73FEA49}.AzureRelease|Any CPU.ActiveCfg = AzureRelease|Any CPU - {264E1878-12DE-4099-B8D7-CC53A73FEA49}.AzureRelease|Any CPU.Build.0 = AzureRelease|Any CPU - {264E1878-12DE-4099-B8D7-CC53A73FEA49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {264E1878-12DE-4099-B8D7-CC53A73FEA49}.Debug|Any CPU.Build.0 = Debug|Any CPU - {264E1878-12DE-4099-B8D7-CC53A73FEA49}.Release|Any CPU.ActiveCfg = Release|Any CPU - {264E1878-12DE-4099-B8D7-CC53A73FEA49}.Release|Any CPU.Build.0 = Release|Any CPU - {264E1878-12DE-4099-B8D7-CC53A73FEA49}.WebWizRelease|Any CPU.ActiveCfg = WebWizRelease|Any CPU - {264E1878-12DE-4099-B8D7-CC53A73FEA49}.WebWizRelease|Any CPU.Build.0 = WebWizRelease|Any CPU - {D2813927-0F38-43C3-B47C-AE8F00D50CAE}.AzureRelease|Any CPU.ActiveCfg = AzureRelease|Any CPU - {D2813927-0F38-43C3-B47C-AE8F00D50CAE}.AzureRelease|Any CPU.Build.0 = AzureRelease|Any CPU - {D2813927-0F38-43C3-B47C-AE8F00D50CAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D2813927-0F38-43C3-B47C-AE8F00D50CAE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D2813927-0F38-43C3-B47C-AE8F00D50CAE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D2813927-0F38-43C3-B47C-AE8F00D50CAE}.Release|Any CPU.Build.0 = Release|Any CPU - {D2813927-0F38-43C3-B47C-AE8F00D50CAE}.WebWizRelease|Any CPU.ActiveCfg = WebWizRelease|Any CPU - {D2813927-0F38-43C3-B47C-AE8F00D50CAE}.WebWizRelease|Any CPU.Build.0 = WebWizRelease|Any CPU - {6D9E7904-B2AC-49E3-83A7-6B48876F46B9}.AzureRelease|Any CPU.ActiveCfg = AzureRelease|Any CPU - {6D9E7904-B2AC-49E3-83A7-6B48876F46B9}.AzureRelease|Any CPU.Build.0 = AzureRelease|Any CPU + {F3FEAB2B-8725-4E8B-83A2-E51C4EC66EF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3FEAB2B-8725-4E8B-83A2-E51C4EC66EF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3FEAB2B-8725-4E8B-83A2-E51C4EC66EF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3FEAB2B-8725-4E8B-83A2-E51C4EC66EF7}.Release|Any CPU.Build.0 = Release|Any CPU + {BC14D5B3-3FA5-48E4-9062-6D30929D72F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC14D5B3-3FA5-48E4-9062-6D30929D72F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC14D5B3-3FA5-48E4-9062-6D30929D72F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC14D5B3-3FA5-48E4-9062-6D30929D72F4}.Release|Any CPU.Build.0 = Release|Any CPU + {095E3125-1C36-49B2-98D2-D21ED7225FAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {095E3125-1C36-49B2-98D2-D21ED7225FAB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {095E3125-1C36-49B2-98D2-D21ED7225FAB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {095E3125-1C36-49B2-98D2-D21ED7225FAB}.Release|Any CPU.Build.0 = Release|Any CPU + {5BE6B3D0-A4CA-493D-BA86-377105DD92BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5BE6B3D0-A4CA-493D-BA86-377105DD92BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5BE6B3D0-A4CA-493D-BA86-377105DD92BC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5BE6B3D0-A4CA-493D-BA86-377105DD92BC}.Release|Any CPU.Build.0 = Release|Any CPU + {4538B585-62DE-45E5-A6DD-8BD48505075D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4538B585-62DE-45E5-A6DD-8BD48505075D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4538B585-62DE-45E5-A6DD-8BD48505075D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4538B585-62DE-45E5-A6DD-8BD48505075D}.Release|Any CPU.Build.0 = Release|Any CPU + {FBD2F5CB-9E02-4E9B-B26D-8BB9E9DC4C63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FBD2F5CB-9E02-4E9B-B26D-8BB9E9DC4C63}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBD2F5CB-9E02-4E9B-B26D-8BB9E9DC4C63}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FBD2F5CB-9E02-4E9B-B26D-8BB9E9DC4C63}.Release|Any CPU.Build.0 = Release|Any CPU {6D9E7904-B2AC-49E3-83A7-6B48876F46B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6D9E7904-B2AC-49E3-83A7-6B48876F46B9}.Debug|Any CPU.Build.0 = Debug|Any CPU {6D9E7904-B2AC-49E3-83A7-6B48876F46B9}.Release|Any CPU.ActiveCfg = Release|Any CPU {6D9E7904-B2AC-49E3-83A7-6B48876F46B9}.Release|Any CPU.Build.0 = Release|Any CPU - {6D9E7904-B2AC-49E3-83A7-6B48876F46B9}.WebWizRelease|Any CPU.ActiveCfg = WebWizRelease|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE EndGlobalSection EndGlobal diff --git a/SampleWebApp/App_Start/BundleConfig.cs b/SampleWebApp/App_Start/BundleConfig.cs deleted file mode 100644 index ab2ec9f..0000000 --- a/SampleWebApp/App_Start/BundleConfig.cs +++ /dev/null @@ -1,97 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: BundleConfig.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System.Web.Optimization; - -namespace SampleWebApp -{ - public class BundleConfig - { - // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 - public static void RegisterBundles(BundleCollection bundles) - { - - bundles.Add(new ScriptBundle("~/bundles/javascript").Include( - "~/Scripts/jquery-{version}.js", - "~/Scripts/bootstrap.js", - "~/Scripts/respond.js")); - - bundles.Add(new StyleBundle("~/Content/css").Include( - "~/Content/bootstrap.css", - //"~/Content/notify.css", - not used any more - "~/Content/site.css")); - - bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( - "~/Scripts/jquery.validate*")); - - //------------------------------------------------------------------ - //the bundles below were once used but not any more. Left as I might need them for the code that has been moved out to another library - - //Combined with bootstrap.js into one javascript bundle - //bundles.Add(new ScriptBundle("~/bundles/jquery").Include( - // "~/Scripts/jquery-{version}.js")); - // - //bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( - // "~/Scripts/bootstrap.js", - // "~/Scripts/respond.js")); - - //Not used anymore - //bundles.Add(new ScriptBundle("~/bundles/ActionRunner").Include( - // "~/Scripts/jquery-notify.js", - // "~/Scripts/jquery-ui-{version}.js", - // "~/Scripts/jquery.signalR-{version}.js", - // "~/Scripts/ActionRunnerComms.js", - // "~/Scripts/ActionRunnerUi.js")); - - //Not used - //// Use the development version of Modernizr to develop with and learn from. Then, when you're - //// ready for production, use the build tool at http://modernizr.com to pick only the tests you need. - //bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( - // "~/Scripts/modernizr-*")); - - //Not used any more - ////Commented out the parts that are not used from the jQuery UI - //bundles.Add(new StyleBundle("~/Content/themes/base/css").Include( - // "~/Content/themes/base/jquery.ui.core.css", - // "~/Content/themes/base/jquery.ui.resizable.css", - // "~/Content/themes/base/jquery.ui.selectable.css", - // //"~/Content/themes/base/jquery.ui.accordion.css", - // //"~/Content/themes/base/jquery.ui.autocomplete.css", - // //"~/Content/themes/base/jquery.ui.button.css", - // "~/Content/themes/base/jquery.ui.dialog.css", - // //"~/Content/themes/base/jquery.ui.slider.css", - // //"~/Content/themes/base/jquery.ui.tabs.css", - // //"~/Content/themes/base/jquery.ui.datepicker.css", - // "~/Content/themes/base/jquery.ui.progressbar.css", - // "~/Content/themes/base/jquery.ui.theme.css")); - - // Set EnableOptimizations to false for debugging. For more information, - // visit http://go.microsoft.com/fwlink/?LinkId=301862 - //BundleTable.EnableOptimizations = true; - } - } -} diff --git a/SampleWebApp/App_Start/FilterConfig.cs b/SampleWebApp/App_Start/FilterConfig.cs deleted file mode 100644 index 3325902..0000000 --- a/SampleWebApp/App_Start/FilterConfig.cs +++ /dev/null @@ -1,39 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: FilterConfig.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Web; -using System.Web.Mvc; - -namespace SampleWebApp -{ - public class FilterConfig - { - public static void RegisterGlobalFilters(GlobalFilterCollection filters) - { - filters.Add(new HandleErrorAttribute()); - } - } -} diff --git a/SampleWebApp/App_Start/RouteConfig.cs b/SampleWebApp/App_Start/RouteConfig.cs deleted file mode 100644 index 5666db8..0000000 --- a/SampleWebApp/App_Start/RouteConfig.cs +++ /dev/null @@ -1,49 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: RouteConfig.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; - -namespace SampleWebApp -{ - public class RouteConfig - { - public static void RegisterRoutes(RouteCollection routes) - { - routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); - - routes.MapRoute( - name: "Default", - url: "{controller}/{action}/{id}", - defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } - ); - } - } -} diff --git a/SampleWebApp/Controllers/BlogsController.cs b/SampleWebApp/Controllers/BlogsController.cs index 0027062..b62dae3 100644 --- a/SampleWebApp/Controllers/BlogsController.cs +++ b/SampleWebApp/Controllers/BlogsController.cs @@ -25,7 +25,7 @@ // SOFTWARE. #endregion using System.Linq; -using System.Web.Mvc; +using Microsoft.AspNetCore.Mvc; using DataLayer.DataClasses.Concrete; using GenericServices; using SampleWebApp.Infrastructure; diff --git a/SampleWebApp/Controllers/HomeController.cs b/SampleWebApp/Controllers/HomeController.cs index bfef31c..ee76b1c 100644 --- a/SampleWebApp/Controllers/HomeController.cs +++ b/SampleWebApp/Controllers/HomeController.cs @@ -24,7 +24,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #endregion -using System.Web.Mvc; +using Microsoft.AspNetCore.Mvc; using SampleWebApp.Models; namespace SampleWebApp.Controllers @@ -36,6 +36,11 @@ public ActionResult Index() return View(); } + public ActionResult Error() + { + return View(); + } + public ActionResult About() { ViewBag.Message = "Your application description page."; diff --git a/SampleWebApp/Controllers/PostsAsyncController.cs b/SampleWebApp/Controllers/PostsAsyncController.cs index 22e914f..3f3c76f 100644 --- a/SampleWebApp/Controllers/PostsAsyncController.cs +++ b/SampleWebApp/Controllers/PostsAsyncController.cs @@ -25,10 +25,10 @@ // SOFTWARE. #endregion using System.Collections.Generic; -using System.Data.Entity; +using Microsoft.EntityFrameworkCore; using System.Linq; using System.Threading.Tasks; -using System.Web.Mvc; +using Microsoft.AspNetCore.Mvc; using DataLayer.DataClasses; using DataLayer.DataClasses.Concrete; using DataLayer.Startup; @@ -114,7 +114,7 @@ public async Task Delete(int id, IDeleteServiceAsync service) TempData["message"] = response.SuccessMessage; else //else errors, so send back an error message - TempData["errorMessage"] = new MvcHtmlString(response.ErrorsAsHtml()); + TempData["errorMessage"] = response.ErrorsAsHtml(); return RedirectToAction("Index"); } diff --git a/SampleWebApp/Controllers/PostsController.cs b/SampleWebApp/Controllers/PostsController.cs index d5cd076..d51d4eb 100644 --- a/SampleWebApp/Controllers/PostsController.cs +++ b/SampleWebApp/Controllers/PostsController.cs @@ -26,7 +26,7 @@ #endregion using System.Linq; using System.Threading; -using System.Web.Mvc; +using Microsoft.AspNetCore.Mvc; using DataLayer.DataClasses; using DataLayer.DataClasses.Concrete; using DataLayer.Startup; @@ -123,7 +123,7 @@ public ActionResult Delete(int id, IDeleteService service) TempData["message"] = response.SuccessMessage; else //else errors, so send back an error message - TempData["errorMessage"] = new MvcHtmlString(response.ErrorsAsHtml()); + TempData["errorMessage"] = response.ErrorsAsHtml(); return RedirectToAction("Index"); } diff --git a/SampleWebApp/Controllers/TagsAsyncController.cs b/SampleWebApp/Controllers/TagsAsyncController.cs index 6d9e9b9..c8d85dc 100644 --- a/SampleWebApp/Controllers/TagsAsyncController.cs +++ b/SampleWebApp/Controllers/TagsAsyncController.cs @@ -24,9 +24,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #endregion -using System.Data.Entity; +using Microsoft.EntityFrameworkCore; using System.Threading.Tasks; -using System.Web.Mvc; +using Microsoft.AspNetCore.Mvc; using DataLayer.DataClasses.Concrete; using GenericServices; using SampleWebApp.Infrastructure; @@ -110,7 +110,7 @@ public async Task Delete(int id, IDeleteServiceAsync service) TempData["message"] = response.SuccessMessage; else //else errors, so send back an error message - TempData["errorMessage"] = new MvcHtmlString(response.ErrorsAsHtml()); + TempData["errorMessage"] = response.ErrorsAsHtml(); return RedirectToAction("Index"); } diff --git a/SampleWebApp/Controllers/TagsController.cs b/SampleWebApp/Controllers/TagsController.cs index a729d08..236ec69 100644 --- a/SampleWebApp/Controllers/TagsController.cs +++ b/SampleWebApp/Controllers/TagsController.cs @@ -25,7 +25,7 @@ // SOFTWARE. #endregion using System.Linq; -using System.Web.Mvc; +using Microsoft.AspNetCore.Mvc; using DataLayer.DataClasses.Concrete; using GenericServices; using SampleWebApp.Infrastructure; @@ -108,7 +108,7 @@ public ActionResult Delete(int id, IDeleteService service) TempData["message"] = response.SuccessMessage; else //else errors, so send back an error message - TempData["errorMessage"] = new MvcHtmlString(response.ErrorsAsHtml()); + TempData["errorMessage"] = response.ErrorsAsHtml(); return RedirectToAction("Index"); } diff --git a/SampleWebApp/Global.asax b/SampleWebApp/Global.asax deleted file mode 100644 index c209429..0000000 --- a/SampleWebApp/Global.asax +++ /dev/null @@ -1 +0,0 @@ -<%@ Application Codebehind="Global.asax.cs" Inherits="SampleWebApp.MvcApplication" Language="C#" %> diff --git a/SampleWebApp/Global.asax.cs b/SampleWebApp/Global.asax.cs deleted file mode 100644 index 610d5ce..0000000 --- a/SampleWebApp/Global.asax.cs +++ /dev/null @@ -1,51 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: Global.asax.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Web.Mvc; -using System.Web.Optimization; -using System.Web.Routing; -using SampleWebApp.Infrastructure; - -namespace SampleWebApp -{ - public class MvcApplication : System.Web.HttpApplication - { - protected void Application_Start() - { - AreaRegistration.RegisterAllAreas(); - FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); - RouteConfig.RegisterRoutes(RouteTable.Routes); - BundleConfig.RegisterBundles(BundleTable.Bundles); - - //This allows interfaces etc to be provided as parameters to action methods - ModelBinders.Binders.DefaultBinder = new DiModelBinder(); - - //Now call the method to initialise anything that is required before startup (which includes setting up DI) - WebUiInitialise.InitialiseThis(this); - - } - } -} diff --git a/SampleWebApp/Infrastructure/AutofacDi.cs b/SampleWebApp/Infrastructure/AutofacDi.cs deleted file mode 100644 index b2645e7..0000000 --- a/SampleWebApp/Infrastructure/AutofacDi.cs +++ /dev/null @@ -1,57 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: AutofacDi.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Runtime.CompilerServices; -using Autofac; -using ServiceLayer.Startup; - -[assembly: InternalsVisibleTo("Tests")] - -namespace SampleWebApp.Infrastructure -{ - internal static class AutofacDi - { - - private static IContainer _container; - - internal static IContainer SetupDependency() - { - - var builder = new ContainerBuilder(); - Load(builder); - - _container = builder.Build(); - - return _container; - } - - private static void Load(ContainerBuilder builder) - { - //register the service layer, which then registers all other dependencies in the rest of the system - builder.RegisterModule(new ServiceLayerModule()); - } - } -} \ No newline at end of file diff --git a/SampleWebApp/Infrastructure/DiModelBinder.cs b/SampleWebApp/Infrastructure/DiModelBinder.cs deleted file mode 100644 index e8115ba..0000000 --- a/SampleWebApp/Infrastructure/DiModelBinder.cs +++ /dev/null @@ -1,41 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: DiModelBinder.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.Web.Mvc; - -namespace SampleWebApp.Infrastructure -{ - public class DiModelBinder : DefaultModelBinder - { - protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) - { - return modelType.IsInterface - ? DependencyResolver.Current.GetService(modelType) - : base.CreateModel(controllerContext, bindingContext, modelType); - } - } -} \ No newline at end of file diff --git a/SampleWebApp/Infrastructure/JsonNetResult.cs b/SampleWebApp/Infrastructure/JsonNetResult.cs deleted file mode 100644 index f429bba..0000000 --- a/SampleWebApp/Infrastructure/JsonNetResult.cs +++ /dev/null @@ -1,75 +0,0 @@ -#region License -// Copyright (c) 2007 James Newton-King -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -#endregion - -using System; -using System.Text; -using System.Web; -using System.Web.Mvc; -using Newtonsoft.Json; - -//see blog http://james.newtonking.com/archive/2008/10/16/asp-net-mvc-and-json-net.aspx - -namespace SampleWebApp.Infrastructure -{ - public class JsonNetResult : ActionResult - { - public Encoding ContentEncoding { get; set; } - public string ContentType { get; set; } - public object Data { get; set; } - - public JsonSerializerSettings SerializerSettings { get; set; } - public Formatting Formatting { get; set; } - - public JsonNetResult() - { - SerializerSettings = new JsonSerializerSettings(); - } - - public override void ExecuteResult(ControllerContext context) - { - if (context == null) - throw new ArgumentNullException("context"); - - HttpResponseBase response = context.HttpContext.Response; - - response.ContentType = !string.IsNullOrEmpty(ContentType) - ? ContentType - : "application/json"; - - if (ContentEncoding != null) - response.ContentEncoding = ContentEncoding; - - if (Data != null) - { - JsonTextWriter writer = new JsonTextWriter(response.Output) { Formatting = Formatting }; - - JsonSerializer serializer = JsonSerializer.Create(SerializerSettings); - serializer.Serialize(writer, Data); - - writer.Flush(); - } - } - } -} \ No newline at end of file diff --git a/SampleWebApp/Infrastructure/Log4NetGenericLogger.cs b/SampleWebApp/Infrastructure/Log4NetGenericLogger.cs deleted file mode 100644 index 7b71457..0000000 --- a/SampleWebApp/Infrastructure/Log4NetGenericLogger.cs +++ /dev/null @@ -1,99 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: Log4NetGenericLogger.cs -// Date Created: 2014/07/03 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using GenericLibsBase; - -namespace SampleWebApp.Infrastructure -{ - - public class Log4NetGenericLogger : IGenericLogger - { - - private readonly log4net.ILog _logger; - - public Log4NetGenericLogger(string name) - { - _logger = log4net.LogManager.GetLogger(name); - } - - public void Verbose(object message) - { - _logger.Debug(message); - } - - public void VerboseFormat(string format, params object[] args) - { - _logger.DebugFormat(format, args); - } - - public void Info(object message) - { - _logger.Info(message); - } - - public void InfoFormat(string format, params object[] args) - { - _logger.InfoFormat(format, args); - } - - public void Warn(object message) - { - _logger.Warn(message); - } - - public void WarnFormat(string format, params object[] args) - { - _logger.WarnFormat(format, args); - } - - public void Error(object message) - { - _logger.Error(message); - } - - public void ErrorFormat(string format, params object[] args) - { - _logger.ErrorFormat(format, args); - } - - public void Critical(object message) - { - _logger.Fatal(message); - } - - public void Critical(object message, Exception ex) - { - _logger.Fatal(message, ex); - } - - public void CriticalFormat(string format, params object[] args) - { - _logger.FatalFormat(format, args); - } - - } -} diff --git a/SampleWebApp/Infrastructure/MelGenericLogger.cs b/SampleWebApp/Infrastructure/MelGenericLogger.cs new file mode 100644 index 0000000..25e3f89 --- /dev/null +++ b/SampleWebApp/Infrastructure/MelGenericLogger.cs @@ -0,0 +1,36 @@ +using System; +using GenericLibsBase; +using Microsoft.Extensions.Logging; + +namespace SampleWebApp.Infrastructure +{ + /// + /// Bridges the GenericServices abstraction onto + /// Microsoft.Extensions.Logging, replacing the original log4net logger. + /// + public class MelGenericLogger : IGenericLogger + { + private readonly ILogger _logger; + + public MelGenericLogger(ILogger logger) + { + _logger = logger; + } + + public void Verbose(object message) => _logger.LogDebug("{Message}", message); + public void VerboseFormat(string format, params object[] args) => _logger.LogDebug(format, args); + + public void Info(object message) => _logger.LogInformation("{Message}", message); + public void InfoFormat(string format, params object[] args) => _logger.LogInformation(format, args); + + public void Warn(object message) => _logger.LogWarning("{Message}", message); + public void WarnFormat(string format, params object[] args) => _logger.LogWarning(format, args); + + public void Error(object message) => _logger.LogError("{Message}", message); + public void ErrorFormat(string format, params object[] args) => _logger.LogError(format, args); + + public void Critical(object message) => _logger.LogCritical("{Message}", message); + public void Critical(object message, Exception ex) => _logger.LogCritical(ex, "{Message}", message); + public void CriticalFormat(string format, params object[] args) => _logger.LogCritical(format, args); + } +} diff --git a/SampleWebApp/Infrastructure/ServiceParameterBindingConvention.cs b/SampleWebApp/Infrastructure/ServiceParameterBindingConvention.cs new file mode 100644 index 0000000..b524c45 --- /dev/null +++ b/SampleWebApp/Infrastructure/ServiceParameterBindingConvention.cs @@ -0,0 +1,58 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ApplicationModels; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace SampleWebApp.Infrastructure +{ + /// + /// The original MVC5 app used a custom model binder (DiModelBinder) so that services could be + /// supplied as action-method parameters, e.g. Index(IListService service). ASP.NET Core + /// does not bind such parameters from DI by default, so this convention marks any action + /// parameter whose type is a registered service as , + /// preserving the original controller signatures. + /// + public class ServiceParameterBindingConvention : IActionModelConvention + { + private readonly IServiceProviderIsService _isService; + + public ServiceParameterBindingConvention(IServiceProviderIsService isService) + { + _isService = isService; + } + + public void Apply(ActionModel action) + { + foreach (var parameter in action.Parameters) + { + if (parameter.BindingInfo?.BindingSource != null) + continue; + + if (_isService.IsService(parameter.ParameterInfo.ParameterType)) + { + parameter.BindingInfo ??= new BindingInfo(); + parameter.BindingInfo.BindingSource = BindingSource.Services; + } + } + } + } + + /// + /// Registers once the DI container is available. + /// + public class ConfigureServiceParameterBinding : IConfigureOptions + { + private readonly IServiceProviderIsService _isService; + + public ConfigureServiceParameterBinding(IServiceProviderIsService isService) + { + _isService = isService; + } + + public void Configure(MvcOptions options) + { + options.Conventions.Add(new ServiceParameterBindingConvention(_isService)); + } + } +} diff --git a/SampleWebApp/Infrastructure/TraceGenericLogger.cs b/SampleWebApp/Infrastructure/TraceGenericLogger.cs deleted file mode 100644 index 31584ad..0000000 --- a/SampleWebApp/Infrastructure/TraceGenericLogger.cs +++ /dev/null @@ -1,107 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: TraceGenericLogger.cs -// Date Created: 2014/07/07 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.Diagnostics; -using GenericLibsBase; - -namespace SampleWebApp.Infrastructure -{ - - public class TraceGenericLogger : IGenericLogger - { - - private readonly string _loggerName; - - /// - /// Controls whether Verbose is written to Trace. - /// Defaults to excluding Verbose messages - /// - public bool IncludeVerbose { get; set; } - - public TraceGenericLogger(string name) - { - _loggerName = name; - } - - public void Verbose(object message) - { - if (IncludeVerbose) - Trace.TraceInformation("{0}: {1}", _loggerName, message); - } - - public void VerboseFormat(string format, params object[] args) - { - Verbose(string.Format(format, args)); - } - - public void Info(object message) - { - Trace.TraceInformation("{0}: {1}", _loggerName, message); - } - - public void InfoFormat(string format, params object[] args) - { - Info(string.Format(format, args)); - } - - public void Warn(object message) - { - Trace.TraceWarning("{0}: {1}", _loggerName, message); - } - - public void WarnFormat(string format, params object[] args) - { - Warn(string.Format(format, args)); - } - - public void Error(object message) - { - Trace.TraceError("{0}: {1}", _loggerName, message); - } - - public void ErrorFormat(string format, params object[] args) - { - Error(string.Format(format, args)); - } - - public void Critical(object message) - { - Trace.TraceError("{0}: {1}", _loggerName, message); - } - - public void Critical(object message, Exception ex) - { - Trace.TraceError("{0}, expection {1}: {2}\n{3}", _loggerName, ex.GetType().Name, message, ex.StackTrace); - } - - public void CriticalFormat(string format, params object[] args) - { - Critical(string.Format(format, args)); - } - - } -} diff --git a/SampleWebApp/Infrastructure/ValidationHelper.cs b/SampleWebApp/Infrastructure/ValidationHelper.cs index ab6bf7d..d5981f2 100644 --- a/SampleWebApp/Infrastructure/ValidationHelper.cs +++ b/SampleWebApp/Infrastructure/ValidationHelper.cs @@ -1,36 +1,8 @@ -#region licence -// The MIT License (MIT) -// -// Filename: ValidationHelper.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Web.Mvc; -using GenericLibsBase; -using GenericServices; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using GenericLibsBase.Core; namespace SampleWebApp.Infrastructure { @@ -39,13 +11,13 @@ public static class ValidationHelper /// /// This transfers error messages from the DtoValidation methods to the MVC modelState error dictionary. /// It looks for errors that have member names corresponding to the properties in the displayDto. - /// This means that errors assciated with a field on display will show next to the name. + /// This means that errors associated with a field on display will show next to the name. /// Other errors will be shown in the ValidationSummary /// /// The interface that holds the errors /// The MVC modelState to add errors to /// This is the Dto that will be used to display the error messages - public static void CopyErrorsToModelState(this ISuccessOrErrors errorHolder, ModelStateDictionary modelState, T displayDto) + public static void CopyErrorsToModelState(this ISuccessOrErrors errorHolder, ModelStateDictionary modelState, T displayDto) { if (errorHolder.IsValid) return; @@ -65,72 +37,15 @@ public static void CopyErrorsToModelState(this ISuccessOrErrors errorHolder, /// /// This copies errors for general display where we are not returning to a page with the fields on them /// - /// - /// public static void CopyErrorsToModelState(this ISuccessOrErrors errorHolder, ModelStateDictionary modelState) { if (errorHolder.IsValid) return; foreach (var error in errorHolder.Errors) - modelState.AddModelError("", error.ErrorMessage); - } - - - /// - /// This returns the ModelState errors as a json array containing objects with the PropertyName and the first error message. - /// Must only be called if there are model errors. - /// - /// - /// It returns a JsonNetResult with one parameter called errors which contains key value pairs. - /// The key is the name of the property which had the error, or is empty string if global error. - /// The value is an array of error strings for that property key - public static JsonResult ReturnModelErrorsAsJson(this ModelStateDictionary modelState) - { - if (modelState.IsValid) - throw new ArgumentException("You should only call this if there are model errors to return."); - - var dict = new Dictionary(); - var emptyNameErrors = new List(); - foreach (var propertyError in modelState.Where(x => x.Value.Errors.Any())) - { - if (string.IsNullOrEmpty(propertyError.Key)) - //The modelState doesn't seem to combine empty named items so we do it for it - emptyNameErrors.AddRange(propertyError.Value.Errors.Select(x => x.ErrorMessage)); - else - dict[propertyError.Key] = new { errors = propertyError.Value.Errors.Select(x => x.ErrorMessage) }; - } - - if (emptyNameErrors.Any()) - dict[string.Empty] = new { errors = emptyNameErrors }; - - var result = new JsonResult { Data = new { errorsDict = dict } }; - - return result; - } - - /// - /// This returns and errorsDict with any errors in ISuccessOrErrors transferred - /// It looks for errors that have member names corresponding to the properties in the displayDto. - /// This means that errors assciated with a field on display will show next to the name. - /// Other errors will be shown in the ValidationSummary - /// Should only be called if there is an error - /// - /// The interface that holds the errors - /// Dto that the error messages came from - /// It returns a JsonNetResult with one parameter called errors which contains key value pairs. - /// The key is the name of the property which had the error, or is empty string if global error. - /// The value is an array of error strings for that property key - public static JsonResult ReturnErrorsAsJson(this ISuccessOrErrors errorHolder, T displayDto) - { - if (errorHolder.IsValid) - throw new ArgumentException("You should only call ReturnErrorsAsJson when there are errors in the status", "errorHolder"); - - var modelState = new ModelStateDictionary(); - errorHolder.CopyErrorsToModelState(modelState, displayDto); - return modelState.ReturnModelErrorsAsJson(); + modelState.AddModelError("", error.ErrorMessage); } - private static IList PropertyNamesInDto ( T objectToCheck) + private static IList PropertyNamesInDto(T objectToCheck) { return objectToCheck.GetType() @@ -138,6 +53,5 @@ private static IList PropertyNamesInDto ( T objectToCheck) .Select(x => x.Name) .ToList(); } - } -} \ No newline at end of file +} diff --git a/SampleWebApp/Infrastructure/WebUiInitialise.cs b/SampleWebApp/Infrastructure/WebUiInitialise.cs index 2bb8154..1b927a4 100644 --- a/SampleWebApp/Infrastructure/WebUiInitialise.cs +++ b/SampleWebApp/Infrastructure/WebUiInitialise.cs @@ -1,110 +1,41 @@ -#region licence -// The MIT License (MIT) -// -// Filename: WebUiInitialise.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion using System; -using System.Web; -using System.Web.Mvc; -using Autofac.Integration.Mvc; using GenericLibsBase; -using SampleWebApp.Properties; -using ServiceLayer.Startup; +using Microsoft.Extensions.Logging; namespace SampleWebApp.Infrastructure { public enum HostTypes { NotSet, LocalHost, WebWiz, Azure }; + /// + /// Holds the host type shown in the UI and wires the GenericServices logger + /// abstraction onto Microsoft.Extensions.Logging. + /// public static class WebUiInitialise { - private const bool ResetIndentityDatabase = false; //set this to true to reset content of Identity database - - //Note: This is also used when running locally - private const string WebWizLog4NetRelPath = "~/Log4Net.xml"; - public const string DatabaseConnectionStringName = "SampleWebAppDb"; /// - /// This provides the host we + /// The host the app believes it is running on (shown in the page footer). /// public static HostTypes HostType { get; private set; } /// - /// This should be called at Startup + /// Called at startup. Decodes the configured host type and routes the + /// GenericServices logger through the supplied logger factory. /// - public static void InitialiseThis(HttpApplication application) + public static void InitialiseThis(string hostTypeString, ILoggerFactory loggerFactory) { - HostType = DecodeHostType(Settings.Default.HostTypeString); - //WebWiz does not allow drop/create database - var canDropCreateDatabase = HostType != HostTypes.WebWiz; - - SetupLogging(application, HostType); - - //This runs the ServiceLayer initialise, whoes job it is to initialise any of the lower layers - //NOTE: This MUST to come before the setup of the DI because it relies on the configInfo being set up - ServiceLayerInitialise.InitialiseThis(HostType == HostTypes.Azure, canDropCreateDatabase); - - //This sets up the Autofac container for all levels in the program - var container = AutofacDi.SetupDependency(); + HostType = DecodeHostType(hostTypeString); - //// Set the dependency resolver for MVC. - var mvcResolver = new AutofacDependencyResolver(container); - DependencyResolver.SetResolver(mvcResolver); + GenericLibsBaseConfig.SetLoggerMethod = name => new MelGenericLogger(loggerFactory.CreateLogger(name)); + GenericLibsBaseConfig.GetLogger("LoggerSetup").Info("We have just assigned a logger."); } private static HostTypes DecodeHostType(string hostTypeString) { - HostTypes hostType ; + HostTypes hostType; Enum.TryParse(hostTypeString, true, out hostType); return hostType; } - - private static void SetupLogging(HttpApplication application, HostTypes hostType) - { - - switch (hostType) - { - case HostTypes.NotSet: - //we do not set up the logging - break; - case HostTypes.LocalHost: - //LocalHost uses WebWiz setup for log4Net - case HostTypes.WebWiz: - //We set up the log4net settings from a local file and then assign the logger to GenericServices.GenericLoggerFactory - var log4NetPath = application.Server.MapPath(WebWizLog4NetRelPath); - log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(log4NetPath)); - GenericLibsBaseConfig.SetLoggerMethod = name => new Log4NetGenericLogger(name); - break; - case HostTypes.Azure: - //we use the TraceGenericLogger when in Azure - GenericLibsBaseConfig.SetLoggerMethod = name => new TraceGenericLogger(name); - break; - default: - throw new ArgumentOutOfRangeException("hostType"); - } - - GenericLibsBaseConfig.GetLogger("LoggerSetup").Info("We have just assegned a logger."); - } } -} \ No newline at end of file +} diff --git a/SampleWebApp/Log4Net.xml b/SampleWebApp/Log4Net.xml deleted file mode 100644 index 6feb4c4..0000000 --- a/SampleWebApp/Log4Net.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SampleWebApp/Models/InternalsInfo.cs b/SampleWebApp/Models/InternalsInfo.cs index f9df44e..d9e866c 100644 --- a/SampleWebApp/Models/InternalsInfo.cs +++ b/SampleWebApp/Models/InternalsInfo.cs @@ -53,7 +53,9 @@ public InternalsInfo() WorkerThreads = workerThreads; AvailableThreads = availableThreads; - AvailableMbytes = (int)new PerformanceCounter("Memory", "Available MBytes", true).RawValue; + //PerformanceCounter is Windows-only; use the cross-platform GC memory info instead + var gcInfo = GC.GetGCMemoryInfo(); + AvailableMbytes = (int)(gcInfo.TotalAvailableMemoryBytes / (1024 * 1024)); HeapMemoryUsedKbytes = (int)(GC.GetTotalMemory(true)/1000); } diff --git a/SampleWebApp/Program.cs b/SampleWebApp/Program.cs new file mode 100644 index 0000000..0e5d9e1 --- /dev/null +++ b/SampleWebApp/Program.cs @@ -0,0 +1,59 @@ +using DataLayer.DataClasses; +using DataLayer.Startup; +using GenericServices; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using SampleWebApp.Infrastructure; +using ServiceLayer.PostServices; +using ServiceLayer.Startup; + +var builder = WebApplication.CreateBuilder(args); + +var connectionString = builder.Configuration.GetConnectionString(WebUiInitialise.DatabaseConnectionStringName) + ?? "Data Source=SampleWebAppDb.db"; + +// EF Core context (replaces EF6 + web.config connection string) +builder.Services.AddDbContext(options => options.UseSqlite(connectionString)); +builder.Services.AddScoped(sp => sp.GetRequiredService()); + +// GenericServices compatibility layer + AutoMapper (replaces Autofac registrations) +builder.Services.AddGenericServices(typeof(SimplePostDto).Assembly); + +builder.Services.AddControllersWithViews(); + +// Preserve the MVC5 pattern of supplying services as action-method parameters +builder.Services.AddSingleton, ConfigureServiceParameterBinding>(); + +var app = builder.Build(); + +// Route the GenericServices logger through Microsoft.Extensions.Logging (replaces log4net) +var hostTypeString = app.Configuration["HostTypeString"] ?? nameof(HostTypes.LocalHost); +WebUiInitialise.InitialiseThis(hostTypeString, app.Services.GetRequiredService()); + +// Initialise / migrate / seed the database (replaces the EF6 database initializer) +using (var scope = app.Services.CreateScope()) +{ + var context = scope.ServiceProvider.GetRequiredService(); + ServiceLayerInitialise.InitialiseThis(context, canCreateDatabase: true); +} + +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Home/Error"); +} + +app.UseStaticFiles(); + +app.UseRouting(); + +app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + +app.Run(); diff --git a/SampleWebApp/Project_Readme.html b/SampleWebApp/Project_Readme.html deleted file mode 100644 index cb9e793..0000000 --- a/SampleWebApp/Project_Readme.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - - Your ASP.NET application - - - - - - -
    -
    -

    This application consists of:

    -
      -
    • Sample pages showing basic nav between Home, About, and Contact
    • -
    • Theming using Bootstrap
    • -
    • Authentication, if selected, shows how to register and sign in
    • -
    • ASP.NET features managed using NuGet
    • -
    -
    - - - - - -
    -

    Get help

    - -
    -
    - - - \ No newline at end of file diff --git a/SampleWebApp/Properties/AssemblyInfo.cs b/SampleWebApp/Properties/AssemblyInfo.cs deleted file mode 100644 index 5605e92..0000000 --- a/SampleWebApp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,61 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: AssemblyInfo.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("SampleWebApp")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SampleWebApp")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[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("fa016029-8cb0-4ef3-a0e0-c94ac71c1177")] - -// 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 Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SampleWebApp/Properties/Settings.Designer.cs b/SampleWebApp/Properties/Settings.Designer.cs deleted file mode 100644 index 3781ad7..0000000 --- a/SampleWebApp/Properties/Settings.Designer.cs +++ /dev/null @@ -1,44 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18444 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace SampleWebApp.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.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; - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("LocalHost")] - public string HostTypeString { - get { - return ((string)(this["HostTypeString"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("jonsmith_")] - public string DatabaseLoginPrefix { - get { - return ((string)(this["DatabaseLoginPrefix"])); - } - } - } -} diff --git a/SampleWebApp/Properties/Settings.settings b/SampleWebApp/Properties/Settings.settings deleted file mode 100644 index cd30221..0000000 --- a/SampleWebApp/Properties/Settings.settings +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - LocalHost - - - jonsmith_ - - - \ No newline at end of file diff --git a/SampleWebApp/SampleWebApp.csproj b/SampleWebApp/SampleWebApp.csproj index eca4d77..f09cf7d 100644 --- a/SampleWebApp/SampleWebApp.csproj +++ b/SampleWebApp/SampleWebApp.csproj @@ -1,485 +1,19 @@ - - - + + - Debug - AnyCPU - - - 2.0 - {CFFEE5E0-3B99-46E0-9A82-2E74621C17C5} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties + net8.0 + disable + disable SampleWebApp SampleWebApp - v4.5.1 - false - true - - - - - - - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\ - TRACE - prompt - 4 - - - - False - ..\packages\Autofac.3.5.0\lib\net40\Autofac.dll - - - False - ..\packages\Autofac.Mvc5.3.3.1\lib\net45\Autofac.Integration.Mvc.dll - - - ..\packages\AutoMapper.4.2.1\lib\net45\AutoMapper.dll - True - - - ..\packages\DelegateDecompiler.0.18.0\lib\net40-Client\DelegateDecompiler.dll - True - - - ..\packages\DelegateDecompiler.EntityFramework.0.18.0\lib\net45\DelegateDecompiler.EntityFramework.dll - True - - - ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll - True - - - ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll - True - - - ..\packages\GenericLibsBase.1.0.1\lib\GenericLibsBase.dll - True - - - ..\packages\GenericServices.1.0.9\lib\GenericServices.dll - True - - - ..\packages\log4net.2.0.3\lib\net40-full\log4net.dll - - - False - ..\packages\Microsoft.AspNet.Identity.Core.2.1.0\lib\net45\Microsoft.AspNet.Identity.Core.dll - - - False - ..\packages\Microsoft.AspNet.Identity.EntityFramework.2.1.0\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll - - - False - ..\packages\Microsoft.AspNet.Identity.Owin.2.1.0\lib\net45\Microsoft.AspNet.Identity.Owin.dll - - - ..\packages\Microsoft.AspNet.SignalR.Core.2.0.3\lib\net45\Microsoft.AspNet.SignalR.Core.dll - - - ..\packages\Microsoft.AspNet.SignalR.SystemWeb.2.0.3\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll - True - - - - False - ..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll - - - False - ..\packages\Microsoft.Owin.Security.3.0.0\lib\net45\Microsoft.Owin.Security.dll - - - False - ..\packages\Microsoft.Owin.Security.Cookies.3.0.0\lib\net45\Microsoft.Owin.Security.Cookies.dll - - - False - ..\packages\Microsoft.Owin.Security.Facebook.3.0.0\lib\net45\Microsoft.Owin.Security.Facebook.dll - - - False - ..\packages\Microsoft.Owin.Security.Google.3.0.0\lib\net45\Microsoft.Owin.Security.Google.dll - - - False - ..\packages\Microsoft.Owin.Security.MicrosoftAccount.3.0.0\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll - - - False - ..\packages\Microsoft.Owin.Security.OAuth.3.0.0\lib\net45\Microsoft.Owin.Security.OAuth.dll - - - ..\packages\Mono.Reflection.1.0.0.0\lib\Mono.Reflection.dll - - - False - ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - False - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - - - False - ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - - - False - ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - - - False - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - - - False - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - - - True - ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - - ..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll - - - True - ..\packages\WebGrease.1.5.2\lib\WebGrease.dll - - - True - ..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll - - - - - ..\packages\Owin.1.0\lib\net40\Owin.dll - - - ..\packages\Microsoft.Owin.Host.SystemWeb.2.1.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll - - - ..\packages\Microsoft.Owin.Security.Twitter.2.1.0\lib\net45\Microsoft.Owin.Security.Twitter.dll - - - - - - - - - - - - - - Global.asax - - - - - - - - - - - True - True - Settings.settings - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - - - - - - - - - - - - - - - - - - - Designer - - - Web.config - - - Web.config - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Web.config - - - Web.config - - + - - + + + + + - - - - - - - {264e1878-12de-4099-b8d7-cc53a73fea49} - DataLayer - - - {d2813927-0f38-43c3-b47c-ae8f00d50cae} - ServiceLayer - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - bin\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - bin\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - bin\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - True - True - 50623 - / - http://localhost:50623/ - False - False - - - False - - - - - - \ No newline at end of file + + diff --git a/SampleWebApp/Views/Blogs/Index.cshtml b/SampleWebApp/Views/Blogs/Index.cshtml index 98bb41d..e334799 100644 --- a/SampleWebApp/Views/Blogs/Index.cshtml +++ b/SampleWebApp/Views/Blogs/Index.cshtml @@ -9,7 +9,7 @@ } @if (TempData["errorMessage"] != null) { -
    @TempData["errorMessage"]
    +
    @Html.Raw(TempData["errorMessage"])
    }

    diff --git a/SampleWebApp/Views/Posts/Create.cshtml b/SampleWebApp/Views/Posts/Create.cshtml index ca33689..d847642 100644 --- a/SampleWebApp/Views/Posts/Create.cshtml +++ b/SampleWebApp/Views/Posts/Create.cshtml @@ -39,7 +39,7 @@

    - @Html.Label("Tags", htmlAttributes: new { @class = "control-label col-md-2" }) + @Html.Label("Tags", "Tags", htmlAttributes: new { @class = "control-label col-md-2" })
    @Html.EditorFor(model => model.UserChosenTags, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.UserChosenTags, "", new { @class = "text-danger" }) @@ -57,8 +57,9 @@ @Html.ActionLink("Back to List", "Index")

    -@Html.Partial("PostValidation") + @section Scripts { - @Scripts.Render("~/bundles/jqueryval") + + } diff --git a/SampleWebApp/Views/Posts/Edit.cshtml b/SampleWebApp/Views/Posts/Edit.cshtml index 49d666f..6f2d0eb 100644 --- a/SampleWebApp/Views/Posts/Edit.cshtml +++ b/SampleWebApp/Views/Posts/Edit.cshtml @@ -42,7 +42,7 @@
    - @Html.Label("Tags", htmlAttributes: new { @class = "control-label col-md-2" }) + @Html.Label("Tags", "Tags", htmlAttributes: new { @class = "control-label col-md-2" })
    @Html.EditorFor(model => model.UserChosenTags, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.UserChosenTags, "", new { @class = "text-danger" }) @@ -61,9 +61,10 @@ @Html.ActionLink("Back to List", "Index")

    -@Html.Partial("PostValidation") + @section Scripts { - @Scripts.Render("~/bundles/jqueryval") + + } diff --git a/SampleWebApp/Views/Posts/Index.cshtml b/SampleWebApp/Views/Posts/Index.cshtml index 197b2f6..e4c389d 100644 --- a/SampleWebApp/Views/Posts/Index.cshtml +++ b/SampleWebApp/Views/Posts/Index.cshtml @@ -12,7 +12,7 @@ } @if (TempData["errorMessage"] != null) { -
    @TempData["errorMessage"]
    +
    @Html.Raw(TempData["errorMessage"])
    }

    diff --git a/SampleWebApp/Views/PostsAsync/Create.cshtml b/SampleWebApp/Views/PostsAsync/Create.cshtml index d22f305..0ae1039 100644 --- a/SampleWebApp/Views/PostsAsync/Create.cshtml +++ b/SampleWebApp/Views/PostsAsync/Create.cshtml @@ -39,7 +39,7 @@

    - @Html.Label("Tags", htmlAttributes: new { @class = "control-label col-md-2" }) + @Html.Label("Tags", "Tags", htmlAttributes: new { @class = "control-label col-md-2" })
    @Html.EditorFor(model => model.UserChosenTags, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.UserChosenTags, "", new { @class = "text-danger" }) @@ -57,8 +57,9 @@ @Html.ActionLink("Back to List", "Index")

    -@Html.Partial("PostValidation") + @section Scripts { - @Scripts.Render("~/bundles/jqueryval") + + } diff --git a/SampleWebApp/Views/PostsAsync/Edit.cshtml b/SampleWebApp/Views/PostsAsync/Edit.cshtml index 75b1706..09ec61c 100644 --- a/SampleWebApp/Views/PostsAsync/Edit.cshtml +++ b/SampleWebApp/Views/PostsAsync/Edit.cshtml @@ -41,7 +41,7 @@
    - @Html.Label("Tags", htmlAttributes: new { @class = "control-label col-md-2" }) + @Html.Label("Tags", "Tags", htmlAttributes: new { @class = "control-label col-md-2" })
    @Html.EditorFor(model => model.UserChosenTags, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.UserChosenTags, "", new { @class = "text-danger" }) @@ -60,8 +60,9 @@ @Html.ActionLink("Back to List", "Index")

    -@Html.Partial("PostValidation") + @section Scripts { - @Scripts.Render("~/bundles/jqueryval") + + } diff --git a/SampleWebApp/Views/PostsAsync/Index.cshtml b/SampleWebApp/Views/PostsAsync/Index.cshtml index 706400f..a04efa0 100644 --- a/SampleWebApp/Views/PostsAsync/Index.cshtml +++ b/SampleWebApp/Views/PostsAsync/Index.cshtml @@ -12,7 +12,7 @@ } @if (TempData["errorMessage"] != null) { -
    @TempData["errorMessage"]
    +
    @Html.Raw(TempData["errorMessage"])
    }

    diff --git a/SampleWebApp/Views/Shared/Error.cshtml b/SampleWebApp/Views/Shared/Error.cshtml index be55b17..61bf998 100644 --- a/SampleWebApp/Views/Shared/Error.cshtml +++ b/SampleWebApp/Views/Shared/Error.cshtml @@ -1,9 +1,6 @@ -@model System.Web.Mvc.HandleErrorInfo - @{ ViewBag.Title = "Error"; }

    Error.

    An error occurred while processing your request.

    - diff --git a/SampleWebApp/Views/Shared/_Layout.cshtml b/SampleWebApp/Views/Shared/_Layout.cshtml index 345fd91..0f327cc 100644 --- a/SampleWebApp/Views/Shared/_Layout.cshtml +++ b/SampleWebApp/Views/Shared/_Layout.cshtml @@ -5,7 +5,8 @@ @ViewBag.Title - SampleMvcWebApp - @Styles.Render("~/Content/css") + + @@ -54,7 +55,9 @@
    - @Scripts.Render("~/bundles/javascript") - @RenderSection("scripts", required: false) + + + + @await RenderSectionAsync("scripts", required: false) diff --git a/SampleWebApp/Views/Tags/Create.cshtml b/SampleWebApp/Views/Tags/Create.cshtml index 216fd78..8bcc251 100644 --- a/SampleWebApp/Views/Tags/Create.cshtml +++ b/SampleWebApp/Views/Tags/Create.cshtml @@ -43,4 +43,4 @@ @Html.ActionLink("Back to List", "Index")
    -@Html.Partial("TagValidation") + diff --git a/SampleWebApp/Views/Tags/Edit.cshtml b/SampleWebApp/Views/Tags/Edit.cshtml index baab41e..e3a01bf 100644 --- a/SampleWebApp/Views/Tags/Edit.cshtml +++ b/SampleWebApp/Views/Tags/Edit.cshtml @@ -44,4 +44,4 @@ @Html.ActionLink("Back to List", "Index")
    -@Html.Partial("TagValidation") + diff --git a/SampleWebApp/Views/Tags/Index.cshtml b/SampleWebApp/Views/Tags/Index.cshtml index 03c2653..a371c20 100644 --- a/SampleWebApp/Views/Tags/Index.cshtml +++ b/SampleWebApp/Views/Tags/Index.cshtml @@ -12,7 +12,7 @@ } @if (TempData["errorMessage"] != null) { -
    @TempData["errorMessage"]
    +
    @Html.Raw(TempData["errorMessage"])
    }

    diff --git a/SampleWebApp/Views/TagsAsync/Create.cshtml b/SampleWebApp/Views/TagsAsync/Create.cshtml index 84783db..0e0ce81 100644 --- a/SampleWebApp/Views/TagsAsync/Create.cshtml +++ b/SampleWebApp/Views/TagsAsync/Create.cshtml @@ -43,4 +43,4 @@ @Html.ActionLink("Back to List", "Index")


    -@Html.Partial("TagValidation") + diff --git a/SampleWebApp/Views/TagsAsync/Edit.cshtml b/SampleWebApp/Views/TagsAsync/Edit.cshtml index 3f41685..51e3e42 100644 --- a/SampleWebApp/Views/TagsAsync/Edit.cshtml +++ b/SampleWebApp/Views/TagsAsync/Edit.cshtml @@ -44,4 +44,4 @@ @Html.ActionLink("Back to List", "Index")
    -@Html.Partial("TagValidation") + diff --git a/SampleWebApp/Views/TagsAsync/Index.cshtml b/SampleWebApp/Views/TagsAsync/Index.cshtml index 92c0337..5188df8 100644 --- a/SampleWebApp/Views/TagsAsync/Index.cshtml +++ b/SampleWebApp/Views/TagsAsync/Index.cshtml @@ -12,7 +12,7 @@ } @if (TempData["errorMessage"] != null) { -
    @TempData["errorMessage"]
    +
    @Html.Raw(TempData["errorMessage"])
    } @Html.ValidationSummary(false, "", new { @class = "text-danger" }) diff --git a/SampleWebApp/Views/Web.config b/SampleWebApp/Views/Web.config deleted file mode 100644 index ba26898..0000000 --- a/SampleWebApp/Views/Web.config +++ /dev/null @@ -1,35 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SampleWebApp/Views/_ViewImports.cshtml b/SampleWebApp/Views/_ViewImports.cshtml new file mode 100644 index 0000000..83e313c --- /dev/null +++ b/SampleWebApp/Views/_ViewImports.cshtml @@ -0,0 +1,6 @@ +@using SampleWebApp +@using SampleWebApp.Models +@using ServiceLayer.UiClasses +@using DataLayer.DataClasses.Concrete +@using Microsoft.AspNetCore.Mvc.Rendering +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/SampleWebApp/Web.AzureRelease.config b/SampleWebApp/Web.AzureRelease.config deleted file mode 100644 index 7ea0845..0000000 --- a/SampleWebApp/Web.AzureRelease.config +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - Azure - - - Azure - - - - \ No newline at end of file diff --git a/SampleWebApp/Web.Debug.config b/SampleWebApp/Web.Debug.config deleted file mode 100644 index 680849f..0000000 --- a/SampleWebApp/Web.Debug.config +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - diff --git a/SampleWebApp/Web.Release.config b/SampleWebApp/Web.Release.config deleted file mode 100644 index 943c9c0..0000000 --- a/SampleWebApp/Web.Release.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - diff --git a/SampleWebApp/Web.WebWizRelease.config b/SampleWebApp/Web.WebWizRelease.config deleted file mode 100644 index 451e45b..0000000 --- a/SampleWebApp/Web.WebWizRelease.config +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - WebWiz - - - jonsmith_ - - - - \ No newline at end of file diff --git a/SampleWebApp/Web.config b/SampleWebApp/Web.config deleted file mode 100644 index 02309cc..0000000 --- a/SampleWebApp/Web.config +++ /dev/null @@ -1,110 +0,0 @@ - - - - -
    - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LocalHost - - - jonsmith_ - - - - \ No newline at end of file diff --git a/SampleWebApp/appsettings.Development.json b/SampleWebApp/appsettings.Development.json new file mode 100644 index 0000000..3e1a225 --- /dev/null +++ b/SampleWebApp/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Information" + } + } +} diff --git a/SampleWebApp/appsettings.json b/SampleWebApp/appsettings.json new file mode 100644 index 0000000..c9da4b1 --- /dev/null +++ b/SampleWebApp/appsettings.json @@ -0,0 +1,13 @@ +{ + "ConnectionStrings": { + "SampleWebAppDb": "Data Source=SampleWebAppDb.db" + }, + "HostTypeString": "LocalHost", + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/SampleWebApp/packages.config b/SampleWebApp/packages.config deleted file mode 100644 index bc278c0..0000000 --- a/SampleWebApp/packages.config +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/SampleWebApp/Content/Site.css b/SampleWebApp/wwwroot/Content/Site.css similarity index 100% rename from SampleWebApp/Content/Site.css rename to SampleWebApp/wwwroot/Content/Site.css diff --git a/SampleWebApp/Content/bootstrap-theme.css b/SampleWebApp/wwwroot/Content/bootstrap-theme.css similarity index 100% rename from SampleWebApp/Content/bootstrap-theme.css rename to SampleWebApp/wwwroot/Content/bootstrap-theme.css diff --git a/SampleWebApp/Content/bootstrap-theme.css.map b/SampleWebApp/wwwroot/Content/bootstrap-theme.css.map similarity index 100% rename from SampleWebApp/Content/bootstrap-theme.css.map rename to SampleWebApp/wwwroot/Content/bootstrap-theme.css.map diff --git a/SampleWebApp/Content/bootstrap-theme.min.css b/SampleWebApp/wwwroot/Content/bootstrap-theme.min.css similarity index 100% rename from SampleWebApp/Content/bootstrap-theme.min.css rename to SampleWebApp/wwwroot/Content/bootstrap-theme.min.css diff --git a/SampleWebApp/Content/bootstrap.css b/SampleWebApp/wwwroot/Content/bootstrap.css similarity index 100% rename from SampleWebApp/Content/bootstrap.css rename to SampleWebApp/wwwroot/Content/bootstrap.css diff --git a/SampleWebApp/Content/bootstrap.css.map b/SampleWebApp/wwwroot/Content/bootstrap.css.map similarity index 100% rename from SampleWebApp/Content/bootstrap.css.map rename to SampleWebApp/wwwroot/Content/bootstrap.css.map diff --git a/SampleWebApp/Content/bootstrap.min.css b/SampleWebApp/wwwroot/Content/bootstrap.min.css similarity index 100% rename from SampleWebApp/Content/bootstrap.min.css rename to SampleWebApp/wwwroot/Content/bootstrap.min.css diff --git a/SampleWebApp/Content/img/setup-progress.gif b/SampleWebApp/wwwroot/Content/img/setup-progress.gif similarity index 100% rename from SampleWebApp/Content/img/setup-progress.gif rename to SampleWebApp/wwwroot/Content/img/setup-progress.gif diff --git a/SampleWebApp/Content/img/task-progress.gif b/SampleWebApp/wwwroot/Content/img/task-progress.gif similarity index 100% rename from SampleWebApp/Content/img/task-progress.gif rename to SampleWebApp/wwwroot/Content/img/task-progress.gif diff --git a/SampleWebApp/Content/notify.css b/SampleWebApp/wwwroot/Content/notify.css similarity index 100% rename from SampleWebApp/Content/notify.css rename to SampleWebApp/wwwroot/Content/notify.css diff --git a/SampleWebApp/Content/notify.min.css b/SampleWebApp/wwwroot/Content/notify.min.css similarity index 100% rename from SampleWebApp/Content/notify.min.css rename to SampleWebApp/wwwroot/Content/notify.min.css diff --git a/SampleWebApp/Content/themes/base/images/animated-overlay.gif b/SampleWebApp/wwwroot/Content/themes/base/images/animated-overlay.gif similarity index 100% rename from SampleWebApp/Content/themes/base/images/animated-overlay.gif rename to SampleWebApp/wwwroot/Content/themes/base/images/animated-overlay.gif diff --git a/SampleWebApp/Content/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png diff --git a/SampleWebApp/Content/themes/base/images/ui-bg_flat_75_ffffff_40x100.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_flat_75_ffffff_40x100.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-bg_flat_75_ffffff_40x100.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_flat_75_ffffff_40x100.png diff --git a/SampleWebApp/Content/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png diff --git a/SampleWebApp/Content/themes/base/images/ui-bg_glass_65_ffffff_1x400.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_glass_65_ffffff_1x400.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-bg_glass_65_ffffff_1x400.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_glass_65_ffffff_1x400.png diff --git a/SampleWebApp/Content/themes/base/images/ui-bg_glass_75_dadada_1x400.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_glass_75_dadada_1x400.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-bg_glass_75_dadada_1x400.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_glass_75_dadada_1x400.png diff --git a/SampleWebApp/Content/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png diff --git a/SampleWebApp/Content/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png diff --git a/SampleWebApp/Content/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png diff --git a/SampleWebApp/Content/themes/base/images/ui-icons_222222_256x240.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-icons_222222_256x240.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-icons_222222_256x240.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-icons_222222_256x240.png diff --git a/SampleWebApp/Content/themes/base/images/ui-icons_2e83ff_256x240.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-icons_2e83ff_256x240.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-icons_2e83ff_256x240.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-icons_2e83ff_256x240.png diff --git a/SampleWebApp/Content/themes/base/images/ui-icons_454545_256x240.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-icons_454545_256x240.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-icons_454545_256x240.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-icons_454545_256x240.png diff --git a/SampleWebApp/Content/themes/base/images/ui-icons_888888_256x240.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-icons_888888_256x240.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-icons_888888_256x240.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-icons_888888_256x240.png diff --git a/SampleWebApp/Content/themes/base/images/ui-icons_cd0a0a_256x240.png b/SampleWebApp/wwwroot/Content/themes/base/images/ui-icons_cd0a0a_256x240.png similarity index 100% rename from SampleWebApp/Content/themes/base/images/ui-icons_cd0a0a_256x240.png rename to SampleWebApp/wwwroot/Content/themes/base/images/ui-icons_cd0a0a_256x240.png diff --git a/SampleWebApp/Content/themes/base/jquery-ui.css b/SampleWebApp/wwwroot/Content/themes/base/jquery-ui.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery-ui.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery-ui.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.accordion.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.accordion.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.accordion.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.accordion.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.all.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.all.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.all.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.all.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.autocomplete.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.autocomplete.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.autocomplete.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.autocomplete.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.base.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.base.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.base.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.base.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.button.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.button.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.button.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.button.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.core.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.core.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.core.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.core.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.datepicker.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.datepicker.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.datepicker.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.datepicker.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.dialog.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.dialog.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.dialog.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.dialog.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.menu.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.menu.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.menu.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.menu.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.progressbar.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.progressbar.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.progressbar.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.progressbar.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.resizable.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.resizable.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.resizable.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.resizable.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.selectable.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.selectable.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.selectable.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.selectable.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.slider.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.slider.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.slider.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.slider.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.spinner.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.spinner.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.spinner.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.spinner.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.tabs.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.tabs.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.tabs.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.tabs.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.theme.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.theme.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.theme.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.theme.css diff --git a/SampleWebApp/Content/themes/base/jquery.ui.tooltip.css b/SampleWebApp/wwwroot/Content/themes/base/jquery.ui.tooltip.css similarity index 100% rename from SampleWebApp/Content/themes/base/jquery.ui.tooltip.css rename to SampleWebApp/wwwroot/Content/themes/base/jquery.ui.tooltip.css diff --git a/SampleWebApp/Content/themes/base/minified/images/animated-overlay.gif b/SampleWebApp/wwwroot/Content/themes/base/minified/images/animated-overlay.gif similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/animated-overlay.gif rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/animated-overlay.gif diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-bg_flat_0_aaaaaa_40x100.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_flat_0_aaaaaa_40x100.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-bg_flat_0_aaaaaa_40x100.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_flat_0_aaaaaa_40x100.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-bg_flat_75_ffffff_40x100.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_flat_75_ffffff_40x100.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-bg_flat_75_ffffff_40x100.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_flat_75_ffffff_40x100.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-bg_glass_55_fbf9ee_1x400.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_glass_55_fbf9ee_1x400.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-bg_glass_55_fbf9ee_1x400.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_glass_55_fbf9ee_1x400.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-bg_glass_65_ffffff_1x400.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_glass_65_ffffff_1x400.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-bg_glass_65_ffffff_1x400.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_glass_65_ffffff_1x400.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-bg_glass_75_dadada_1x400.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_glass_75_dadada_1x400.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-bg_glass_75_dadada_1x400.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_glass_75_dadada_1x400.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-bg_glass_75_e6e6e6_1x400.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_glass_75_e6e6e6_1x400.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-bg_glass_75_e6e6e6_1x400.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_glass_75_e6e6e6_1x400.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-bg_glass_95_fef1ec_1x400.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_glass_95_fef1ec_1x400.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-bg_glass_95_fef1ec_1x400.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_glass_95_fef1ec_1x400.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_highlight-soft_75_cccccc_1x100.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-bg_highlight-soft_75_cccccc_1x100.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-bg_highlight-soft_75_cccccc_1x100.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-icons_222222_256x240.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-icons_222222_256x240.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-icons_222222_256x240.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-icons_222222_256x240.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-icons_2e83ff_256x240.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-icons_2e83ff_256x240.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-icons_2e83ff_256x240.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-icons_2e83ff_256x240.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-icons_454545_256x240.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-icons_454545_256x240.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-icons_454545_256x240.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-icons_454545_256x240.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-icons_888888_256x240.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-icons_888888_256x240.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-icons_888888_256x240.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-icons_888888_256x240.png diff --git a/SampleWebApp/Content/themes/base/minified/images/ui-icons_cd0a0a_256x240.png b/SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-icons_cd0a0a_256x240.png similarity index 100% rename from SampleWebApp/Content/themes/base/minified/images/ui-icons_cd0a0a_256x240.png rename to SampleWebApp/wwwroot/Content/themes/base/minified/images/ui-icons_cd0a0a_256x240.png diff --git a/SampleWebApp/Content/themes/base/minified/jquery-ui.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery-ui.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery-ui.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery-ui.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.accordion.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.accordion.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.accordion.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.accordion.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.autocomplete.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.autocomplete.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.autocomplete.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.autocomplete.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.button.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.button.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.button.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.button.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.core.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.core.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.core.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.core.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.datepicker.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.datepicker.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.datepicker.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.datepicker.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.dialog.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.dialog.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.dialog.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.dialog.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.menu.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.menu.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.menu.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.menu.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.progressbar.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.progressbar.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.progressbar.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.progressbar.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.resizable.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.resizable.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.resizable.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.resizable.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.selectable.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.selectable.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.selectable.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.selectable.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.slider.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.slider.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.slider.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.slider.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.spinner.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.spinner.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.spinner.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.spinner.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.tabs.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.tabs.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.tabs.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.tabs.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.theme.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.theme.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.theme.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.theme.min.css diff --git a/SampleWebApp/Content/themes/base/minified/jquery.ui.tooltip.min.css b/SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.tooltip.min.css similarity index 100% rename from SampleWebApp/Content/themes/base/minified/jquery.ui.tooltip.min.css rename to SampleWebApp/wwwroot/Content/themes/base/minified/jquery.ui.tooltip.min.css diff --git a/SampleWebApp/Scripts/ActionRunnerComms.js b/SampleWebApp/wwwroot/Scripts/ActionRunnerComms.js similarity index 100% rename from SampleWebApp/Scripts/ActionRunnerComms.js rename to SampleWebApp/wwwroot/Scripts/ActionRunnerComms.js diff --git a/SampleWebApp/Scripts/ActionRunnerUi.js b/SampleWebApp/wwwroot/Scripts/ActionRunnerUi.js similarity index 100% rename from SampleWebApp/Scripts/ActionRunnerUi.js rename to SampleWebApp/wwwroot/Scripts/ActionRunnerUi.js diff --git a/SampleWebApp/Scripts/_references.js b/SampleWebApp/wwwroot/Scripts/_references.js similarity index 100% rename from SampleWebApp/Scripts/_references.js rename to SampleWebApp/wwwroot/Scripts/_references.js diff --git a/SampleWebApp/Scripts/bootstrap.js b/SampleWebApp/wwwroot/Scripts/bootstrap.js similarity index 100% rename from SampleWebApp/Scripts/bootstrap.js rename to SampleWebApp/wwwroot/Scripts/bootstrap.js diff --git a/SampleWebApp/Scripts/bootstrap.min.js b/SampleWebApp/wwwroot/Scripts/bootstrap.min.js similarity index 100% rename from SampleWebApp/Scripts/bootstrap.min.js rename to SampleWebApp/wwwroot/Scripts/bootstrap.min.js diff --git a/SampleWebApp/Scripts/jquery-1.10.2.intellisense.js b/SampleWebApp/wwwroot/Scripts/jquery-1.10.2.intellisense.js similarity index 100% rename from SampleWebApp/Scripts/jquery-1.10.2.intellisense.js rename to SampleWebApp/wwwroot/Scripts/jquery-1.10.2.intellisense.js diff --git a/SampleWebApp/Scripts/jquery-1.10.2.js b/SampleWebApp/wwwroot/Scripts/jquery-1.10.2.js similarity index 100% rename from SampleWebApp/Scripts/jquery-1.10.2.js rename to SampleWebApp/wwwroot/Scripts/jquery-1.10.2.js diff --git a/SampleWebApp/Scripts/jquery-1.10.2.min.js b/SampleWebApp/wwwroot/Scripts/jquery-1.10.2.min.js similarity index 100% rename from SampleWebApp/Scripts/jquery-1.10.2.min.js rename to SampleWebApp/wwwroot/Scripts/jquery-1.10.2.min.js diff --git a/SampleWebApp/Scripts/jquery-1.10.2.min.map b/SampleWebApp/wwwroot/Scripts/jquery-1.10.2.min.map similarity index 100% rename from SampleWebApp/Scripts/jquery-1.10.2.min.map rename to SampleWebApp/wwwroot/Scripts/jquery-1.10.2.min.map diff --git a/SampleWebApp/Scripts/jquery-notify.js b/SampleWebApp/wwwroot/Scripts/jquery-notify.js similarity index 100% rename from SampleWebApp/Scripts/jquery-notify.js rename to SampleWebApp/wwwroot/Scripts/jquery-notify.js diff --git a/SampleWebApp/Scripts/jquery-notify.min.js b/SampleWebApp/wwwroot/Scripts/jquery-notify.min.js similarity index 100% rename from SampleWebApp/Scripts/jquery-notify.min.js rename to SampleWebApp/wwwroot/Scripts/jquery-notify.min.js diff --git a/SampleWebApp/Scripts/jquery-ui-1.10.4.js b/SampleWebApp/wwwroot/Scripts/jquery-ui-1.10.4.js similarity index 100% rename from SampleWebApp/Scripts/jquery-ui-1.10.4.js rename to SampleWebApp/wwwroot/Scripts/jquery-ui-1.10.4.js diff --git a/SampleWebApp/Scripts/jquery-ui-1.10.4.min.js b/SampleWebApp/wwwroot/Scripts/jquery-ui-1.10.4.min.js similarity index 100% rename from SampleWebApp/Scripts/jquery-ui-1.10.4.min.js rename to SampleWebApp/wwwroot/Scripts/jquery-ui-1.10.4.min.js diff --git a/SampleWebApp/Scripts/jquery.signalR-2.0.3.js b/SampleWebApp/wwwroot/Scripts/jquery.signalR-2.0.3.js similarity index 100% rename from SampleWebApp/Scripts/jquery.signalR-2.0.3.js rename to SampleWebApp/wwwroot/Scripts/jquery.signalR-2.0.3.js diff --git a/SampleWebApp/Scripts/jquery.signalR-2.0.3.min.js b/SampleWebApp/wwwroot/Scripts/jquery.signalR-2.0.3.min.js similarity index 100% rename from SampleWebApp/Scripts/jquery.signalR-2.0.3.min.js rename to SampleWebApp/wwwroot/Scripts/jquery.signalR-2.0.3.min.js diff --git a/SampleWebApp/Scripts/jquery.validate-vsdoc.js b/SampleWebApp/wwwroot/Scripts/jquery.validate-vsdoc.js similarity index 100% rename from SampleWebApp/Scripts/jquery.validate-vsdoc.js rename to SampleWebApp/wwwroot/Scripts/jquery.validate-vsdoc.js diff --git a/SampleWebApp/Scripts/jquery.validate.js b/SampleWebApp/wwwroot/Scripts/jquery.validate.js similarity index 100% rename from SampleWebApp/Scripts/jquery.validate.js rename to SampleWebApp/wwwroot/Scripts/jquery.validate.js diff --git a/SampleWebApp/Scripts/jquery.validate.min.js b/SampleWebApp/wwwroot/Scripts/jquery.validate.min.js similarity index 100% rename from SampleWebApp/Scripts/jquery.validate.min.js rename to SampleWebApp/wwwroot/Scripts/jquery.validate.min.js diff --git a/SampleWebApp/Scripts/jquery.validate.unobtrusive.js b/SampleWebApp/wwwroot/Scripts/jquery.validate.unobtrusive.js similarity index 100% rename from SampleWebApp/Scripts/jquery.validate.unobtrusive.js rename to SampleWebApp/wwwroot/Scripts/jquery.validate.unobtrusive.js diff --git a/SampleWebApp/Scripts/jquery.validate.unobtrusive.min.js b/SampleWebApp/wwwroot/Scripts/jquery.validate.unobtrusive.min.js similarity index 100% rename from SampleWebApp/Scripts/jquery.validate.unobtrusive.min.js rename to SampleWebApp/wwwroot/Scripts/jquery.validate.unobtrusive.min.js diff --git a/SampleWebApp/Scripts/modernizr-2.6.2.js b/SampleWebApp/wwwroot/Scripts/modernizr-2.6.2.js similarity index 100% rename from SampleWebApp/Scripts/modernizr-2.6.2.js rename to SampleWebApp/wwwroot/Scripts/modernizr-2.6.2.js diff --git a/SampleWebApp/Scripts/npm.js b/SampleWebApp/wwwroot/Scripts/npm.js similarity index 100% rename from SampleWebApp/Scripts/npm.js rename to SampleWebApp/wwwroot/Scripts/npm.js diff --git a/SampleWebApp/Scripts/respond.js b/SampleWebApp/wwwroot/Scripts/respond.js similarity index 100% rename from SampleWebApp/Scripts/respond.js rename to SampleWebApp/wwwroot/Scripts/respond.js diff --git a/SampleWebApp/Scripts/respond.min.js b/SampleWebApp/wwwroot/Scripts/respond.min.js similarity index 100% rename from SampleWebApp/Scripts/respond.min.js rename to SampleWebApp/wwwroot/Scripts/respond.min.js diff --git a/SampleWebApp/favicon.ico b/SampleWebApp/wwwroot/favicon.ico similarity index 100% rename from SampleWebApp/favicon.ico rename to SampleWebApp/wwwroot/favicon.ico diff --git a/SampleWebApp/fonts/glyphicons-halflings-regular.eot b/SampleWebApp/wwwroot/fonts/glyphicons-halflings-regular.eot similarity index 100% rename from SampleWebApp/fonts/glyphicons-halflings-regular.eot rename to SampleWebApp/wwwroot/fonts/glyphicons-halflings-regular.eot diff --git a/SampleWebApp/fonts/glyphicons-halflings-regular.svg b/SampleWebApp/wwwroot/fonts/glyphicons-halflings-regular.svg similarity index 100% rename from SampleWebApp/fonts/glyphicons-halflings-regular.svg rename to SampleWebApp/wwwroot/fonts/glyphicons-halflings-regular.svg diff --git a/SampleWebApp/fonts/glyphicons-halflings-regular.ttf b/SampleWebApp/wwwroot/fonts/glyphicons-halflings-regular.ttf similarity index 100% rename from SampleWebApp/fonts/glyphicons-halflings-regular.ttf rename to SampleWebApp/wwwroot/fonts/glyphicons-halflings-regular.ttf diff --git a/SampleWebApp/fonts/glyphicons-halflings-regular.woff b/SampleWebApp/wwwroot/fonts/glyphicons-halflings-regular.woff similarity index 100% rename from SampleWebApp/fonts/glyphicons-halflings-regular.woff rename to SampleWebApp/wwwroot/fonts/glyphicons-halflings-regular.woff diff --git a/SampleWebApp/fonts/glyphicons-halflings-regular.woff2 b/SampleWebApp/wwwroot/fonts/glyphicons-halflings-regular.woff2 similarity index 100% rename from SampleWebApp/fonts/glyphicons-halflings-regular.woff2 rename to SampleWebApp/wwwroot/fonts/glyphicons-halflings-regular.woff2 diff --git a/ServiceLayer/App.config b/ServiceLayer/App.config deleted file mode 100644 index dac3ee5..0000000 --- a/ServiceLayer/App.config +++ /dev/null @@ -1,29 +0,0 @@ - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ServiceLayer/PostServices/DetailPostDtoAsync.cs b/ServiceLayer/PostServices/DetailPostDtoAsync.cs index dd27b14..d434656 100644 --- a/ServiceLayer/PostServices/DetailPostDtoAsync.cs +++ b/ServiceLayer/PostServices/DetailPostDtoAsync.cs @@ -27,7 +27,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Data.Entity; +using Microsoft.EntityFrameworkCore; using System.Linq; using System.Runtime.CompilerServices; using System.Threading.Tasks; diff --git a/ServiceLayer/Properties/AssemblyInfo.cs b/ServiceLayer/Properties/AssemblyInfo.cs deleted file mode 100644 index 2793a90..0000000 --- a/ServiceLayer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,62 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: AssemblyInfo.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceLayer")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ServiceLayer")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[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("35097f07-8bb1-4da4-ab04-7b4ac4894e18")] - -// 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/ServiceLayer/ServiceLayer.csproj b/ServiceLayer/ServiceLayer.csproj index 09244c2..ec9f173 100644 --- a/ServiceLayer/ServiceLayer.csproj +++ b/ServiceLayer/ServiceLayer.csproj @@ -1,136 +1,17 @@ - - - + + - Debug - AnyCPU - {D2813927-0F38-43C3-B47C-AE8F00D50CAE} - Library - Properties + net8.0 + disable + disable ServiceLayer ServiceLayer - v4.5.1 - 512 - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - bin\ReleaseAzure\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - bin\AzureRelease\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - bin\WebWizRelease\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - False - ..\packages\Autofac.3.5.0\lib\net40\Autofac.dll - - - ..\packages\AutoMapper.4.2.1\lib\net45\AutoMapper.dll - True - - - ..\packages\DelegateDecompiler.0.18.0\lib\net40-Client\DelegateDecompiler.dll - True - - - ..\packages\DelegateDecompiler.EntityFramework.0.18.0\lib\net45\DelegateDecompiler.EntityFramework.dll - True - - - ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll - True - - - ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll - True - - - ..\packages\GenericLibsBase.1.0.1\lib\GenericLibsBase.dll - True - - - ..\packages\GenericServices.1.0.9\lib\GenericServices.dll - True - - - ..\packages\Mono.Reflection.1.0.0.0\lib\Mono.Reflection.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - {264e1878-12de-4099-b8d7-cc53a73fea49} - DataLayer - + + + - - - \ No newline at end of file + + diff --git a/ServiceLayer/Startup/ServiceLayerInitialise.cs b/ServiceLayer/Startup/ServiceLayerInitialise.cs index 5fe79ef..1a5df1a 100644 --- a/ServiceLayer/Startup/ServiceLayerInitialise.cs +++ b/ServiceLayer/Startup/ServiceLayerInitialise.cs @@ -1,55 +1,23 @@ -#region licence -// The MIT License (MIT) -// -// Filename: ServiceLayerInitialise.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using DataLayer.DataClasses; using DataLayer.Startup; - namespace ServiceLayer.Startup { /// - /// This handles the initialisation of this layer and any other layers + /// This handles the initialisation of this layer and any other layers. /// public static class ServiceLayerInitialise { /// - /// This should be called at Startup + /// This should be called at Startup. /// - /// true if working with azure database - /// true if the database provider allows the app to drop/create a database - public static void InitialiseThis(bool isAzure, bool canCreateDatabase) + /// the application DbContext + /// true if the app may create/migrate the database + public static void InitialiseThis(SampleWebAppDb context, bool canCreateDatabase) { - //Place any tasks that need initialising here - DataLayerInitialise.InitialiseThis(isAzure, canCreateDatabase); - + DataLayerInitialise.InitialiseThis(context, canCreateDatabase); } } } diff --git a/ServiceLayer/Startup/ServiceLayerModule.cs b/ServiceLayer/Startup/ServiceLayerModule.cs deleted file mode 100644 index 39b40ef..0000000 --- a/ServiceLayer/Startup/ServiceLayerModule.cs +++ /dev/null @@ -1,57 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: ServiceLayerModule.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using Autofac; -using DataLayer.Startup; -using GenericServices; - -namespace ServiceLayer.Startup -{ - public class ServiceLayerModule : Module - { - - /// - /// This registers all items in service layer and below - /// - /// - protected override void Load(ContainerBuilder builder) - { - - //Now register the DataLayer - builder.RegisterModule(new DataLayerModule()); - - //--------------------------- - //Register service layer: autowire all - builder.RegisterAssemblyTypes(GetType().Assembly).AsImplementedInterfaces(); - - //and register the GenericServices assembly - builder.RegisterAssemblyTypes(typeof(IListService).Assembly).AsImplementedInterfaces(); - - } - - } -} diff --git a/ServiceLayer/packages.config b/ServiceLayer/packages.config deleted file mode 100644 index 9c06c52..0000000 --- a/ServiceLayer/packages.config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/Tests/App.config b/Tests/App.config deleted file mode 100644 index 875486b..0000000 --- a/Tests/App.config +++ /dev/null @@ -1,76 +0,0 @@ - - - - -
    - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - jonsmith_ - - - - \ No newline at end of file diff --git a/Tests/DependencyItems/ClassToTestClassWithPrivateCtor.cs b/Tests/DependencyItems/ClassToTestClassWithPrivateCtor.cs deleted file mode 100644 index d4e889e..0000000 --- a/Tests/DependencyItems/ClassToTestClassWithPrivateCtor.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tests.DependencyItems -{ - internal interface IClassToTestClassWithPrivateCtor - { - } - - internal interface ISetType - { - void SetType(Type resolvedType); - } - - class ClassToTestClassWithPrivateCtor : IClassToTestClassWithPrivateCtor, ISetType - { - private Type _classType; - - public void SetType(Type resolvedType) - { - _classType = resolvedType; - } - } -} diff --git a/Tests/DependencyItems/ClassWithPrivateCtor.cs b/Tests/DependencyItems/ClassWithPrivateCtor.cs deleted file mode 100644 index 5ac6bc3..0000000 --- a/Tests/DependencyItems/ClassWithPrivateCtor.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tests.DependencyItems -{ - internal interface IClassWithPrivateCtor - { - } - - class ClassWithPrivateCtor : IClassWithPrivateCtor - { - - private ClassWithPrivateCtor() { } - - } -} diff --git a/Tests/DependencyItems/ConstructorParamClass.cs b/Tests/DependencyItems/ConstructorParamClass.cs deleted file mode 100644 index 252b109..0000000 --- a/Tests/DependencyItems/ConstructorParamClass.cs +++ /dev/null @@ -1,44 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: ConstructorParamClass.cs -// Date Created: 2014/05/22 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -namespace Tests.DependencyItems -{ - public interface IConstructorParamClass - { - int MyInt { get; } - } - - public class ConstructorParamClass : IConstructorParamClass - { - - public int MyInt { get; private set; } - - public ConstructorParamClass(int myInt) - { - MyInt = myInt; - } - } -} diff --git a/Tests/DependencyItems/GenericInterface.cs b/Tests/DependencyItems/GenericInterface.cs deleted file mode 100644 index 240e14c..0000000 --- a/Tests/DependencyItems/GenericInterface.cs +++ /dev/null @@ -1,43 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: GenericInterface.cs -// Date Created: 2014/05/22 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -namespace Tests.DependencyItems -{ - public interface IGenericInterface where T : class - { - string GetTypeName(); - } - - public class GenericInterface : IGenericInterface where T : class - { - - public string GetTypeName() - { - return typeof (T).Name; - } - - } -} diff --git a/Tests/DependencyItems/MyDisposableClass.cs b/Tests/DependencyItems/MyDisposableClass.cs deleted file mode 100644 index 2fbce42..0000000 --- a/Tests/DependencyItems/MyDisposableClass.cs +++ /dev/null @@ -1,64 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: MyDisposableClass.cs -// Date Created: 2014/05/22 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; - -namespace Tests.DependencyItems -{ - public interface IMyDisposableClass { } - - public class MyDisposableClass : IMyDisposableClass, IDisposable - { - - private readonly Action _disposeWasCalled; - - public MyDisposableClass(Action disposeWasCalled) - { - _disposeWasCalled = disposeWasCalled; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private bool _disposed; - - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - if (disposing) - { - _disposeWasCalled(); - } - } - _disposed = true; - } - - } -} diff --git a/Tests/DependencyItems/ServiceTypeClass.cs b/Tests/DependencyItems/ServiceTypeClass.cs deleted file mode 100644 index 7581d98..0000000 --- a/Tests/DependencyItems/ServiceTypeClass.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tests.DependencyItems -{ - class ServiceTypeClass - { - private Type _resolvedType; - - public ServiceTypeClass(Type resolvedType) - { - this._resolvedType = resolvedType; - } - } -} diff --git a/Tests/DependencyItems/SimpleClass.cs b/Tests/DependencyItems/SimpleClass.cs deleted file mode 100644 index c4a1933..0000000 --- a/Tests/DependencyItems/SimpleClass.cs +++ /dev/null @@ -1,40 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: SimpleClass.cs -// Date Created: 2014/05/22 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -namespace Tests.DependencyItems -{ - public interface ISimpleClass - { - void DoSomething(); - }; - - public class SimpleClass : ISimpleClass - { - public void DoSomething() - { - } - } -} diff --git a/Tests/Docs/Flow of control when running action with progress and cancel.pdf b/Tests/Docs/Flow of control when running action with progress and cancel.pdf deleted file mode 100644 index 32a7d0c78101539bf61c3ab1be2a71dbc1857c00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 196946 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%0Dk;&8DG>FNK>)Lox*Zo79>e9UsWDB9^L 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%0A!;!054gO{}CbHmR?-+LJ$R&m%JFyxtQH}II z{x!LP~O_oh1&UEJ(!9yO;nxF>37wmAQw!6GfS*{Y&=P;E((35c=SQWG@%zp%*k1sD6% zqkFaQpM>&J#U3*X5+soCxCZJ)%FxdNV!$BxZG$_GfqW4`^mB{f3ZkmS$wT1euH*U9 zjnw(0gU!_mGOvbH`DU}59$U;t^RVX?lGLp*okLt42YOq~(MrCosrl4ZpO>9i0p(k- z5d%AGz4_#dcKP`=s))WIdo;nYmt{j8uuG>CezNIR&||FQZ^eqR){kjV;`X z_1^D!5(8=Lh>K&?)XMv_SEN15r#~L_q`_B;_CQJLw1 zj~s{j214lf7V`?-zJ%A*W9Z?*7pDZ?xar-yXP7)>`W<*@k+;-3-~9RlZn4T@`#}wa zYrQv$!GjHmU_+F)NV0Xn!#gkparswa12Q)RcR9pjBcMQP+d6a8lg>6=01I(;>c~JU zHB3x@`%4X-_zUBIBGfumYt3J#Uo-{j1=ijcx1|JB8R zSNLIG-6;Nh(%5!XYfJ$#nZ*rj{!=P(E3ELlT+EEB{OiK=m}*vcua_=qOmU@N@?NPq zbaAPmmAxsV&xNB*WnW-SM;ywe<<^_$p@ZYuY9+O8rs^y47X@OToMlE}x_IMH=Bvn z<*Xo7QkVZ=>JtG;^yGg{8xACqPiVt&=U%E{qpE-sn4abs;qPoVz@1&y3x??OD5f(eT)HM*c2TbmSaZdwW0N{WrzIuCh=9tZ`;M z*O%$asW4skQRhFghU{s(bI}smbpA~otSciW02*dGb1|4)>>x6MhrJESf6+o<|1hG+BHD@e ze?^$B6g05rzoyG)aqb-6*d4_rQ45URe^q!ohm+wy`h6PT0R^fPOj8*x=9s5v`iMZ# z!r3{-CU`{ud*Vw30k7#+Vw91@|G%J8DhT*%b`)(LWTohrt7+Fvd0a|UvT%!Z^&FEM zeN6Z4S$(APQgzE~Vk}$=aamGJb^QgT52b1qQp(c`FJ|fXxjQOzQO8$YfFB!!j=~jR zRJf&n*&q%G5~{EwR9t~C@)CBzEI5Xn6*zsiSVSvmgPY~ffFY``eLEmh^now3TYug! zE3mJR&YvMVS*u5rJo6dfZmi*MimkhK*AfN6M^)nkfxML~nXI;seG0BOo|YO|LhL!K&o1-!BItHxH3S{ja6?Jt~>y}GLG)irDY?jm>B$1zOwe%nY%%&+6dJ% z%b`*)HL13LbOAa1s{($QWG1`b4`t%xan`0SooQiWu3`KSpAXjgU+EFFY3G5RYAAI|72!XQ zK3L!LAuQ3(OLhvPT>rz#|4N2%PctvmDtK_E#4Ov&unnV$&((-G)RZxyjmuRf%MGOA z6f68BgRW%xOIb9QFl*-Bi#6M%Q0OXir9>xN$dFqVOBfOnE`XiaA0M!$R0Kpn&YdVP ztfHu+^j1%m55EfR2i=%d8t@&hY&abpj-R<}5HMp1g;IClfV`X@)>&A6<(yp}C^jVG z{Hz~hPZ5d)a$(GhPLaJrc&0t$m}~PlOPVBSewYe9%$PBdI0KK3n*`<Us3_piRz} z_p7eGZnu@aI4WfmP!%NaO|J9?73S3Z1VL!TDM3UlR#Hpx1hZYlwUol;rxU&1)Z$jB z=6Pj9+1sD!*^l<7^XsYQKWA63BHRRaNsv7H)xc2vBYn5oYys~uL4gH`N;mGw!H4ak zJ@dF)tIJe+&>U1F*Kp4LMhjHi$yBvaNolQ4vIOdPjjPl(u?7)ngL>6KFTqm|m2sL? z#q`9tKrdtsLiULJt&Y6JTc7IG+@O~DATa5>NsD{;<>e(8muDI`OLx)7{+I6ruYqZKT^VsL-~ zZDm5iRN+zN*=uE@Q&j>e8e&lHC>lmQL9?z&El)CE2+@9CbBDixIeIWyO*X@EK;Gv7~9e{F&nA5 zp)vmVQzpq#h+7|eD0_TA_;38ZGzcZY1$7WuKmc;09I-CI`<Ki5@)KCJ-A}(SiiqMJW^0w*{bJ-cM`B&+0KJle2U+rn5ZvaWK)tJI$Bu8LZ5c( z#3o0OY6c;>>4)QahZJ<73JoZ_`ZDX8S$h?6`+j5RHcF2VrC&@xQo)%YxBrhvKZIgK zXp`FgK`CYLO!_u4UFdsEH{R&LGlwRwgAEth)XApKvVFd#h1<8zX{+< zYvk7KB~9UYfZag|D&%>6_oDj>0IBk6XKj`WS|)BM2QWM_ss`4NfY+$#MU5QU%22&r z2K7kJzhNvC%a|5NFBBQOI@W>hx)tp4d_%mlkO#fa*hd_my3@SgM0)b$U3iZfkv?~w zov~2feNOA@vX?wp-!Ls+7};Vc6$)K5RB8}b*ZmrhT=?3oxMSfO$xUP1lT6vy>#S{vfT? zido7Q*>9>5Pea`7U=`Kn1YwYAys$HeP_7N$CGk+iP9sV+NZKWFL>QgQ&G3~!RmVF= z-?5Lpw>rGU5HAf(ICTBPn#fM1=o%lE&7mSw4?DdT}Py;^uV@_r=W`{_%h zUw}S@dn3?1i`Jo)_UwK#?rwJS>cJ%@L%V-`a$#*|Vc7WyOSgG3DS5V%89L9TyO2W! zb=h##ZO{Wh#*D$@fm&Hc$Fr>E&_r9^^9m--a?}IW=W^9&b=7B-S^e7t6tm*n`mASD zJpsn(HLc3I-gu4N_&>;gm&>T`vw)iYz(Ut|%RcmaIdXH9-Exyr1bkl3Z3*+29ygvw`BR|Bmmg$GeajyAa z0V_0$b}{jhD4)-4eg7o2f20;fReOps?OkorrYTU8X-N$tDqJj}O5<*Cy^ zJoDti##J$Ew)e>eZK(%Kg{>=Ztl8j_5WvF#_x)o`hltbDNI z?p>6tL{us1d}GDl$(8h#NWM5c57fLrV+*KF1|H?9`0vkr1#l(;iR5!#RSJF9R4rM; z7v;0Lrp*Q1)c!Ce%g2xEX!T}-@`iDzO+t~YdTZvbwXC@axRTM5PXWnB;(Uf+X#qtDzEgQ}`-N7NjXQtKXXbd#=G{BF^Yp zOO#EBN=I0eOz*Ek3e?3~vlb|mbhGwx01xa!crKoO5I8b9D-X0t38e zB-DvqYbDgJoNG&pIh(Yyi%oP(qi{uQ@EvCv7z1^9p+mIlz(&UqT+y;Lm#dQEd>w)9 zgYYuF1|hjd$$3M)V-&kV7^6C=YwxJ(0xFelaj68no~F0BTiGI8$= zS>qj|cVE1cSyD>tAf56r2OdDDS<7*p(3IVPS?gYy+molCP}8c|jx4f_60TnCEM?Ul z21(FfLqLS~o<>9a>X-IUtSvNw;NH_Fe7*ebwN*E=;A}zrXMxGPerPW?F&@ve!#K`y zWB)*-5J1)2-;nUbGzRO@{0;gTaPlU^D!;)s#3-M~HN+s_3bW}te=!91J$V5E>7MEazsFIWk;i*5Nls}SyuBQylZnk(+)IuqsgazhHpPmc@~6w5dc~8k~I!BBEHPf5H4QZC^2;`_bz#&4_?0R7MDxEN@%P2TBr^LhwQK%(tn|@ZComOVb^j8 zS1J7TQC$_=mj5SxSlyEG`LHUsB0sb8H_9ol$~z`4PCrmGSU7e3P>ph2sj^7YdnB=X zYCe&DY@Q|gcx-TfP5t-+wW0U)+rQ!*jn~|MT6o37-QTw0Fx%wHYVS*wI8$6hJ&JV~ zNd@fmC+!r{>YKtfRwPPnDXv#M?vGpIY#j~r|tl3l%mEL zj-61}8h20$26%X3=wF)b1t~G+6wCrzc2U=c0NwX>;z91J1HKy9-Bo0yqYo%v0d@g9 zn8tz(7aNl$L?p=-7|9g`RWS<{BY`Gd#6I)0b5q>1Yih7M-_x<>TK2N&ESotT<+9(N z&$izCd)&UXi>4M!GE0YR%bE3_%Um$V^}SSpjkd0U_|hEaYN@1=aawppWWxRa`f0<8 za{J$rn1(&=G&8iwdbP-k)20i}p2pzI_Qhx!{%*#5T5>-Czaok2%U4wa-LHl2=w$PhW0)LFw`(571wbzm%ZNx@)CBaqMlOKX$BLDXZ(7{Xew5 z1yCH_+b(;H>s;AHVo?rKL&GhLyefqI8E8OqqM8DG9+bADFlAgSDOLp^WyU)PWay1RTcT^*4 zHfszH@>q2-E7~*X^X|N$;wj@G71-A(>9@Ko@vz}3n7Uu;>Vw$X!Ow6P&Hkv9k#JHd zR$L}~Y>z$66{iv5E}HxiDP!)akP}OsKE0nSOhd(8H1Q))=8L037KmFg!)ExximRQm zKiz)$V?Weh3)l~JE)Fc#1ZF~=&}i#h*OJj;a)DhMfr|lc zuCV#Q!dAK~!8 z{Pq;cj|SdaWUg@i$AYeB?wWl^J<$g9Mlx7q4u`K?#HGDWNc4P96SOBO({;evy*0ib z#@w(?a;MT*u`SOaT+pvsg~dyMfF&E3TQz0TO}^LVl~*;PMl6QgmrdjxmIsq9xgf;f zwEf;h(a&~ouzSAWIjZTnGqs=Wm5_nCUizx2d395;BDXwe8v~A`As@(yW<^mtufzX! z4@7SY|9j#7a}Cx@8WDB7A)Bn8WU4{;UtHRU(ktx2!W=?ytzZ{Kn{*k<^+Z8d|V-3%hb=ubJWq!8O`Pig265G-Jg{anM_XNK`-nU=_?!u^)O%U0*Gw=9C=7qE;#+oQnIo6f(m}fjl zcV|SE3#2p_VQ^0{tco-f_wwhDw4;w{#D9F!PsEV#SQ&kw!hYh`P~_5HO;cgKS$)2* ze?D04qf3s$0?NA-K>AL#7~KOD!MMlRk|Uv1yFKq53_`i8atmqL2%r>^WCI;5Kja0R zVe@$+f1ZSF{r9W4gg+~VA&iVH7!udsp*q0HBdUj1BLy|>OPi>~P4qoagf(e*f0xW^&ZpynDAVCm8&WJ8t581>=l`By>@s ztzN03Y}TSg()nXR`YO+{oBMtXm7z>%ST;g-6)n?Kurd1U0cr#+IK+kK7wNMNBH-;w zutN^oq+27almoe?{~dZcWWH56^C>%9}dNV=^2p5pX3x zU?mE$g}oe_xz6ft`qqoq9ameQSggR#kys3{X^JIg!Ku+bNgOpR90>W?#-n6c z7gnOIRkmq9lav{}%Mz{6@9o!rftb+)ym(Krsd~rm9YD+*2|j1=4i{02_&?)J1RaiJ zC-3IXCV$Q+M`iX0>boCHZUn(140^VPn0dZ(X_2%b&jneWEHH)nP%fLUImkt`w~oN3O$kf2 z1zC5NB?bN0hyc29O)}7tVgcsAFAMJ@EbB*R%RwqL?G~*y#QVBsHKACiT6FWJ#^hlh z0k%F$rb(aFhZf2&Al>{_;M8a$o#Cx0%KQGT`Y@cH@0{2)fpon92VN|&Fy2TUT`w&D zWs!O1DaqPfibEhj6`(j8U9{V8bY*B?rST;LxlV}}$VT|;d96Fakw_Yevq9uZRG_a= zIB7QJxX6~SqI}tH>NyBa3S4LeM7zJ(_0#0w9OM`O20t$!JeAEOvlqb9l(}#Y(umU) z75@@O(jWB8?BRH5KOg)l{vBiLdC-~Fbp2MUBa0I=cng&@H0R^2LRCUool?bGQe+PX(iSP`hLRdci2i#wnK6!7+-K>T3;GNSJdxozSYic(% zE0EQ{6`XfTwA1RFjFI2slovCOk$(>dhlC<8_wC!lipaNbO5fy#)wOKjMv{a#GB=JC zqOwh}A;!ExlP;{J{wBC~TSD>R*fW{Tv3C1+t*E@&si7HKaV1dDYyAsOAjuwIRsz@Z z{V~!SpTc-6#@DMZUBXH~cnDk(l6ov3EV9~ zxSIKnmMaHO7xxXF>X+dE1ST9~NZtfeJ%(x40w4S|JFWf*5WTTRaq;!jdrO3QI{mCS z?Z{oGk(hyoPQvbJ!)|@(M&*O8nipp&KdE%)w<(&5Ycw`5`2YW5SEGax zNqR?S=gd0sd2Li|=%!INXELn}b=dztbPa`X?P2|IA`GXK{RSxSn@HOs`JN~fW9|;# z6HNszkzqHcm$y0zT#xkvP+ol-`dG6PMwrQPHtiEH2^F(%8i)h@epcDogAK}aVeUpv@6~07ueaEk1bn z8--o27-f9wq8xTJ;)-V2i`n6=P7_PG8n7oP0lzufbts22Sr@)*bKr%;3!{IZyJi zaiI%0TK@k{a`iQ5^UC|r-C@{|2hW^fQ=98|sw5m?Es?1`RH8O^?UQ0!;FlkcERUfU z#$d0i;zBJW#`GVIK;YP-ND?wZ*bw5j+;UHbI67i=MS> zVs}X8!;;>3)~({fvywYxV838^u#ATYi6fZ)sC0>S2q}V9iD^o5$3xGpS;_m)8b!a= zFTg>(ePBk~^? z>J@Z6gnwpncuY!}i{*jj-Z+{^$65R}GZ&CO86M2BncQU3;3e~J*g6<-W?N{*U3j#w z;Y)7KJO!^Z<=&%ny9KrnJ_(OAH-xOE1P=_TX9w|WkH-%G6ieVwr*}<{;qQ!=XhN=N zl7ak4h??+7p%05K5>o-2tDpR!QdMDau~ViSayjDbbL#pVE`m7!4Gu-v4};Yg#o!~} z^n|2{^n{AdI|$0{k;o?8`A1h&Ud%o}u?|;eI4Q(fweDW`I<;(7lKfR8aXmlO|9W&2 z8u=0xqM7?G{=puAcl!Rd5XJtR*8~w8ob-3l1ZnLX#_#kK#IEeUc~0Sq){3bEhXKn}%W)}RuR z0cp6yLyyZ9;Q59h5#WcvZlf2eV^oG@SBYJULh=pX67feRnk90eyL_$!u%7Cp_eqG3 z`P^ek2U*mtMI}oL!)di5A+T-_0L{ebjRJ^bYZ7>%RZdA$;pPwtz+e?;CPN9KYaB z&T~{E9BSXtb$MnqDP+YCrE^YKcwV%8zXLsFR|&{bdNHA~D6}P+X<*_EJzT2_bys%K zX>;z}KHgO!Vgl4F&Ws*`Y}kRD-XlPBG5+Jp;oWOmkHF&{81Q<$mFe|V6YX8DnPoYd-OjNzquiCVe983v6=b%uHbXVU_a>Il^QU!RdTW@*)%=kJHdJ)B#f?v{p~jY8esLosqe%?8 z+E%a&@YGFX6nM*3dd71}88?kSDe6tfT{%m34#j=n9q9VF$jUTkumTa~ViVo7%&8Sm z^Viw;)iGt1?8&=+l!t;B3RwRJyTd^NIQ?2ZO`7ufk|NZ`nRc~b?sSF#K8fX%vfJr* zkB-UX$-HEHAakC}jh&GV*TH0?VRQ)~wI&mlW`5Th?JC(5F;yNGS2OdIR28|CCQI;o z1FCb_RN;k1lu9UXIdix}WYg@r=34VUaQp3K!o81?wyzF|?mjNZM=o{wCpE)X;jf$* zioQwtD1LmapH!E^|83Zf#pMZauBIohK-nK>XB0v4_8ohYtEdkO;kBS8LOz9e3E0p> zBtjGQo7BT3qQ5-9baTDo<@F#Z=fjE42!>To^x4~JyEehQvgnwuzsB&0Km zjVUzWcV?T?Rw1mgCB^uAa7$H)xFp)oS#&g(biZsacRJN(kAK4zGe7#m>xoa^jvlQQ zC|2G@sk#wUa^9{Sv7nxa_}Y)hm(dlQ-L*P<5Rko!(|3#whQcE>)_G;TV`)S)wO4`G|WYmnsA+Hh6 zlTocbpmgifBpUK`6<`z`YQIp8Ab8^_)yBvG5}(uY-DH zTFwlMeS*lE3bE-VwSuNrezU*zpJ3CR{D3As`u;UvD_^%_)*iro(?fPOxGQW)*ny}5Gs;fC?}6En@y=TPE}XmbSyDk# zL7~rUe?%wod;zr`3#hsJ0~VLmzBJe>No1FJ)9tz>(Q;DjaIlgEjs^XY*S(&6>=|7L zuFITygHOS#yE6!wRICAuBEo|*D$Pk;CtbSv`^Fq@m+AMP?kJWa(}wl7~#4RPgb(`jg1HC!8ivM=Td;Iz5&?WztweM#0e zhR&d5(%EDsGF}_}9i|(pqHa@~kWA6>w@Go?-$-4*4N20ax+*d9jvuM`eXq<4k=RwG zlfm;6=COm#b%{P*{*S?5n4fZ1uSd629ap6hFAZNmo~KhCSpC2 z6LSpiS%k;qO(WSdoc}%7NO3E-^~hl(OScDp={l1(sW)-eFSqfE@_21+`c${aXfNuz7oiVlp^&PS`>qm#}hE0~4Mj{ny;QCW~R{sr6>&W!;kb zMad{YsO*_h92*n#BZxj;%(cR3`U}OC>+ly*=`9%?)-8qMjTK{p4{?CAqA+?+;c009 zoC<1y&d@%UG%$r+qN~bEf1){J)=a}fBSC3=V_Pr%uVPa7SB-{0P->0D;T+zo&f}7h zEkj`~;`BdImfh;eRgH-yYIpjEY;JNLW#rohJa)SwI(PoQv=?F{d8@x$`n&S9Q(d_; z`h85b2FIDXsYvX9OA6&jTstMGisYp-JHJpJ7y?TkWpBe%_0ow{ZN=9CLt#dte36+#TK#Sq9ezceoV2q;OgD2vDq1g{h7Gk2Gu@Qpy_=hjO&N z6o+!E{xZ(F6bGvTl!W+ER4mS=xLcKFyz!w;R2=;o!zV3K(+=_Px{-7?f^MK8O@-Ak z`-crC#JYeO5~Vp*QS^u6(N?Lk)5>bPA{2XJ!(G+X6rTMWmMc(l=8qCG6~!?Qgi$)1 zAL%M_btVw$^OEgrg#oPqdbYBM5q4GKVh=P8Le|%HbmCQkM0 zSWStMjk|r*W`gPYX*S3yiUmkc8VUvMPK&=5{2#Xik5VYBlf)_wf|JDvt_JkTbsFnO zxvW2wuj}vr>Lq3MZ=o=9J!zUb^7OpvJRCf4j&7hW$*7|c<|Lsx z2pz9Qrv93dh0W5nnazMi1)oZ1b;zX?JIxaZiXG8!4iHM%17{XBVy>Bp>If~T->O*H zh)fw*E>fw8awCDDelsau=2m5;j$HKi#Ps&8^!C;9-F9Bj^eUfY)zb%yYfY3j)c@(H zw)|-`9M`b^tYPy6R;#$Ziyr zdRGy`)AOz>EeFSykNSmaHoS*QPfi;xD>w06 z2$`sAPRqR2HJdy7TI1wC+-^r#g%XHGGp~wQa9pdqGbG?zxnF-eg*IrX2PrXvs zlq7Hx_(MS|ICYO0oNP5(-^aBZXp&)9elG@E;~a0DZk@hsyQjI5*z&AtTUc!zI5yI; zdg^SQJvP`*T^X_NGd7W}DY&4iiFT{8Yg(8)w$L)W0oiaYCI^h__hpW@j0Q&@jfjni zMYiu6IiyUkrRnnTk>HFdEZIM1Ex2o28@j=gIo8yEN zW3e119m*CWD8nsMpTq{`^BMaGUnda+-;kei>_K-K-kV$bw2}-Y5s9bq~8hv@7oT6NLguVd;sr`fK&17TE&nf;lyX zNDM^{b2X@XYWW>q=rJoK>Nx6{9TIvReasO~8BBq1@?%?kJEVz6;X@IdBxV0`NK?Ox zbH2LuT&+clSxde4+_ZDlikd`A@-xZ7BBaiTo@8NfF>$cZS*)doccs0vT{go|Ku_Rv z%Tn|_o{_9aHJ|#bk${P8eA@}l3C+&vjpO5odqR(TKFynky?KZ2Hy#;$va8m>N{nr? zo2468w}$8T=NM88A4?yKvj%~hxj~c@EN4NPx>#ogetnxNNP_HQud{?q!|j5yeg3HnbVER#}rT zC!^}HQ2mgLUUF2~q0F-G8)MyJ5&j|Q=yRP$S%Zvf>a_P!!{Hxp^Ey>!3C%gqvh-OM z!oAOX?~mN~=Ee?GT=p#YEK7nNGNxt^57N%G^j7w@wzZ6)&M(_q`cS(?u9MPs8I*z? zr*Mb5sfFg5rq!lZ;`M9i2aN_E7tVlEo^;$XREs3g;s>jho#m}%@X87AF|R?SBQ+;p z8OxXvxY{WiG?Q$;awO$oqH)UwSxT0eXJaTG? zUg~%6ZtFb(<2N=mHK^M(AuKPIHLUoZeml~3N#YsNIF7OvQnf&NFfc%H{k^&$6Yx0T@I8+D1UgQ1iB9mhdy=l z%(Q$~*mt_H4kf*@zCvDcIGO1BH4D^dV5UYcH4G);=CHXTHx$) z=3o=KvJmcJ*V59kDml;L`s2)^CGj@0VeTc|rGv*3=PJrw`GyuqhIccc^Z|78XrMAu ze-_PEmGmrEYQnITK{On?Gaub=Z-{k5V-RV`cydrRTQz%AIzKUsD3azZQDge$B(Vd{}chMBE~MBl~phDdvCcEms|gTOA0yHu(w2f3ao@CB?DdSqXSrn_?qeMVSs%}uGn;9%nagv}Tb1{! zeHF_&Lk@hfXj1{qs)o>7xP+PBv|Sx!l1KqISIKgNU(>mcq7Asboij3Mc+Xe(o(g6? zIC)CS&1CQC!#$Tj;istYHda&D{d$u6ix)U|70F=w?3aA|4&$csIU1HU7 zor7qN0%(7866%B6Yk-?Az<=gZzvS%D`voNV>AXnLD99tWSkm+1Wpio%$y-S&k#u|L zw&o`F8t&Q~D{O3+$&;gbm25R@Wo`CF{!yVV96a*s+#4V(+I>5^R&nKURbHO>)H(SF zKrP}4P1*#t)=@Ruyq;!ya~Vw~s?PylxgdqXtZko-MsIZM4hQs7YIpm)lfb=9jUpCMnf-Vkj>sxUD{J^;mZfoI?#C z&QiB34zHwTCU%W7N_peC`0udUnrz z|3ZG!1Of64>r#P0hsqNmlD_pGv5 zc1`=eFI|V#6e>1QS@4WaKMv&s-J+O2%<(2g9tX+N#Z!P>#h$!!p;HzXw8sf(c)ch- zqaD589_9e9ZYR%9q6?h7CUp=cXe*kJ`P!1mUmjw&Yy|AwQg{f?b53)4_W7F)olf?= zr(gKhEHhq8UL^V!>#xbU74MobdU*=F^9-6e>7SG~NUH=(3HQPx z4T2jL-jf9F8(g!xhw|86`w$4h1A#$EOghWPtLE5myDzrTSQeL!2trv*Le(kAzbfup zvoM|S8nmigtAvD_5YwK2l0 zmh_g2pNLysG(9IgC){;;kLxhC*K#bR_Nvy`*Qw#Ta#wvlccjQFS4bDuUq9%Xb8SBA zneCVgwel;#qk?TkFuVf$6oZ$g`Rm$@7Su7yXEJ|i$KD-+oH162>&l&DvVIVuVIGxY zF^$HXF3)l9C~CpG;=RSToc5KQ`)?@G3TeMxBze@H5itjMT^hG2prBlFeE(>h8!J*X zy-!Bb(08iK%ox*=$?-CR$Igm_M92=j1q)gR<3-^5y|RiTXABVGyHXfB_6#UvN|mELoIdwg$oe2ytIuhXqk8LWRC3nJbo|#X5ULHjHS2uh2in zf*k>b9nlFR;{BqTi{SzKq!^w*%}hi=AgOqDj+%@E6Y?=$bL3ZPeIX(iQ6d&S_4RLF}zT>WqYo={7N?CVizQ;Tdq;t9Fk_kXrxn=b_o0 zVvexU!V3G+j0;N%)@ z#EYo@H3xbQ1b6aPEGF+#xqUz`u~7179@CCn$T_dp_rdr>35mrbXThSI;x=0)l#Eyc zUK-WOdOTT4Hct&!f7x%sQri8X*g?>gG@Ihe3|4l~VU~M{N->SBeAzi&F+RTtvh1W) z?O_EnED4lYYB2p!M!)!zIc*N6V)y<%Q${UjMr}+jah|9=zeZ&K3sFX!+THPo&ON&6 z4+Z4<%NOSGV49M_I4OBWQ)rTV1b1|aS)7#WRPrDud%(L4*$w1zn&%OP8dGSRd(~BBg`Q%3W$LN)l|UEy{HCO=9=id0!NbBN|mtz+)&g-_6Mt zf;lzIhv+Kg@JF^QxdmUvX5`(=mEy0p@`{DYoTSJMuWKcyROrc`+KcgUBjLa5W29CF zO3!yuTk7N0SE6ao|75i6BKV4nYZ|w@*EZ~YJx<sG z0~gM2Ey6;;ofG}FThGHpH{}_gNY(M7?<$mK26EwlKgj&us zCRzok2_3RUvE!;&VNnxsnB2bl`_-eZ;S6oi9?ZazVVN-ToET5V_W2=c3dV}LKLuo%@R~eW)nfkqE;QtER+z@_1kM6nIRds+KA0)aO4+W z4eTybnnri4bRGzB8Zq2uk*753NcsCap%Ckq>$v4Few~r(f-+m&N|(qsYW)F>pbKP1n-b}X-OL^BpN>*?F5x3l6jgBU)`fXQ8HG; zXL<#LNcRed*EunwT7EzKt{4qiI}ccM73Um^|LCw*&@L-C@rXQ>8ui^O{k2jp=TjebubHvD$y6QhHU$K+Kmr|Zd3~^=8>28 zI=p_|Ak3DKRO>hoxLXgnLj`At(bOxv2i%)J9l0I)a(^rFeXJHb9Y$*cHl#cjuXBE| zPunAk`n3HjcgtrhA9w#cK5{xT##G}gjvkWxGeqKNh&XD#sL|mEut`R8%hM#LvAXl1 zQT#%0&j<)aUo$o`eKo{=H8L_%;g*q{49+((dHH@hJ;M7Bb>Egb&P0-%SEzbRqBHK1 zc|USx1BS)2KZ1N#@7m&x)AD{NGj1_%`6(xSAuzb;;s{hLW}K;8|v*MFA)!97y+_e(N}4YaV9DOGaX&)(ozg@PvVI8 zG2*VjP`8^<%&e`H8s1vy*gZKMKECMuQODdwaExiF+|V)E7L2aBaFhj zj^;Nzgk2WGzvkX1Cpr7;x}7-h&tlFdV%>9PyuS8l112Hsbd@R|RgK}gds!A<(pHZj zAzdOdw;CF+rR}m^Wq$itM9~6t1S@582f-w|lTD5gsOr8WcuLIGim(kpA^UP)Q+12P z9`*6B_t{XzFya!|%@q5yMVBvG)h6BX0{1hg!ugO+fH+(A_mdUcy6}r5a>f`8E&bBy za-Y23ccjwY-pV&9)n0B@B^VEr7!{)jG*ExI^~ZEp-Y z5U={ZPgQ4cbzPOOG#CjX0S<#27*N84D^hK&wE;W`e=a0q`O%LRDn=j>0GSjhZQv-% z3~-E?eQq49@IUY%iF1u8N4cEM`TCp_YCeS&PIYTB_-B(mI>{2i2$pebf+6EZcQS1>% z8gPI_`I4oT$wwS zDia{T<3+|%8OK-y`#siR^}m6TwsLfxRcU4K_~?|d=p6XB8Rd=B+&%AN)T`_tk;FrN zPJ54UxC8{t|3ISeryjD6Z)=+d6+$?;L8&GBPKhWu6plv^)0` z4(K;n)=*2!<_JMAo)f9O(TL+{z>kPbu zPunIiOY$7wd(*tm8pe49o1+YRA}c?gyzx277|q}s_jYfA``~_NlF@!|Z?Vjr=&t1l z8*iLn?F(PLLixwn9Q0;GCg+}WN4p*)_JFOK&SP4Y_x`<^)b_|vWl z*>2oK_wTOC^7hDy`R!u<-i5~NT9|nfCT8e89R8)uvT^LZQib&W<@~+lf!}}b!?YuC zFxO-fW38AF^n?ILh_2@E+#6p$z)s+Ghi=Ve&e810UV~|0KSkXV-p8`~xebgHLM9U_ z%bJ?K3-gp-V;NLu`t}|^jr?R2*yP~*xy3xt^bBeChELn-=_S&OeQbswTlsT?@}i4x zxZ!=C=~wsccSXZ|xVG!rKA#;uEw*0*#h1#h`{KpWTDLNedd&d^sio#89&sFTbVTPL z;T+&-iRgO2%x#9wE_NmZQAL5YtTVTw-&)c9>Vg<0~7F;B(M3V&{j+-o2!oJ1dA!EjMLDf+$C{1~Nw<6emClT=A*d{!jm~r>c8vvj^R_r65A!&Nk@#kB# zOqRwCN}nYj>UL`CJm{zJczY(6zN9Sg^f`YzzRACRNM&LyuQixD<7IhKLVy6tB95UA zXb^v&_U)CB*E*!u*VIfOaQ62m(Cc%R)~dZ5`K1IH8s1LtG}yk6<_}mS%jF^Hq#U-N zlzLG7RzmNw%5M*Jb-U}aD?9La!rSep{Z{QaT_yxt z2WBPfM%Qw<<#cQK#Z>Qb5E-Ce&IRq>tmViS(NFUx&uVv%8iWyHkocM8wY;X^h1!`p zz`v?UYX}(IoRp|qQ%}sCQDcM=F7i{47O*VXjQ4*VCbdJQJDuE-Q9Tvgk9oWjFK$-H zue~N+VuA8|Z?)?-L0tFn8k*4#<7XcjAU!}cQ8Yt7rZcb6@M*~JJwW}{EhAm}O$8ou zdCF_G3#w=0eBU_9#@&O)Ysg>H*>`Ez;T^<-%5Iv!1D zwDUoW&$aLa%lsYRmXsHB86=8QufRL=g-LgAZ8GyO$2t9O?a831)md2shncX;VV-;4 zDo3R#7pdQ^qIXRDH-=!< z{;X5^oxdy`dow|~(ic{Px;=Oc&B8OT?Y)Kx{&g4K#KVGXh$7sp=A$1C zCcK#49PB31WPFWpr~)4Ed~55!TyuFTOQ3I(4b*+0pIt8&lKZq_znifeApmh8+%Z(= zHW>e^bgQdJ_L{wri+_~u69I~QJ(;;Z;MnqP$}DR3(ZT5{;^cW|Q6BDisP0Hdk3m{X zqJAuaob&B3psxhDG1($1oaHV3dN`m|cUTcXnX@oe`m~boGIutMVDojK1j=_^izr|i zZ6L$_Hbj@F>T?Pgk9?7Cd$ZkzU0WgWO*^TUZm(gJsH_Smy3wgIf;zP%WqOixZQh1U zL)uz?aN28v$9Z4m@IlH8^LW-wQDiez0O9KcdLNG{u=^I6gOAk2vdsa=Pkx|$ zN(df*T+8)|Rr-ENxLDK7Gtp<<<4Sn)7%rLE^kFdLz&D8yq>DL2_F#D{<6YuXLU3i1dP@3sw)Htk%C z$IEU!Onuv}y!P|`R%#!6mt6S+^?Um~4t+#bcRW#v4F%AKH=RNl0r|SSjbL)E8287B z9e0~9#PVBeCA&6`?_2IR{?SKmXt8-Vxo3f5jeV)i=@zYMGq*@cF)X;FrKOl9==;f>o?4uW@`h) zIVZeS2W<|PgrnwA4qI)Gs|WI{FR>6rtH)tDnJ6{eGLrFhtoHQLbk%J4fs_Z z@gy6wQ`H97qVd>8l!PZs2Eu+^(|wW%;gm;H?CK4U7pGDvmCuedwX6QCVa6yUzxd^1 zGe^r#`iW9i3$MVgm;J&nuja41r~grTD5&W){_5I+PbM{kaxN!Ik!WUxgeTTDb<_nw=WSu+*{^ zBu`<^rM9HB5HBXRB)5<(rZ|kWVTJB$Ih21|NCTf5Hcl?jEsy^)e@VZW5lXoyzj`aA zTGM^Z>R3}-^_i%;sW~-^P}K#r+&Qy|>D8o>+BpaV@mgi0a-%R19fXNa$J*Mpwg_td zM}L)*Hc!$A&6$BbOIJ&xSku!qx%4$JHgm0K;1Z2_S@b@LC$lC$&(G9G>XO_GE_E^)nP!8oB-e zJ?XpTcL6S6uO934x%yJ!MOaFlce^RqMBTF{yS&ba&9)P#27oSpx*2ag;?Gef3G-1ECw6nrr_0uh z0N@W@m>XuZ(n&}aE6J_S;LFAIL5qSe3rNJ1!QH9S-Kh%;!1C?a%F`~7E))jMd6@NA zXjSVchb)S7plsq`L2#@r;lFM4=S*+<`|H$!0`PCy=s;PYWNjc50b$MTCjF+ax~3gk zt0%A9z3b(r)%uPq!YfWYf0U;e{Qbl1IrJ6L+OOXRAsT{zhx_DBdjHIM`N+|6R#KYY ziGG$TzA6yf>f_=1N;^CG)+)p#9g`)9C}9{3zs-VIi49AjLWspAlf$@zlia<6GdKQF z?Yn}tQpMi?3*lIQ-;Xtk#5ajVZ{tj3P3BDFHtV*;rr@^Zae`;YEs3VJGm>M`2->X7fZJ{*{TPz0-g>r*-geV+yV0-WB@r z?iIS?eJea>VwXCwD0w=$TJPqe`$8X#nf_G^>rJgc^gOq=9XQdtlAN)o1Odfut{bf0z zzjoDn;ILpy|0PqI;8`vhy(Yd^NqbQ1n6e|jCb4E<3C;x(jl2AH8OV$uqj+t*<~#cI z{PEd0VSJdvf{Db4^5~Ofbr0f*Ep^bKph}YR*I@zz>fnJ-BOgnuhq8@IERDJB3rWLR zlaTIxoDyNB^m0AP4n+qiX#tcC2DtX6%fyWRgLV=0f9jF?hA&JvknfS>WPjnwwWp{3 zyd>MkF3p2EEKxmZn(#nFgZ8W#@iuXa6ED)2(uJvC3bO0Q?7?wAVyEO9!j}V!Jo`j+ zSGKJy!9(h_3)-hq1l2nkQolV08?uZt()y(?PcBc0uF@~hF4~ZXTymZtjdx_;{p}_8i6((@JZ4YNW;}KePB(6^hOHbf{Bj-LbOZk$f4zh?O2I9(712pI zHnDnX8#3r4G(5aLSLGDg3h%TQw+4%yY(=M9OHj?(=DF0cd~RutGWONC^nK>L=SzUk zxPTQA_|4II>GuRDVVxi#JXm(A60t|=MlxiX*kJgRXFHl@H~mt^Ip-<#3GImb?6*r6 z6DPX)N$hRb&hw@BG&ci4)Iw}KhxRq^iE7A)(INJ}ii8U+NS+pI>@e1o-K4@O zDeq3#CWkSCM!-xH2j>9q&sBvvmZrwROd||G^gQ&;fbvun5lAPKM{3-WEl0?J?p#S5 zcTETD-ZCXh0r_N99wPic1ku3DX!__HN8=z?gu0FrHNx{^^-A8H^+H7xdLO|T;E?Xb zoaB(?G4@!k9^8}x!C0-Yp2jz3#*aw^=NLN{&f)e7T%kHIIZr4jzD`w2W6i(j@Y7$< z7(s>&$*>HtY%T=DvW^a^Z@s0JplYkuUVLPfFVyp3T75z%uxLXdx8Ph=S8eE zB-WUkZy(h@p6ft$W;Mw2u??-JAEzJHKu(R^Y1$QwN+d1c>q?vnDhLXZM*a{KQ~m-J zMG4%*tqY^s5PYz2tQJ?>S(#0j`@dvPs ztAKOT!83cmUSl6<;xco_zQ4FZ-DHNq7hC0q!CnmDdsb z8Ii-`0iX(D&ItV>{rp491F>z<14lwBlVYO&(b1v3rI(`iAa}7%QHh?LrWXmpx%S69 zrt`By?pc}V;AV2;Rb`G!VJIJzFK)TeS{Rr*gQLGtY%P?k*KO)k(2RE%+KgfBT#~7O zMDB#MxKMH`nRX1`0Kr@HJ-#JfKBC1I`rZTku&J?3i)tLWkULWq)~uni=Zb$^BpLP!i03? z8$^uanLO~?ggIn?3HAAXr^3ea#G!g$IG|GRu(~r*?-nna2Y1ba! zVh?->;*dR=zh{Fq&lyC_(6{F%C3;j*%|c{wS?(@I-DL%$IZwC|XbQ+pn}wxI0{wXUL*2m`7+#{J~Io3|(wb zA=dyXfePxG9zA&D_ALe^Ud@%M>U^oAOEK9`tuYJk^{cPXn#9v1_W7B2PghgdubB5i zDKTAgAO)i4C>X>Qd*!pcPVE)zEh8}4^^HNAG)=UF9ox2T+s2OV9qib)v18k|ZR;7^w#_@=dn4|R=!~p7nO$8!Iw}fT zCk24Mk90b#TIDvt-$!<~t)-eun_kLVF`~SBS_wwcqT;0%s|wr{KQL%RhXw?zFVQ8& z#i91p_v{bax_{@tG`S(WS34w<`Y>dRWLx6tGGt>oqf10c+=BNJ5(AuLkm2HmgtIFM zh7#U>2M`S+g2-U5_(I=)vF?4I4!%QRYhf7~9$yFy*@3Qn%Y}&6exn+FmxV-!M2}M7 z#QSH#>1tqzf^5bDSWW72;5bO|CG*^J8;Edj1tWIR2k6XmMnI`hp*G~=dJQ6eT@_0j zFb)B^8+T7=5G-qZxc`_Ps1O;O=(}PgQc^~2ITqR%3 zOM7^#$1kQwbE9MT!3nv+iGr|{WB*8!t0d*#(LZ~8NP|Q7Ahf)?@)EDGT%dY;pzA5-(XFSgZJkV_Kuh z)jL{u^ovX;SF+&^nQR&WSj>SAmq<23b*7w78=Czgu6tZ3Chr$o?Sa~0{57#pCJ94I zN&&jr7}ie}L`E;X-PWI`g}6FXN{370E3^}zu9K!G@-CCc3{l2LjFu}w!vVhTK*t?N z!-2i-KyNUfC5-GCQRYgD_LbdeO!u(sPS5J_V+9b^F+OsDQfudvDfPh_`Esj!=l;rz zNo_W~IvC~H8>LMQ;IdcP8|;#`mb=ujH5zUkjJhT=^`g1m(HjiBCc@8@;cZPS%P7N% zW!YH|13pf-VcHB}Z_C%fvi~nakO!)ceo1qfuCu8`-KxH8Ty7-$R@@eQH z#|%P(qyTNy!vN_V0u0H2=Ko*%8B}V03JI1n9|nE~6+=)-feZOLgb9kzTFklsy;n(a z8VdL0^8x-}YeTU^u;(d_fq$AG| zZ&#A?I921MaW?It=b@(;5B`4!j2{E#(O9uLMPPmwZG;Q+q?#z_YM5PmT{i0Ofl`no zjTmPOQNM*hWoZ!?G+6=Cu8ES>e8gVbR+!mZK}vL(nJ^-t5R_$7vln-ekqC7lh%lrL zWwam#F+xw6(xVM;b|P1Bu-`a|C`=?oX^?r688(?%2I<_8sxA>|L}M5T4;^C0!XAW% z7EQ2PY&oj&Bs~s&)45R070+UpjfAe<6!jI8via3pvLe>a#ZhuQcDn(eXov`(JuLAo z3iT2bY1c^@wa++J9(BM;QGzhUqJlp+*{|%rwTMoPHVd&Xk?2}w0*Nb1b)^5N7dQ*I zXKothDh&Ck_&JRQFNG*W6nKa^vcZQjVM^SJiF111I^MX4?p||J-db6~RRBVMi-jA*FRfzw0lO(IycmOrxeb z<&Bc!#f_cU(yDJ8aFo+5pi#aizoB37^0!Ip{(B)6`-yGsTY3zWRiYx7DoHiTZI}84 z(&nhpHaL!x!f@_r$0Ku>jj#48zY6(e86?$3Ot=uUd`CZGX5>q~6uq*9rRJ(G426mUy6Y-?LT$nF-P)G*;mmQ$l!)?Tmqb zRqzDKKQ|thiEQB7ZA%8s7I5V8O9se4N@Kt3c4Zt50!7N6F&h;ErIKt3c`2E=&LwQH zoCC$YHA9XC671;td9>zlFM%j*jxFm!X%7S_hwop^j zG4_b0E2#081=k#PVUr|IEIWy{$Xak?OnA3kV(KR$*=!4%1;w32oIGKcIQNK#e^?=5 zFtHf%5Mk48OdjE_8Gpj3HCiDUa!o?`LSS=UfKFle*R4|4>({kLYz!-=Md~*G3#zv# zCDe40Bu#7$%-Y8(G55-)W;8&%9YJ*^WoJt{NA!Q+_@9NnvY5+8JocQarvOh^H z;PVfU5|^5y|AEjQksQ2NsKwV;xiaXsGx?lVVVnOY4Cp!w2o(N>Sd!@J*#s~e^ zbti}g+Z=b{KS}La7s5;Naxrey7v80vhVBokLKc6(roV?7wv_-tBM)gT05y66gz9NT z;p-i3n1oFCsYGM*ePlbrx1~R^*LHIOb)IwfmTz$z0Z*Oj%VEKGATc`eao?;K&bPzJ znPA0}_z)~wz>4PLd*5tVu#jljbih*PUCp{lf!a8TIS)Eh3mrJ~H#%6RDmp}_axze+ z{!-mvnwmpAQ{OV$MQzRxMGK$B>D>`&2=&W42C50dN%*6bl*j6|fff%5H~~%W%JS*% z@=68OECGUEmZD%)i3`gKa71_zo7@lZaa(#E=nXYfh%0Iws10@Y;xovaLuVifBH!+X z-_9F8wUc1HTI}#{`LY$<)0bP&8Fh{MXNjLqtE4+^^<{c7Q%YxL+}ec6Q-qmfoDij` z2OuI7N1!AVdLYAzbimD2+Ir5(%Xe?k$P;Q7j#j%x{BWMlR#n4RbkY=-%o5io+E%Bm za&(e3>p+vV>y>32ds#;<5RBbU#ps4I)LB(xXb+U@=z|;ex>~3$o@U^TMNZY|>N71? z1iL~8{D%-Jcwq1}JixTHJaD+GF7#pWB_~X~{NQ|@_4 zmcZB5Y5d-{X`LNmGyNSSGk&`=N5;cYi`CBRpX5uvr+=$jtPM`Ns}%a6%?uIMd0@IK zV3xQfEWE8mq&fbAS`Emw%wXaMq4j-;mq3tE(QoF#QLpShfZ2yS*0YbQDYa|ky!Eb0 z6YQGwTlB&uvG`}un1QyaPJ>;Q>p*U(w`t&vTQ0icb856T4x2e9|D;u3UzrnG8-<8g zs|Lz0)sY*$FQHksAbDL%A8Upx8ex6)cTB=zYZImAQ)8KmX$~)s1^N zRpPIA;9xASM_(zvLu9PGOJxsPE>DBv4g5%)yHBqmZM!37th$3`Y(Pf0sY$cWxMKXf zFYV#RdE`OM=4h?JMVqcRw~R7fXTp4_4Rp^}*V~uvw!^4^TsxBhf_o^n%&J#mY8XC{ zpxUtVlvyR8p`x^VS|(RN zMa!mQtB_IiEcS%4w#21clOa3jRamSnSW5myi^B&1Zm~N^PXE{Z80}>3J_Zlq?H7A= zx2ah*T0a<_Q%kyd>MXC?drik9Ys&t^)?uxU$Jf+E7Fv7kpPkhA!34nGkpg(^U;)T? z+yQFVm*xd#6f=9P1yzU6mVd2z@Z8tH*YPEMt?y6l6gCxVgO9_SSJjR&ORXF5>|tkJ z{zX6HQt+Zpj(AT0?XVib8))(_NEmJ)ERITP@@`g+Ho7$EvpHt%PwUkhCvcbs$9J3t z%XXswm2FQCp6yD%2!E%w)F#i<*W%H# z@@GWjvQgK?=3w+b_;#9ZOR?iDH8+b!*5Qh9<1@i4q5(biiuc!~13u`JQ})92t=1Oa z6Xb|!jd_fN>@9V$`!q}M*Ytg_|DpI!tV5)F-3V8)rwB|a3VKSYr|UWju7W!WjLf(; z;xO{CC&?w$q0}hPgtDLU#JoSsctb1Rp(PAO@^jE1Y4_~s*sg+oE?e2%hr6%dl5q$R zZW*b8KLkg%E|2V_HqAFs9PgKB5`?%2I**W&qdiSSyEBdh)I9d+#`1UTTR~dIq$&%n;CtYq_7l5f{BJIPbkw4;?6dgl>OG08t=^gM2?=) z7DsXkbrr<-*1gVGmnr)to>p@|8eq;ayV44hnJekXAqV-rNCxcFaUcO;jvF$xfA)XW z@u(cyJU~a<-d@b?^r3Sgyidi_E&b5dS;yEUBllV27%I%mEh%%7bX*9Ju=N4?Sk-Y_ z;{tG zwO#3K7w>gnb$_Va9WMhehF-7wf(HBonVPGH1~!7bvxa^WV|4Qk6>Pxk>(&kE?(!(< z>^{9jV|Z@xZ&L}B&>?On^zD7{MrcUa0r=oHlH81MO`c_USf8zGIen}$=_s8*BhA_| z)Ef3yuZ9*KZgrmL{x-Q0F<7v)tE*&D>s{#S;_aH*JaJt)t7=E4v~%p?QbcQY_IDMX zNeV@IN-VDKEnaP&cqewCzZ+(~Bia?brzR_Q4tXQvTGhS74mS*V__o^gb^0iW@K+UNPli)FY zAuA$5EE~@gHVwrMaiWm7Us&TQFP81tC=oC3GKQr?2pY!};)kR<5Q&!IFBGrh)5b69 z+Fv>Iq>$t;D~=*22-ZL)p4+k@r_AviMcJF%(j=$Nf!0jre}yfif5jclWVr(iqr2^# zETdu})IZC*ri?A=ZD(T1NDaJ0yU7N-W8)Mc-9FK+JsNANm59B5pl6miJiO|dgnHGx zhIW+pndunMyv^GRo#e_Ps+@1ls%>dnOhIR7#_+=G9R}8SSt(>DavV#+m^LZ)3f{#% zis+!v1nAr+1w}4k=8D`T`7;peg|zv*Yd_9T(&>w}CbsQYz^AZGtgJIXdujKb16u~u z@KnE?4J1v1E-%{2jR@rw@q~(XAK678r6{~;b;wornGMwi#lX@1@a;jpJLOP3#7^CS zwX>{R=|g6F4qyy@O+es|9=(DS^~`WAWLePM<3)QyHxIhf>P#fRisxD*$~>6XqIJ(^ z)3mzof;X>m6f;{ttGZO!;+~Z~%lTmd<>1&D(M_}LqF?-EL9lADW!~s(ek&f}wS1fk z$#UE1XD&12n0Pzt=c_!(2xWt}bK@))=i$7xP@i{G*;na*w=X{mLWp(3Y$5UrDjd;_ zvCY#S0r!gB6lV`AK*CLXXl(es9pM501+UZ!<0bS$YPxwN)x6zOK8&_IuLa$8vf2m# zh9A&FcwDGYu}UPioCUyFi$eS@sDs2mfv+t47Ztclx^Q6>86I^uuVNwBDpMnM{%NP{&CVD=O%S*Zuu+rRAb( z@4``sfX3C>dz!ep`%b*6O0Z4|t(#mb=H$#KQts3g0zPDr!ZsMOOV4hC_}*Tq!JT;9 zyXapnNGrp;f)-E_+MZvhb8D{dTPesp%LZAISD-7B=X0yFysL5h4$%=EEWDRi9k)V$ ztFvrw)!>$ANvj5i@5t*U+quAobc#~aPHwC{NTWMn$L;KV^QE$EWv8V$>EX{ zeu-%7JT>AH;o6RFfah9b$%GWj;951fHsq;WVfU4LZg>zC6wr=IhZQiKN>~IY$CQ$Y zG#N#uKw%7*dsw&G{U ztAT}s7#YY`7pNpw%kCms4$nULD-Sir%a?Ek6};4MPVrk zuHU+I55|Qw+lP5nM0!a&p6nzDEunqb{g>q=R9Ty4QHxe7)VQLrrJd_VkO|yVFE@-h zp^LOpAQPP$7ok+&XP$99g&QF&1z5m99g7mB8>x%DE`s#z&g}|VnSdL!3)Bc#9hC*6 z8}`ydZGE&Z(J7k+r5k!Dcx7&%z94po|GZ6oar9=tLipxyCwzsv z#=zA?GI=1!BHDR(XJMmaD{dzo2|J!nfD?L&+rQNYWx1lZ9bISLwi?lNge`=BQZRiI zvBLZZv{$ngmXqFpq%6Rq_nuS}oGQ|#X*}8c$B~v|-p`5_`A%!)gH#XrBOmM()XbOi z))QdL>=lH}rw!MXaVub^qtF93)R#CNGOs-aOv0V=?%AnZI?!&5KNiL%=Jn=}zO^>d1gQnr_#SP@631An9tzjdsY zc-}>mN=M>M%H|rBl(Ctnli|QqA9${qOw3b-Hoke4fm^c?)95IF_&bQa%+H;9Z*EB~ zRvcCS>6}E!Icw&KVOReBocOr4!N>6c#C5BO#38)nWE(4OkN$n#vjQp- zyA4YK�}!hsYtgs!YJrDxWcDB{KG zyQtJ3aHk+P|DyAqG()JL3oF4AZ@C}&xtzcHLH_;E9KUDPmqu$;{qTzu zxCf(ZXX*=L_OFiwkXXwd4`_%v-!{Hvq?Q|ZEN~g(Xtb$$8BHvP)=rY3VPhHsxHPdL zKQ3it^PRVUL}?NMq>6;*mw|z$${qsPSpoi+c`q{D&g;LB7nCJI*6|!@R*Co54In#y zUvh(g@a2vpIWV=eL|?*!XIMK7V7#*fA1Z`Er%8g89#K8uEzvg|AfLOkmfk>W8Xr}? zh=r~op#=pW4m%o7Q9T%#{tx~=)Z8`_{P) z18#0>2G~h)vr97nwv)`RN%x|bH9e%%7?sruP?%YF$~H){7I3wEm^0;zA6AN!{7q!H z7002iP8kf{I_#Idner~@6sGpSRa<|~rdzaK|A-T;t?F`lI=fh?f9Vx$4nRC(S50;F z@~ne)NIwhHwp4U>4B@Y-wsFkkZ>lzMjBNE(xY%}k+o=z15m$SuD_=v)KPQ)0_`J_l zCwCn_4RowMsqLNov4x9PdRp4kP3(dzABw|^`dpJAN?5WNTBjl80rkwd7;$kHji~e8 zUJqE_@m#NEzq(X(4TTigXo;a5P!tFsyeQ~+xvJ2ar8j$4wSEq{s8|`vtnT7Iao>D^^HK@a6hMJ}g{2p)#MapTM4gZAP}UKIGHu zK0|v*J*U&dbX88wcKPegqMdAs*PKN-6NuEDc2~W#d+-(UAMz!3<=G6RC{BX|z!}Cj zZxY}HgxtvyACQ#0%a9H;(q*kjjXbs+F}xQa{7*+Ht=g@$gts~9GSp_-%%^gQ_+GCe z$bT-M0(S+Z&qkJlIp`9V z^BXm|$DVobnY?VdOf90ofr$-aF?jLq+l1{|mHS;+yVMU%Bh;`s6z#;!NVPq|EjNaONv{x%{p1ZTwg9yXCE? zfS+*N7=Pgh7WbABsOgdVZ2D^cN?9=cta<3kk3RD)_{KOB*l#&0-N(_}yrF*7=lHN1 zAo)93+ove0%hqY^7TRw1l4^+Zh%;aYr@CN!i-Esz4Xe+(aP|V2gffW`3yC{0Snp=zy^m4bxP_gIv_km5v8Xj<4^{4RfX zUS@m#MczdD$kIMvrZ1V~gi^M(0NP%(&?Eg>k=VFkTZAv~PW9MPRzOv=_g#^G=W&Lh z1SmQvjxPBkB}3>zNK{IEiz#!Y%22K;*^)1l{rq#*Q`l)q%bYD`!T$9Y+@j=T^Hz1* z;_=ay8T3XdC*uBMxnEVnh6!9$DtT7g!*JX5c&%GOmyj7xds*E>^(a}VRc4{cO_P;E zzZ5N#QiOF{?xfpJwaISFiXr(v72&kA8RF`0p}|dzmm)7+G6i3B{SE$m z;ktC22+!P!TiW09Cv@g_+*L>WHL>(F-{$kqn#Jbx?}#gjc7i;(138tztCIE{Vv<+n z3$RUqllrXq9sFNx_xA^~O@On21o_?8=|sE!sSnta|2FNEWS&y#pfB83tdXGR!9?9f zVr3%j0|nJ8)hcCZC)Jy{w7oQwM}ikxa*9%x(!aYg4g=dFE2&oyYC`=X)Oc5Re&|bu z0_M@tUDWUtMa521`Ed0?%RRW;WH$*N^y_d0QqrviSf%ttqCY4HQo%~$t+Yu}Xi80u zs^uxPN(~Ftnq+G6q%o+m!b&PmK#FW}+l&&h$2>W}b_6ywDghO)&C$Va{yot`- z+_?3|Ed?V;ju)Zak+=}J1JNYW`!l|0U{c0#A5(8MCbIQHN{aMh_-J{qGvF%F@e%w` zMxv^O47q<}|CNFth^a(wk=dr$f-d!K>vl(dfi&eiEx^YEcZw9KBO%0xcS@4$>s*m< zYq=zFjFV78yqthOfWM)SW}FE4ALM-p$mho7UI%mriwi-|AP8-Ve}fhxenK7;ocQL; z%yd)58r^Nz3WOZZ2;?C@^ax4M3IuwAe1e#uv`6~DS@*Sugkp{_9 z1e{UA3UPBd9x(&AnC1rEQy7zdkDDMadQ8}ekbFeRP{W@4ZN8gkCQ?nr@=(T}wY^j) z%@ziMly|(|8fB4;rc$*EA(~7^;gnKRBUqt4vkXsR7U3l_9aOxGQeiGCI94pYbm)yQ z;^s_UAH4jHWwFcMGuqat>-@ENY)W`?2@0KWu=#6+=mbl6a*uc;Z=|_9`|KTV{-G@* z9e_+LTcYuUM0DalJQ)L#&Nsu{ooMzh2APh5SnCV^r<7+Ai=2N>K+&!z?c|Lz`>24d z%RtipMU{V^L*D*{HRFs|PWbkznZNz*?~yPL+BK4{E64ioDB55-`izuAvDO)Eevc8x zZcDcIAvSZwX8^jX!m$GMCA}vjnsFY^&Y|cl^+~n@x@5uf%AX%+-Vki=h{6Wv(HWSY zXF8MePoK#Lj15QoU)2eXc*ksX&$9fr)OD!4bYPt?((fymnGOd*vRrV*ibFP_bRarE z_RJDrv6YKzL^EFj$uus2YTmdmot3>U+HuaWX_T{#$2|~(Sw}n(#tyo@@oNZrk_$Ty z7@p0ly))yToM4w0Rj-p~X>Nd=ze_{>?Q>uvle-N}fOb6dX8ewWCnTz?;5hJsXXZiY zXai}I#}%}Yt0ZJcfzqpSYz__I^H1v39+i981rK~FIK3{$9eh&G6MSU&HUt?t>Km@B zjD~(>DCd_FDc05js07X1R@Wz)qfUUUVC%8o&vuf| zIMlBHJJAoBB{xXmNZ77YqVmhi=|dK3RW>}+lrb_3Z<^&UG_~2FmBMtx4m8cNB%XV= zSAeiWoW>rNH^`styAs9SGB1$D?DXSdHH9jTYYR7MbcKYK3k!GXs_bS8zxPkvSd(k< zxW}9P1N&;2R`ScIVi~?ITBYgzxEvT@fDO~ZsXKIQH>N=khkBHU5diemuSM|U`9i^9 z#*q-%%Nx^fP+N97#*;&eqAO#F2*7A@jV)QyrF!sDdpz1enDuBAH|=?zUAmuo{DOjc zo9PApvK6VjvETc!(CKn|0=BM2Iqzg(7(F$Mw zBy({VOA-14H{-heyBF$ESSLrfWCs$^w_Mb*mFu*PlZ@~Fj_Yv^^u!STZ!3_K;CU+U zitk|b4u9z5Z1gd^m-m$NCffnk6JS8FvvR-}+LrZz^{`pD>Pa*Wh^D?K8$rKDy=p0# z_5_Ow9=PcGIqqMUsvYngsGIkkn7!)S&+VFk@ACxg-tpT}GWYMxcp>7;V2Vf}eiR-7 za1Cz+);M|IapTSz?Ryeq$$5#ujDGoYc zcoXhY-wm(A^}%x_-dv>V2i>Dtb_Oa`41E8MJVT|b_C$T6-HzO3wlWM$fXoogwXpFg z^TOW_N5a2vl*mKgiLNFooBfrZ|age`{Q+O2~QS964fCxZ3%6bvJh>Rq9;s&13 zJvm~ikaEK8v=XPp?z6Q`+KW^ZzV;GCYdbXUM|UpP(Ju2`jiJZKSYy5;TeTQStYqUN z9GFtXYcpYR!PO_Nh;6{L>XEjCJsM;?76WrwunQl-xWQ}_9QT%3S^m={dm-EMDFwYR zW)U&H&E#qLLuD^OkMMLfnZP$K%;mR!NgF3J&CDguiTe!kwo@7Vp0#*K*mkY?QP4Ee zrn-OI`fntD+}xVnTX$e2{L278dVe7Mk;v<;ayc3uV6jp1Yw6B}S>4Dd%F%?GLReD? zfj+RN50f*a%XAs*F#bG~IoRJAhj*K_x-D0S$h}u{S~F+NS*i^^MqfvH9L`K7n~)dW zKJ+}oA#xD4*JAp&`z%)c$Uc+*dAdWW9rn{Vr%kVptBB?>|C+N*+i`mVubuoTg6@RR zLHjXBEB?#;#%Rti`%A;7#TPGff`ymV)lgj;I!9b81%AO!dn5M^n`_8VFbbKCI&pL4 zh~YE7Bcl*+$gB~94o39I#_AU`?se<^$DiAGDfbhESFGX46{v?P-IE$ZcTSrqkw}!B z-Zc%y$j@v)_G-)h_Fs0i=p$>b^!No;C>d=sD!eT019j>SAHl}eZW~Fc#=Fh&p7vPQ zvf1@?wE|`pybp=Gnui0om=j~;Bbo8M0d16e)2DF~b$UFYcbKy!oCrJ2D@TIgqjmb( zPVnRN2VRod&iKj4jPaLK?y}hAjwOhCu2ozg&WVL}&(_e+He64CSg z#v9;ua-7FrY18id^8H_o5OgnhP|LJ$5t%gIO2_3jxbNAVcD}dRkt+lbtFJTat7Z3# zvF-i>-2b|@<`k;DO2(FF(oQYUCU2XZj^5W8e?tFWxw&P$z0BGGtD2_?b>AfXi1#Ri zzp~i6H?x|$@h3;J;JPt28~hk9tnMzat#0v7tnT6VZ_h4n@JF5!->Z=Yy;lGRn^(Mh9nm9Q_pR5a$5PwY zm1bEb-ZDW02KYRHx2t%|WAA4vJPhv`#uQgQwTCR0@!{zTX^&%PvWolS_;q(}suLZh z2%c-|jGGsiEp>Jj{DDv3LY3VDnHsCUx1F`pg|<1g1{#^w-EmbH@&^bbJ6zvZ=tLLw zI^hm>Dv+^d&gCXe`?hk_;7Nj&aLY(!r$s8m6wOnalfPbgh|j<6uGaEkcbKcQ#)UFN zox+%hWCI~TZ#gJ^1$%@vg-lPwI=39Sv+PE=J> zyJqgDa91|exAllDiXj_vM#ToakL-Mu;{^eik{(Mrj;kQeshfi~rWGr6R(J)GFo}!}JS$mNJjN=)MVkK3 zLR`U(h%JyQgUdJfJ5X*p-$e(`$h7lG^n)>aVi!54w1vEDQ4WBezUCIqZ7w~~T2 zBv7QG7a`q3E+X5c9eD&q9eJ-N91nE$IB)E$aCHBJ$U5?_V>f4vejuiL94%oN5dnD@ z5t+WD;#qQ5&^xLh?58du_ah=MA~Z7$GYqq4v){mF#Gd)S(odoS5^IC^+H#5UnbEmfD!)d6elrnEfCSt0KzJbGbDs}{ ze4+%!F|#BOlySoCLG%SQCx3~xrL+{Z39XB@EojgyIoe|ax4eYsGhpw$Dw()b3tR;~ zYpYKTKPH5JG-gVk)nn zmeegaGe^lvi>+{ik2{Z%Af|ti2v-T%SiU1*@{qJd=Br;3 zo)m9?vM`)G1t*WR$=9xBY;($>mIb~H%7kwZq$=i#Ka+xN7;Bcihq9k@&{>#mnHq@l z^I=gHbv;j`lf_$N8jg|(SoMDlT!k{bENm%)oq{YB139hGLRm`GWR{tK;(F(u4FO|* zi!>=r!NgdR$BNPqu1f!HMIwtRzB(9`=j}ZSbW)$h1^I?=06)upM0s*&AVJ_5P#ts( z@0Tr_cR_Uo>p1-s+t#aNRGd4c@ePqiQ<$QbS~t;5=?EvSk%}`(R|=y|cZx(+wg#QO zSz49W270LyVP4;hh@c{F@lb)ZKD=UXE;&YRgY%H zHmcT)U#Y4@m)ul4bzpHr+PsMVr)q^@pab7=OY4J*N_anE_w z#}@6HbU>GboN>jIC%KmUQ3IP*9jq${o&9by6RP__mQAWN*WvigbG3J*5jKa1YO{sc z`Yw;*?FKfGnqzrvv=8LxcwMm{X2aiyvks>RSa<|Q{%i=mM_5mGkI(nQqCAB%3f#}+ zXw9Su2~lABgNgq_VH_gm8Ki?sYqnZ<8$n$rJ%D^&sTMLbXbd9GQ=v4I2$IeNXGLWh zp{~Wk&q8`{_12*?#5t&eY*NHH;>qtTEF5Rf?NeN?oH4*bPPZx$jKn=ffx~5d`UOC2Cq3Z!auUF7tocJq@%Z(!d z!C1WT9t}n?H(*{&J>lDv>bKe_@Gkf<9oA9R2j^}L*1_9-*CrS*F16V{gqZ#={rAUx z0$WEdeqb4X4ct2sk?JpmSp%W3{62mH<}kD3Ux>bm0)`of3b$rI{3GE#Kuzf{G9QW7 z@PD(9YXmc7XOb;H;J(m(L-miYg>XvpYznNwr1@(}I{KDu6+oNEfVAuVwoC^2igIa^ zo_J@r$vpF{6B&+@TggoQIxI5Gem1wCm_3Q20;ly1YnpBUlw3Z#ME)=V|7}^*^yJ$F zk_gvr^1J}1#M^^t#qwO(QkZxWdXN3A{lpY7ATTsXmh;|=p_vrOMI(>VIj9Pu{n$3C zBnf+KhySA$6PWpn3(f)kp!3m-ChRf)aqr#n8lcG#IH_SKxuqI=PRMypK5C8FYI}S) z{pTEcRF_6?;7k^M-o;IvTXUAMK7Tf@NftWX{n3Q3!N1Z7mh?!DtOAonbEs2Ljh-Ps zNd`OIU5@m~J8iJ@)MV-oTC=J%qST3dQ|e80i>J{>JaG|rgqrherbo%QU+bCI+}v-U zsy7Xxj|&aXn)-}^mx3O+c&QH!4UQSNhK~T-W5-QofDX=8rIVuuA14G@V#f>1?%IMi zGiX21tYDXRhj$^86%)upA>hFpZfim#@WL1D4k-9M*Cfk>X?!Vn@72KH-nRz3_EAK! zrr$ws$TRs^lqJ_0PeWD1U~9`b2LU~G{h1UF9}XBTndhwTmK@g%m`L!!LPHQ@>)e-} z_PLQ8oDCKjzNW9vnXw+c;2Sy$czC(*mw^MGY)#+AecmoR?s4TH{}Pyvr3T2x;y4{I z1v)Uzxq*DeJrb^Z4#N6_o!1K{T>FS*qSSJ?sD4YT=eWC2;hud2hQ06^6Z6stWBxJSHWpK=oMydl*YBF12_R zERQI6mG|x!O5VgBL)O?GUFJR!7P@0|0Os8YKJ3R9?j`YdHh7hf6Y5KSO{CxH2gWEG z^8MJ~={G6g=mKeG-g6kq8U*jXq`oOTw0`atF28#IG@G-7e;9)2n1BJ3E|oo*fD0HumFk$lo4e$#3T0x{+3b2S0+4(n)+KYswO_t|K~y(YvALifrvzC) zT3p8bb=>-X@lnFRn1byd<1K7nhvgrO@}B7&mTE=V37jlg^9JnYHt}}rrMYD+@9qz> z?HhYhF7rhy+~*7`^QKKE9ZKP*4Tct4b*mLC;ek%ht_%4#r&T6&KU()?=un)jJjD*@*mvVD8a23W9Jo&w6w+70&kdK3rxfa1y1T(aP#C3h zBJBI@wcoJKlwAf&JwIE1mMM-z4(iObT#9JvIU}Df_pNEnw8J;r>*6evAxiiEw~+hP zHfmrxPqy zS*o!H)L2?c*9%ZCujH?3lf0Y^!vod4WphFjWT}imJ-5w5#WuC)5&Y|D^7(s+V<@+b z33>s6TZ>Hp7ZbNPoo*$qtLL;NP-pud{R3 zjGH!I$uL=y7s*TX@VlSHU)Zo$f$1sq8{p)B)OOy306!b;xkdXHLD;`zs*jUOxzQxq z5;Aoz)(L7Orb!cYh$LEs{EY@z{%(^X_Nicd)G&j}=vsLCk-4{+58Hcl(Glec=wZRM zh@hIi5*pz6=LknOxCk1A==FlMCS2u*mYJ6RZoLlDRRrtdV8f#zOn!&L@zul2!1e@S z$H_8(u_hAJL$`!~gu8s;p(!klqX?K@LEm7d{5-Fl(i(E9~$0`Ee?Mw1J#~ z8nj~UL*ID!<`Wa}jR7(|Ax$$|EX&FJsx7v=WPlAfBX(o8W^G z6T(Fpj&}(ODvF|F;Sd@85*6i!1rf)NTQMMEW|K3H0!9N)1CeHtB2i|Ebiy{z1r8Mc zRX8?P@wsUKS^fR!QDv)fURC-2r@?Z$x?H#8ER*~Bh*`PE^n983Q>#*c;(OMB&5a!>5bN{-+nA7rqrXJh%D4e2O+l zQ$$frQL-#=o4Q5YrTP|liZ@rFRQyIQ#G-#Bu9{;E-aJMR3Vl4g+aSrv1>bx%51`mK*r z{-s^C%^bho>+cNJjC)I|iDhvl) zNjdlr^$k(EH7ChO=U)PRJRd2se$8E|a&0$hw{j2GOq8u$j}VytjD^9Q=^HV&G+TX* zr*C@zZAE_4*sUnTM>9oBf;3+Tm|`SogjJ#zyF4S8yu9L$Fkf~ zhfV#KbHZbF1}|N07Sc-O)fB;}r_GJ0;f>Z?0sDP`uW#vD(dC@L`y6~pmLyM+@AQDO zh1gpO=cTEr*oP$7eL^#h5|a{{5{Z(s<@sOlf0Fx>_l?SNOK~n9a`n{n5s&Q`$nN5R z#Y?aGkUbuDt8U`~sFEP%L>wD}tK3ezW4m_fTW_4he(!!w|KV&BY_}%v#aj%vEMyG!ta7v>!ZHcgCwj;5&khBzCMY?rlWj6-nvrpAwRjy*TF*!u6Lw_nB9JvW1 zWGJNzpMG9}3fp4xSp*l2%4N~4q;gL7u8Vh$>99ID&f+xtZPsCh0oYy^W@|g7B3(eQ zv8Kwh^){a{51MaEIh0srtY~qj`?7u3q)%Xn9ilk|9kKYY5&t=hnw(P?ajmqBe8C;K zb?OEOuWUPg=RY=g$Tf6$DrzCEwnv%PdWtqQt&~~{)4=&4zyw7H{xSP_K=nLl#dnBH zQC>rOSGqVS&I#7u`Fp|84zQRgeKw=pj_qvnwrxl@&To11>|j-B<3_poRredCODcUE zs;a?Xd|s+g0YtX&iZB(FrlTnFY5qkDl2u2qeBg#{-Nr0=AXX&KZW^X;B9wcWt?h0|6KY2(fCccqdSR7gj zC13E7O0H(jDPwX+SJlC!O)AuT|EDl>-poPjDEIu}y3ax6TejX?E}Kh*p9k#|{Fo9C zk{ofmsG4iO+tLR3azfgxN7TNo&z?K_B-Gh>JEqvQdh&O;c1shGX@9pJPUo+oW2m!i zLhSdOW(0TmyL><7F5QO)ZOP6g4%W1g&dHhe-bqvD7$pz1*Zgmq@Y=iw>AYDpEklqu z@5u{(RvJx`CIjRSMUdbJ}% z%d#s;X<1jOrqHQ$72v(fbq@8o#ygtMJ<1)wXpi6kU-S(*%o*_oTYUAt(xZ^MYS?*? zOpv!#5p3Fx{qpu^9@E#&d#85M5U@!S<4vet4PV*UcXHgzv%}Zu@GCild(0~2&O%*! zeS-EpiN?W8@YY?wmV#ly0nNcdAf420qlWx`!lxt5%O}&@GwC9K3)sOSN5i9Otc!E@ zq%8qAI^}a?&04LFpXQtf9B+JRpLc;^~?5t2peExvp`q1^w<))BVuxmceqt?DSbZZ+yE~x z;o$GTPp<6kzB}sd?~o6UgXouSy0~RjfW?D*kfL{(7cl=-(r*WSqAvo2;o%`$cJ%u%2dVKp>x@7C7o3DidesRemDvF_}4KIPG4f~EB?(2q}XXdX7WxU zD@dhvtF=%_p}{@M>HvjvH|^UJ6%TgP~Roe@Z-lS9?Lek;u@N> zfz@`GXpIir=-UY1GZWbG&%t|H_0M6bBZ&Gmm|aOT*ZM!yePvf1P1NlJ1PJaBf_rdx zcY?dS4el^FNpN==+;wpG;DfsccX!vz``)$gf4E<2b)7z4y?S+3SM@o&_AWRwJ=c}g zTr8wX4>g8*HaD+jc09MUF8UkyQabT?#Nd9G4H1lH@aI69qUk%f!Wet1;^6&+(=VKR)=%8*1PCRekoqM zc4!QIaC&~*S8K*Q6K9|lG zJE>IYV#T`%A9PNmh4%xTD)pVP;5i&93M~rD(dW}9drjZaUoZa}L zN}zJx0;eqT(Zuuj7K?HJ+=nPobJx{w$V(AndCS#W%W6`F72SMif8o4VmOW9{4YvC^ z5Xf7x->29xpVIzE^7C!U^k>fMi`Fd@G`q|%F+I>sn4Zf3Tu^j--?ltC)LJWOdnc(q z(TV>IUAn@Z|7Lcv=NokQsGNF1=0&P919lE_9%{4(xSlxU0U6>J|7TW;EL2xCT!-D> zz#ny~Df$R1=8bn2b6bG@oXM00e1rD1Z7Ol2i>=xs27S`Ohkc#rku1>ct?Y!uZvgm- z!quL(Mo11yLvT?dqfc3+l$w+?@#Mo7eV7|#uDSINJ{Rgc?nHL}4%s$Moestj7}5hZ z?(Ev`pbqNI|C#$}lbt&$Yh92eP&FPlLOT0}8&`i}l1zM6?CS5a9yQo_{DovpeTp

    =WQb{pBUf|&Gsy2}DJ8-7<+D-lyVj<1>_uWwllh?MX z@OnFh;oHcOdv&IvI|n8GeGAr6hB;WwPhP=tg5!{t$T*U&Af`b~ilIT`w6M_3(A^c35Z)^6O2Wk!RpW+(D%5+rciW+}HsDsLAU8eFV=caM9mF(_3*?>tyulka)eTI8qf8>ha%GZLk$D8~QB1ak^(NyHPP6hI7CbtE2 z@H!@-J*_JaV@rkEEGzw8%8i4Fa(%~mbzrV|wO}``B zqPTL0XdxjqX_l3o*^=rMok4$ppR?y%32g0>c;xd-@hdCJY<#;0Ka*=dQ0K+$I^2V# zZY5emXX;k*l9TyKI!RJ$aB*wQWUO(=P(9Gf+=Kkg>NDFL#|3V04uxNmg+)hg4_$ql z)Avb&95Amw;^O^>PosMFul}lXaPq+WF`2nt#Ie`)saXtVuEe<5{2R`GWpkD>Ung*4 z^2x9(+dk@q#1<^LpQ8)K-L!De&C?(OseMkr9>?UKBk$^4k9OtYzOXY#^4y`BOH{k` z3PK{BraPEQT$+jBd@)}ft>O*6)Z&Ilmsh<|mzR)-#9begR+*1pq;!%`R!3Y6azhUw zuCD3+Ve*HNB?4Z8yB6NdbmB?gaw5YRYWE8rBOSc1?zt>L&|W zMH*nM1p3NI8tsGfz~O-B+Jd)|Um=cv#Cpvur*@S|@Jd_se8)kfQb*>4hA)+qhKCPp z73rEO_Cxv{;bqv`AXf2NO=046!p%1Z@dqmd8cC{aTQjN<*}>NXBQ}q2ObnSFWd8`= zNeJ&+E0Pyh(ZKCN&aD&Gv!fR?#ZU5`#o{}z8s?qxU*my3a;@c>MGFqRt^Wd&6Wed- zuF6Jk`oz4K(2804t65_)K%7~f>Gv)i;kT~DC25393y@4@7j0YKOgEQZ^&+{upZ)Er z{KrbQzOYsI#dRbRgdrH>0uq<#J>t>~kvu2!SkZcD;}{$_`hq*S?q}&v-w*brd6|Vr zXu(tm?ah1OLUz%A|HNwqq#~1BKJ0!q!>KMRNM@UdStfYSGKl0LSGZa%#$VmDx8+p{ z;qcvDEn|LIy4i1zy4=sb0k9vzp_ATG4Po)PKf$X*1NAw_M8B$KaJRO^#kXfkTCtq1 zPNc(=FEJ)AhW1{oq%o2KM(6%3(RF{i`uj9GB=>BnI%oJ}FNq$A$4l0Rb%j%il5gsS zjO31NSuhj`fDtL|21j}@9H-3=?)%%ekCju)RJZqE*WjEI=I*}Fj2JwgBJ1@Od5&_` z_V!t5XMFAc5;_`#w?c*yb|NO==yd)`k@CDn9_m}={Z=^Fp8EBomkq}&4w6T-%~%z= z3i4!~2xP=h9gfBwbD_IoBjF`RtE}}h%0}avlzCnIV!0*mvg6Pi!3(f(n{e4hgy<|~ z2BDNDBkzF5WmOmT$l1>sB{#4~fuOxbiKcF;*%?PvfLxb}j)tY$!La(h$d-`rKE;N3 z&QAE&X#Qdf_u(0e=8ucH)UFbSy(Isb4*m7f5Za;(^2OiF*Gyi@&&2wF-gwOW=vd%8 z%i5v6VArp=w5+eyQuQ zbqZ?Jn%@0;Kj#g@n>{1uiG@`yd{*R$3703AM~@yTtsL4iyrqfb z?)6(rJ9Li}EEMEmcO|P^!(|GJ9A_Xc5rIAUYr)#e|2Efe#IXQ>NmpdF=~abKpAE@i7QieU#%PHH>5V97v8j`O{a}e(<-n%CPbYC(zfKzf6~dtw<2abNU$= zg2Gy zYwL6eQ=`4W%IBYpy@tIR`V!~f3d#t~b4NWx>;KpNqf@Ouh&4s@2E*m^KgY6?{+ig^ zKYON}{Dg=?%a*v%4Lei%NQ_*h>GSh8E~^w5w(LHYfpf*{3qKin$?|nFH1J2bok!Ce z_%lYi;5r7~95M2(Z2v(Or(soSUf6HTEhwMFMz!7W#)}EEtS&_fKr<2%{@zMNC=1sW^xnCtOZp_h8%G7b zzcLN)bC2HM-CE3&A#_y@?Ye2$f>D>FN5X1U1R>Z|I6h~;36`g<9EAj$;N`oav>5G@SI_x7NKk@^OKS~FPsEnr5z<|$a-Kcm)eu3>%&FP;|I=>V@c`@&@KXS@1cc|ATFk8GJ zyM(ANI2m2>)Sv4_sGrLz?U( z2UjFMvAV5g?h#63BPADW|HZcS=z<1AnQe2)IRON?eO7K>cE_#TZM{KjyPN_( zw9v}S!J+)HU*Bu?tMr0&87$QKRf8>Ro7?_6h}~sPIbTj8I0~MX*8x^OA<5UAFAe&f zaW}P5+hkH}Mx;5xIXakI8n;`2?&R#3rxIu~y^ZG5^-?-U^-Xa`8~-{myp#*Z1JCv{ zESPnJXGrqy;tYOr-0QZw=zPT4GRX&_1g~Ti^F<3FX*MXDdZ}viT_f0L>MLBfF6x%^ z{(DxflAghGM@8HCsdTC*J6tlg<{0EJaJ>;fdUJGJ2YD#?_%Hf?=e=i9Xl3-ygL@2q!mdTwx^HZS1IXd8>HHJeMouAz3eWZ-%h6Y{)BSL)1o%{P=vo&Zte zAOQ>yNp}1g9NpUm2l1l=Nbv2@5HZ*yL3pyt_w8k!E ztR*vGdiw^VcQk3@2{le~#TBQ^ShE`Z?y!pkK?)nz-NoA?*ACSU_{_gP^7Jiro~0Xyda=j04ibn@h%hRp`wvQ9x;rspDXiZo=#$4xMl1zb)DQ zY=icYdFJ{<7f6ajbJEkoq>Qj6xiBau&M}wLal@PL7>guk*2CcICNfZ(&APu4|2m3O zX{VmWotk7gz372qedxXY{aR}q@6&7&0GII)|IgIg1x$pDw6mVt_Nfx51fLP(`S@k9 zpn9;>77JvsG?|ygxlLTCsjx!cG+|eN9=3&XjHw6Y>%bExF`NDN(Ld`S)>bi9KO&G= zA#ODa?*C5xaCrmEmU3@9*A_N@kvoi@e-On1l5YoMRp5x7=y6<3r40AIY{JwKxId6_ z4~QcQz;{avM>oNd3P+F(?oGEX5{`l%L6P#i_V@5WT0$5fQ#0LHdJg=$-!mq0Ue4t+ z+pckt(5V(JYiC05`jT2WgZeg|*7Y+hIx!EpP_WabWkyzn!N5D5&v9G9mJbVF=Q2Tj zR;QH*X-=X0^@z#Yl2)nYf|n&H2m{Ah4esU1YOKRiY=ekeRYoszt-a_aBmt(D9TteeET z==Mq%x)<#tZ@-gKU*O(_lwBrF@uH<7b-ElnBG}_~#T0XKDIvU3Xn(FQWE10GC?0yR z8NT11yP1^2U3VrqgbY|&4Ll)TlkSGs(5DYOfv57DJqTolrI`wag}8WGVrT3jBxC_7 zB)^q%0TPM`?$OO_mpG3M0znq+=7W2$k+?b1>#_l;eMnaCVa>niY<}-C-2y49MGQsc z7s$K6;`Q*&RZ6X?+7V0mC(g+4mQ06|nq4vXNhMAE65r~ZdrtDeI?6lZ-EmL-yD(=l zx6qu#M(#u54)Sy4T8()#_580`d{&%&$5LPCl30MngE>lRf4WK%bv5J--)>#nA+iW` z;t{9ooHV#5DNJO?x4nh+P3efxoNZPxOhG{a3qSOopG0lto3O;7|JOIVTk~pwi}BZW z`H&3#H)uhwds{0e)n|Ul=~90WKEg&%259Ji`&ZFRT!tz=YKG0^|);*3*JWckn z7kfUm-H5R;Ni=9#;jq2$i%brY2Z1m_PO;Wl`wNvhPRm%ADJ8de2IwBzb>0lfKUz!meh^=X_4gphS>KCGhi5{z&ZUpEk`; zp`87(J)H=~?=LxrfCxh&i_z<0S+~$-x86iU`^)&b*;iML@`9xoPRqx*Y>OU zGe@(pF0c4}S6e1iIaniH6pBKtAky{o=$~h4_`A|!2E}60ob)^Abwx26x!#aG$qyoW z7qHI}XBI-^6j)t@GnRrGd$~2M-nVSZ8m2n8HCzC1v>TxlMr={cvCmg_CrFdk1;Z|? zv)7Uuj8vk`7a}w!bsn237l~JkAKH;PgZ!G*^MTvKaoBom{v*B7imUf1E}k#z2TB3x z+rPgby-eBM1G_(sF|(z=_@TccfGA3$m9uis5qXdt1+Ho)bC1Zl94ga%H7gm5&<57$ zqsmGbwEh-{Tb(+}=UjD2Ja1}AtC7}mBKbWmNhjo(UN{up)+8O*j-Dp1*&9tzieLrH>$#g6nVDTf3U|;IV zeTZskLyMb-#q+ad==Z|pCBxG=qg5UvhU=G+z0)G~sqb5MwdJ!t))CsLo;~uXiCeq1 zbqD5bqI^+C&pgwD1z_Gx@@onF7&)|P$37PI~h{wMi}W=sE}YIBYt0*&+2)0x=fQ_Eg5Lp}PNS zLGX*JD^%LuwB8Iteue|zxJpME(rUPX~=t|D5{IQ6#bBx-fV`Dco7uH!*EVefuEc&<^k3d}r^E~Mz zoDZ6u>XYk<(MqOI5Mc)#=Y2GC)aX}pKMP1ghrq@ zhxcfJ>AvIN2}rH1=npKpMxK6yh>Q4jRnHck6F;bHattTC08i<%K}i zd-f1XNUB6i_x7~=;%M_~t|N60+?@aVLAy@Z&Wk-4;@-vAq=atQ*nv?a*Z%Fj3sF=0 zH{_?3j48^e6oPm;M2Q%M`;9oqRs=ta_c!+5DT`g^fq+AS>+ZN{1@0y6QGcgg-;3zm z%EGDJLMjm;VfJrMp1?nbfs{Rh2U|7h1u>Pg!WzWmOJibYv|B+I&tU|*(v-xhoZLyoo!P zkfga_hyDEDlen*gSoZJnp-bSQ78!|17oA{|^ton ztqId^7O=9Fyod@G^JhW0!mpokx}H|5bvSazDJ;hcun@rI6JWOwBAJw+LNzp%*%#{z zEnUW@>9GpChwN!>9uo0!2NCU4*Ocm>rkIm0Qu2@Wa7-<{9nNo1Un?4+HKHmvDvv17 zYg1}eM=R&}jCabu92OgDCeHnL2liI%%r!(g9j%Bfud*rU*Pxi!_wkaERA;_xaA<7* zUQKI+q6ZgG1TZ_4T zQJref?R=#%QTF6r#yjD7qrivq=lFn}MHl-mp0{IFksy~!<$Paxfvi^NJo|`>y9Qcv zQE_Pxop`jm*}U8FYH`9`r)-s5w`y5=WO<2yWLHFa?v7Klta4-HMsaztO~Fcq;xWcu z;c>}}fzh2h)|~pCEvJ68DsvgWDB8KQg+^U@@v#-!xVqlFsJo_t2FbjUSNU&mc?I>^ zIdo33Xw9A7c6s>1sPCHsa5*7?TVHwLEKv?qSyw=CfF3U=T79TR)I)BYxO&+0AfHW9 zPeNSOZ!7|{yhxG3RVeg-zt;%aakA_z8?_S|V|$SBY`1PXFh6n-ehuxF=YfkM5vbev z56G4Ywecs?gjgSz+j{72HOmQ2;A<=(%G0Dp@9Si*+$CZMl$qG%xTk|ih!&jYFAZZ9 z1D=@*gp=OE8eTh;e?5wm;WQR$JkFTM!CPWF*&BRj@?7b2b2szHtlZ8yxsmq2>hmsCua6j8kL92w~gSBs~Ky$`J6nf8Znz(9_C z27Ya$))StR&+aoRFkBb}d^Okn$kE=SVGqyddu{TU!0(B5-};b|HY%elqZ3vuk1{_w zQM;aeev{L<0lald&p+dLGx|}zO}z31CuaS=2wIOu65bzliobVZ>!pB82@Rjrj8gRzh8Zie^|w%H`F@ zM%w(r<>TW0!T-VM{UBh~zp281?xK|6Vs@eP z$XZwlZ#G-FN@K-apinTtSHI1>$8Biwr6-{iSY|T;AVe3zB#A3lN_0fjALbp!kHn%qKWw$$pqvMR(d8NXN z99cbPET7P1XEI(U13})itKq%b`Pqx=)T(t-gHDqbL$GqJtEoBPrqy8-*1*4}gD(QA z(oid`9#Y{rwdmK!GrHBNpV=#GPDg~Tp8~@}Sv~B(JW(fq_ab>hacC6S7^|R^_c+fs z!x!0FcXua6Xk2v+e86HnolUE}oByl=>@UlZq70{E}S;+B-LDC3jxe73OeLNcrSFPX z{`aCY4{B($6GKd3^A$sOaJ(l5b1%OqN_EeV4G!Z5#4_|KmF(+HgJczppjx{65#$|p zk7T033ST-Bd1Xm;jI>fr4YRaDRdplnyyuGdnuN}e|Fnw?m6>~OIJHqis^^qBvAZ-2 z=6+~btZQ8K@^OmW2jB6HXu2At&Rc91S5?{eG8$+tN*2)^{Vc7-w*9W_0pAXj(!{@< zRTH%~aQ?^Q%)x`30U&HI96jt|)Xuza`_TMi=JirC#RA^sa9!E529!p6&PHC@lmR-W zJBN?^tcI+BcRp^$Zb5Cb5xso!UO!?dM4o=+#NTo>rl*%P*(wzjHv4z!jwAaY&>VnsCUc=5KN6)65XuhA8GYA2J%GOU=j_gh);Q zFi07k`eqO_IHR2;`u1OCE>0V2 zWxhrmQ)M1!8?m2)(aCc|%)$}eEs9?ONulGB-dbE&!G#;e^KbvD=p*T874E#8Lz=ZD z|2!i%_7zz@ch?oge|O>yi5|zH*34(~jE9t2bBssGS<|soynH2k(_VblBt?;KKbtLg z>}lSS`d!Hk2P#en9JUzmiJP{)enqkC4eH1Yf>aRbpnB=5N02Zyv~l317fmkqSI*Av zHXiKJ*(O`&gf{uEe?Ux&JlhaVf{~DZ~Ge$STFcE@qm8jZj8AhLSw`>5Uno;&_ZQ zKpU)@`{k~{UpXN=50H!9DZ?yA-YLN>iiuL(qnsWxqx?g>dfHYwMQZBn4{67lj5zs# zg6^KqThvaNJ!_8W5X4)iP9z*_!stL*j^ETZ-Psa}n?mVgYPpCC1=h;R>je*+{^>v2 z^S+N4FDqxQmptUbjTd++Cko}F<>LBDkcisrNB>juq56sCh!{L42?cvMM5T!O z=_-!q{eJ9*{{$MDZ#>~}m~OPH`26TY!v z$r@zMKDZ@heq-TRxP!E1n2@PR0T{k(H%h8&Fr+IUiu^?~8*5qk8hR9)sq+UL6`Qj8 z21M@DYKZ%3MI7z&T{VuUjVB|2kut30&Ex<4gHB)#9aIrr1|qE zpV`E)A~3eZ!h1%TFCOW&-!BLn6nO@;gg-L+6RpVZ!GG~a&=O5w!t7Acmx)R1C`8Nw z#`Nvb<{t2nQ-ru>0@8YBk^RO0;$fi3;bA0DVZ#Vf(RndR>r~K}8N%$a~hftFB&3(Nd;!6J3x64}-N1-XDC$Agw&f(z3}L~kV|b)gd3)%^vz`!AjV zikurpuQfR$3Z@LglNJ$Gpc?P&_G?Tbte|Zt*vWopQWn@a+B^Ajjg*HA4BZ$7avme)>66GNm*22nTIcf3Us&)i)wxqA2O0(HdG%OiW4?PBRC>2bc3lZ11Cz3juLpz(mtJJw%B zz2KhC9oMoA0>FSCsFFcb^E3FlDf|)>`*!1lvm1)62~HlatBkV%*WlC=jy4L=+r%gL zMAW|CF-5u)K%#Gj3&1a6x=o#Vu#HFuGk)E%j(1FUweXzLQT3f}r(*Tu#v#hHUZ+X` zkh}kFo=s3~a+iJLK41}iaO4&B06p%X6tCB}(QHK0?RO9IofBAZmk+4wo*KPFd@C|6 z(>j{>9$$Obo)D6o+^(OTc75e%yYm%#2~F>0Z@%OgYOf9rxKBU_F4nJ0qV?DX`~rQn z2F$eWx^{719-Pw5n|i{+^`U#>g!Hm_Mi1Scu!yZQJ>zzu1nj81qelIiW`SD|u4RcC zdi|32HPM(&{&yKmwBTPK78uK3hBOq{O}~5i8)G5g|ByDtAHU+(0Uy8N_F+DLN$D-Q z#D9sH+(OburQej(MyObF1^=$zwADsBF&6ag^WW85`nu8ca0z4ghh(|p^^0&Ha}8`$ zFW1t9kR{FOpS2qJ`(B~PWWfn2p0A;sEQG%coTA<)oq3>Wwy-lp*qu^3r!Sm{nf^+) zd`aCx)DO0GB69ev&@x~dRUU3ro?fX8Qhl5Wg zqy0%77ay3SE!?3z<7mIF(V>83@yt!>Er}Q$dZ=}${1!u8LUSB@EB01v2o|2tIl8z* z^G_ZL1q6pXXN`iE2=FL&1Fu7$>FfW6$G!4p}vdx+UP*1^g4R`^57apQAwy zlWr<_bOGn2+9an)e9nEr<<0tk1;zUV56JCRb1&cCg89Fx-W()QOs;}I<{=fppi$LofWY52CeVY z&JGFKtI8YAPTq1)rUAzPQ=H7e8;i8e^&0N5g9B-e8MF6y*o35;>~pfOb~s3-agSx} zGu|{kW#C({vlfh5u@83G4yHR>c7Tkj(|=mlflQ0jtu5QUCdXKA#(Zyn>lh1hkbr_M zRlh;V0zXdXxgKuMQWo{2#)mrU2uQ*o*roE)| zullVKZFOyR9d+$>oy7oYTCmoBo|^+B_~*0s6@eSBfEM;OopU>2%u5&lV%CBGCXebzdU*02AHD|xNd3;aX!g6{}i zC%dQt_VXVT-T2?c_|SADuG3yL00;R`vTpnzCVcQZK56zY>VO07#|Af5KHMD{>ygHCY;Wk z)}QvtZ!Pf3_bPbGe=2~@hb_R$$0|t7Pb^T&S1Xv!pDnof+-C-m0!RX+44kK?^538&2N zw0VBSzs2=e_I*mW$*l6xIiIAxOE3p-P>N;N&}rjfn8O+_$DA4G6PXPeCxB~HQQyAv zMM*2<(?*tK>8QX zY1R|{Dp~F!0quBdLO?V%9Gf^QkZ7^F?SyyZ+`sQh5x8?^*6d=969iH+57r<1FQV8` z(53n1-&$5?z{&akD?gC=K)8kGO-Z#QKx*VPC%*0xkmR}+SO4xDP2JmAJ-p>h)M|Zi z9w*3JM`M;QsAHkTwVX)mgDugrh}n8ELjPg^Gg+NVxxA?yMR#7qy+<`#ouVcSml2P% zy-bv9M=ys?3aWxaC;7j#-?U&}#@LSW5t|IM>hKI}*JGxSxAJ5QO&-Tzn61b|G9pKX(JR`+Ta3CxPl@ zr{HXv9o6TEiVQ?#M~Uh5O=)jGJXYAX19bY1bV9N z4+e}6JW!{7ZLyy4Uq=rqehSM*<`q2F48P^BD1>{B7dlHcR{b=JTirvHF??_OThx7& zXw>KdvAnCipV|x@R2+D6!TX`OW<^spd5zla4MGhFB#8D1_B~B`XL(tV+Ezd-<|crH z6AXW_11tA8^8^K|*SS?d`F4a;ypxJP4ihm`ux;1hAKGA9-1%h+tbaTNKS&;_nOtawiEs&YKc zcwXqPA2-!tprS`fdDSH=0Kb{<6_UZzM8?zir{ltZbTz1E_D0!A?uRGy@+t=>B5~&7 zdMf8&i6SZDZ(>*tyw)(5XdgmovE25s;g!Tcg&*o!{;T^dqPXnoMkn(Z`5Vl#R}{5~ z;#hDiY3eGGD_ZR0U|hzKEj@%n%l&3VW;|4|27Wj7#RAdT=oB9I3fA}c(5>y`ckG@; z=P%d;%~$q6CMY}wk~T3qzQ}IN>cbW}F;)dqu7(lhMS;1KljBnvGTXAje2vK(B}0zY z!G1X4;AG=MmvYMF{wP)*s+VpQHBJ!gg4$ggE0=}>h_y+X@vr6jEP~jWXSVSm&loD_`iob65%g#XO&z?o*n`; zR4W}%>d2;wC{GgTqnU8jVTBeJWhw>*QfnnB^f(Y%yKP~mZV}mid=Sa=Qz^V9C9Ack z=_hnHefz&Nx(NL~%{OzHX03MZ=Y@mK+L^Fk7+q{Av`VK;r;aS%<9#3Bed@8xwou2Z zv<+WCbJB17ddEw*wh0QaR{4xPw>%$zjMNrbsgEpTWQ??g{?ij#V8ihkcyV-8TOy2f zWjw!k7JxqgBWa-ls=dUhEsVAAp`vX0)ZM^f%;TU>m!YMlQZTR zdOlPW$-EB`bwXjER4_W|Fs`2?~#nrAA%`t9!Y{2PQtbw z+PfV}z8y+NN)jQylIQuU4n-4v8J9l77nwfX zmykZvF7y+45vw8L@wc3u{~B^*K?A0)V_(2tMzM`N?ZKE&?W~E1TzTLc>EU3p*WXT${cELXam3JIK=)epKueg2^YN|85vCi?_nGe~y^tsPG{KB}ufJt5RU8|w>#Rxr6hxvp!+S&#F**EeJeV{G{# zd=?ViK0Lx9uHMO-NWeRdrycy_%~C>LUF88lPqyD2Jhq??Pf!_C%OY?~i-)6Tf66&)1+oK#57_ECDa3%OmEKN`@P zajh>p*q52?ym*l2QACf$>t{#W*70LV@59G#f7I=Nz<`oj9ik@{AhoxH*We@RMkcG)Rp=+{H+#e_>JEDTOTnZ zOZEZBk8GLnfGaayO-~e(Ufjp8P5q&@6|)HiN)>bNCi7aIr6Fb0-W~o%%=ss7fetf_ z_tlA+!xPwma`ti1dB?$+u~GYo&KcOb%caX>f$t>q&Mh3~>0Rr(Y#HX9C8yPp(}M zyP>s9uWhViozp%<`Ao1IE=79A9C&Br-9bh-ac&}fs5%l1X_=?xu4R2JI_eC0nU~ua z=`S=c>AaIWM%MidajMIK-CE-n=ku2~-i?rg9~c9w)DZ=vZoyTm9wVafoRB|kCorI+ zKrME&Qw!!%chx^>cq}P`5>#j!qP~({c{!PAm+?@7wcNw&0YI6fxgJ z)kDl1uIvgC+<>aySIbz}uMv;zxR&gFJRVxRyf2ugJ@sd2Q@;SK{9B^oYbaD6+zCr- z+NMCP@HK_cO5)O*zUhNFW;;pB(wdklQ0{?R`b@gxTg==Um1;L>{4-U=fy^7?Nh`AM z8@u3h_1$JbVb1&ECk*3@C_6dNAY#li?9gkz7s9lF4u>OoIyYX-47vM0U^L^sMIY_e zeeF2zMDaz*ao}T#Sj|3kGERj7wqLd3)=B0$u~3*@CSXt|z%uDQD*1hk@(rKn4WIc9 zr1Q)kc?-}ynzWnAL0EOvA@!N^UM%L9FoDCBr6bMSjLt6RBzsz(_zRSi1cJMhQZgcOg7k4lXNp^4_q5QHwD(`G`+06 z(W31YK&yvED6`Uu7X1hxQDsXmiBJcXPra#U*{BlP$PtyXyBB58MP}!B&E;el{k~;G z$ur@|T+eN`qKwXGfKBYvoH0)tA7wrx zUX-Q}Q&s%u|DnD-jC=vkzmiIvk-o5&5I}S?(GU2UG4kPeUG2RFdbKqNDsavet-Rwj zaFk7N(0tgeWQDsw!H4gNruXxeD8#NZI={*!ek*Dyt1J{gA(|~>%53`xoO^K??gVi; z&&g)g70G$c7K?Px-H+hE>t;N{+hTq7;qlkp*ER~(@o@D*9U)N?zRC$=BU}$*6?g%m zx*9`G2Bh@JYLBw#j@LwA$tBr#el&YM1<*R)R__80K4c7tuC$}B4g{6QbC8_CqYU-% zAK&3kF|wuUW9|!D1>iRJuC;GB)&)TTL&Vfg>kot)&y)lDgI%I;c$eg<%v(6&pv4wn zB1e~}l2h)MF zS4*bW)tJKG!^Ue5Ytz@%$nt!Brs4?a))qR{cLD`jr`E#jjed4fh0SXT&iK*9IZ7s_ z1vH47{>h((yHojh*KNCnMa3H1Cnc^1lK<=%YyUk>9yPT)x3+(18pq7PwZ2Au^#AY) z6AT)yUZL*^=)0n0sz$8`pweecmOJ%8uztl8V_15}XHP#s6}T1%oJ3DVR&8G&A1>+} zj>_ZE;@u#R+g+!OT`tiBl<^UZ-v@QPr9@vgQ(FUE(6Lef^om}_7{%o~{oi9{p06Vp zLZ2lfyyzC`55h0Ofw}*4Dq%&8O8!f5crFVDHuaxg3FWk}h*+W~WGCtp$@Y?V51%?Y*=m|ZQ_SHFD>hJZ7T^8po%v9q zemL(dqhj$Re7pPM?8%W~mYU1r;d}|OTIfu*?TY4_a((Aw5mfiy+U?bxoh8d5XT4Yt zJRjsNr`jLERG>@j4=9qOan8fh8l_6*EffofRjp{v z22WQ47Zv?n7VR|Yft8jh^b0azgC+@3|Mf7H%|f|>P??BnmwL3zsz!lj*7NPjLY~?- z>6i~q@4H+HTy5(1SU+D0}(Va{;eia^%eKanyuxfRa%>Mi*Zp|5Xq7GRJ+B(`9usfx%SgPq(G^@iBELzmLT*L4uhrwoOsVg$`MCJxvBJnKW^O*~PfL zSeZ;a@fr&K7(oJAGO1@z;nd|B|1-ZoZ?ArDFXu$|b=UN3_Os7)h5*C?c+P_EvrcU? zz4sr*F&NE69wNOd|M#?8vYJT zfc_Ev;peWx0y0}GqCEFqM_fLtG=LOSOqY{O;&!u;bCooXX(pOnf`byaChDQ8s~zbhQq9V@ed9Dl1HI25nicrWoq?w*O0nQ zXxGX7C{#k<6ohpw-9Cg0$Kv;N+$ji_a&`a?waOGS35*;Y{Bp{|IVoEX8S)GLDLgLO z?X>89A$UGcYLrpojLLaV9(b3|R;@A*>wG29iHnSS*kXKR%*T~M?fY8cX6f#3EX*Xg zr+6j{{$-0cDPzd_s4bH`4qvwSoP|k zb}S#Un+{o*B{RMWCaq`oHnKSQ(N&xH`dqu{l=?Jb2A8XL{-&W{YjM%wUkY_dAi?|& zUb&Z-^3#DBS2Yy0}p*+h~Q3 zpHYZiS^M*c?i>BYP%v;Rf-*~~843)vZ4NUX$8?U}RP`tqDHUS2e4f*5<9 z&6uOu+XmL=_@#EBx1nwqkDkM$eIw_iGygt6ZC3Zc4i8SnXwS(>n@u#9!fsz349xM| z!&1?WZ=#!<(pbnmW5z-uGL`Se(0FHko(;gLz_8!j!Kzwb40DDQY=`3AYGN&I2#1_N zFQ5Gt=c5G*9m(M34SNScon(vS6I`XHP)qF)_ci==Gby)3kFwf=?eWMK(%-G#2)eY< z??*w~TT)KMe}=WP6qnHKj^T)O1Xz$+5VB#jD@26}@O^f&n*f4KHi2uMXEd^IyV1LT zElTArR%Qn|?of8T@v`pbEIupUWo*3GJ1B2bx@q(yDmPJ%73|$) zeo`rd^qsQ=kpGZ0B$qTSy7C7n!kRE74HB}2r6ie^1cMR$sRKr^E>48;19?+?ciUfl z*C1N%CBuERCrKG^`LxdBtaqlS{OJ^H!D5mSpWp38-VoAEJ10*^9FHpIR>)F)68E4p zg8J_yNntsSgs7IM$&6!pC>%zsMoV^EC7{q-I(bVO&d_{&F)P0yEBhB005yBsVD#yC zZFHUKz8`O)BCC(#mGyC*!t?-BE`TH~nuEC4G4x!3sb*G7M>Xns_B;>4b1Wz0{CJqC zUOc0zPu_K9sjF>Ityn?7^#FCSz8iI7HAZe;l8(%F2Du*-lC?o*pEY5;2SuVBmWhC2 z2LjxB8J0I=*;k#}&GcGlM}k2Q?{Yo2I9OsR@@FONT~6%Bk#~A5@*CL}FP? z14Qb6q)dP17@~XNZp!za@%u;S{Q0xYCJ=?{?di?8LC~AQ^+g3e&CXmU%{k#LL67?A zbuU(kp?-)>z+7es&$puuu&ir1RX4Ro%hDmVJj|((;Hazj=G=PL9f2pzneD0TKYAk@ z%ErjPx}P_GM22o9&Hd2rid(|H3XXse0rN4h&AX)c-)cl2zmd-yWHlTG9;>%az+aet zxP%aK9aC6v0ijpBu47$SJvNP_gff@I2gzA~BXp5w1>ca6Re6z1^IbtpWw8GYYX(S5 z&i%Q1}Ww7E5N#_}31R@H zgNp2HuhiivuK4?X+4mJD88}ef%%Kdc#AR8f5zqDSDs9x}*w3IPEuEeAPj4jO^`YoI zf?i>wMzM8a*`ygLd@AL%4S$ZxK5Dzo%9f6E-(5P;kMr#e-~8%A+0Cms=LIliLM%B# zZ9buBT(=cZIdnz~r6cVaRS8@z1~Tj7ZY}+E!hiHz8kH^5T1`k1@#DmILvduYw+t~x zJ0tPhrAF;(^;2D2X*Utd+XUsj*RL3KUV0nB9F89f4aVm~G(YjHT^c5HtGdVeE!mQ# z%PUDNI++#cMMQHx(vzUF(p~eYCllLOXs3qveQwuxH>wcvjNzuop&bIj;A}d@t4nx5 zYp(j5Df{fg_Fv)Y0axe~e{ZH59d89=;i&L1tQGu#jD-CtCj0$A2P?uP&rA0@Qx%%n zyPn2ddW?OkiP@7h^3G?iC0b~b<10DC;t%ZoA~g0jZ)r80$!an*fCYQgotgzK9YKmE_&vgMBIf?9SEo^w7HtNbZ|q9^J`~Z8&<{>P5LG$)So}!^Y7pY zd@SOBn$V_-Bo#eM@wFJ29?Ge-*^c_+QWy{BF&d=-Thq+= zB8zYMVK)YJ`hk$WL3!xaTq}-Mf{0XUcRrgs-H1->Lba8jx-yTkh_o-Op|+38(o-f` zSLGTbt1zn-$+BnOgk_+j+T63(A+>&kTZgS5$M5KVpwa=nKO(CGAV$Y1VcOM1K@az9 zd9J>5wpXMm#={^VYb8VQ(zdv?1=zP;reuLlZN8R}>dCG>G`%+dOdv?6dBxu58UIig z`zl?FNwFcr;RRzAAXj?%6-GM7g>$+*dgOMQv{|Wrt%gz*j!kYBxxO-}Y}w0&fCX$% zLH3X$Cv)@D%yj2f&0VOsHNGe_Oc-VfIY}s3TDJv~NubBFsH)6=NA~vvl9VRc1>eFJ zx}{PUgr!P%+y_(7t~EWH8(+v}oaI?zbvc#Gj#CbeN_ELILoiS!Zkc#v)) z03kcc{67aE43Dq6kop(-MK$#qw$SSk&vsI|yH0F*$8zs51e{+-mKI?m-Hb>krr0te zV*;ZM9($mtCBOXV-%BC)1kR>f^c?QubU=;9@^0ayKnINdry0hWM!x(Baz$JEj5)^` zSz0}MXZq2()2r^kaUZ|u=J2y^T8d5~IjQl7@-@_kzJe})n-8NMHGo|Y63EtNT|Ngg zs7*ZmG9B{ZRMk=8ABGu_t%V1-iq%?4C6L|2Jt_^St$^3;n0@s^9Qs)8mQl<+*8Hp& zgRLP>%F-Y&F^=QoS-4>~icqHyJYO=SQZlN2bSI?vSu@65J0Ih@blF#8z>6?Mp`N5V zuZt{aPRoM83GZJWO|YnqJ3ot9P9I}on|rIg6CE%Riktt0iTPg9Zc&dZoP|~t zXTFnH%`;SnzG?CsGZRwV1~l6-jH)d^n|2E{d(2_US{Feba9FYo0BlTFl`M3l$fK2C zTzg`Ad=JMGL5_t~sY-cj`xAs=Jn9kr1d0tyFgN3`rzF|bDs17*P!Un8nq+l}aRNWE zmL^TQ5RIC+{!-ISMC)bM+Suhnqj4wogSW}rIN}{yO(S8PFZz*vR=A1v%9WH7x|;W< zC-;!|Vl9Rxx*UEKQ#KdVH*@29p-#Fgh!ysl~FkoMnQ?ab;N-fV`8 z=ajv$+Aiaf%vFrBk`g%80E7xNHun6TNEwwS&Px}os z*7O;Q;{&=Q6D^5h=uLykh5hj+Y)u+If26<*DE8GiYW?sR;gkNGhQr#UhQMj(4UIYv zQ#YB+O#;Fc+9rZW>=AylOx6k;`~x{yQ}`#bzTp^pRV(DTa}Zb}a60_!$eaw!%d=zu zvU~FnR0+sA$zD?uPXXq5L6X@v#N2s}c+;+Dcbw=-$iI@o zLKfd5{}temxFbiVBKrX-K7D2@5JRDA@1uUIF6(-kXb8yjC#k0+kNd&X5=MIP?4VBB z7v^u1FVx`IVz4HzZdi_{ahP@6@lBC3Nyhe6T3l{A zs0%T3b8ot(xAH*|cB&Y=T(c2kM@2%Ct>Nr#=N&87^OPR{z$qimcZu~KACiR7$jp$^?bEX4=pe{fTtDx^AQ8a^;34tV^jyC*IHQ!i-Z=ONduYKl;-) zco;K#Q)d?^Gb6kI5*>`K;bE9qScw>k{!7#$VrFLlr~J>0g^8KyKhJ+`%xs+hkGlWq z_y3mJ8UOPpHfFB>YXloR3lS>^%m2lPm5Y^#jfI1Vm5KAeN;XE8fBj+q7xmwEX4e1i z@qbEACYJy9Vfk-gMj{qAHX;@-E+Q6Ij{mA*B;sIY``6mPXg#9;IR^hR{?{1r@-m29 z*}9lHF^Jn5xtNKXnK+o5G02+PTew&faWb>Bu>5a@iHM1Vot1-~pC2CP|BR_e_C+?d zp^Dn_%e60qOe2L|Qj^>Usaz7hRgz0_$b9G(Y_UxdI1HVcT79!3JNTRukous9VV9X3 zf!a!tE-*5ZJGLNpkTY^(_cXe|4d@HD@iF5|K?UyOl70E@Yrw$w+U?n z7>pwPa6=4;Iih1z``uEs0qwp8A-um`MM>wN_x?*5k=XqN1+b&7#NB;yF@zii-Tuj6 zR##rpRdDxN+Vdy4^BhL_rB|Jey{T(OzLo^&A26G>U1NQla<|`P5?r|nN_@}UP=%25UEgB8YO*T)q;6)$Va8hHX>wU9Ue@z%)t|+Jk zF}f@5Z5iWm__tp0a~sUOc5|hng(PoitCv8eETgf38gPkq`jD10Jjxk^pD;`2WBQ{8 zps$By6Y5p^cJYIn?LUPtaHlm_-IwjUd%Z&AY5H?F+|3o-S7@Gl^~6V=$cQ6iCOXug zhfzhy7sGCmC$#h?FnaX1niAq|XoJg+AD(CpkXeyOcl_vSt}k^~-!Br->4lwe`^#IA zj&*KHu1CA4PNo;oe5H&@pkz7)xSzp?)6_?|Io*DlHeQ&VEf~^};Prz&lA0#Z`rcKK zAP{U(zH3@q>Fzt2;>f|Aks1s2BhxvG#8P%Xw*HAIOWgo1M&8FA;+i!DB>HFY4kSPg zSQX(hpxkDkBJBn0I~gFolNI$08595VH>HUc^1?l-L+TK-bg9*xx|AS8tMg)Z20 zH6|4xj);^TR49M`)=7*`ocfM+6FbRUrT?~3zPmoP0LT^PCBDo^EeU8#s7fr~UlzSd ztS{%przNfvs>E%G8h_6@eo~-*^D=#6@f=s)uzhA`-`1Yuu4{ekd5wXae!hIkW6ONT zWi>LrJK8zc=B(1^iCO!};%>4CT(;k-phUY*2^cecMdpaf%Y8V6?-{TZM6f3O%VNot z{8mAAXL+57Ygzg_$#oTAbNoAoO{Did&Hn=XRey5x&jZ!!U;qA(`~QdX&`Wts9D(S| zb3t@ic7y4R>=|9>V5PMiNro;3up$kTB{3_?ZHg~0N_$9BGlgHnfeWRjC3T%F$Z$zu zk=jWIhxdcl%NZ^O&x7ef`{3sNp)F$p)+y3G5{H}d8z^X#dq8qz^ZIv;mO0HyRiv3U zmV91yUD9F>VO`|?Ou8dhUznj#V>atFNK{w=!`j#Du63JeCZvaCB%wF&w9PLL(S*-G zS8xY$kv}*68_+9a!0!g`{^%a+IQ|KN(Fn*;0lh0VOFPE ztWyQjQnkKVl@<>ev^$Lnidk?qag@cUt&L-hv#^Z*(FI9^X}c?3_ky&tWxBu+wF0lFCTVGyXuxZ-d0?VyT-gK0f{8}umlUi&$d8j;LIK2IPBDBfWuT-VI zujP-8d{*9dpfsq@P+#AWU(Q0FIn8rvwJ!sNy=T6_pt}B^`}&{yj^lcSG6UO{by`pZ z6s#`0mjhHbJ>nQ(&1Yhrj9Zk6ec;^<+wb~*sJ*W$b@o)5ur5=6(+}Ltbw&r`dpVGO zSDuYeT?(2tT>80p&9Ts5W15fhSt)XAViutuLMuCm&a2 z(R#3uwns;&t;_7at$6fZdimbfSPyOeJ(Z~T##GKCDp@;re;*|_r00I1VX#BW=&T1* z=UacBG7FqtAS~T=(u}XQ(V~Oq9B~RRr&gESVU9r);7m5ByB)^s&QA~TaU}N_aZ*F9 zW6<7Z@yNjv@ndSO%c}Rb;%~0l+vu!Ln~#+|mf{CqRSCxl)3voGRSgbbOcy^v$>3V- zZ>-t=9#DoRY?%j8&JMUhYq1v=|APUr1{krNl9~3`$Xh}(cXd}~qTg0oYc-Fp+Ydds zhnm8~NZCG1MBB)~M%FVK3GDE&HkpG;H>%Ro5_0sR;-H5?U|C;wj*KxG1apVtAlq_R z4vKZ*tJ9xyT8b;yYem<;NEH@OwahNt2Vvc@x72%^^k5vf)(okyuvW^YUn(Xy<;D-* z{hWM_K#v^6u7NYIo40~dsEn^gxieWiPl~h|7)t#OrK30T!)6o1I$qNdykAZRk4-NP zL-crHzAAWYN`1|&(UL9&R8OQI{vHydd;9lxIA}|13m}Pc`MAZkq`9h6 zQd#1!whRl4;WZV0)0~`KkbXzGnfeAj9j_02a|<}xE!`2uxo9=Wjo<=U^aRJ3VU%K$=^Lus zQrE<&JL78g9TT+R(a{C|P=OX$RInQY&a6d3Qc)$zK zP4O3T$HaxaZLaT7_Lg(!3ASq!Vl2O%_yew023}W&c3$@@SbB?*gYmcUCw%;^gXME8 zk5;Lj%tpwsc0{#8jCTx;3*km>a~DP^+g zt_=vWtsIP-mT;F=!LkE=YL0w!V%rG7h_KLMi6XI4>(B-|b-TfFAjDpn9*wT8ROIFS zlN(-Fd?%;r4_}*47_0=7Y#I^tJ|0EY!Qr0*n1hNLXQ)*fCB*Z#I`BNOxJ|Q(Xpx`P z-g20>Uz!FWI66XYPGB1(X!-0<`Re0Wy3l?nm(?Qu-nKSX2g>H5F?@KMhA0d4P`2~@ zzZwPvHZn4h9UIii${-;CsylihpXm8GB$Q)+q6znVph?No!`gbmQE~!mK_jpOYLN^8 zJ$(%`OwZW+DnMi)MR;$)5#zpzs$cL6k|WkF$i6So0Lfpx3sW)~WP4~c59t~V1ppHE z6S_V?00Lz*pcUDHcw4mVH#sEJGxt6lkPxXB;1|ak@PfaO4s<|fAki1@3J+S1^8mT! z-RD@nbhdo80XBwPASsYM5$6i?MtJ+>Cl5TkeE(g%L zqpG)I)gwD1?+XKGkTAhy+XL>Aagk1lmr0h1r^T{^G@~?wG-EVFG$T$Wssw2z9*C#K z9{^rI9X$gYktUEV0Mmlmv6_*Zftt~p!J6Tk0jJ`V5-!Bt$oELj$oS!0;cMYq;ZK4W zq=LA{{5_jEoIM0l-fPl@u!? z!h`be;{=b7t^<#z{gd=_c$987PpIpCImK1WQ@iX_=4dG=ZJO-zwZ!U8)AQ^ zF@QhEp!5p9?+mmES3s6P%KNu%#uE35eu26r-e=qg1-`HD82p65-JJ=4{s{ra_(s34 z03rgiix12X$cMWb3CPF0Vc(|%W`T%+@5Th=qx?d;{Wpg#t*OdyeZMY;lG zJ~94wM|(iu0*nRr!GZUh*Bq-4&fx|JyLn=~L7#m1jLAQrj6zE53Mm{H6%0+hk>f}R zM0g`tgH~faz_PYO~`B31k7p)2ts^b9clqh`iW$g=ychwer3Y7jjKexMu@#CHn$fjD7~<`B6DY$7zEo5GIT z-H{z<3EG3TgB*Ir{}rqOZ-+Rvj;|D~0c#g-0s3%_&Iqvw=|V8e4f{^ula(T~xWlyt zr=NNLrfk7mfdpt-RtwT1o@!b?{`Yi8vLH?+o)*pi&55rRoQ^WfEGv!%fI&(^dJX3l zr3XMJ;Lp}^P6>M;B|zZ|N6iu~LaF^AHw&jmh6%}C5Yc5iVN6;QE`MFMcN9;)yJK! zk2eUK*81N|F_~C;4siiVUlh6kiwWI9D=u7Il<8vMGZ)rl%AIf6*_2|GA1RlDGu0W1 zj`QynX9Kw?NdX8Gs8U>dY?;U+z#3^OoLZEu;HOfoq_C#r4Ms3_Lb#+LkVH0|Q)bryN&-{@kUO{LZ@)dS8PiPy|6Z24k z=(_LX3epqg&@+A~fEV)4Cf-6Q7sM0ClyFpqNQ4M+Fj@fYj%ZXq9-oM#aqUEWcH}S8 z2_O~1Bpfv zQEk8n#-Uk!nxH;@*S{V^ z+^DkkJ>w28_RE^HiaurcWg_QK9#N2cU0<1N8{&y1~%W`p9T;2bD!0p zux}a<1`GZ_(B?be+@G%ho`eN@cPD&;t59=17|hLxiEv50m4}vBf5NyPMV|BT+}Zi^ zD;d}mavVkRdzHmG+=0rTjJ~4w&Uvw&CSid z_iB0I-6rAx2j)Rw&!g+OO^{J>S9NaIBS2qhiik<79pA0X*f-(r=3E$@sL-b55T6Tz zz=@Anzu3ImYPw;(16cXFGhhenvsLrjL$6WlkXt#(;jRc+rgfmgmR<#i;`W4$b+m##mOwUXOR-qWn&QN;|ff_%lDUPy} za__}1@u|D6Q2>~T~P8@mv6k2S@oCYQ(V^R}%k@J|03ik+er_!ufTjY>Kx8k86Ihzqscpj!Rz= zxhHv#`S$UQ=^bJo65Pp*e#3P66MFt|DeM3E{Ie!)4|%!u$4p(e760pXj0id&-;`n! z`*^UOxFL;KlmOx?aBWlWDPCgCgfY(B$UG0tMHY41zn9F9U+gKNbd2Rt>(1s5PjvYH z5WFF;OH%($icBHSO7qI>PUj8=xDImXeMkKY>Y39ev`y|$8aA3obk5IT{J~bo3B~RZ zQnd|IDUdX1$OV^b8OH7aQ%nd&hZoQhHtNk9=p)7D6b-f)IkoLN0JlXsNs`6K&f^a4 zXMSIge`gzdg`Ji4-aqm@=+l7L*+a#Oix_Z8gFwRr^*UI`;{%s#{vnwj5jXm7vT_|Z9yVq$MsX;!cMtW7_LMX;h8h12 z!zw}KUh!l)wQ_UqaER-KW`3i?%uLVWq&xo1`tY*kSWN`rG?p|}i2B1! zT`FBsV7=GLKc6IxWjHi*8b9kC=|YrB zx#2bst6+ILh1x5ecBX0jRO6kdBady`0omMgpkctQVNWOm~&eMp00UM)NYu9qJ%ExjKp}`MzV1= z2xFPZ1aWd!i8mlWii)x_iWM#G?9pjo1p)qD@yDl}>vScin1}7NQ zl!A;x$0>lCaPC41E}hc+1evyu<8<;kTF#-=8{=h0UUm)UJ#%$rr1+u|Oad_79yOAU$pp0%m z2~YFCtkY%1oA8x^nrQ8(@&SdyjijT*bd{{hp87t+gns#WTGEC_nX>o3UoG?!6Z|eA zDqCD!9e6iaLEr28vnOrnr?$!91i?hjXT!$%{6rO-I?Q=4s z3FZpQi6eMparz@vC|iFN6b~)7PpBU?lUc<@lT?qJe!l;qB2!PHT^T1sc|jt>^HwNM zx;G9{Cyo?&x=R20$o7e;X8hbh&Mi@pUoOkXc*kI#3@RfyCeBMv(s3krv)1cieYL;B z=G2tmw?`;SISuY5>1-0o?^{4ndPk^T;bf~y=N4TcxYN#xHnIpn&8|ZV%Lzg1T7xuX z2yxYd(kJ+^s*b)lhq>Ojqv)8+v|}W{qb(?o=$f-+oYj?x90XCPtq^-ej!0@;Xhcme zK!01Lb?|DWX5tx2NGh9bnh(uZUWj&O(Nn+PEC|k?Tr4xgc|HA1k|}g%*086wqzhM2 zwmbwR2$vQuSDkS=7Alz#bn}yl0cq|mYAW*F#BCgtxtr^T(Op(wz_(i@>rEe|Rn)nn z9ujwrzL@KC7UQ?}y4`TxKZC~B#@3`!-{1L_Iy7hH08W{&@%AVmENCHm%B-R+-Q!l| zj@nT|n!6BBGF-J-m@jpWU|rl7i|7~~TkA%bjIfuIsn{4Tuq(Y~S~vV+{!s&QY(8J@ zr1>9X8xg_1wr}8wE@^ZQStzAQW2{cD@+Jx~7GC;YrG8(DuaCKrUv!r>Trop)%1k3N zYA_+CPSd2NE9LGSw3-cup<()MrzJz}5YEcFsT0`*rFA9RF=s=u(TTLB78MR+DkH}T zY24&Y+ICGtWJSYN2i4@=d>s7|M-#*im3`MVuLALS`^8rIIhy8^`1|J9q*PRX{iX)G9myNZ}Me;POUv1?uPuA5sn z-=-sbRjhBw?tyI!dspW7on^4vFhMGUguec1-QY0?qeUMsB%{TTN!UOvW+QS#EBj+9?`}r_a%5E|pB}<>X6;^SRY)y&9S4 zC4HkdO^WrBnu_!#n}zy}rhZy>o_-<$ejZwFtTWcs7<3D;jCE(23z8(sxe9#yL$}4G z8j%14*^xntLS@V~-!nz$-rYGzR3UpaL?3%@;{Lu0P)~t(b)#B!UxC+LB7ONFOuP-d zMo7}N|MsgZEkMEW+x#yDD>mZiB6}Def^wuK1LSThjjXGT8ia=>Bi|RDQRlC*m45;kE_Gh zIVMipX>~GVY%uk5HENQiFx5V+FuC~Wp)ovfunG>-$`nVXu|4YgDO+t&PetduVO=Ty zDTg7?KAeR`yu;N<)0F1M1U#W+jRLKrOOXWmOQf&`O8I{twXg>+E$VvLJj@>V3PYVQ z>KYh$Tr^)#w7K^dQMS!U+r}h^3AJ|Bf%EBO%`AFRt=U}VwvT%EDt{;L;Fy^RtCzT( zDjQE2A|}db#;R$4m6=MHj}lr$&0$qLYF~Hc(6IA2=VP&>1d$J8@T|e-yML-JSuCwj zAvA6#Pw!VFJSAWPCw8lJC2Qb4WsImdr|Q3Lho>GrkCc|B#f&1QisTU?VXKyKYH3T@ zHQIW0M=u{L{thjysn9k3BvzJQ?Wb>gFcWBwxjl)#wZR~WFcBKz!8?faOnSjQWU`7# zUDOmCdUVFHvsakP@L%fcXcmJZKHN`{xbM7gtjK;FZMxfRtIGC~QReLGu*o7W=+Ih~ z%MspzA6b{Q_jFaiALt5P&}m?kN>a|)vF>+3?Em^p+O8Vyw}FgqHf6ZO?SottJR#j z_35IN=DoDwuts}shr@zKJ%6;c?#;@tI6iG6oZM_8xM6t062#m0AAGO%gxCogH^xTk zd`8SoovGY~cqZN<7L&zwnPkp0Rl5kqNRX(A-(*t?vw1E@&a3gLD^TfsUY~XAV0iZI zTFl(5wwrKyEv6`~GSN|uW0A!)4dYBg#BdLn(P+PqcBsV}sA{eEy4D;$u#KtcY}P%Q z1WB~x0xS0pyLnk@An1MvjdtPZx^()4lV6P1Mmodc`;RaR96qY*l-N{`Oq;He)lEJh zMPE!9)sl7Y2Hze~$86w)cq|rTk{-l4-`qe8ID^%Ox8aH+J4L8sW|^`U1F5cq2ZK4e z&*ja0+?<@$0}D8)rQs@a58u?}s8Y(UGbA6h0_miwW8%**RI;a>Osoe;pTlJkmVh_? z-TS%8@z%*JQ$40Fu=?pHDo_ftg&OznH@zf7rVtqt?X$R2LBk|Ru(r)y%?e9*$J*NO z)6T!H)Rm8%=~(MShMQ(n6`uc=D=9?iSDvtX`C5Q{%PF~bkQKTpP)SHzoqYvrPuW%+ zS@iBUv+f4{G%hr4Diw7OeS?L#? zg3^6Ho`0B7=OR+dhO1PibErOc%7K^fTLt;aA^OJqyS>51vKF6tDbJ3TOdhMhinCXD zN~X)(oCL1T1^CnGFtx;QK5J>$u~<&$WYfLu0qk7Mo`r+R4C|cwlA&^q%0zf*H~PTV zv?)63O948bwT)a0y3AxdR`#}1m*Umql}XN#G^#YSXg`%LtiQCZX&k^J1spEAg~5nI z+f-3Ix0<;<^OMKN{=yHMUp=Gb69Xr%;2aF`IRtz_*DFccIQ;LQD%UBVEH+6rCZz|% zczzcBtpw@geQ}Kfdv;2kxPrhuFApUBEh7PcG3>k)+nGoWaWYJ9-uwFjix9?AJzW-W zJzr&I&eOBeruDAi@rHy;qp26?z}6zmvEnV;8GaIvWP6O6fS}|Q)!i)tdAQ93(%jQM zA2JGauj!y|O*{D5FEuRQA%o<8`d`*-5$@<65tL7G773ulA}hJPcV+wPJIUoe%LVoI z_cnX&pd=xkH?n!UiY&g;#M3Bxu#H6&Wcf=KN@rAf)M!o>099fDqYk3i(YiDqf-CF+ z@^lw|3BJ*zd+g1k5?RhUJ6@0|ghHEm1N;c1Cic+N91v*B_0Imw#1V!k#T@mr?FZE2 z5;-Ei0P2$W(zaFeP)Y_kTgF111bCN!2;trCuCRx1=*q5e|J1jti2#zt4yK0}94`rh z{v%2T^R|h*2MQXuPA;FbJpT(-#;a6Xa^6KI3r6f+8*3xk7G-UBhoiENSPOk~PYr#s zuU(GWWL`G?eNi8;+F%}TkM`!Or3=Pd&JdN7SQO;>h&s)r5IdIuE99BdlvWdR_coQTr7X{?fKSS1%?)n%gq+U z8}wpws$z6@VNWg2p=vo@?|6=DFGuRZjgv98L|!hcW(P}Ct*wbm=3kqLsY|9DbOWw~ zml%FL^SIg^2=Eu_`eYFcqf<_;|B@n|++IS^e}oNS)NcO6#Ik%y#py_YW^d z({z)WoOTz<=9BoQ^7o3F+m-VW+zn89Cw(E@4MY$KzjLx}F5I1twn+;<{4adHJye(4 zzt$Tq%x8Sbjhx7WiT9X)Z$hPkL18H>U4i^ori~wqfs;)%GDjgt5^ho*x>K~~OBoab zE}K-hBv&-A{{6+IgflCQ7o>|r4>NBFDqR$~*6Uu~ZNdE8L;C%Jw^u;^_+HQZvU%lg zxwGe5CykF-JY&pEe{{&Lpc5-aM-VemSEnY>!k{SQzTM|->PGO%Y#sbfY<*G__Om1u z=!9W*(fmuXkN>XKYGQT8iY7ItL02pE+sju?!|>hU>eAo^Lc!5acxXAyiNKGMXZg<} zR@0jjc+_xdG_DaoyXW)=S5nv!t-sISs3-UtD64cXCLGS?4Rm9Jij!^Xp33o59)}rc z8t(>&doUM0KRJo7qIGn9e72=@69su(16gqqCT(}A;p0U@=qXksm-(;FKD0_CR6-MJ z*=7U+D;blXT9`vNTvsdP6S3W8|k%92uGq)wZ9z_qy5Dqn$~IF{mjljjZtyEwp47F zBudSX$fqj27|kAk(7;cqy$Q|J{}LS8wni|QZ&*hu0BhE-)=tZ1`vIA^cmDy~=3eBU zYA)-T0;AHU2R%4FzfK+hGdIv-K)y{ockT^&J`F7hod#wSl-WFbwi3l0 zE(Q@F!~UK7_q1ZmMI#5&!j|gw-_EeyL28}Hk&`DM*g0X$CSt4G)lCc^o55^i+nef{Ejdu*M4a;V%ayh zu?X`k;=GSgSCD$(j)BgfN5-6a+ z^>QBQw-(gB`td4}$fvdB*nF&#Vm5j>S6Eu4oh+bAnX8%^CXb!Ng6)p4jefx~nVVE} z;$N=VHHwSc7z#guS9W4>gw8;73Sy_ZEQsH$;~>-H3ZNeTql#@z8);hoROy`0;|Kgh z?3IIEJJ~@ws9^&KG4u?l#7*X#_cdOecAc!vQiZqiN%--%?oLseSnCyDzLG6Lv?_IB zn-VM2a)E64TEzo)61)W1&w}CtYJO@?b&{Z!k7^kVjY?OFTB}H7j-Ow`@}PxpjyoVj zoWf)Ha)Z2iQ-6o;(w7c$;mWd1P1$ofk1<_uF+vmEJdCCGjBN4|T&2V%MZSkcsE8;z zgU@F4r{rBxxXLghZeP3{RrX_b(TE9WJ09tIi3Uc(I9VK(C;Aib!sNChu#EawfFwzf zf0%o&FEG?Sx7y)UZ4hF*UY6o{)A_B;hZ^RSG49&4xc$=N%YsX9fYMe4nwx%((Ib0{ z->pu`43C+gj&8-Ab=_%Uei)I-i6O+z)-P(#S`~H}WH{@7{!V%FIJv7S0abbGc<~uP#b`69Gtm$=urDs(^gF5_(=D zr)61)N_AsVG=6I4Ke)abeplnGKLOK4{df(hTz_kl6Y2wzWZZ|Bwq~djRW~H5rCv#- z4ts!iMtfiKi@_Q%`cc?b-w5p#Q4?>}9%Pd6`NIHAd`z1Z|GwO@#%u7RQ#Bx+?neyx z`6`@uqVJy!LIX~E$K4mt1GLZ=){WUo5B=st!`6erq%AVJRL&@Is?(6j1Hx?G1O8W` zN|j<{kA5^*euSF{h&*D`)2y4M=cQAuB?qC2=#{Cg+9A?&QsD;!J4W$Ew0XqWk>l7n z0uFU1<2K$Q<3jYgh=b#plPS(r;8E_G5YK214O1dmn<%3|mS{KMhWr~Bh=ech0b^~3<;E;TUqN?7#iZ-Ba3V4%h^0~J^a0ZLVQqv~jUMro zuVSRXMen14y-CF$UMXLX*!4lQM~Oquk{scs@mH7(BzEE**_1<3rd-lBM0OZ6&M?#T z`Vt-g{X;Da@^{;#l8WttD!DI9vElr^`K{d03thb?&;Y23(<}QQsSFlP`=bfUc;Fg&ErGT0}@wzM*9nyC%-i*iUD@HkzJvG___& z%~f5gDGq{P81v@Qj-W5u2kecRSsDLMGTYdilWa{^)r0fKku>+^>h#?M=1uFi0u%Iw zJAS9wnwxyMYD_xvi)SdV}$lv4s@fYy=hC4$5&iM@+32^omMvJgKWQ$oN z3y4dmX-Kw6urqdNttG|unOHRw^owd8N3_JH7$1W(l@zX%o9emQ&jn zax08LaEBSRvKuNy^&sD#>v_114OR&gr;7A#qrFpjYpl&TjMW>%91p|GmOiR-SkIT* zW=wC9&ZdxMb;uSJM=lgey!q$17ft40Cb0au{l*vwFyJ4kA0>V5f)Lz2SW!k&obVa0 zmdDn8u|f{>*Xz>oXvOg;t1sAU6j{>(B7z>&E}-IsuBLtwbk|1GzYH5KF*%qimiLw!^cw@|(HP1Y!&Zs)I$Jpnrz4uxq zHpyL}$U9vByzX|3PMe0A;~J!Kw@y1>#!uRX|eyo{UM z^`DYD6t$5OZYD;lr41veCVg$`U45jf(5# zQsp^KjffQWf`$ZZMfG%Grd8%o z`6eF)J~fRwwG>aK8Qncols4YRBH}hiTTA!m(uHNFkE?s-E%jA1s%M(5Q6syEAfgYPO7qz)18EX!Yh{h_I=hTXNPg24tV1#jg zZvM2!cH!E`ZJ8vG>|>=h%^2vpX-a|bHe@+6CG6IF2`FKReZ#`(#xsg&H&&S%r%d{2 zGe#T@j_J*&JC|rW>myHZ**NRUr#H3bfuB8ZAda-C=8uQEbHeAf&ryrC>Ml|;;4GtZfn2-L*`0UQ9i&p6+?~RZh`0-TS zjU5pa7L99cvx@J(m!Mc71xuzEO&?w*Coe}H6IMJDjO9cYk-NbvCeMEr)z;l)DG9fX zDyuE+Q&){Ftky4?Id;p1wdQFAMxf9Zt846z)P+1$R{oGZ9p~27{>EuLn_tSL)~xuY zTo7G`fAIKoKdULUZ3f)VToRUaJP1T%Z zvyfFD(X{q?ZIv&_YDvwjjpzqN*-{UEG5%9&0a?8`F5(L#Dnj_D%w`T_ss* z5$_|v;$3DUb?cH*t{@?IZeKquUrrFBksdibo;7q#eLZF-Z(DgV=PKK9YrJ8_*8x;D ztvo0zm%qfcR)`rv9WgH%`p$#e!{>|a^M@`Cop=)-zfx&O;<*Y8?cvQNb~DNYW1VK5ONRL|gB1lc8gc z2M)!L#se2WIzH(0@tKP~;kb=K)_uSx)2HS_K8ngSHVAHzA}ypG5diGkw*q^T`}jeN zc7_dz1x_%6n~_8px}d114C&_jGTcibM1vmwZ*c-Rr%=_Sx#P zAcX7$O~`?@VMGf++wg!GP%WO1Tfl^3w*>`+J4g}BM-&D?vWlQEWV^?*if_jOiG~5_ zftx9O_JR}{As*fP%HVr8$O#+(5Hvy3e$TKG4N8O(bpxlPh=zb_VSF^+QhR|tNqusl z0Te+KHXvsxpV+_&ZE*AO+>a3ihow>4zzGKM5In%U+d>q=0!zUM`3?s-51eoVd&2v? zbiE+Bvx^=LAc?|uTi`_`gr-fC7$y1>}Ob zhoC=UN}>L(O1v0@jKV(IcoG9lh! z>C<`PvMq!aL(FPdSGQ_uV`YV`etr$KcP~?ys5pzhYplQ5_Iy9N6slOHBR$K+r+#R@ zdr^nNRP%85mfR)4Fdvs^_#|(f>fsZnwX3ggrVz;fIC^%rP#uev0_i8zqvb&=1N43V zJXU?>G0pQ=VJ+BZR3FO)Co6jED~XElsl+lT%WF%gKU8p&-bH+$|0BPJJg0NOYO!Zr z5OVe%tmZ&WI|Kb$#y|~hNjP~Skza?0H+lJkilo(60t4{lBlUzc@!Z*3D-X<+<>jRw zo2I*J;+HWixL3;Mt)GVZyW9^#G2_ps`8IPB%pVcoQYHn@Ex`tLD=AXUmKhs#Z#Xey z6)%)ZRD7r^W^cVynV(((U+NED3g*pkeE*Id9PIkOKJl>!ScROr{xfFXv-O!rCQlhJ zg!JQaQx2CaRjIZ%@*Lh&v_ z;(^cYh`C3+J*lXbECRUW zUF(#d;ac;#0`k^zo@ROZo=(z<0Xnzk8XtC8n=nt+B&vq5dcP#ZPv-x!`bCE^%g3`; zh>zwaq*MjE#>Oxs=g#?#OD%#FqSMSXvcUE3rp3YYj&V8R3yJ=>Uh)$(+;8q5FiXF= zy$BZul=Lv5NpL7ps}rab$Ro)i(QqGeOH7gqYZ>GKC@?Wq+$b?`opPlk5SJuHL|KM; z8I2KB659t?i!JPCZ6XW^GJLj|b`lFWUcR&=+@}AzV3~1t+s18=pUGUgTD}r|&i?+& z|L1w|*1eGr$OoJ$6+9X#)NRbjz#yM36A*DWZxxI1O03Lj+V~;hHu4RNUp#oNRZ+T( z-5L>N?XtGW_$_Ek95|!Y>xPKovOuENhjlnj#jl)ibzs-Li@9nYa7dlxKN`*0%DFQa z@Tr@KYK?f3kU!>7t##2eKBR!AeCB5)7VMsG`}J?e9le;ynXcy31U5XfA@ml`)q~$< zQiJVa_L*rKAuZGQ#QC%8uJN_Sl_Ekv$tG>8X_W~^M0pu-5nR(OekYE}jALz@?djIO zD?Ge#8XQB|GY`rkM58n5$&EtMf5(f!i!j;2pky}bgs^7xr>3SDyFIu73CD|rGmT$d z&0ED=#lp|RFSBe+GBs_Fbxaq77=zeS)|U@^=o8)A4!)I%0I}F8-aR@Z7Ti7EjcMbP zi)0uXg({yC4k1sLGQH=~R(B90yBokH%G2N(K1siL!gRvZhtAe)f=^-En!kdrb93uc zd}zLMKha!#Zh)f^bu;3HE{0WCb1M?#E?t7xyR)-skC*q4lV6o2CBAeOgQ7PD`bBkM zi+DE3N#vKJziKI_;eX}bAvw_Z_^O7umh>6=osp?Txv7bf!NDOnT3iqZVEn4aapFrhNU4lQDcY};S@(K+7bwf42hIPj*^r> zN5$75#O6I|MroLb)MB(wN-|{7WRwyk7k@l?=Ysl}$xU@B z_zrJA)-}2v_|;ttWe}?E0-eRtdu<0krDJruoy9k(pwsj)aPC_U(9+h;fB2{-CorZyB7@W5BA%tJT4;C7XFS5+7YmBHQiwGf{p?pQ zSM&JIRMNO3O$*uO3>g%#&f-5?liWCNuZ!+-{GRim`^+}z)P#9In}nN!JE%2?`;{@V z$c|v!ct&A{e1uoqO=1vLuH!^DFG-oJ_Yb4Bjg}y7MC_^f$xpfC8SFo@?{0T^YhFgZ z-m};PeUPjyrq@y>R!q@r7#%asJU@KSF?af<=*fOI^0QC(Eo+h!fQ9QZ=`&r_u8qA_ zlB!NsgtU#;?|F+YA)GICNpvSN9udQ*%Q&~!v}`xRsk8No>GtW*EIskFRXxr1 zs6QuTkMip)IEj>pI5zb4JMPNqdSafKiL$B*MZ&Bjl|!ixuh&VuZVSA-A9fDC%i-(c z+2vx|JE5kpKW^@LmGD;Ds#Fm5TD23IS{xb8ZgMq_ec&9*tPdF4uf?m~wkR5XAZ`Bq z^`7*Dlt___!a`PMv$V6=m-aSK)P2@0{qVZ9z4v%m!dJwob8^$D`yUvY%3&f=ooy%UzOf+SW8NEI&LI@{@9MVv3MKr<}JL5a+Bx~E6%BWfwMo~R1@&^>M!T67f`wCk_wVhl&(}9A3!N<;1qS*QhGMlH zb$*J^1?bd#5Z;re$@QPB91X_my*TLIG4nC9d>wTc+XKG`#C*m|>+f!pOYT}`JaVND zA}_;Bq<+`$*qCpOuI%fbr&INN0ge?d(IbDZmkm;zdIwix#>pLHTYdXgRU|i}Fm>x6CgH(hK2W7oy`e+M%e7Ek zl=j@H!EAGQ6zzH;_%Pkl$ym3=C1Pot@#9G~w;t=oL;99LgWd{0L4$uOP7ALFL8Xcn zxhjq_&LlYsAbou2!S5<~J-H9aZ{ye`Jv$FaC=aZ_F0-Pr`M#6kweQ7LwJgsP`x~$B zeVyAh4;k%DiNUI396PB!ppm0ccX?Ct>!X^jK@i_AZzi3X!%pG zH^Z%*IEDA#jQdIYxwH`N?N=L17LS*Lz97yeZf5qqUdUrtMJiu0o;{$MGD?;!VOb+G zZI-tBMeaz~Iu-KycxLp9U0G3b^lUU(WU6Mfy+M6`nV}!{CJNUO**mlVjg0Nn@?0o} zg^+Uaq`v&})M5^V9c4v|dS{&YyL$|lXDa$gHtXWqgCg>Z|G7?2>-ECmX-eL^_14ZW zi*|ksJqm>GjE%Zs*|JnS3Xe5cGQpEyQ-z-=hO#qWIa^zChQ_bkOqSC(cvSiB6Kaxk zT+(J|5}w$+T5{bJk1dW4nx(wHz!w#|c&Q}FEE%|HzjLEvGAd&9va`;d9vGLnUY!la zzc~@k!vN?O|0XEi$0H~`Ob=Nr7@;R&1jITk!m}C|k<{gDGS!Ld6sI>(-EwCaB6}+d zW#<4)&}-$cA`i8ra%$6dYTn_9Sk$z(dG@=|CICJieE6hjb`o4@WWj}05r=;b7nX6& zJ@5RMs+n*1LoJZjI^uqTMrg;qW-6en&)JP~ZgkumrBrr$#hZNnaAJ^w&{3;}+M4Y> z`R-df%KXlSE_O=ub!vm1*N@ZTFp4k1t-LA6Ac6=2WT4;qr@(9eP6^>y_bbglHm9#A zTajOx_TNV}ndr%eXEW0dty(|W&-C9HH~(;tILE^95~Y%v<;l1EaFn5}3A}dwHLsqx zo02FYJkfQ9=aCb#Pc-?qQrE5S1$jGP>P-FN5z(i;39#{A6tTk;a8^A{8h)1JL3{W{>haHBl^2mU6l_C_w z&%^lr!mw{T?rR+M`bEA7#SOJVhirxeCIfMT96`uNTwofoz7Z;zZoSJNcJ*Ti36?aB z6ch#njpwS55i}U98p|QUQx7MiH(V1OB`x~O!3k!DA}Go0tnU{4ta5LkXtwLTr8~UV zb=Ae0@Jkq@4(1&86A1PfIzO}zQWl&7bdmIrVXB6b<^D!Be_9!J#7oTpg$vgD$Y|A~ zO~Ft!BsYRk4a%=Sc1rGGIuSbFd-i;NM;{HN z@e?i=i2-3Aiu@ObB^)`l5w$T1*cT)K@-!hZ=)OS#GfpDw!B;{XLRIG$!ZE-P2N1t2 zqNP!^p>+q+jJ3BH(K#68iQ;YZa*72j}1piH1VR7rSUR|WX7 zU$g&sDJj-xITj7pNX+%-bLpfyW~M1bVimL;3Q1wI912VE@l@FPu`6lmg_O~O$r>^V zmg1c@tkn~Cc_J6|!z6RF3xSXv426-?UyuICDVXHSc8&!8Vg{_Ry`ZrAqxw!wY9g8& z9LT}d3R-$ciqRXuw~9Z}j+QH8Ij8Ot*+i$+5KU%KPxuL%Zb*&Hq z2n5O}Af&Du^$SzKlEoo^*^{l*Z5B&%-o0ZSEJC_ULw{L3BbIs51=US^%bd%X%dAI4t?5&dV24JxnSGmM*)Gp zRD^wne!}uVcmRms$Nlt&zSsQu3V+!N52A(^efKvhM6UHPLj7Z7x%+~}0V5zTSg{W? zc%;jaGX(<_3F!bcg82^4g3rpjctFmxA?LwtN&bP}kguvRNig5QsXxBcYIq#U_9Rwp zMS#x=de$bt{hww1#QSMGs{e#YK`c)F z@H93FIRdIe)Mv6!{-;kLM&S^ZSp51@!zn1Oe}ree&!Y=3MyC2NWly3$*o;7U37#Ec zv;V#D0(=$xX8rrNIe10aZq-j7v`F@F#y6SO5As^ibme|;OQw;_-U?)pRa+9UEW<~+ zbw_^EszKF2>v?`|biI#w!}znWU($ zLaUv?_*{o2r@QpU(BlQ}>4I6<7n>8%OCe5Po8V9JNO-e}SnNw&zg(?ik4NI58P-5Q znUaz+{0PFX8~eDDZ^@Tktb8RoyBd(OuXM#;+#H$x$8x7_lv^Zv-x>VGkTXM=jv%iK zzV@{IBR)fEDPwUXv}ko9EZbWBn(m0Nhtd=v^NZL4)&>d_1e-&nO%sV)-Q0n*49IKe znm9x7lO4Ex40Pt-&!L}j)ZjLKZP+SL>oV-Q!O1FT%Ri~&PrtDA#AP*c{3G{ENNBnB ztLSY_0l&M59LoLf30kN=@#u+>IU<)(+EVu@hPfL@ZBRPdn-zK>PJy}I_qMbc?{{Q< zU0wkmYlWqiq%52* z&ATkkv?BS!XmJ%?ZF#&e=t7J>(*7GMFE7-$m-k&TAW9?3sV%soeq@CxoGg5L{)&{B z@!#+83p-!iQ1Elc#<$zTVjN^1P##!m(4%nX(6xaAU3y03)#AdyXM$>+ zMR;Mv6NDT@Ke#7C4`_%zND@TfCEKMKm>Q@V0Du-lyoKt7x`pY4Gk`aMH9+*E^+Slt z+P;k{YKHCl1i}L2PX=F_a}Ktnx51Jkyuj6ggdO4dQQD$BTXExC^@J;ZWS``g;J9J! zVb7t$0>z+NyRc6XqypXhe=*4j7yXIcSLgi5f`!-zi@fD|a~JT6J5gc`d&5>E{+tI% zfB4t0vY_mTwIJT5JJ?B&Fb7no*vEHG^)Mi$$-zko><&ODr1GQt4OP;mWJJh8Dg;F8 zigjg1CyemQ519IhaRvk}(VXz!H?d)f%`o&`5tA#yFnvTv3P6~I5&Vcr2t{oKGa3LN z4wDxM9iT2;6aj4#*z^iqX$J!J7w*YlUFouaH!HF2s(fVofy6-N4v#yf{t3?2-Bnk( zOuzz~@x4cG;ICbsPj;*@tkvqp?@-!V2ntS?%V&{hLzlU^X>6;lrt8N0<;(?#s!GtA zH?Fdl28~5p<3t`kvVboaPIjI5&!T|4$E$mvPA(TJj2;)#XmJOIK11pk;){jw&b_Z~ zBvPA}ZHU0|L$k+FRj@JhM*3T7UW(o#u$9l;&C6Tuy0%*$pnj}&6HINkDTZC2eA80R zmB?$;Ho)cW$)n1=1USO6)vRy)m?UlN5UE#mLf}<6Xgd5tDYlEmFOl2gQ0E4j4Ks9CM2%D_YfoNul?UAC{sg%#m)qX94-=;Y9Flngf?MH`+_V6WUAW& zT%fjv&p~LH!OU&JsWqY*I&*>OQ?o;l67`8ilHT&`|G2hO1|{A-4o3#6mK~3%YyNK` zn>dMjM)EZCkXe(eA=;bZg}$tJ&N8Ens)9Fig9SMu9;#bByC@|Dq_1%~kIf63pV}BN z3j5OE6&-4ReO~6Q^0Lhac6NKY7{LnWmz1zA+#<8@;uw?yoilryq_w}cQ}P0iREW;W zoZjl9iMS2F%~%aqWGhM7mg0ycY~`S9T%*)%*CedWiEOXI#6a1en{nj8=+5=fRMYh( z!~kOR4^)EN`SF39G!xk;x42o>mpOs8pK~8hEUo3KmdofOnB=~o%oTUz&gNmu*ky(JmcZXQwxGuEs*!v_YRj&ljGl>RlI+z;%YX0Y~q_qz4KGPL7RpreX&U$xW zR)aIi{ELncJri4$Y9~*7$8V5c$fLl&uS7x$3=BhebE3!^N4z)CwpH_fW`1BS%~mmW znsJb+Sn(C^G~}M+W|ymBk{6hCMl|*!%yHttVD+cgK0AwOpUrM@dRs4}`+R%lEaI=b zOOkX+UWO~LkVVju)K>j8rlzL*qEU9a{D?z=cGy?KPi^*Yze$9>Er(yMEujgDAXLF( z`MXqnL;lx=aipqQgJ_}ESJAUR{U(w-kilrL&uSP2$WJ%`u?7nD0*icr8sg2;gLy$M z90{x@6dOj)N!y%p5O}HWqlgky$Rgr>W1pVWY-8Q6%IdLI!JbjU zp7^TS7xhKG#|6l{7sMB~?`7>Unw!=>unSwUSR_Lnk_x#c@HlX+Ec} zqE9=89%-lK5|l@RyY}kv|85z{v46@DmD} ziqTJ)AY8&7In`@qCT^A7cmk5*$-y}Eh^xGyZ(^#qT+KJo00V#F3!;al2-lmwzh4vm zF>T9TW$1s?Y?^dT`oAN~-(RSCh)brv#(c5nR>_Yij+y5;>jv^+%el$l9TZU`NMkj$8A5IswxngjJD(ooYHphS|B_Lz zdnVbHj9rc-}fGt}8nAj%Owy`SFE;$a)#j`%puwu|?)ikHYK5u4?^suC?8( zQS+o`(X<9=64y^2C4%qGa;x=!W9+8$P=C+8HAiXe5UCv|vW-wkQI1;h-@kFRi*_`P zCNYim?X973Iav}c&?p2RCFv}Ym&Km3PWWNOI9kf3u>ScT|1F9|*KCPu1Yf&h@Q>vG zz?!o9V6`{qwO+0`8i@g#@FLPHg}oFsYLz=n9?Jb7U_ci(yyKBRnmAP3raRGk^ABP# zGuP%BDb>~(`(vG=UR$2=ZI0!CVEGE?PXj3u`oCxki(PD(jyy)vDrftw?5?maxOtwk z7d^LMM*A%9&aeU8?(0U1L}X~qubQOc4GEkgn%8}+Zj3+O3%O04NspqNPSL!!3JH#5 zx8f{#S2kZhh4!6JCH0Z5+p+_+2v4&;7O&!hMO?!`N^PiNn+~Lb)E9PoKV%(=IzmS{ zQ8hs_dLdQY)_OtqpiBsUM~n?8$yQk_hDj-o>KeMSA}v6KN}hf%I8X0G1fn?Q#ZL&k zg3pNFBd@vlt(P|Mc40NABiCEq)ijcJW=C%iPR(LXe$ z97K$2`3R~?QG&Di(B8&Ow*#V!1dqnVw?JrqEJR~Li~-7AiQaeUvfM0F)&CH4*+jha z*&($T*gm-XAX9z<3Lrh0074@gqPQ)b6(_sn$jH{a;2>cBR(w994D6~GV*^I_!P)3( zbYwNpM_${INMYXyIx18fm20n1!m>vOV<4P!0#R~o8p40vbJ zY$pGr+TW1sSj=OHlH4d4=Q-+%YnK~YwLaqa1=*@h^i$!ZJ!QVQ`3p<3e@Dw6vjh3O z!vO z$lb4+GJ$KtXM2u(ajl;Jz2(jw737JrCqQ`BnjFQs-{4R=*!*r^CX3mz^5iw}=~dwF za&?6M>~^(1D~BRy55$2OCcr=1ZH#fY11c6g+%idt(q`LhPTM!hiSqm(30YdU_07HLDI^-BqtOt$h- zw2B3{;JO(hAJKsPCfWSea^KpYrXm%wJa>Oe^4kY$V?AKZag!q%U*-0I>uOUh$%5my zpk3Ddb{%=q4SxmDN<`tz}ctQfIsZ=3%MEqnd;}KeW8hM|~sJsaHiZ4#VUP z3*r~3yKU&jZu;Sk?@z!v(XKdXKQypu00rz5AqWU1h5+IG=d6$2!thtPqpBQ={}9!y z=tOHjr~Z4o_df{b4x1*Gab_6H{ilWIJS0#5u;Jjkv1lQPF1DTK^s4UlJe?sGq@ovE zwdphpGqIbNYHAScDX{nNL>2Qw&v))k!D7C@>_(t%!qn?wdRuJV*osq8TzZM=t9IOC zE8mjoggUUXY@v0n6KG)7p}2vX@0%aRp!rKL_YX55h=h!1;WT^iMIYR(XrH3FpWsfW zxwOXS@Vd$Ic@uk1Uu{kDf6*`jgW)fqz)Sf5L!oA$q3;%y_echcIwv(ywesq>)l+h4ffY6K;@a3~lH-t5aJTYHZS+cI}&aq|{=i8@r zEDb+pP81-@C&9bPV6JqFzH@RJo92;SV9~F28Jka82$eXDXv$~V6 z2kiy3>%B@7@5M3L!-Tsnei83X<^;KlmZZn%GMFPtm{T}emCh&Y?IxP!gaiQUQOVeow#P_{WIoPai`p*watF?(cN@) zE^iW0{sp}}rZPu5XXifA5k&!2DA6M1^d^SV(BI0ks`K5R_%n~)+Y;{>ud81#LU#MX z-=AZekQ+VE$S2mKJi(qtFVGVr;bE(qA~#|#u_+uHowN6V?povG7lEf)XR#~DzTK|c z#$oe9HFl=(dh|w1Cp>H{3C8nH{vz1}NnyzM-WPtTux%vL(|hL6-o316QDvL4KW&=$ z(0Ew7s6AF=ce!v%?Y5^f)z&2DL`!d#Z{pO}KF^`4^C`Oqmu42XL}b8Q@0Fw%ndKyS z%IuXiWk%96r4(!B8O8rtVQ7l@k;%{$^G0d8Mxk#;+C3M1qjGiJ4`1Aq{J)*Iy?<#C z-4R}i=5K=tFWO-|MvXkJ2oqYFWCry-wRjaznO(-@BDI`?N4K|ec4;g^Pb=?_1?^U~%s0dG@rQ(=YJqf=sDzu% z$7C4*zJeS%xqiHlVw3oszwmt^*j?>0dHA(F!$#hZTR2CUPw&G;jM_$Dr%VTx0CV{~ ze1&p**&Vn9IOo4@E#xt^X&p44<36BlaqQTTKrSeYnN4y^d&YUbe4y{$R<=rEx+SvI z%BSdJq@mZlB{)mul|^}qwx%pjJCk~naXup~SyGF)AvoY-VeNex}{jga%1 zjMZqPOM|uGqe}yn@qTV=#hOam#bjJ89az?I4>tC9*rgx8Bog|?)^B1a`}Yco!|PF? zj04aL28DJ~#WN)9_vnaR?W zs*2c}lT{B;S4dY;B5h-RS?r*DY1tMA1bX?9DpYq0CZF#&`P+p{I(Jx(FF0Ero#md9 zi=-BUa~|v^W{x_Mg?N}oOI~9ioqL33M)UiGeNzi>*{sj=ZYv+|4g9;DF}En=C0xX}fo+j3uVpyZci z2`KW-xV1XB_SpZP;4OVd+nlm}Yi-?aVI{cdT2IV^J z8WjY(s+u&I7*UB~9;ZsAMiteLC5G9EAWv|^tpLQ;-XTwSyDBn1zvWfqm^KJs2 z?>Ks7bjEhi>fX?N<7XScAj>`8C<@8&M*PAA3dwO*7hhhx%aDQK4lmiCRHpO_8S}D) zrJF{NXAK_;_bs+n95N+;_C4c{Z2}KFO7csHvGA5~l(66Isp)3-1I4yuT`=B_VsO7k zP0GVJa`v~Nsd!p$nYq@IjvD9#UejoYQOI0H!OK0k_95A$+fnRJ&!(yR1+exCZ*cuI zvR>41v>gNWI+2WAhKPg^RG~24gmjy1|%9! zbjIP=71>VOAwS_?&yXWEVcyS3q=&@kw^_(G#QG}^s*A)FXX zjjCBTCLZu%`x(D`(g1Fh)OJ?XrXDZjwKR-*ksL4j&(;XJ?9#14{;>II5ZKMS?jM)S zx=wEk?%9!Dago)^r><7W&L93DP=C#f*x+yf^7p(-WZECSEQc8kd7 zdboOg)oXRtOHXb0@LsWSU-k_el?6C99+^BG%*$jNRlH@InfLW-J5_0_R`KphnjFd& zqnTuTV;J%FJXMbpqUPpz=}T|@_G+Sew@R&134?pYWyWO{ce#Ph@oSODSwZd?%Dg$e zt_{46w|Cs+&c)5wc;+;+TJDb^F>v}L;L6k-q zkM*W=p=YX^q0NA(!MrMpjj3xQ$#Nj~cs5``6PvBf?wk2EFB`cQ9=c^6)$#@0W1jx`43mmNtuo|>c{uN}H`IBJ)gAFC*w~uElBo>UA9d4=6hY8B3`ppz< zz#a0jw#Y?YnjL%~YLN?NQ?T8c{i0yYjrSlQ@Gl$L8~r5;*_~g2RZ|x>E>FZ{{~{|| z+SMEHj&2Rs*2`9OUA?R9*xm2H=&u)yw7PhvvYlTF@Y`7Et*Ziv2l8iJw9E5}U1wp) z>OV?7XH2lRnDZH?f?bgfQx8(m3{idb$7gnh^((1O^s%n;LI_v|f3>OFDPPnu8U7k3 zD87VmvsB)#VPZc|`fH=qldnBx#;VzRUA}C$j%l*=SE>8VTWHpO#sb+lW%7+sNwE_6mhx$|qpF?R39!d+%Wk^iwaOw)cyKe_>TfF7Hwy@AnM=lbeVb>m^-C}K zc2g?wGk&S;gSWcNuA)U%N}WU-;dGu07+yfU}s)OA#$A$L_|9z*2I zfrBP-g%2B%bNw1&qwG_@uanwRdy-zo$lP$*Tya^lP2tGg7yXJhrkH7yS#>EZ&ZFV{ z%GKlH_R3Y+C}m9w*BfQcbJrUK&2y)})D4lb4J3DzZ_q180_ajc2Xj;tAHUh!43cfCxU<+!~voaH;$lbusLSaF#B0B(Wl3n_1(=oJcq zmzrUBx_irn6WOW2Es_ka{f2NW*=FZ{Zia`A2pc86pe;gN;4eZ1eec2gFuhivHP*`3 ze%HpPb^L{uEuElB)sBIb14|2kmD@72^@muVUr*Zp$;^06T%8SY8Ig(O%gSFLEA~rn+I;2( zkK?j!@d$)YSVovHu5f*F5_g&W4U#R?JVW!zE_KV6xtvy6fMZUpqjMNSeRX6e%XZam zpR4k&nPjR|Ziv|29h!rV%8EN=&TJT8+g2Bby}43__^X)&gO9S+&Xb&5(IPKj3W`UD z-6NacZ~ZtxnLYdMR>Xix#iG=lIGn9^_S=a*S*T=HdQ(A@NvSEZC42Vtw;jE!(9J@n zgP1MvG<8u=Inu+Sgw3thCZ_VVftBy>O8rdF{K3~aH}#Hs;o)c@V)_v5V@SBGPan4F zJeX3bbgQp1T6}(!@)#WM>S4B}JCHlv7+tZq-sv~PZ*odja~s>XojHJgd={=hRqX0M zIBq#B$ZztNdHOa+LiL2(Eovvs4ZmQRuc;`sye!2(9*m0!DD|6dr*%|M&Ir3IZ(z`s*!=Sp8X<0Ys?L?1RdAe0G=P5tq^_Ot$qoutoB*CSK*0e-C`8>&+d%;@ej4t(g&+@t@{ zWm=7sZ|+|Phg5F`_o_@UDY~=C`sd!Yt+mg8Y3@-;M5PLV^|RV>ks3w8Ltne(Y9`~H zV!UYNwQ_zOvG43b{uc_KhvF%z2vM19)!aA~U$uk$&xS75!nIDL!<@Rx+Y%O{Ly{Z;CNRU*f=Yq)`3^_N8A>v58D3LHU#bk2GI95t061w z>VilwU}EdDUhssmhRfn_!_Zr4+s$3+e;K<6Eoeo#wMDva?v?_3eAS~aOv~?@U`gID zls01ZJPmn=(I(!ZE6U~Ix6qycW55|L_>pd(j4L{Ovt!ngpG-4^w&d@TgQd+9HJpQ- z42l+&?9JU-t%Figx;DLM1JbB%hqp_#)Wk2W{QS*_cC^Y5iIouSL4wd-d!*-4`f$hK z#d_<(GFl}aT$w>re$JB^|Kr&v<_$Nk0}uMDVP4!u>~bMI?E@JGrt(!wm=qZ73t16W zE&k~%nQNklw~Qw!`l?wr!+x8)2ln~C>Z^Wfq0f#`7=7N3EPv0bVC%AQq-5*a2YdQJ z`$u&4q;lY-2IDcghYaiII-N&WzV%ML84hHXK=e(kxu-g7KOG*iiVQ$y3$u&bT8#HE z=F&Z5(X-yahckjEIn_}w((YIX;(BNF3^_ej57Nq8>F#nVU~?2($KIdc7@u6PQiw}2 z!9O0&;?8cpmjik`pdI|o3p(-;bS+((Sut5^yic zYE`+EAJT*u(RY^D&OAW8ReK9^3WvjMAw9lTX58>Xk*z`dYo0~W%|RD}%Uh`o2?7Ht zK3-FAEi1ZmZXAsaWc~OFVP&*+DQmvVC1948twK33y+$TZ*;vG!`qHF&a_>23u&|GL zDN~nd-S8V;{tOG0W!1jX@VPfCW%;~4bJ^Gr>vqG6g|Zv3deN%+{W<>__AL{j50N2q zSy|OJL}zrswTXPA|FjAAp(5kU9CvAnuD0|bnsip-m33A&)w^}ifU$0yvbKof7zoQOT31# z5K{fYsW%#*A`p0>k}}*mh$8jnd=Rh0)ZBM;CI1IKyFasuUUXY}ZT&t7?klmI==L;L z-g>I$aD?u_B1=lcOQEeqYNUG`rPHU^_S?0YYoudylCfTHF7l3P#nvAkjX%R6+`v9#vIusq+fRLQ*&s;h5jJAC=Q zD$>OjvmJ|=QkzX2e6DRPi4HO@Khi(&xrRP!hDh!Ksjf`p?`sC1w9NciK8WFGQbeg* zGrGdgPOo&{oTCK2E}Y+vboO^Lv=z_bAJv5j+ODs>6)08o4=Q_VY$U&Y>U?>wNOYZP z8{PmBJ3R5CeI7f^+7+~D9`{tWWVA{3s0pLD-RiR%jkXnhz+05(9{+1gN2F-G?4cPiHX5_i;!o) z7C{@ACr_IC{UqDzhc0eVHEvHe+V!JvsW~?>?EuaGQ_)04rQc11*U0m_5ZYY8<4s|Z zcUL<|lmm7YuD0vDgIF5u-VemCpn!{uy})~rF&Ihfz05nl$drgFBQ!$Pfxyfz4+pL^ zC_CuJA1hrF9LRDAjX^?P*&sFtzBHJ^ABP}v2lgh+Q7Eo%77pFI>$rEc@Qzb|x?qu~ z-qkn#(61KtiX4hO7@{w@y{Xnl;g#(+XIx~#^ELfU8oZ&O1||CS2h1d{>k1lfpvfd@ z9h5#43NidoNoX@=DDAW=v^{2V0{(;fT?D-$2SHa6 zM?jUCH*m}d6@oVVqr!+}5yLG2>V$iu=OmfKn|9OyxmNQ{RzJXL`NEWoLTdn^$`n7& zSWI3Mar+|313vx#FKfoJX*JlvBo1u+n5*{F5_#P54DvKGI1&E?X^@A)UIX_Zpd6A~ z+#{>DNm~kjr#`NhZnu*E09FGs7XNj9^&8`2SW~7b4HH zaFDEG?gcc1puz7w2Cv^c-M*pAU465)6s)fge@tOS1g5l6P`z|JWCzv^}o!p zakR;FXhE)z76=EUP}xMkxL{q(1OC1F@szi|6ypTiyIZuHVm1giK;)BI&d0yNM*pEG zVsr-VPxNGn@S58F`t4t2>d$^!Ge=|rz0WB~>(mY1aQq=G3Y4-m?DPq#zysB2QS2#i ztSQx|(C;i07N&3OSx^^0M&ibchU5=!G5q0=WQnDc-BHB8SLKgl8K*j~qdYhM6inhfl_21vw>3C#=l6>_^6d}s5{kg92op~gA%^x(@c*C^*HC?(~fh21jY?_o?X{B zIMs`z>w5LJytx!0663vc#QpJK9Dgg5TD3Xg88o4=x52#uK4Acpy&F^W5GOc{zOsh^ z4)O!a5DSC~q;a(0;e4ZgW0a|D5Y<}fesCxZkm6c5X~c|bZ2WUd(Ss|4%0 z2-r+DvWn|HIl_2gMb1 zZ-YSs2^t_k@Bl#v3GNcyT?cn}AKcyDg9q2aJ-EBOySwh>eZQ}E_n)m_ZGBTM=XuWQ zQ)lMZ-0oX5eY#LWNs-Ll4BFfb*Sr`V%nSwI*}P?PeMQpd^PeBz_@9X-fXE|>yymGt z70mxLv1RpOx_YCiaEOOcQ)(6Ff%}UloR{pBOk zjos~CH>uHk=jC(Nvf-9M!taeKyEEFg5vAVn!2L`M754{$bLfd>B%wv*8@inrIK|^g zST;ZUgf-VOn~xa62))Symj!YjR9|)ekBCq2e;yQc6g_&ktR0$XWpApV{3Uyk=L)va zEqvJfaVg=JI?#(2{CmcC9`~RZmv7>f3nl1SVT{1)k*qXvc)2F6W69}KKgk@I@fwIQl_Tzl#j(|87?Fx(KlT-;IjN#K#N+6^*t|n-A{G`ZgK{ zooYW(R$%-5)4O185gRdA;K=>NbxYK(rD3MKcs8_ciBh19({}GBjcZm3UZ8LE@5s~Z zJh_-^7hZzYi;Xg8tNXI_$j$Mx9tZZDUrOzxsp8zP)tl%$fM?@;#K+e-Zr^pNP}2fN z;;pa1)JfjT9EDe7DHlJACuZ?IC zaQ}(!w-x4+O3wednZ4d1s|70iQCEFwMZ)s!)%~o7pbb^&XSBgmH6*1{+SQ_qtcEz} zi{y&hipu+e$geCFzmzSS1HH;CGo{!z?P?7v!I!j)VMEQa%dU0ZOofZ7lZMwJdn_-* zfe+<=+xB0>Exp9Fp?-mVLGtHE8v+e1(@}fjVQcV`YcGfo4m4 z{QtAyTpqcPW{gMNGWPO?M>lSlt9obp=`B-1oK#L4wMrqb&Ja~@WX`Y zWlr=KSM9?XO*@kX{m)sUy8aNu^b^k7*)@ZDk@wm|Opkqp+(|BSNmzFzR8`;L($2ri z8=K~rwqV!B3BH0$S+f^K-0`m)snFbtJ|+kkQczh`outYe{?r##n67aM+(I8A6B}uO z>=)zWE}N#O`{W8?FNJkbI5#K!*) zcd-89|AREA1%a{JaDU7HrEoN!%z?tK!&=4p%?5L0Y}GnoIGGZi%RnToXgryq?j2El z*Y9Un$f<5vPagiuVFIfTW?S6*$J22k@*cw$C$6GOsKKrP13w)a!LGt&*yU@whw|59 zqug+*@T>@@@qzhDbc*d$#Vf7JNV`g8@9@a6VsfXpgD~v_oL3aCmv^Led0OO-;WH7* z$`pw!RS_%Rzu;&nGVKkv4NY6ZZ$Fwh*SJ?S4pz7|)38xHoRlZC z6`cFWb4^GvP!9zKC8#DDMUOUxh7odikHk>7`pn#TBus1BIi520QyTC*KXsty1QD`v z^KpPm9RGxNd$WaR@y#!nCG19w0?KkQgu`muMyYu{#m1J9sV9OJK@==Rn7qa6C{b^+^UL;- z^-mDHz!&0X-)J&{G(S48e3?bi|m0scOJ7ub?3>DX#7UhcpLAvQ@4s0)mt+r#ZF(58joR#D6?OU>j@h=H^;0bx4|s!p(I#b46-&Di6M0VmgW z&L!?__fu)w-4V?+1wE@x8z~Ks@=?U%4!&j=0fW>3wT z;qIo1&r2P|DZ5EMQBy)Sm|;juSKeFv19lnZywgOZ+y7vZk7tpeo@<>5FX9-*g4ut_ z`|kt5$mF1WZV3A706|f<22Seup#{Ireb6>;qJ-#iJcmAQa<$8`+PINDyObI& zkomxA&LV2@^LzH3aV^agdA99X&CZqBqBLK-tAOUVPXB;jS?uxRd%7BGI*xbIW$GQr zP^Z<(FXRQwnp`2Ie2Qe>b$`7{wr?|&+035e@hy}?ZCO~P*!|$qpZYiMs#{y3xy&l2 z_SL|u*`16o-A|3UnlM5BXfqlU4{e_|G{pN``)~cjv&*O>e>FB?Vbbc0p!4-3$!~YKbg#Ev4 zZM(e{52wiqwme};|!_r5MUioBlY2#c>g@qqsnV&NNh6O;@Ux%x9pL zMVGDHrZQc7yP`3Jx1|)tv20jVHn^=8-(QR&EyDAoxx`Jk{Qwv6wWyzWvn}bqTsQdO z2p{cjnc^Fbj7yLYp-0+MLQA_bCc#g*37^A!3fGiw9f}!Ugkh?=^M6pDkhe1 zM9Xr+*5<`UNgfOPe@=s@TBx*S4?Sk?gLr#{93)T*QD^N@4eFEcJtK&yn=Z$guD-i- z+OR52^FAq*4hiYm$wMn6HUupCRNKx2NI$Wf&ObW)Ky<&sG#4 zLuDfwx^!eFea_QFu0@Zw4`iwhn|v*L6p&>e!+_*a^2%+UY>m0++7tZx)^Pp(<(%uS zZ0r59u@;gPd~Gt(hQLJrcUVAaSTVTZLJ2UD#%M+9{cZn`@@$d?0sHwUPP=lZ`R0HU z1(u?yIZdm6_aa*)CA91dq>_(rKw(w?KNSj7%l2zo*HQ9k-^)bV<t3Dr0D*J4UG=Om%$elSj z{jm^np9(Y5LQ;N)UH0}SFU0HXM6?ofJ;B4uPYBKl;r$v=iyo<6Ry|WudCS{+9)#Y~ ze&Te*r-gB{tB*p35J)xL~wd)FD~a!GitI|-({%hx(RCfe$$eiQ97?;m)5?5zS?xP9+Hx_c}h z*+13;3t$dc2H>@Hiy)|QiS%BF>w)K}V|Cz|UX{qMZ>w#50fG_D|T*nPs+!)WJNtX*d3SgM__ER9`;Hn5*lD`=ghjz-~D z_|J-hl5oSt{oS9oxP$bFk}|I?*wPO6)n=g;J*}bV4-$dvT#mkOT5nh^Gs`29?F8o` z-m%BGl=Il@jm-DMvg00)gY|Lj8x;Z}+r9KXv94$Fy_2~`?5g;rbYD8iZe0%QvqJ$r znOjJ94Ul^vX-SVhFYPXibSv3h*ddAkzN^?yS;9m7?2k8q2y}1*g9&$L$DZJI4`=$^#0+}x$D`@V>4^xo^Wnr8Sut8Fn_&2$GU?OrqVHf}SuX>d_PJk7i# zw1{mRuV_eG6hSyfHj^}KqXJ6-Z3Yu8&C3&nYX*R%>BA~>z(sB6D&80ZBMJbZWq`CS zdKcADwG{X!_BOEeJvw%^EV8EMB{VUaA_v{k! zc$|rbFSqPnz4IWiy$@IxB}vc}^rv+#YH-rNE;GhpS8X|&X-A5SDmzYgk?JwSV~j3= zehB-NyheepHhrj0(}ak;bl1cgTb&}(Ga{@Q`WaR^AEiN7k)j0Sl($4vy6(ATdG`8_ z<%kTtkd^mVp|XHls%)P3`e!LWLJQ|wKdX&#uiwL6x$NiMj5dJ=f%~{N-t*79(9Fp4 z=<LJ9W!oEsSNHWwZG{=l;6|4TER>=M#eJC$%<$9u!Un_oBQ^ z=$17qM}z{$G|pZH4%$qGL(bDo1EZnG>T83=E{?H7;^BaHr)-kspHz5=!LMOt+zZnSo^ffDP zU2f`8c1i4&LmC-u8EiX0Oq#BvGET~z=LXEiI4MZaoz`5|l9@81Gop8;DE2L5Yco4J zz7tIdEMG+fkDaf?SJhpTZ4S0?L+vAZ#j}5`Pj}4l>^wgqy;?k0pB1go$}v7@l0(01qVtX1VpxrN2^M#7oN*SW#yVs>8w|ttB&4k z@~DC*P>+I@Bws_ce*+H@+T_5K!#DP`%9S%*$}Vk)aV?#vC(bI#&A~0AB~WLmt3<`? zEvu_%M+o;tXP4$N&rJ71PKnQednA?~o@pLMt>d>P9u2MitmCZ8pr#H7?;?>#n3dt# z+cTCkC-XY4A%cRwCW94*Bl3Ildt;Wh%mW#fhDMi0my*!4uP$L}Co(QYrOT^0XZTLR z&yCOUETiSNfEk`M#WTetZI`0wrsnb0(=!#O)wVNj763|W@uD53s=172KR69H z4IFhB{In}GMYOrT@%1V1MP7!#gVw#pL&UQ^!2j{rxk1hP)RqRR)7Nml+ounevofAI0`yzJp}V&&8G0 z49ir@Ln-NciF&(2GRb&?O!xTA_{>a>LAyb_v6Y>No$@i5LGi(sjNtg`xO;YQv9;uk zO{E_u6ee8W5@X_Hc3Bdi8nP#lp?5`fWp9!<2_9YkGs5ayr4E+xNSok4|IZ=Gr#qqgV7mHt@P>6Duwl7;kh# zk5-OTP1>Esrd|GC5j0|5J9@&LKGH`YpBCFp+kA&#o6JaWTfeC>95-xPaLZY%9+0O( zJ=7zP+_paitWBD|vU7C~sV8D~_}jw#x2tlL%D6RkV6k6E`~9TUTEwzw(PA#ZS(843sQLFRpIIB9Q^LB5(u^;?y8jGVr zt8YB&QipriNgGKN^>y{#Xsv(bb(8b+{KWk`1KwXQLnqINNIM%h)B@QMDx5&9tsafJ>-T=CR z;IIv=Yp&^GO`|c$ZW3g2rg)rrw$b&`ew}R`jT;OM+XLthUa}V*iY@WY@S>jZE!*lZ z=WDcAXMAYG7iayU_ZMe8c85s^R<{jL;d+hx>mgSYY~g4*29Q6osV)ijh_%{?L{#%t z@u3@>n!C3(;t;ipujt!U^I75|;7E<9aWv6M1&nIhXC>-UJ zh?*$@IL(x$-yP*u^bT^%3Uk71h6J#U2q5IKlxj0WX~S`I*6jT4Ds*Y~a*vg<))rO^ zZJDn%pdr$!N#m%#w!(3EMP}~H{r(w!nT4H9vbvz1SbW(gdp=j$u^_79>K722h2ep4 znS3Z7hGKbj&fluDTg2C-Imx&9xA-~08^}BO*8I<9xr;!gO*t}4`>i$vpbAFX7(uEh zy19pi0fbnR+t$#45T~D5+QAev=W}av9U9L9uhzSWTOU7bV131|tIG6i`}lmyerzmV zXI*Bxx=@ymL;0Ax<#jWPU+t41>SlJC;wsRX>!-XcR63-m+(xsdk7h9(K9|(L1eAHw z*wTvqJ;#!uH4GRuf0p|iQufCVF5v#DbUIqaL{Y^=g}H%GKa$lTQY9Sg4y0m!Y+6tsreYp$ zT7V@A0RI3Mk6IewO-domS)d)y?hQm!8qb=Kr8-Y4^r?3VPa;_NBDBjn#$i`San(Y0 zZg_nzZE~nfTdqp0?N%Tvj_g)pp{BqGi(6rQ25X(72N$oF$mGuuI`Joz_?JCLO*Y$L zmp?;dv%&ap_qX}IfO4wnNKsfIyHFNGB700Gq#9%FdqL5e_)zMTRL-sX6V2w4POTtk zmEc&8CH^Pb9HZua10^@;W1LX6UEc(-D7}o;XDI+_c2`N*yr`YUJqiRflhmZ|;!WGB{Pu=km4l z)FVNeUfD~$6GY+lPZ(`k42!?nCg+UXgzM(B4}l`~rEBCvH_mODSS|;dH*U#m!egr- zHq~QCfvCd7-Y`-8#ToE={K*~v0G+Q*`&x10YWq@0m98s(Y67i z?A@gJn`luNpF~{)NV&Vw2+^>(8DqD9xWrWnvZ7HNV(0~0l6Wi_GWRpAvCDt64~wxK z0&Y^wkuj2_y3$uGehqpdF&v=JC3~sSX1->7z!Qq?m|Ulf^NQ3VO?&3x>z|c=BcJSE zKe53of2Dm>8Ebf49_UzIm&qb{L%H%e^B#Mo^KPKLJbvN4I=Q@$GwJBaF1>w&ioLjQ zN286i^q!G|1X77uOGDYxq%Vkd$BOlnNh|guwoQp`vHFS_iXG}9i$pddKa4rUM z7Yx?tQZCXhM&T||aM@}n(U5xg8;Xu?a!qY=DG-YBioK$e?aP~c+4HjS#cA?qMw1g^ z_Y%W|g+K}G4fy1KNqSNwg^}4M>oDw8&lvZ8Htg|aNI4fD%SNZSEBmU921B>|qU0f-<6800O;Se=w@vut)BEvEhSggky<2GEiJkhdi_6JJk{l=#FavI>?Gf9%Pxev7 zd50mBTaghe6~p23^v=vQ4sY0e+&(KOzk|2+T#^m z4qL=OFG`D^B$*mE9D?1Q8zNDBdv z2-AZhhs;u{y>0{6z>YGVO^;NsV1of`Txa*}>zMg45^X?~D=pzA@H%83DAYQ~xCM?2 znMZ$ec;zS%a0WyzlneJ*lSQ65f53`I3n$YY1_xMfke$4xBCEJ>L3!gtgT*B(l(^=>$oDzz+5 zRUn{&AV8(FTbcm0K-_hR6~;nSPZG{IONVQ?AvbF`H2V=>C(s)f@=41OE!GGPOBtO6`J&bXit2!DFV@@$;@NKCC zL^E#mdq=BjQJvrl=sr7OzKsxU@+Jwt*F&B_r*b3-t_nssppNSjDW7YeZ;Bs-Lqr+vl>xzAr z)nRdNw$8e@_Hrq_j05z>ZH|`}v3zdMxt$3kdf)-S^1aZ!($Kb?rGW#NG=bTZ&Rb&- zAL<3t%V&eV?ropV4DBe+a>^q?YtgkK>LDAg;yrV~(;qJbmlK#gLmKGS4u4lKMrGN@ z)bIRj3D}x9l3N#^rW;i#bUkJcmL(+!TI|Q)EhJq>j<2(wD_8!AHXE< zsikzWXvBS#i6QX(pQ5IdlJ}V8Zk)2|wH_X?+3IPL`sc51X>!MIk_Ta;cR(HCs0fSa z3iai=>;|X#+D^Q{y>;e!BMnvy)Zpn&LL?X1d+gxJTJ7tM3VY@=hDV!U^Fe3h206#D zGb@hxFr)A~Yl;+88o*d5J2=}9o+?O{R6WS;h*r->{S}Y0rpJ)1k_?D*8+iU6u)J?f zoO5I@ggiFcT9X|_HYcqL2Fc$6kq^%$ClvN@OeFWW*$q5sEbn)m2-DorDi~>s-2N0# zpR$Q(RLtpNO%Ui0*ERL8&=Wc;7FX>$zU#ynN$le@YX^~FV$4QKr1+!|iJSNf;g6MyAJgQvKeHs&k z%Z{2z(lPTtsAOYCtT4o(`OOn_JDkw+7?;-;QF=Bd!kU}OYQ=lM%Kk1J(~L^RM-uS3 z#CYS&1a^lU(5KH&7mcGmm4(R5v;@1vQLV?zqBKv(eX9FbhEd=zuM*;Usm=rP4p=9O zbcGK%OS>3xuA)aN;M31p*w@GJr`t8QqVqoAOx7Xc_>mny-M-WI#&X{nvA&+M8|NmS zras@^%8HR!>fw;bjOE5-_ntvUcsmN-hPh&hG~J)w&#ugiN(Xt?eFTD81+V3vzT{4l zEoBR6L|L?$y^?WXCS#{+?uXN^!V*b;N|_> zPV_OBA>HEanQDJcO~=Oyo)7gF?xr2eyCL}7`|R3cvm0V-z4&%opZLwZ|HE>qSRjds z*T=eZuqv3Mj{Am~YvV6A>sj*jk?HJN5D@o8YaQhkGfdx~6pDr2?(nVVJq^vSBva)O80fH|u--|2=XkC!CEO-GT^S{;ZG02fkYxB9sU01~Cu!hS zy(`jT$uBz{vWSZ-i4yHK$<>WKt}-&4&A2six}auk+JhF&)@O08^RC~Dg^T!NW)ls# ziMo16m9#f--ZFTITqxzOG1*+V`<=~sJv<`thK~4fd`NU&U3VS%$4%8>ZGvL&{gKR@ zMRWMT;-vR{!_XP~Y%;y|!jw7VEn~|^w&K*+l>3D|dReIcD(L9(hvB(qb+N;NhF?#} zIZ8#*9;)psuPHl%Y%B}p$Xwf256&sF)6fTtrQRih`X7x^Y7cCvJdZ#PY!97n&gCZ9 zXWGvNRKf=9#{&Bk6Mk9AV28n5BC6K&E~2-%OVPV0)t%I9+=>j(rlYApv2ZUEqF${t znC_m0pf$6x>^*Ax30FkKpOVaF3|?rs)>_6mOF%~ zByydn7c+No-VNBqBq@w#G&1*|c7|F zOp}`uW7J3sZN?(uSFvK&R|(Q=pIsf66~pnda7Q#^1{oq!e7D%v1(t=9S%d9(N4 zYc+RXu6zy_yxq($mUlIc5C=D5jba|6w5}#Yr0}PpelP{zJ(w{jk=l#cK z2$H(~RGBE+>rn-l*ZuLm@4?xcbD!T1zML>|duDGA;=u7u3LOjY8vGS?7sJDsfHTQr z3+~uwhF$mioT%ZRSP##$rupE0WXGKC9IXQ7o>E};sPtoJ{Sfhlcj<$bpEI9=jjiA_ zmichq{lRMb#^h2J3Jr?IQ$4=R3nCwgpu%!`=y%{7FxVk1rT}%9WO`nC!Ub ziBq?Ed4qP}7j+Eo3vvvGKAGqI<$}l*UpVn&>T3zHbk1ROb@TJ0)GCpqw{ESt^Z`|- z23zLrp}CX8B0>dK&zzk!@g3*RCovbQdLN&a)JR*0+P`RHXdCDt z90www1XQWJ278jVQndEBW4+Ox=oSTLcJnRZ=p|Q$XJX!ca$j%(3ELR%-&{VyI%ge2 zGekQ2emjH?eRA|{9^-H3XEcNAJ#x6=;3S0zu~>54W>91?2y#rXYOkKnLa(l#ITal5 zcLK>hV2~q~W~t~r&(Z83={P&aB{IxB6{qv zGRQGevp{rzmzt+J_#e{`VNk=@L)MQA?TrXm4K!0l*@6Mr2UxZc!~{Y2_^Nx8wA(}6 z&1{W~(bg~! z3BtGn>jy9b9wCz2_ZGwC3mVlKG%Pz|f=!N!KcqBCM6pC@Z`AWc;BJLSJGa6MZirfY zBaE}#9-=PWf(Ygn1*EOr5VxvLNl{fv5Vw_fv;><@5V~w1$k~ktalOz9(ML`WP8N4B z{|hP^5|l<$SX5Pf>DH(BjS}|m22D)S@kZ(>?Y$EAr-udkYO*JqH?m-_530SBsLDtZ z7_V)bsG@u_O|owM@89SDPV$Z1+TKLl^WeWCRRrgG`yFo{nAky($3GMWLD&uuq|-zg z<&{{Y=JxBI5i+P_3^K^(pBdIavt)=_!#@`?5cD1cLHGYqN1|+k;FD})TI8Ezg>fF= z$gJf}wgU^^>$@$aq54M=Q1lEw*=!{=vcEny1~dw_^lb^ zI4_KGQ5v_x(3NROl~3%$Q=>CHy`aOr z&cDtSsLPq$mM&LSs~dXRq9B|XOSXqamxb@ESgTmhEoWM*&ortH1X=eeSFO<8Hmnz{ z4?3YQHu#S^zW>^FSV-pj9q*R7_fhiqW%Rduw>h91IgLSaH)3~qS!5M7VH2&}PW?`- zO`xbYst1f$6XxTt^G>qjX7W4A3e>p=p!Hg2gKr~GBR1Mvn3ofo7pQj#BIR~+znUQ! zRCMtvlF`q+9egrO%8{Kcs%l@cAVsbmfpwm8>C?VgEknFtT>!{t!;j4G8(0u| z66yN3e=yqU_r2I2*j!&k{(XJ|H`U+-bFkd(d&8sU{oqJ69IlX8$UwmTEM*)4A~8p4 zp*6QwBCx={E&B73hTmt>(^YwJw8p+JwBy_68BJANOpL3t?Lbu&d*F&%@_23PU1II3+k+| zvNam6(S8P=q+Wm1!cBUZPEam2E;Z_o%3QH%A7x%p4jr~Q@;k6QOx(7-d)|NVA;xv4 zNr0%rcExjlFcLfw!}#MR8)5;3B^gF2dnKx+=&9nm(GY=kt~3ww z#3<0HvWZKGxS~>!#G)^dD3^1vC}z2{0)Rgjiktn($(%vioi1=pu%UMncpOtOaSl%) zHu~NXJ`*S`u2oPW727PnD({V241YJ8z$mXFTTC%zD6YQHkUSIKd*OxF->lV4@Ytk4 zD6uE`_$Q}fCOTBX`%smVLk)KXX)1Fn)AV|Eiif>2cFIQn{Wb2hD1BU*T>|=`ABbEG zL%m&zZc)u>))b!Le zjcOYGXup#-B`qv3fL5QUv4(Ic4_g$OUX1=jvScGu0p=9K$#Yy?+->|D`71I@Wt?{3 z9Lp5$$#cmK_0_z@vD}rD8IMFel~vDNL%uXk`2FjEw=4*itU-J^#!Cl8WK=In^m|0c zi~?9AxfG~!n)DXxd=`6G_4QEjP;d@1k(~BwZy->5^K<$v@h0(#JdWp&%ZORi;gs^Rzo~F;b(*shg4ja zoRgS?e2h{*8M}+iiNjg@D+oyt+qosDGzVbcj039TLP`yinwglMz#ywdQm33Ao3LoN8pRU5xXK3A`~?v2O7CHdM>s+zvh@Y$v6WGgc>5O zLmkZ>sgIxl`aE4>XGV4mdHNy@RC^5!9l{{T5z~Bc>}#(4{+D>tI-ujDO^m-iL`q2Bb{1+4(oQp&RVYIOM#RTG97M;T#u`$LD81$1x}T^e6ZT`Z3uy#Xu@kVXZpn7ZHY9d! z%ED_T)C0@u0j1Tq%0{%uWvzu}f@8-+#{*D`uzpm~>k6#Zj=NSyOhc`CmU^d&E{QJk z_N6tLqKg$CJ{g%3JV&t6La*)#Je{bCZIrdLk8Jg4s&{!=(FrhO-en#mAU_>1zavma_0mG}4O1>N&MxARZADZ%_tBM6FuTrTBJy z8NEsF02GFi7CQ#yx`i_OGRc2Wp(G_ALWdAMouSR>7zAQcO5ag%4KsdK;NW%9M4sF~ znEa4=1Z*X^h}aJ4U=&IHka0t_8`|rkiYHM*6;j}d5xeF8F$=?x|In@c4}THA{T}om z4Mh5<3H%R``;VFbuYAzY6eZLx@mt+b#e_&?v;Hk&x4Peo3F|)eM}FL9K8onEj_j$jp@@-0oR`E9(X%jKG_ypp3$);`2r@ooPX=lf%oY!uA$tj zl<(0@|Kbn{?a)gPyZ2-(LHgvGSj5=$nIa>POZ*DajdgsiU7ag#`yv^5?5 z#QTNMmiWyIdy{OFY))MbQDix)(b9dZh9K}h@V-lvBisrwgLpgePLX1vF$FTEdXaqi zqhD^8KW=HIG>IF`W#bzA|PYCm-5<8#O$*%Rf3Kn>hG-TO)*M9j7Zg9fMB>T{gVPHvbK>?Y-!oRZEO$crMZukOkC4iB@(OQWhpNpOUercI%p&U;&Vq_S`*H3!v zp?Q|PRp2q-c&YJuFk-zN_Sj1H4ADXP?v+a7`NK1yJVTw;c4&J_e8<)}Rd9qcIc0Zs z>f<5wFsV$cXa*xuM$N~m4Cy;!R&`xd3)Ar@^r92lj4SP}gx8Q?SYP~GlfM~y>&FZR zEh9I;aQNf%Bh_@|ROZkh?SKFXhvgyp4Y@IEVFDn4et`3g+>{2IxQ#G#1am~sWYbZY zSP1~3xB`iMHqli<3rC~`Kr7}{@UgfeB)^#??tiO$ME_J!LWuaIFoFMA2>+PH3{+C> z`810etEBo>K?_aXi7ZP=6&Ulsht!40{Ue2mXA|}Q>*`z1KaUbf#s6^?cQjP>{~Qf5 z{O3wYK}%lD3F1ESSAH{NijwMc0QS5-$E|NDdM*)_>h1 zLSjIJ@#*!uY%uxQbN)O;up31~MALyW9N#jar53fKeAZXf_0U4fr#Oam`DV!>dDaW} z<#{~GVMp_OG}P1Zqdo7@A;momO42zjO6<9S)!!Y+%EQ);T|cM=4RvR@Bi=jMgAny5 z7I9agE?do2@k9wkLSuq8sHgjO0(8A_ zgZV~@(r5x%+=5w9J9gb4!Z5COiVPp%!!T;71O}3`W3zvaIb1ogb3%^ARIIbDd}(b( za=%O=*71_}LNn5iQ-yYWnNa1W%@#rC_8Lg+NbWH4r1WY`-wK8fBf84nHBB{Ae2Kv$ zz##CiL%S5zcAP#aq#Vx+dHX7SlSiq~?|6N%7s3D(qR261)DOiEBZf)0h$3*= zzF-|)M0-AOx#ThqgZq?%ppSo z{OnRn#cr_@riCzHrsqhC8O^^u4?}t=3;7p7)oR#ds+?By1;+)c1^fk%1(F4Y1%w6j z1UH6BZP3}_WbV@`f@Sk0|IC0)-%OJ-F`vPz#*ON5bUmsnR9g;4Xj`3gs5dm9j7|S+8%E)MzcSzyLL8_(TI?r>c)ty;Vk4 ziB&8)+ovKR9!rdfYpRy4FoG4r$xe!}A)$G2~z+n-! zp7oCE73VlD^*S|r6m9Ty&MWcqKDfBLyQs0!pw6MPeq%k^N_+R}CDk(^ncLRe3vt33 zA=E~MY|wPZcK6#?IYFMqXyna%=A0_=?_0JL_avpS#a)P)XxLOu!iqPXKdRT&zj1p z{pUo1+SxM=Ip&!PXwikDCk%w)GQ#z(+{rs&w|an6r`_GhPW@;74VXJ4{!&k}2_qet z49nYx_%NkskoU1b%j~g+3iE9HU_;r20rG;!I) zQv#(P5!tce%9uQk5iQDUJ=4RI7F~kv3OuuIFvjmqf^37FvTQ6SaV>XUe`aXg@IkK_ z@}aDl^L<>=(x_>Kaue2Ot&eatZZsd$hU2AhZYN^F~)%FkUlsgL2-i?_}&NnZ`ocE+26UP zT~Qhf~V$)4u7LL9Go$ za4yMUwldh{NY6KxJ<;X}tV*-x{Mlkp{K!^U+4=HeeoVG!bvMi`xX~`I9f;bNvse6so~F zAOS~pnZ4w<)5PW3SV#nGU+U`%N)5n3o88#w@;yV`;O?kv56kt-YHlUYUMi(?B-F0p&HHehEHNks(JIoWHzITpOr$Tw>^)A) zK=uW3KxShqQ@*L`BZ`XK`d^&=a~fdTm5o#W1(uAplTm2v>pf@}5TcKJtG~~4o1kxS zE2$FKy2}!dqRsM$Sp!^Myj&0k;cXPk_UG>DHMu6<+%?^j-#!)fE6sf9R~`9~1~7&hrrv`(#YCLN zZBJfTIw@A$YDf`Tq&Y&GR?}$WY+2B##{c%cj5tHSS|W3_;b~Z!JY6u;gi*O{cVN1= z7Qp&vSQ=~j$9mb88)o|F2CXD*wQ7vUe0@|~w_dM}k}$z`br1TEze?8Wxpd4Nma|83 zTVPC4Up#7=4{WL#aMq>lMRW|(HPWid*ylf1wsqgc3#sZ;k4m;)Q9|X2rQ}po3)$mh zcy~;ZxsSx)vuq77JeH;26Sk(Kq;@hKb{X26Aq^^ZqE=)J7# zd~H9v7=%`J)BZ02fk1x0X#j!};iS$O`Qri}^u-vhfa0Ob09JF(VZM(Xs#Nk+dDe`>( zijql=b^g^QQyd%BY}0C6y}G}o+Ob95&(r>Orqzz^NUyW)r8BB0yqL~#8~{#t90tyG z90SgAoCMByoWXB2+i@P}j(u^y8*K-C`%GJGht)$Ri=09jmlCdU%IYE0cH1%asHxs| zlHUW)IKspRELrVL!9B3oc1Ar>vd-Bij2oRDfLokh{ToZRTL=5Ml+-)3z)v_g*j}>N znd_@9Ip8b+9(E22_2BiqAN21nIp!Sd+gftcIl{MZ$-p*FHFS@i;lHo{yt#vOs=Cdz z$XN@-bqEONuFhHfnmFr#bf)Gk=K^4^bFsRF_c+temnV2t^gi(XH9~okcdD9N-r8FW zO!v+T`sW&%d%2pp@(gdCI;K3+yFeYo{Y*__d5(86_c`8WKzNdxl=9x*mGB+|yld0| zzw`Z5%mvP6>M-*l=gNR=9_m~Zh%=9HuJ;`@k9KbIspfIct-h(|V&{%PBFgMWnFpNv z0x4#z^PoS$>~bDaXPYNGj|bYARp%*Roq4MBtnawF)_Eb&!92?q73gZNbH(^pnisg@ z16k(9uI7PU^DxEwD=ko9UgPQ%7-U}W>K+&x)&7~m1t_`n0^<1TZ+YCh#E3%JZ@UG~6a^97eD zpq56tyn(5uF|I(MHpppl1ehvXs(z*Ni}zH@ar~>Pnlt=Aoy?y%DG@+Ui;u zs4Go%EeR|rO>->|EH3TjS`~1WcBhiruC=~RrFpImfn}xrT$_;|?AqpYl@4?51dep= z@zs`&aqS0=cOCLAE;YN30?S+{d|ONHuG2t|>zr>#sn^Yb0k?$q)VLMk40l3cWzkS~ zl5aujYV$u-dC)N>95Tp>#Z9bN+l)rIw!KSCaGLsx-n*ocC6Bw=nml zs_vA|Cd{))?kT?Y7R6l+J`7e|)z6aPo*v}DRf7qK5soZ6;-2Z-VM%h&0k-DIS!>l8 z!ts`L_xvDJtuk9O+>3nsESc`5K;$DQ$GsxRTC2(k?Svlw)K_^413|R(cCYpww+yhZ zt*WsMaj)~8vJAIwsG4CJ<=*H!YZ>d_0yMd|`z}~4?s{-b{4Q0q3FleL-FpLZB^Ecl zqQ&7pT(!_L$$hM933A{SEmPcQ(DG{c`KslX=^mkKm1U+!RySDYc;c$oTIPEat2Q7% zrE0Tfk*7`7Hp@~^2Y7Yz-j)@fu2nlNt36rp#`T`usy#tZXj$hesM>GY=owUX$g;&V zwCbp3yJtkz2}?b3fc>7)=nI0q4EgO~A8py|8HXMpy=~QL%K_foS`K@P(bK_eRh=st z;(4IzoaLCuTFopcJuY>v<&0-?)uCX&T$1ilaW3aQQ#qIL)T%WT1kWtqr+eyrvnI%% z1r5FJggDP)-hX+PsoN$bdR8JQ#j^(3#x1G*t~|4vR?}h_hS6vk z%wWtgn86rh8Dp$tF_vYFWd=3fZH%>;VOY#{eRO@%^hb38JuM7P3v&vF)nZmBW1W`M z5wgr;g$~O)S(Z7LWwit*Fsow;odRnW80!dGCu5eA75H9eRYMDDJaX**XUB_QW_49o zR#xVFzxOhgB|0*pXEr)==vwb)$3D8jXY44X8DCsSG48jHgQT8AUq`;g;3Zo0C3RRZ zhj&!z(GH{?H6*Q%L^YDD!$DFK=XAJ8s^B(s1W4LJyM3v_({#Bn16rcuXoL<*-R%ZC zyKW5#Ie!7SBFhmy}r$~B+#1HFqpDz#m1srz_leC{6@D&6n=s{l* zL=+HLbd1nLz5`km(Qd$L$3>F%em&Dy7Mz8v6_B3u*>#V4`;@GoaW^_CP_L?(mCv>Iu=OUOVV5PluriV4Ica(jr5Gq3!WPMc*h-j z-q#vjp%;Da!Ig#yUl?@bvhR5C9_jPDB)w1i;Uc}{I}yA|FZ)ggZ_}&3)8Nxd6iPqv zoedW7hgz?M(|Jqlc*i5Ys&y)y#n-gXbWZX0t@Ghr-qE`F&M42fE|D_JP{!4|3URN} z`XHRo2U<76`}vO6&2S0d-DV7z^1W?wP(y!PVz`_?)s_^t@@Lvog9rHGwv2E!Khl;R zuH`Sb<$>S4+*S~7;IFk6y|cf z;UR4X>db3933D!OrbFfw!rr#i;d9z7Pe^Gy3u$`Wd6*GkUq9*$w_OO2@}{;+;V~hr z?P@qA>PdP@Obu5vO4?zD5=K?Sn7DfY(U>=_T z9!nC&0=#~lO41A*FCB~YB+Ooq<&m@ix9V7ta3$b6Rz!{ukhDw~4=BM3VJZ-S*(=Op zk5vdWfevlPdQ3}?kQC;Xfo|xr`9NnpixWFXDc&5N~FawXvvEw8?@%CC^?$}8&F|ZIU6O#hBf~{g|;7+hz%m~~K#?c$T z^TDvA+jjw2YtwfLVpIiK@jPSnUH!&QCeAm}vCbs=t{?4Zl6=k%n?ZQ8`czNIvM7KQq?IkCzYB`H*;F4hxDZ4 z=v0}r3f~zdX^1(mxH@|vRUo~f1lmU-?PwpxT-w>kTvEC_2bil$Z|5L0q4akSG1rw- zo#&WY40;bNqWliR?aqN+>D1Hnz~89!iBYE0n<&`*TCt z>_LBiD33kl-ybSqE&h^F5nJUi4IN->{N|!b;!>0{@TzH*5z*q)j`UH z8d=3JhB!9hcZX!Q!>=B7u-*P($jkQnL!nl--`^8z*V9w}zED`xmWDO|KyZ#5ES@ynv)KOar8agY*Vn6D@FZ8Q%3W#o{i?Ssv;LIY+LZ%odvKPk zRl{BTAU)o-uYN>5(N)Mbs3(IN^$Y6hu40Z+&vqT;MD={vATQ zUV^l%Mw|6>L3N_5o(rkhyU4mt7l~E6TwIS7=u$L`!!gFu9DSwYaqGCOtrci11D$ne;<;=B5> zb#$H5X8qhbb*1YJnRTus1A2wJPyJtnsNYcVi+V`?78$AE87O2j>@t|pZo_kic=Vhh z(eNUA-te*^3B6!QF}#XiG-McFM=u$&4Ie=-8@_G$HhLxIP|TN5@~*O7UqmUpT)Uc4 z>aL&c`Uy%)06`y0NKZJ7(i5x+waAk2c0womTEe>tKSu2dQwgi+`w90F*3k`UjSU&e z_p1r$1+*Kzh^o+Ys2Vk(O4NwHiE7b*LdQ`D>P0_8A@on^=jb~67b*_@FDjmT9{rAb zfqI#us1z!jGUNS=)GJgCMN_F1ONFQ$DomZA4p9Ttx2dmC|DF0N^|hGq#e9$Q8r?<@ z`Jv z^cSW^L#oMPav9Q19#g>ZG1D>Aal@xgy{1!!&zQbrI%_D$-vJoxrV-OW8oq3rG0hm7 zOtYp1gUfW&bkopcS~4veT1~$&-8Hn~{ZfXbreB-Z3?b9HY10snMX}Et-i_T8`?BFX zv9H9wZupzntk_Q(Mq@u0%Nwr6HpliER%8Dv_OD{_UY}Dj&&Pf@b|mH{{P*BuUWxrd z?4_90*vqj$iAlrzbz-t&|0#AMrXY4Pb~$E$>@Q>gHRcQEEc1n!D)X;*zZUcJgx@Co z)`-9O;!zmVc$9{}2>#rCz$1hX<^!@&mU!k%oH#6wh!?+fUc4+`6DP%KaZX&2%r>`_ zAnlb>Y-3WolqKa#`Ov@f2qToG>_M&cduu6SQu7avK6!)b5!fL0kn$L|vz z{|%z3-%-Cq2GHn46a&{jNOpuG!*>neMU>%thVQ|(QN#C9jNwOyAE8}jN2tm0Q^QY@ znS9H%+we2PJc=WGLF36T(B}<5H~btWko})87=C5=RphUK#ZWQS)?Yi^6=On4HlO2*#-gWTGE|d>H*tGy(0q4w6m& ze&-X*UYYP$6Z3DQLmxTQm<35qtBBs7E6H*t>_En@7$G9Z&CH=i&O*EfZil~x+}={iH9kk z;*o`tC<#?k9?FZXR2$Wf?7*ENbOhM*82WSSn^X__8r4hnqPNKRiFLrFm(bhPW$H5e zI(3cu32LM!slP`K>K~|oKn(Sd)HGs={yKpLvJr32G3OwO?4Fa&pD^d6CbDC$*<55U zLT+=3xdeI0_cC6xKh9^aH~$6lo4;=UI%d_nSdM}`*ain ziqThvWFbw+6mo=pLZMJB925=-7NJV05$Xkpz=OB|iVzSwgl?f%=od~2XM|y4M7Sti z7On}C!n80aEC{!RJHlPzzOXJl5)B|`F+tobrikfcmY6H%i~GeAVNxs=%SEeLEiQ?* zVuQ$tqUaV?F(`(_9|5iQ?KwEShFT2^<1Lsc|_MgPIP@A(e+Od zUH>G}^-qDW8&Dz9?@tr`{twg#sWi}gtl7mxvp+*LyM%nF@L8hG2Z%O*j%f2iqRpQN zZEgb_c!zoiYyf|)@I|7{hln zn7@Lm%r)j3^c6E}X7LxtiNVBf7^isX`{xklzJL(l4d?~*15UxYOOT%d3ym@?|`xHOmJ|pgX9QYhR=pGge0ma?|41UNxA|Cwxz-9Pz?u-1W z`?7dw8~8Ur=DsFc09D>1{)&52toi*QW$L{L_;L5N=x|T-Q|>u}8TW$716qs5T?)wC*?sfiw`;mA`13u#M{FzYZu?iKQ>i0tPX>~!cdupErt|9+T z;fSY!pw7b(G1=*wSglp8lB6vN)_e1jq^=|Ve^}f*R z2@$k=dW5j2?=c+r3_O7op25d((lhkTIPEznob`-8f%Bd*;ezMN6WH0;mptRo0&&vY zC|vbS2@{@~rvk2t(_T)T^U9>$b1FeE-G;GU%>r(y>sa5LZvt+sk0ScqyaG8qM=JN;l&s#{QnhzQs`cKJ8oX=RzetSt zAwEyu4Sa+o`VjUdlG|sJRA0Ol^zD&CzGSJ#mnQZ3GBLN~ca{cxIntnSALeIi$X6(x z^A$^@zJr99fzxqcNMpW3m^-B_J`1i_8uwL6Q@$E$##b-R`yA4ukC&EwE@|1P5Fd$s z5cUbU4_Cc;(gR-r`!Q(){7e_=KxdY(C`!ryGjs5mx z7}ET*T;{$={4qQy;)`)k0Qy7TZHJG=Ifh)}zJ-DPW5lmUAlu#dF}8dp_L;hGjP{k$ zJ~HAbBan}P9|T`Wd>{Bjxz3Z0LG%{;xeN_*qwgBlOPTXc%Cc{o9D99pa;tBF=q&Ju z-0r(2hkbX*wd20KBtPN1FQ4?SW4o14`yOF?BJXupG05i?vwT5GAa)V41DzK!m&%uv zy_o0ZtH4dVjmQ&93g#_*e}n^{u&o_-wZ$*GZQ(jFZ_3xbYx1m;j@!6(Ka|JzCf`u9 ztV2YF2?l^-gaZ+Jfr(%aR9bRLiJ(n3@jz0KrZckuDn z`(Pf9;Ju#p9(>wl((`z493G1Zp5V!7uEhKp;m9aH#AQi6xD4hd=!2#`-t*1(S`2uM zo7Y;*_&u8+wj{Vw%U-vsB?X@+oF%Kn?)a8;62E}n;j->MEm%RT3g9$% zT1!5O)AX3Yo!PSAozqf+{l9x(ODX0$cVP?RLU(bC6$9I-`(R78`%p`*+tSj2dDvam z!nkW%L=uw$U%KmC+~i(Ii@Fsv;h0B{QAk~S9r&7?ZwWTr)o#+RNNg904eZ+-Oc04- z^wiyJ_8@hq(*$N7EyJ0rn}8@-BnF$Yu5)a3%Q5TzmZ$SRY;K{v)m| zf1NAW-{{Ksb2u(=?f1*L9^8Mf62I3~>Te~nEsVdb+~4l9`ojd({^PjMao@RW{U=-v z{*x}of7&Jb&tmR&x&7x!dDVZx74%4Cw0dPei!c)#tw+@k_1&|Ez1!e*@1) zT<83^@tndn=D+8<;$L%(`yaZdRD}D{HKUsFd<6S$*P^-y*Wp@Hlkqsamen+DSFTkx z)Ac~jac!vkT$^fPvr#Q>j#Cd}|BkOUC#r|A&5?4@?&c)b(wwSRHD{cC^(T%hvJMXC$GSMvc?X)aR(%@t|~;RKy?F;6xhQG2nkY_3!Ln;X?r&767$^Ifx7 z9cgY=FJj%r{e_R4+ttfNpFtOz!|Ju>F4x&v_6B>Cz0IyvUt#aD zYwSY~ai;2JE}q--)g&&tdWlP88#RFv04|fuVL45zr@orV?c)lo$GBqdAa{tfa8+Cl zSI;>(o^x>u7vMVBBN2fT-CQr%&z)lHG~v#0!`ujzyGYuHTZBvEYxs%q1ia4w{5jC= zFa5i$gB}Lks04YDtb^_$>!2@@bi5?(pqMsvcqMxVIs5Dec)FiCStQcHFpS8!$^E&EO41+`g0umo2Mg94!$(1HKBnu<9`bywF$Nf;H$Z!^t{9>J z^Fe#Cu9%3f#Db=L0dxqjnePVer~w_q`tcmmk9e|9{ye;w6Eq2HLn7$HyP!{45B7i- zoCSTt8n73AALM1C0ZBvyUV-tS0KLWQ;U9o8|7XxJJnFBKQBNgn;2(sMzl+ky7^hQ- zFvhQu(aj*^`Z^iWOzLf_9(|aM=o>JiGRmgBFrqnRmHVSq4~$|i8O4w3|BobI)BZU1 z1L_jmhbVKQxp;d#=xXDOboEYQ+LbyYmK6)S`%q1xEgfLg>A*kUTJ*vx?Cd>p$uS0s}NnvK`ae8V? zLXOFZY}FjvDbh9Pae9WHkBBr$FY21BV)v_ki9KA}fGI4Nbhe!+3E&73Uhu#3$ z#3J1lXX#DG$iziNy3Zu;6zH8WJ;WB%^GuQ^jyX-FbtaWbmF_aB+wF{M@gqkslMxYm zgUOBv)Tq^+$K2QBWotBHS~X$ov3|1-qPrr?vo5R)tb%oh4PgCXJD3}6H+kDKwwLWEE$Sz=pJKd> z7i)@aApJ2Uo8<)DtMXpl`*I5IY4!{|%#N@Z*~{!Tx|W@U`=+7pId*||v$xng>|Hv< z-iP)Lvg_<4&cKv!liRrTrNH6xW?sk`?(UXlq=_~Ts2n8b^>q2_0THU#|?0UbTu~wbx%UM2C$_u?i?J|a--ZB zq*u6cZi<`X=D9^;%c>^a61R-smRsc>a2wpF(+JjzWxyHdOmrp@9fv15Q|U2h2DV0L zHXzSg;4E?;aF#hM=y9i=o^l?+wP4G0);SwBO=Sw4oKtpsovn=B*-pEiVdrtCkx6x) zaGr!-Zgrk^o^_sgUI2Y9gApilUUFV_PJqtYo!3ETnF{9(qJeo#o;FsbTpiXJJXX$| zfZNU$=RGFRxdvCf&WGUCO?*7RhbiEbxj{aS&*XFHd43;Xi0|Nw`Gfo+5DU@qBDR~H zt>SC=ddAK>c%FBGD0~2P7)ue~!FTh$(CS7y$oKQ7m{k4@)>D3%AK@?Zm-%b_BtOlA z)$$AU0DlYgQO57a-{J4__t}G>pbl|Q!aaPWfbLnL{AM|;X z-jMeLQzXhI>>arjYDVK}0;w-jnx>U9@*>bg9D>rcEY?>4gy*-4r64(s$(*}Ml zl!6lQYf2V@sW9IW4c1Cxh9TopO0UXpN3X1cjtAjMc-oBIC(jdE1fDZ$T*r;cyo}jQUWS@+$yND* zydiJW<8qJ2T!gz4Wdq0n^l1ieiF1X2B;fzz%`7Acdx4>bg%lyhF$}tLT1XeNFelLs zLN4bP@|hxGzfj_A7fP8jpgaJC}JShwc zL&7;>R2UNmge$_hFeS_g^THyFgeAbTuqr$dHiS*l$mNQ0Vj_J`Sahz?SHvVJT}v-H z!{iFtlS8}lt{mqDb{Ox>p$E72=G2Le^pePt-8uT+9C{P)%@O9=JNo{d1SIF1`%EZ=mrKMN{OIojVe0^;5S zi5ec*4#fWffWD|mehT1yDl(tM&c3e5c{Uv05BWYo;d=nC9WDWs>g9@`5eJ{HJERU= zrxo%;&xXU*kXs1CB(I7>q)daJGXN2eYqp;ijl*vJxc>cdSOo-k)Zy3x{z)7T0eaxr z1-#R!<%b8J-k$e_0th?>9f0nqp!abc9^B^c$M`nFmk}Nt+UA$T=N{*eEj@`I*T}d; z`e-z&Z^s^Q(-x;h>t@7;BesR>(skZmwL`D*cwPaF1Ev5oj`m922JkP37q#>Fov@EM zyyPIh!~q<8copyfumOPgw_v|jp}nsKe3b?JDi{|F+-re*ESLvmoztNoEZG`gTJp4d zE#OZaaNPp_!vdUQfx0ZXt|NN?M*0)(#eUL)xgXbAwB66RE{j*I17EWMms{Gkc0Dmp zJH}|spXlR+>%zX#0=#d5ak89<{_@}ACtDql`@*ne+XqJZJIf7CFD=0TmfQL<=$z%AuCt(T7T|Kr zL+y7Z(sSVI%6QFgEB9#jgx{+Y__q@Hw=z?=i-;ZQyokB9GDqjRs%;yoEY$c5-@nCy zJ8f%+U2XA;Zd;W)7i0aeJgBvC>;8Jp-YVh#O8gvnb|vs%WxdvJ!b|WDl~7+Luiy86 z{Ii3{pIRo;=BM!S7HXpKUe9_TKE>nk7}VP{+yiP8QovDqHSKR-u7q)_g#NF*|8#r9+*r8|fVqv; z05EUcn>8Woc(0BW4cPXq>3}Rf&)v2`Yd!$@&RP;>fAG%MQmsAKa*eaBR?YWBfMZH4 z#B)d-#h?f3G0%^-PUEjJj4)Ih#{;SS`292bZl|6 z&A9ECY!FY_61Dk=EmfOS*uY2Hz(?93Zm<<;{b)O&%}22BwpD0#*zDRk+m2{OY- z0ZD*Vtvt@n8Gvj+9-shF6qO$UlmRLLcEAz6d>x<>zyV}{7tji52ZRB~0Ve<_0jB|H z0p|f10G9w)0TY1hfLXu|?Y+!50k`#hB`S}Uzo+#n$rtten5gS(fQRHye52ha0NCs9 zJ=;0%pWVrTw5U82kQ0^f0~BuOxXrtZ0SEQ_5B*^vV-}5a4fy$w)t9^j7C@DrTb`_E zcMYIk>+jtT03VgR01EnBTeq#()^9syJ7XKhFe$bX+eO=D+cn#yZQ3?xTd>_S@wPj* zySDqbb=xDm!EOdgu_80wH^q-;=Md?(S z%1)h|IzLrAb#dyFqPtU#Qq5CsQ|(ioQ{7WVsotsnsoPRRQzPx)G3t|=ka{pRBQ-nq zWa{bEqSTA2rKuJCeLMAT>SO+HN`1}Wt*IaRyC-!ZbvV8^bu9De)cyJm87WAc!BkY8VT@&9AbJg=%Z zlJBdmHkTPwe{1Hi-RbrBWd0t={5||Xxc=JRUH?>u@6ms_-SONw^S5&5uifdnb_eC! z-JNTda`T;TZj+3@WG(;4|GzTxzt?8|cKJVJ=Js&^KeyOiRv6nql?$sD)+nrF|Kt|t z^QTE+%fc%QuPy9S*rTwRKYa@a6b>mIUO2k&UMrngIK{GAwnu(uH@f|(ow&GgwOy-o z_@xcQZ*2Jd#zv4VNEVnd*(urCM9Hqn8%%=V+o+tpH95$x!yUx-;ISzw01#00?QqckAj~AzZ#uJjD8EFoWm$r!#lv8 zeoOR+SZo4s0xt;Lf-SLt1Z;-96;Wyx4P%tH=!iE9=F@9Ens;M)F?kbf#<+KY?-I>jL!qp}z>;9L&MyL3HYepINLOeqymG zEYm3B-Z$U|JQ4oQ@;KU}Xh`l2iZ)r?7uwA68%W2Tj@DU85$JX(WE+xcNd8Ni;8hW~=nG}RVi}SK@N)9O=BIxf`V;6|fW*K}vGtl}F zFmB*R%%N8fvpa~jgUsusJ?<<oa+p!()3-IA4+ZPRW6;?M zz6PFQ+!o4h=?9TR;<*o;hqZY`Y?F4Dtw@W>>UYUihh!jpr9&()fajo}!@B24VpnGb zkq0$98^aOImpv=AqwgjDk}M^E+JIfDfi0m zu?up*=GZ9^2D9Odqq%r)dj&19|0sRiqrV&82ziFsqNCXsIp z)+GLo!J6#H#$Zj>qA@7_;ILHU#1 ztW|TY<*u5$?AyxIKqnxxxF%B%H{*|RzQgzl@EFx&5l;)MMW<=qnn6{GRQz{pNDKC? zutVZvPU@Z1sGUU8p48sQ;SR?7o%;EwB17w&XkGx%r*bxqrd$3?c)i7chr?JqRnZoV z+X9{dpJ2XUf_`+|&L}Gy$@wlj&3Q`6B~~37WefN@`k!IpGgmnoy%%^~YvEl&E&bPwzP_ zEYjSg7K&1oCk*B(Cv9D_)`BDA;aK=sc^(w9$~CD}e`YF`^6ETU3oep}_B7P2t1_>j z!XGVf8h&c|>quJS$?xF(_^_RMwS^bcw^O*nV#iP?^^@ZE+)=E4L^Cg_X8CVeI}N^q zyaN_mh0`ql4t9&|9`{3hyO0szLVsDfLHUNwQ{Xh@$Fa~BYn$N%k*|+-;IlG+s-D*D zQ`uOHb5+T$yrZ>$Q{2qzj|#P?h6?TTp?Y;9J}*X}vhT)|fx=Jp^zPS>Zvw9X^TBMe z4>-r7d)6&NvpHB4U#^NL?tPQNd@vjA14?HI`m?b%8%Yl&10vPfEc#|?bc^|5HrNN0 zek(Nlqq)u@&vK>MDaG><@DUlF4`zdXz!K_Ae;cK%dG=0YGmW*koXzkRWjJ<9uv3Da z66};URlhy7oXjMPr_OQP1~uwwX_A{MvTOyiG*;j`)${;4PA=#Y3kg{O{I#Bdz3 z_0exn-)-#QmfU@M={{>?RZ5gfiBc(1DrKcgiIVsy_%jgw0A8Osj}Y4Ek-bq*WvOoN zb{0Ad{t>=!CABko>oPN&Y;-x9Pj+SNzQ&s7A}_^e8hk5*I_cg@j6q*IwX|wBA1-Hh z4qZN6j!r(UbCArz+k0${of6pnnC=lA6-M=pSN@gWdz60_Jz({p(G5M=6b-QPY@-Sv z4i*oVgHIq|5{-b7_5pUM~m} z7a%_$3unNk=nvp#I#KH$ys7FP?0{bfHWP+*b)O9{=3JhE{(G$K_rmCTbef5WwWJx$ zq^kS|A4=<`wAK*D9kJkU&`ZHCjCHkYV6aecJc7-4Dwx5&;A1_v2kUhsw$Dyh z$D6HqdW(tb1SC`Sgb*FZ&bwe4_$~N7cJ_i_f@8x9eXjTT>#P?Zz9}5qIzd4izi)Bb;VL6)5(CdsO z;Ta@6c}7ohK0d`0>Br!Ba63R2V>j%;79N8O3G%vo$ zTDwX&&0v+}VReVHVDUBZ4A?`nqm>(UuwIg2F?|ncS9(A4oP0kx7yOXt$;sSFr*kKL zfaj&zJR5LN_YUg`&|ie*8t|`mYYy5)Y3&{4&15IsBmYC5y~Du{kq^e(!FW3uZ)eM^ z@Gjk*<1grCcw(&0+_`rLDe!Hc6W(A(bGbp!;YsXs>^F4CC=D5j@T=T{|1FGa>NzbMr(SV8Mrn`DPdOid!t!#gJqRXs z;|^ER`U1Nt2Ru)$XYr;et1maN3RUT-RP`up^H%JsGwhdzZWkkov2a>8 zv-*b5*8iTrDKga$0U*cA?F<6tG-WaUOdNl^s_k~z> zU>82{rXnnkYwL`oUTpyHqlV<_CLZqA?K@l{wCA9*Yg7CJd9FSFG5id(SV-Sp)W$a@ zi8rfO#KVw(0NzG@*hSwP!QT>1!D%`HC5aNssKf>6pAWu(O)6@zM0f4*I^8?MfnW|N z@=eh~vg;V!>c_p259I!}h8tfgd+q1ACTE|ON8DuX9@PEl6P~G#NHctZIxs~~`-!L7 zk0-Q_ad%epDM{iEk>XQZw_2Ows%gCI^A`#ePwNZ{Hf#3{{&AiA?K6@Gy1e9eVK=G^nmSyRAse@qD?eTx@ebJe##>2o7S^CWNZDpMVw2eIKh+ z2OVzr!5nZVSctrY8(f)Y8g@leAKoJT3j4bE5jXD#qEVS>T*ys)if-}Y`0!Wj;b3}o z)ALnyfNc3VyqQ|0`L3bw8v1r4TWS;eL*NYjSzBifuHbpn{NGKCEfaiySPFBhF3k9^+n99le~&PBLX)eU!hq9ABOhU5I(C<+`i_%H|k+Ikz{ z{~P=L!6M|lvCvCAdIH|Sjl$cxhU`kt$M^?gwHo9}ICuq|0J{BHjpx{P#4`wgusmO< zQt&a+o5%als*KVdY)`~CQ5njqW+#ZxOz=8#tPyvm)nLmEzXHq$v%x;J+PhEm2+#1p zqWKW`X0*iGZwqe-&dy*ym<`Ipb!gV%ra4KHa1xU9ksRiRJBvH!BCrqmHFtUZ@n7P` z_c-qsj_G!0_nPhHzli2B#=T!pyy0SOE>_=gDtvziuK@GGY*3#3u6F|V=G)&!vLSPP zOP^>5|BcOjZ~*v$Zoc6qSeu!_E5Lj(o7O&{jac}VEXVKbQ$LF@S_>c1D>s9R(h4kh zQ8a9vdlE6>qs+aI-Y3{uSV{Dg-Zt1##D9e6GJ38g;WB)?QWzW!?fp6!6~3o^5j{+0 zQ|k#@kAp*z+^?H;unZg~Nz@Vjdx`Bu;4z`C46o~ShA#&9t5;Mm47XylRPtatmg|DQ zQXgi9D=qe=wFMDg1kRC8R-Ph|MI53>xo;lj^xP_*xRWz<8Lf{H;YmdADsU<}HWv$d zvYE9)Pek$K+(y@gYi#SincTMb=-{CD!m*6$a$h#R6f_gLqD4O?QC9(4U0<#qhDL{*98vxyq2}dF0K&8u&R= z-2V*=55>2D|Iyl^bH7$U?nvu8Bv)c{DUw1wA4|+XkUV}rJ{zCUCK~$oMY9Tf3Yehc zQ~0a;{s34|@e=$}aE88(kZFAxw~qyBIMtI8;}eEdmzcepWl%9NY-IF7fC5N0=e^f1pd4QF9BnOlnH+9K zW)9XTur4#x`rPU`d`>#o@;}loSJ_SuIIagMHMsobN3V z;d$wE^|YUEt$kXqXLT~rdseaaRw0=vw3c;yq5=dxv44VS&qs3}nOPs3C(HGTK%=zI zn(oXZCK|EhM7|cYJ{t_c2I;O~CGt~}vxvhX^)kdQxF(aais7x`d~_ZFOOcGtSW|2- zfV;@g%b;{VPTMoZPcqXtiI2-woh!^wr%T2nd%q4YjxG?{i1hQE&Z;q0wW8) zzhF|reDK^x=08!`O4;|$%K~%Q_!00Ni0Sn!FYW_Path?=)IUWtr1ZC!{^c@WmWyr( zcxzDazgecmm3;o%eegT}|I$d@H1{t|P*Rch$DPKqs78hFDYs}pscHvC$n2jU@ZQky z72yZ#Z|kR;;?>kIznonJADXG`W<^d(j#TI0V0O^IJWB|*?7CAWe4%s^4E21q>#&ai zx4M7JDR<(COA}vU?-31Xk*$4On|ze+%PIRqEEvGJ%s;311nnX3N9UaRtAu_-@q+ng za%DAfJLSwC>{s5xJmNwix|HH+q9hro1u^@)474t6fcEevfgR-E$nAGX^aw2=;`eE2 zj3Z2 zJ{;{;QyA&aeMGPnMru3cAo>!#O0c>Gc9wm#2Jt=w4+_q#gpZB#QbX7hh%-eYV2G@3 z=b#g{TFK>Rq{#)7R4j7eS~*{&5$)kqgNQ3G5A!Hry#(wkFnbc;B=q1`{qd$j@f&|A z|8*I@&;h@yIhVe&03SQBDFvW7?@EcVF;}<;F`%dMldrNF%Llst7xpkdrpOQC5!%{3 zOXhsQ5x^0FwB94T@3)WhO5Ve>lp{~GDTa}Wb>s9L@xD8_dpL95vz>6lgZ=dO;SAO~ zv*SIo!PBG22J-gHVfU^`k#d=p->bTOGl2SbQ;VN=A*=FapP=I~?7OK=a_gIW=|xfv zI_NvN11VK<5rE~{x>y;-nUWrypYwA^NhcAU!qWk4XTKQk^cK4Zoj9}UomI_W^^ zC)hKw7tL=ie-r+ebl)zkJ@y*zHU^5-Kh5nx2TmlW#{_h9WfJ|M-p8lK&c$=iy?Ppn z+w(B0=5t}y$~T~*5-L{>o5j}8=s=K2XVJ9U=~%JEqHZt1*D$l`czkc7XVrG$LiX7W z6~GyW2m4-vJu8j9+iu@5#JkCYCq01(`sjv^Uz*mfxz4yHT|1Z zqGw92?2}C(KsBL<1Irs1KDeKZj_%o9OXr++@Dc*}toUwFQc*^>W9f{^WF+88AIJga z^g&nYgq#EHY3Oe8%T-%hEsfC~>PFa8`sBd>B=lu>@1gmR6W1GF1~y2CE;;g@^n-gt zxo2ASTh5`k;ydY?|K7zSHD5ETCx@3W;!R`o=2LoBPA@lw_4Y>%X{xbvv-aRTD=eVR zt$i09=}Kp+oJpLrM5`M*`?xiE$Zu2YT5K26Krhs;H61zgP$LV8z26t?#@xu_@G$S0 z!a_G5FnG`Fj4JG;(LI%SKlHtW{S_mkY`7&~b~CFzet9duKf3SMm)C&v55 zH~Lz-`gz>hvc=B1w6_?4w; z;^^m#0sl9OC`wV>QyK)-7!pi#H7~-t})QP}kH3Sj!U^ z`ZmZe0&o0j?ek_>xzHg$<7-=iYtyas+m!9~XntbNFI&;&pLQPWRxn%5V2g^DDus z?EdgWIo+M=0R$iuVfs1ea%MXBDTV0F6?GeLxjcjP0BymQmbJv@E=F2|ac9yt@Yl)e zBPvZ0*8a5@Lz0(^-TyD14Iq2zlW-lF>l~6;fN{Lczh*+tOugxNV*zh)d}zpMFDwl_ zI5}Tffb_20KIwcpDB*vtg*OM9P*pSGL%aiIkHUexmuO^MkK1uw{MkMI zwYM|3<+p#^v`0t#wG*lW8yW6)(?ce2yVtT2?V>(7STocQ_}k=bQD3($dftBY`c^3(KH72r4H&bcS2k}# z#Kd2}8lg4U(c)4BCL@g{m$Oa;j6$TRZp!VpWsw5GZ=CJ|(*-ZKNZ4xniW7%KLSF~;+ zMpxMZ)fDx3w72w?TT-A>&Xl^4!K0kauI_kDg9l!b-|lt@hp-5!&qa6oi-fMF4?|@1 z4)L)@_G}ibKI%8|{d!_pJ?qsk^z&($d+p$PGs89LH)gu%e^35Qga|~SuKg#5rQ>If zk9PY(6Q0H=0%0arCq8LAUj(OD>rY*hJjXlfzdZE1KWYmuGrTZ_MPzp}GZhI?7k9nAw#x?2V+xveFh|6!3T z?o#X#A6Z&@md1a8ed+*v1b-CG_^X*eYH!aiT1+2r=08GKyoMJ=?VGt7r%P zT+uGf-v9QeX%dmgDIQzl4(F&iZpp^POCh(Q-10LZYT<8wHF1&k1f!_;U_L?>ubxe39ho_4**SC?I5AWw zoqMGo*wGT+h$irkM8c2yzC2355`P99e0h2h>M+)Z>Zn2G;FNJgCR765lVUAFejwY)5^X z0I4e*QFBHYCO+WmGX6b@)RlML=eo`>0=g^>0vX!+zKaavCEy!JG}SRu)wVvB9c+!27_qqe&>XUX>9Xm_IY=T5oI%zq zWs0J1(Dwx&2jO>13Yjnvm;8`^8kbwkgeDSe;OCQDuWWbkt;6h`n+3)D_e2Yhk_SZ} zZzm)N%!_7ABv34wg}z2JOglW5%HRvkz?j9S#i%0yPK$6C#dyAo2_`X8PF@EY42{niwI(x zNDUK`e>StLPU9+uUQ4Gl#jq7rX1PfCLfo1Te=}(SM9T|E=?{B185!NF0#t%d0gs z4*2ZCycfS_i%!`YiKaq#kA}~lmW+)Y>0F4QktKzg6%`tivS)EWCqLt|m39Nx*tlct zP)g%&ogR^B6X!|l{F^I9U2utg@N7(lr>Hg~-jbGD72fQuahIc?u4J1tC?fVdO-{t^ z$?LU7YNkk$%!_(go{W+=Z%?sKHW`!yYJZT_rUYCM=~)o24P>p9DnlHqO;J47TdxkE zfl1T$pFExNGCbQLIHru9USt`mQJ=-Qt7fm3_Ye3LYKZ2th^45MaBq2J^1>AgevjYz znbRXlS0(-(FHHPVv#peg(@uqoK{`*S0&O9$y;l{=B{Z%l=(eH|*3%yJ?{IUxVyvNt zhEisjsiQTy0w>Q}C(et#%-H}x$km9t1dV2s64UeAvW2WQAM5a-FH`G!CLqV|54a_S za{P8*VgqFmr@`#y-tnNMng72TidqU{fixeEj4EtO+pnWP@2KP8kCVT7JgLo7E8ie0 zXpTfohqpe)x`3U_r(M1~%}VO64Lnu~qLe{{3IDi=W>2XL>CGoPCCc9BX-ynS;BF``vP>R~5-uj`3DX^0}QP7SEu|Gx0A6X3on&0_~f`;zIE z&-|;K1Ir;ly1kOPpZn$wBGpVwF!91+As7d!IlwZGnA1w;Rjr9opfm6GYEGwZM@ZJr zXO#YaIV$1(2<}OeC79ebkFC7(D`nbNS)uuwvoqAhH*pcW^S$}c?#LZ3bJ$#-LYo^C z>drEU3=)n*9B6B```YG9iI9t62m5mo+KD$nOX7HU^sM4ChNSgRTJmZ0&I|X(hyH8V z<dzZt`i${W4ACKUHL34V7vjnbspNB+{14CHv?p+Sfp$^Qc9UdpRoXCUbP=> zD(y&llE2wQJIQ9H1~!fQ$Kh@b|La2dsMT1D`Qmy7JCF}}p!7xc<6mOTV!l+%(Bv4r z7j(82^P}iuOV3|jw)YKUV1}RZM&ru}5woaq~i zZx->NH+GKC9wsYoJjd|q^6S*b-Bo}72U8b@Mxo-w>SWk`?H*6axsZWA8Pq?`9wn5S zu^SNDfaN-61b)K5qP5G9K%5>Bt~+Y|F^wDIZyDYz;{c4=*IOcI*SX5vcl2!&FO~*h zW}$PRqOh#&-dIB3DH(kJ+w0y84DJ9W(bW~U76vtybgPnv2w5BDT@|(%892P%=Mzt- zq;qo{^vt^x5M`@tCbvwlsmJKAbqYfU*7g(L#kHm;wHoGa8N0>ZSS=HZbf{??voajZ zk#wAo7i-YxN2nV%O?^`F%-_Q(2v#Jcs84jUUz3z_m z%P7wsg;jVOh6}aTsZl8x-#8$N_Tod;aLKb|eo*_&mH{vmgrbhpyFSCBl(sAEPbtT&i#{X?`_`kkiHIW1%Tt}-|7%*;1EZI=J^?&wsM zVN#OWn~8G5;FQNVnggXOL+(`H-lt({YNCv5(Q0Sje1y-gmh(Z=VAu8yIij2Y>Kn0sfMnz1*B|RhQ z=-v6!H1;#wpnl_XssHV`oN1@-@^ZfTq`JJLuln+6*Crkc2wWUi4mJDNtLWrOj`n3p;3T*@Obx~sU0b8+ zWNgkOfBz!CmK2j3Q>g)SKWsI3lh;B8gNAsWVP$FFxdk7|noM1afmgp=pe}^I)q~DM zsv2W|K;R(wD4ZNxHZ^CQ{MMEhMVpj;_1+1hyxY0O75WyX`=8t7J&*oM{tdM-b1m08 zf_{yDxRG93d`ASz*2P^%bU~V zzm3VIrOG{mH+{qAwf{`}&ZNA&eW&0zy!3F5Z2zXQL>V@JlExmQCd$zsfp3lG@(rtR zjcz}ZYS!oi`NZ97i}^xk6R(hoKi-`(P0c=dO+MXi@Hl>&ZMA(63Gf>v5nm7(5jX+o z3jAgs*+NYrwdxHLuna62gHcjqs|Nsw_(2QS(=t- zSHyZMA}Ek9v$Bc%l(JWfTok%G7cvymo@sSN*w*SVfjvs_#f;{E>+Ub{S6-ITwo0fI zrq_I&Aeho_e<341#2DO$HYiirtY@V^KRB~ry&Y!#qo)+yc%U3ArNxqP^Nw*o9$iRT zT&6U1+HfopKA(76Ov#h?`dl9^-Of9_Y&!lJUPzJNQaHIw6QJJy(o<3c5FIF4Yt;Ex z&?jp-MZN1#JgY(kR#$>`a@Bc(dL5XFV^O26O$1bZUfOMu$?j z-F8EbPCqIkJtLJ9ePhq!u7#cxByQ=~7aEQ$WCVr-^1ampYAqyv$y-x=Yw#@<;qjr| z9*p2me~92d4lh{dbxCJ`q1PELGGye&JzoOHI| zLIad%pJe2LE%>eCpc^v33s+BMBy$HW+V{$6o$~ZxT^M!t2gd<2N0VB6p1(#u#6q9a zcRXm6Hs`6JvoY2d%+A69ChciKa#WDxUH#y3GyC(1p#`qJOB;}g7rTXq-_F75sBeGt zwKt|;+uEXIN6^0We(dSDt*rjMl*IRBw*a|r1e6_9*zjh zsQmc;9idu3Wd+(;(S5PwGX?a{MEccJ5;BE8+wfUmcI^A>8{=U1n&C%{}V4M&Uz@MNX?}PvTKW|LsJr{g`uswSGSW*Mz+@T~U?AZfNcRa>@a_j>) z1ndf78t}p7QeJm)Qw1D@wuyhg`=L{0O@k6>YA4`|R18(I#VW~EiAKuMmmyBdZ7cAm z%x}I)=oGe9ku=IYD|hNNo>YDIwb}k41dv}4JR#DlCM`i~loV}QGhF`efY(`8bzy5O zvA)PGd&K60Y)&zf6`ZuSY#mx~weDowu@$fsh%g1Xy7JIjyS4BbH*61I2fD3o18g;B zzNnXwCV7xJr|;SpS4F!nhCN>@u)4&%>o1BdDlNR8q?^p0^E)IW2e@V0sasZA+?1-t6+re1v1Mn53L!RUTPv|?XF@B{YG*ww5gTWID`^`S z-wO!>7m%OH(Rqk-O;0tfLWU(#tPBEC2-4c^5!TWId2o25raQlerpTAoWPA{@qfY8seS)$M{G@oe$)mBT2n^aZ{j+=CL<#!if zIvA?|rF0N}3JRP7A4xyU@aE(nlWZj}EpmMQ+2s#a~5RJSaVk57Bsm_i4JErbw04dPlda}vDTw>2dx2oe}^Cb!!d7(Zj6s+ zDMD2x305Ucfg-7hrvZ=Mh3jwDUZd}8)LyS9wrZ{4{BPanss-6tz+3>T-Ze4@6bDe_ zsvcgXlMMI!2Rt-r%u93}1WqFeL5zk`C>);=sem#jJY0rtQjDqsib@@kc*LP#8wOBG zoe)Os2)g#qR>_?hv{6Z*5oYK}x(?n_38|=Sz5le+yX$>B8h~k-<8(O#&!7aorRe(+2CU5Fj=OT_#avf&PBU z%nEt^&w&+@W)VE|Kh-l`Pps?0aaNq`l9w~SGO3%zcY7osK_WpmU_5`Y*SRqeyJE5Q zk$Ov<#gbwvfA-v|Oj3UiOCjoH4!=y+$&z6S<=d_IwYLMngC)ZEoFkpjPj7s)?%!i< zw;8Wi*XrZ1R^Mv#r*eIgU&4BAlK+qO&r0T!%ZyhTkIRg;WE!6(bIx@GF>c}}j#q5- zoRhUU$r&|sp79ZmSI+z_y2`6~rWSc3yq12-XYxmiESaNqWW|5wuQhwwT*@5A-2TM= z1R(7D+Q;vu=iB*4I(bKZNL_o4q3QUB|JjY`9qEa=X|pjmZkV?sy2h3dbiDvnB}8iu z`G=uUz<2qArKySN-_L|fF~ItYe$prWin!8ewgwTlhfeF&hwPbfDkRP=u0+BZeue6x z_;+cv_<-etzMVZXV^9B z(R?!{4v(0f{Jvw2AtAu1Q)~x$ll~ra)7E>7xSl$}FY*c%=YP4d`EkJ*aM0b2-T4Q| z>>ATGzIMgP^jpPhhwC?;!AXvP#y$uODX5tkAf%08Vm;8ni8K%vCs4B<*z`AU12fycsV@HnJ5Vu9@Mt=CY)y2g z22O*cP5*>q5YkCdvDBZJU@_hM^o@-UjGZnhpTLny|9GYa6H|kT{y=7G;5IlK^-stH z6Q zW5r`~WH31L?i&m7Pml&7O#>6F0gu)}08TWknBhy9j`aWBQYNB{z|0V#Nk@Yd76-;e zdrMz?K>+%#RV93&Ar3LPrI%-(9WlO2t*i3qGaXUaCHiyQE&|*7NOQH90YHRYh?|AZ zC&F&^pTqJ5;-f&c5cY)Pqe8Se`UK;nl(*1(wg{AAUH^{Z*NLfogBt;UXVqF?Zsa@b z>S8t77HbC;Z(g_}FU+2w5?3iZ!~Str-%d&CdjNXaKS=}0Z=I1oY5qJ>@xlJS;PNCN z5}y>CoS+dQ;Z&2mWT#C_*_<#wZob!is|HmQ>NWEgH8*kLQ>`^YTA_#pzQ3}RTd$V! z=m-=l*#BYnvypP!<1-l6{_^sM(+uhB-gheB#j_*V$f%l9!=$ZDu`q3Hc&P97sSWf- zHXhc*q2Gkn9D&tFnXK2DY%IjoWLB#>u65JYY0dRc_%cs+DOJVcy|lfwCEiJc*L+0h zQrMo_jyXv3i;J z45WCw_7Z-rOACI;&Uz+!LYsGj&V0;n8{H(%zI6xu{I09b1}f+9fPL0;SU@2^!qwVA z!MEd!Rs-aZB=NURCh*V!CU>aNL1@B#5H3 z51X3oQqcwTvI?7WTqUK7)3R{0O0|mhvKU|aMulrdx2Keg0>Sd)12~_mWZ|VCilM>#LIBoe7p-NXVTAf+lsuoX&3R&s_W|a zvsGvP&lbW0@yoa;N+1iLvR^^(QspC(XY-e0?YzKwvuBQ8Eyr1mXVOkp>shsD)=rJv zSq{*=vQTyWTh`vXx_L&+&ZdrCE30aH1=G5+d3wY4s?JqQK)bVQdxg-twt05Lj-U=v zE39g81?95LWs2K2r%q0*v`W8faRukH%4LSzPPdLhE3ImB1>>^9Wjc1l;lx&XdCRyW z!%No1DX-knDpRYZrQGpZ+h|s zV{x*}$}@}qgl%#4k>zvxzlRPSiybDr%+@L52YHsYpA1rZfmyo8C_D%0lmyE}G`sPX z2Fpw|2inx1hnfr%ex}9gFtgCNG4H?p%z2r!Q!*@*-q+tXZEp)x%=#I%(>g4(-o__c z5M~9MCYV`v)2NM0bS#t8ZYN%i168b*Q%GjbZ}U~m0vXL_IhuCt=`m(W>wjC)tIe|3 zZC%rIPRtu80qkB=dX2LH4yY+1r!jnX@hL^8DSQsfDM_b^Y!0j`QKxYocJ(P$Cwh28 z)}(3lhujRS9gf8*#*-#4eJ~HoFeH_MokVYbv)Uo)Ln}Sf|lW zw5^Ei&TBHa2A*M`*_?}>8#yNddjV(jHllW-&b+p~j=Xl3ZOvwV)oY|{s~2&%nD?a472VSsH;xX0&d%-bYu}fAuQk5wTxUNA`A+k##%r#Z zF0cOXGd)MfPW5eTLiaOjd9PG+uU~ept)rWlR}ar#P+dVgzi#T>hIlRr9%8*HyOMUO zZ?JBf+(vjVa~@{Au)3ml$Zs0lhC45GqlD3mXex@-mSRH-DR5)O3gwn!Jm)Qv3z_HF zEJ7`GSdCfvGm)p!r}3vzr*UPY&7#cWPQp*3cQB_hrU|Certzk+ritj02`~rfqKprTRy4HKAOfigf(GZ=#gG3n|UW&`BUQVAJMJcYN96J>=^L8h_ zlvLFh%!VEQkfKlOa6!zmLFQft+WZ83kdu11lUn-sYj({uJDW+ih(;v*SaoBu`i)~W3q~7iAf!FTN7>DA{pgX9SvTsSL+gXW> z4;Ce}?`X#wTE`XroB2O&kMvy8(&Ms?lw!|A6S?q~&n5|cnx^uF07c||HR*#E+R~5H zDcXw2d=(c}f~JactH9!ma!&&uJ03fcv5c!J$ir-Vx!bp7KGn}x{m6PtQo#4_-P1S4 z0Fe1n?eN5p#cU))tt7_M`l}yhEH3-SajJ@Rz6wOVgo9j;e}H)*F1EbB{)zslSo}py z_{EPKyT|#e4c^7v@zINkP%F+88#Tz~yNiu+WA?Of9j9`hFla6)G8 z(|v$wm7S`M$MhX0D5z7)IsK5Eq!jqq)+mt74dp$^4zkMY4Q1A7y#ZCa>^*LdDckny~~FX z?JDY7bPCg`gUPGR?+jrI#gq1t{R9R90bw+-AfbR+gO!zm6+t?*B+SfccRMW=`>~deq?4tElFPW%k->^npbfc$T zNH>RjN_f^mA%hNWyrzxtnVS)=>^z-0gEN-9W~U8Kn;w8JSAL#e-982jtOmGEQ9z+9 zb7!0G0D~pvdNE+(`RWy|=0{79kYi75D>%ym&UV66wDnN zY2T37$Z~SQ{E5p)?+(l(aPZz(EqSp;i=>Q zW9*BH$MJNWm?%;fA{jBDGdX0=gyv$RJPFRecb>B0)w>j7Agq-oZrxg*CM9KKbnQco zm(NWbkJGKAMen;_%Ncd{10aRmx!^;K+9M+d8u12-3p)_@H|B%Sj6x`&rtK+Fh0xkV zY%yHQnwlJuN0ro&SISMBET2bQS{p_MHP;pT;#2x>km94F@7=z|NTfP&Jf$@P|tWFUv}NdgmId8H-h};`k^ny53lb7 z%;-N8H^Cg89?uZoKF0nF;rcD(U)VzwmIxSK6`_9K+03W&x+RF8;`ip*>i6|#Og?O1 z_NAKb`5;y?@bkr{X^`r*B5uw(Uz`S~!q4_VI&C63hzYso2KgYqWiw{m5oeeijTSUG zEpQ=KYl=LE#8zQK_D5AAmWVLMel{9VjRIwv#5TU*EZ-S_a^3Jw|De3d`Sz^OL7a-A zrjiJ6V;=qA@Ymx8L1V8e4S$Kh($<9^dO)kykBoy}YOWrIUR9Y!_VKHcGvFJ$B!I{{ zM#~@J{O2W{`-=~5Z3r?hmkxE!X!QvqF)O% z?nE38!hS~*MPdmg6Z=v%zW(}-!GUXs%&jOmWkU0FCK4+Ma_~;^sDn-&fz`mUHWcaU zz+5BbF;rh+=&mE`i4b|!9z8_Qj?Fv3;zYtabZg6OU!UN`?=yDCWo&prqLv>nr=uyI zD2-(59M=f8)(>x|VrYR87uaPVzBkG;gs6`*7Oj^zAg`akldGq%YgkLw5dBL_=+R>n z;}&HTv^>-@cwxk2|L5t7MMEAS!P970J$prGWWK5CBb_!-V|Nv8INMqvxnH){Zivdm zh)?<~#i<5Zwuh`=9dPI|eM(gPn}VHuV;L8+jy7bUt*%2evKCy_T}!Y=WKZ9YE#=^8*mR~%9X^P zrHeL48EJ$)j2LidH{|VPiZvMa=UuKIR`-u~j=uXA9rTNH)AcCnK~6r=z_0paNO5kR zQ5~`GSHne-Pep)DC2r~FQvUq6Zb7AU%;zPxc@@hH&W(&c1@{ei(%LG6 zJtlWl_V7&W461o~WAsb{i7e(iI*EwkX`s`5`;m@o4X1jJHA5%gOWw7?i;Y`2&l15& z&mp3lcw1g)<2K_K<2Ki|`t|Cyj$3Z$`u2sbn_EZc7T-1hi@(^!FuL#`$^`zLk@VbuG93lH5K{PHD$O zGy{#iK+@E%k;zYP#kv;fkrId&4(Edo#Qq&>7G@?Qe5P}Tf61O(DQMHAc(cP*CSL08ttK$!iiia~nrM4A zB;?}DU|tQC_*ans-KR$2cnMO~^x(Ghq}Ts3b}$ z;z*S^sszv|ns!80D6v%tO_yOb7ql!TLnmp^$dES0)98#BUo223gQ&S6)d4Y6 z`iWbYpKkSAc>|t)kaitk2_4)A^*AT9UVFBF41M(sNmGO$Uijf59)#7L8}B!i_@OuU zzMR0DR{Tj8#*oHa&Qtk4$=up(BfCI+`dP;>e7*Q|kBEn~JDSs4>hG7ZV%bSS~>T6VNkq<@77Bg{*#+(9byOcNg)i7GC4J<%AndbH$ z*TV02O;?w9{yA5KPOek!wJXluoo{l_*yU}`@2>5v2Oj``w%>H_P4D}LUf)}Y;q#Q? zaH9kU1F{D!)55O-DaHk6AisgLRjZMnCk!7&=CR)g%tj;k?aXJg$f0o zJh1SOLNatDs*oZHl@z#WME?J$#@-&HBjBbmYFa}~T6O%ZtWxbzt#ATK?Xvro4tfmk zF0BK%U1kNcbh~6iyl!%nRMW3=k1=XoVK}etf;rr8L8YL7MjU^~`I%2A*NaH~1b)$NcKQ&;I zKLPVDW>{*EqJp+J5=0oWP^!1d$;2J@M)QK1-6 zI4E*8hD^vX8ru!<`(AyT6~NnS=B7;tUX&C`4ZY}@CH!3m^F8MK-#=N9QpKsCTU`-5~7G$$@h8$ zz47+zFL8QQM%|`{@gcE%pup#uIMc;N9Td3dNTL0)oT(YnG-B<-)*LJ4Tf0j6UBHSc z^!5Aq!gHdwmym0jmJ$6)%{uD<3(|1ifYK1c?v2rnDFs z5g|AySfJwdA8FrS7D6AYs$Zv&g~eH|?VcQvktGS_Xv9;ryanWOw?oaA*F9c zJaIp%aXvC8CgD_t4lz$3MGX+Z@w%p)>n$r2=trFSZbAb^DRcWc-?aD8Ce0)I*cz2S z5wenPgBd5`#QG`Y!%J(e`P)q~X_bVXZRkHjzPw3~rv+)Kf}|Q64a)XqFG^J&vy7Rc zGUYs#KZIK?r;s%-C(gwy-4eD55++2S=7+|h(0Uz3lqnXsfv+IFV|^v}FQDbp>xS>| zvF6V0yPQ6O8IJ6}nf6>tQ3uf-HHYUjVnbT zV9YCx5XQ?@s*j^Y<=L0JL-tRz*l^$42EX8;ePumssy}V7K~r~fLH4S&1w;EMjOsb@ z<<4oxOnS2f0sG%@@t^GYUr>YJ=rU-k!NMRT+dw!&=pO|Nc?<|u798j1IaHXr&o3vw zIe;BAbZBUpvF!yj;JN&x?Zy{I-=r!8IodzpMj4h%RQCldsQlj_Vu(Kmh1cKUf(n!Q zi9#qmAbX97K?9)J2514#+Q{Khg3z`?`9OVn#AFgHTXB z1=D%!9A}62Y+Z1!EnGvi-+%fwLwUkrlXkOoCRMadz4?;g`xS#Tc*rAkxf)s<8f%ts zG83C@lc6h9u=~c^Y6M_Paqyn(lVisY>5Vn_%PD5FJl{{!B8GZ1`DJn7xdko_>esn|S=#_2$K{@yPk!558WM9*n&p3cBgNv)|sm zW2O9(h=i`=q>e+S|pyQLNZe1AU(J!fs7350fNx0c*@1ytSO)Jz|TcLE-9ITGH8e*gr|Kv3j zJbj;3FBy$>!LD=vfxt?-+AxOwMHod>7qUlMtk$eh~eCP-)THF{d}vl=B| zv}O^fqYBy?iDZKW^tO6mrDB~GB_Sr25+(BOiUX<=G(h$6w4~;6n=0+4!|D*DDPG+Qq!g&9ppb@54d6U?=)dsQbXsS8DQQ=pwKT@ zsf)0o$BL5hOtzm^9c7s_f2F};>e9V)KAN&q?i6_ajom^f(E)-4vvuacSPZK(zExQ1 z>e*OucD5zP5Pfzs`U-g~0xP_Yk@IamZ?*rL2MkY-XXPhE=pu5L47#2 z|7a1?<$1V5SEIQTVN&R0)grhx@90{5*}vH&RJ-^w$hdKAoDWw1D0i><&z`a*6e;f< znuaWJ5CV)09p(8J-|Ou|WTR(vnGZjOe2Yp(MOM(_2IOvtn z1_x#!8~|xf$bhLHd5)yMp;@Jag@P5PGFmzfDv<9avk?eF0WffB+{vm* zh4zEK1v_GoHm9cDT{`Mjt+T*-+&NHr_qzN^5l2iy#i?NSh(k`cu-RJL+l=uqO-0{) z=gCb^22OH(W}!{vZi_NTS2Qfy!BY*eFHwn45X9@dv|pd-FLQT2#Vz%|Mv+r64w)q1 zecAHZ<#6-$mF0*o-`8U3)cu!sl8ps*rTg$~#qfaBCwO-q2I}_c7fULYKf0+hTC;oF z{H<$nQoKdT(Y(=)iGXc%VoGPb=Z0CAwQt=GNf?OfyXA5+bk)lvDw5`hyY8aTQS8s+Cl;3**Z98?r5`8f%c%O|&`0+ls!klTAM{m8pjtV{@GAv$R~K zm#DPelVm0Pl@!#eD&@-U`)&1ts$I3lg&!nhdpd(+`<`6ylM&fXbf-A?L=NiQ;5Mt= zIi>o@(`tc8?6+f;?G#y?^^=4A=lMlG@%BNZ1$k>v-^-9+pkJT2d_)}kxbpDW=yvL@ zn9zGBinVQ(o2{H)+pNxTzzyR+mvED(nykrR*n8H!%~_o$Vl1n}J2%NnUrpVOoOfQT zR?zymtz)yJV^G&0ouaW=eu*33P@nt@pN68e0h99dPR$d=H#>+O$gA|Bn1uapnp#47 zmzNRwt`KvpR=#ys^cn{dzd=u4BN}559W7}-vP7*gS5m$4gP3H^q2r1l`kw9yxK|KY z=qlBqwsdZB?B)mEYbtxC?A8j}&f@#12V8y)4$qr+l{e~Jn~+tL}KdqBZU@LsjK! z&;SK5*{P;5JDKwIx4Lp$THMWa>TF&=&vbiPV47d6=E;%Zu}hV2lxjbkRs_{8dxo^^ zTx7P=T--zaU2+M}Qm(64y?9O%ZT`+5Oe)nAPW?_P(%l>SoE1J#Jnywo#noU^=^ z`%q_d=g%orfy%-rMeXw)#m3$Sq18ruIyBwL^rKpv%x+s8{N(vYUN_0Cc%?WsL#Er( z!`0@pDEg3Y*UInCCeSqVGySCYD>TsV)f_)_#W)+^abZm%v%uJolBK2ElVMfz>ROFH z+IsPab8EaGpV*cmy5E~rZu0iFvGxbQu{#Ia7aumA!@sW(e?@n>&kccRn%%&~CEVrh z&Z|6vwtk3bHrp1NS0&2@=?1SGics5A81AQRW4HGl&Ggd10gGCHiU)Ve#F^@&&5hcX zqefLMd%It7iC~#7tt;Y(?l?Hme6w1!%g_pb{!{88 z$!3(kG^6jbEDunc^3Mzg^4;?l)& zrA`Tn?CFkO6-fLVVbuz^g*^*H_l`}Uwj6(E`d+)O#Vm#SLT|NW>AbW=*Pacf9S`?@ z+By<5C8l35Unsf$(X9KgnjJpv-uC(zIqO6Bv)FsHw+}v@_|{uOhbdnSiGHz7MZ+&Z;{(FX?`F%*rV?>1KdK z1Gg$=@mZz9?^3qtlupR$J@@hr>im3Ydfl6h)1Nbvj%_XX6iD@tUv$l-%r`hzIIy4U z!&gy$mz_xQ%hKEb>F26>sVk;tzJcl8-=!Dh&1tj|daG2Yo#a@$i?Sq8LF(=wD9_3>fw?TZN1tHVVBN zc7Cx!I{78TaT6V-v*=70I%8u=WTj$57PJP=@+f z^wA=`$%?VdU9RF?pRPZnaG|dMg~F+F9YK)oRJqoW%Jw~XtwblDn{ISuD`rkf=J_d1FDl!fnr_rS=jblr54kxTSMH2TUv! z7f#Gi9Ou;Au zno5lxH_C|3PK{Mn)Jr@{i<>IpCST;H9Oi&pmka0!d?p*p zWV6BhalfR-KiMz@2l@bGB0w7$#w0UxhA)c)w1MF)@P0TK)Ui>ZUoZ|E^yP8@HWtbP zVqsxS;CZlc0_bNJ!31q=7Vz9yTm*;@M^L~QN7;ZcP6jixugJ*<)Dgr?4zhzW4mid! zE@&hB8OQ~4+=DhI#D+m^EQk$<*a(OXl9wz92MfYMjz1t~GG{;=gae0g;1CWR!hu6L z$UFkug>c{y4g$hKKsX2p2La(AARGjQgB(LZ%mjpk%mq*f;UIGm(6J#LYzPNAcY?kU z4l-vz9fX4o;b22J*boj5go6X&Am>;h77m1ioa;axgo6X&Am=d97sA1TaBv|UTnGmj z!oh`bkaIB*3pqD|HV6kOKFMTEKg1q#DtsN@Fb&ut6)f4*1wwi|H|i}<#DM!6V=z+|Y)mYHoZm!bZ(rbc9_ g|Ci_(Hetd@`nRCI?&s_xg1%gm{RRY1u>TJH-z(>hT>t<8 diff --git a/Tests/Docs/Flow of control when running action with progress and cancel.vsd b/Tests/Docs/Flow of control when running action with progress and cancel.vsd deleted file mode 100644 index fdc3cb9d946f8d71d5cde502da7aeea7fe31931a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 267776 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

    0I)*1No$|5IL^uG-kys?DfZ66nP44Gj_hp z&Y;0ZwL)b$kEf#ku*y}HsAy@|RB2t5H0LtwR&hu8oIK zdwqS2vuGWfS1d!*x(q*|e^6{%+ALgJ*DNQT5AH&76fQfh%VY=cAnrzS1stAjp>9Ii zTs#EXOq*yz1oC2M;+73z#AqVcLmmGBrNqez!{1>^T2Tnot z9T^#v^kn#*AYUNgA)oHHEPqXI_(}$pk{)uomFLeK|I?V9@YXxsd)|dnyeh3IZWIsz zcfQI|$3b3DPIs>?2ji6K3^PVaPi#4b!DPfTpv9!}eT)-~3vh6Ec^d;L7$Xo5mK(Bd z*`Dl@9&o%o5{kA0h!y4KYSFe8qHc~l4ua>M?!H$J9C>tJ1h1s$art&A+MeP;qc6(u zLD9A!4i1)U34pP{PEgV_S{@8V+ayQ;EiZ(k?G1=CYhJ2F+bM{qH6)RX$WK(#V_O3@ zLecgxM3))~6m6f0@Ph}aH9tgYUF}qrl{m0YbBQ>u>%(gCCh@8|Aw=4DvA9|sSN9n5 zpLb&XxH!2^Uy{~^A&4oGJ$0IEAZw>e_DK%al|rOVSFfgaqV7FpJ&Y7@D6OnpC{61k zESE+~2ip(0CQFlh4DzJqaKp{_CfqPmcj+2zcSog`$vwt%Wsb7Jb`O79a!(j0;4ii zo#`_ONw7Vbo^AAUYg9V0o>>(9ffLnQPQy#d#8>KMt1-er?GtU5+=qIbD3Q5_;V z(Mt+EL{!H}PV@$;=bZ2dq+s=wTS7k38-iC)IU%Ibf5`RZ$7E=Xp`LI0loP#SZWL?) zWep@|2IVNF6ap!{iPA-R4{3#ZjtLhsPV`1Fg9mf!w3uVV=NQFVjFJ)TUvKeAWiSeZ zlh9(T2all3Z{%rS&aIp_$n_!M*3hG@U=-%`Jmd{+8qo8rPAWAyoK)IIMWQh%Mzi8!D0v7q2>+LrvqE;8_~tx z|Ak>PCF(HD!-&>)Rs(^u%WX9)sdUSl2rXtnvN6=TESWR61#2-QSZh~D9hj5I(mGLi zFmJV=;Tk%#DxiaPqVQ1EYRtx1*27iXf>34{YX;Ap2gp1cZv~IbyAqJaD@;t^Y~e$A z=R-5ljSw(3P1nDn0arFPYTcSb)<%|qc`tTnxbhKicVyU_v+TO4^D`UzH~LX6w=WQS z=fX@a@qev@n)?bP&SXcewlx!N_Sv(~a$Dhw()rBQmdst5NZ~4^APQwun|a;554>NS z3nOp>ro`XEa+|B5FwRxP-cDE(F%L1+jW|lvGF`8uKEtFt8y*VOC)kt#FWQrPx{df> z_~uiK)c<4aqK|NSJT?HrsMSaFsk<_}#Fe5ON4Ew05cEaj=|^cZOxI7pDgIadTKrWU z24M1owZ#46YmVQk&`KK@NzJo}bCPRKQU9b%l!qk$w_Fhb1H~F=jbBYi>-My*^Rv{PrX7D{|?%J5>f)=(EaywOB z{>@!e?|jYj@4m};sgDL7F0M)Enl3{0{vaDUH}a32e&e%|W64rtlT&22(uQwKp&vY- zdh7W+TKe*g6rn0h3Vzf~?aG>dxH8#IV*Hy*Eey|u8T@}J|M`FKanBEECOju8R)=d0 z(ls=ot!BASVfbKmA$kfot9yAjHjzqG*w=4e4wjc#K!%k)WMc;O1e+nH~C zDwwMsdUXgIIX-{sXyybA8@@xX+<%*?#XbCR!L8>TIqA!>$%QSxN57n6?M+{Xuilku z>ealz)3}iJ&d})V+-UeP3;T6$1bj69I=8v&ouMTYj2PQ#gbQyyt1>@IJE%qI(jI}5 z<3`T^vZ=yIftJii%+-Ir_t9dCept7{)XluNnc7a4&_gwOn`z+mg#eNoJHwck%*?x; z?v(Ybj?(%`r&xi{B9^UV`f3%1U+8)0YwuRMgjZQ_yBx0wUOFb7_Lq`jSkl%Y3h+8 z!j~@hZSL4Kh~*phX&Uxr_s>c4wP!L47+G)V=RFSk65##0?+kxJ?a8Rs@pF7WO!`Dz zcUg7iZ8nr0zckR3+x@>Dg9Tsi$?Xon`NAuu|Iv1b+ISm%~)LVfb$B2Etjt<}TbEpZ$i7zJ=kd|Dn+a9V3S+)K!V=-h!LS0~818G)4)1 zF4b3y?+$j+cF``#c6NW% z(R^?;AIpDV_P#8;|55d$>Roi~@sZ;rw0@t;I0EKJ*^e^#Nqo6KC##$ukROmARdZ`3 z=GKTVCv92dnntkvTb!*U69j@(S4@y@>d|}`5Ij5eeHjRumr89k0HLm_Rr(BCsvc>3 z$CDj$G6^svQ^QCgTytY;V*iS?)H%+-nD7TN>BICRDKxP1bZWi)AwB#N&3w4)yL_%c zVNFx24bh*lwmo&feq?W|O+Rbhr&LRSLe$SxE4X*Prtmug*aV@CKcOsou5f#nuzkVa zdH#f$Fi)W!a$ z(lXmG%qsNqC!|^yE%GO%T_6`N_9txfF7oy#Z2xz8(Gq{cj+I5hG>~o`TV&Y3GpQ(I zbl2{pM>UNZ2aAr6%nqN!JO}m0xQe15<$~&>T&OqRD{`JTn)SHo)(FUcQ8c38@RIP7 z@PqTVX0Tc#8RSHxMfhY>`fQqcGRQTp(6&zo`)w;ck}LbG`h1fcr2P$jJ35B?hWgeg zgTqhOR&0iHt<49Oc@ATohbYJ+dkO|nI5)I=C4oFZ<8rxx40AV8HR=mysbj) zM^&WO&5BfPRdjMSb0M3QD{2*e+^33T9^kX$k3tn^q?)JlQZ=2QiUI3XiKnrH3}1x8XaXzz1bPbms3s52B|bfhwc>Xeas(ZLJFCYvW9C(e}8e z^K1C$Z|eK`pO#o6t?#N*uXjri^QUlVbteu%0_eiBczy_ujZ22l1X^5uqBYT-*jhEm zS?%qBoy4Z|NBIAfgqqHuHI%@wZp?8gQoMfe6`1O3=TH(>&f6TxfkM7 zzS`%pra+?}tU$^-N+PAT>H}Zx^?({UI>uMKJrj^H*}#mk5GFx3oyTRzGSV2i3~1CW z`vT(*<0%}p%N~LKquEC6rt|LEp6o#OI!M4LTfoj|pM@Bf-O7H!2A|k})W$oBAJ`|Q?ond+EaMFEQMlnz0XGtP!cMWU%yUQ_!^26Wm%Z@L z64)h7qJ4LfT5>!ip@-aEtd<<#N{a4!Pm^LzrGH6Rwk=Uhj(iBDrE1Bs9uh?@Icfsg znKr6gatx5YZL8P9C(HKAie=8-^lDj?tV>4c_xh+MM>9ozuP;S`Wh!D7;ESJHa=f4j z_+s(5R;S{fVq8)DF2GP_s}g#uy1pz^OO67S+2nG3xvEyxs*0TqR7;M!DE-1@kXmw# zfDN;Px1-ntFdx!WH$*Kt_M-w_Qm9&Tw8PQN8EVN<2#bbw!_<=F4G2v9OWbGN6r^yq zt*C@9Rd^O;$e#-RnXoK8DkAvci!#p@I|v>H(pT0p1UpvV8KFcnYRQ4qp{&i; z2RF_?>O|52OoPFVtrEjS)-j$ReOSE|tcS7sJ_ECaq~lEqrNooBQ3@F+DdU$Y_bB)O zCo*2#(z-ZpcyXFiJF$J?FIb%}jPWFpeD<&#LK)Ga&&vZk<|7ifpw z;yvMw#`7GsO7IrKd0@k(%`^L$3yM3L6}khJcLIl()236AiO+7z7>^cd?Y zH_o0i_-j?#Z4eWWhZ-X}kBfu#aR~;l0&+h2nORHG3zOBuxr`!49)2GCza^qh2`~=$+_EYqM5G1@3?P%w<(RZu2LVqY3H&JG}4$+?tx^I z@5dWKg0Y+N22>jAO+&XszY=SS(?Gum{rFE?QP(g&qP(qm_qnpZUUtNTiNU04Cq?(B z)kjBbW|~G*r}mkUFdAQ~=3m46*{6M)BKiI=%?>|ArTO!D{iXJ&FH6%r9A{De2VyeW z7HVbX2t8?*Q#v>A?7kaNSedb*!C+!}qejcP z@KQmva~Y^e+P{kAgMBBWVlZ5n(*(F^dyD32<6-f!ftZCgGg8+Ef#_LIJ5%hh&-{M> zp%ZDcNkKS$sY0}$DpV{9U$Y`$vJ^2u+f1Wjb9ibk$~r5}?;fI11^?+RK{9F=@`@JF ze$YPUI;>H+x1)a}o<|*siKC7gxH@Ht%8Alm%O-nd3={Vu>~x(=Lo2ov|ZRD4mON-Ez#?Q7in41Jk|8R&5vG~c-}Cu zaY=2-s{k|-*EyOQ&9vuF5+(_Z0%SwQGIN#A9;#}O&n^5I0Wo;`mvGc?Nm9h#kuxJsE0lhz!%lVh!1NK9 z70TTu1O;J!@CoI()3Q9{{AcD-(EERnP`*}rOElmC%cO;6?PpL=GA=RhF`CjcI(iwb zad(uOSs8vl!oIGDlKc$IW>E*LGXJ^1uKMmt%@Kk{*QDY3k7!6xK-+X5;dXfTU%YkW z$&CDru4TVt&5t?fZ(osVE1vFA0LBPZakw~6yiL5=v`Abf2Jp_bgt$Z3*}hCyLaeYa z1I~nn5~?Iz5+~Uv*)KUM8NVdCCuy?yPk*0m>nSz=iC=$PffA|y(T*lFwJ+|S_*^BG zSbvgZB9fgwLyWZTmH_XQmMRAt0gxsSs*hzt^xb9 z*Y!+~%$rLHH|w@J>&Y^&T-!$Rlr1(MjBxyFgJ=*m?8~+_4Y?!sWvZ;@t~4$CGVg+v z>?^W{Cggz(^vH%ARWKIdv_nO2MP>w(r;7)O%0TrB{a++W z{k;eBRr}a=st2kb)sSjZg+nb!s0;dEI@g5Lc>C^=C|Y5(6L1p_yX+q>c0D%gdh)x& z&9KiLmk8nTSB}q;B*!I59ZNeW9j&XjnNhM%&8;p|X-{xr%h1P)sx3k1f^Q3$&aYi+*>aW6 zxxbQO4{Leqa7W^g_Jrx=yp%Oz9CF@}TKjI5Ds2PX8Rh{ST(-!3Q;PffTZj7PAJenfZMCIJ zm_>R~t*PodQgt27s404MYOgvk%8L=i;4_B7D;1K( zC|rK%&~DuCr{mWx!e@#mFjGtAYB@K<=DX(d7u%ZN{>ymH_{sq6vkG9%exT@43@IiR zscbCo1RGpn-(f#xE7_xLreYQ^O#v41f_dwCNxW=c5wD7OlXrnT>2qwDesI`pLA&RL z+;)f5VgJL!jz>pbe9sO4iS^n)e0=0uA1!s%$SHf+v!>tq7}ZiB`w4EG`G`gfJjTWd zdjxrca=~z|pjGff@F_#xqu^}yxs$j{+NM*j1j|#*<$rsto*<6rQ=q#e_?B)8fqz8wM z^MdDAS7NH1*Vdi3#n7c1r^qndt!6HP<@IGAb+hXZ#M7eOS-8;6d|tnw z-p~eDiEQ*{OzG`@;?4Lfl9kD>$y#JE+v20loxO~`mc3XJqF^h)H^p8>vEm;^z2dRr z8e66K?<}=Z{eNevVZN#}*5g%-n?_h)pLR;I?_f0je!th}{B497_~GYhQwotKTibmE+DF{*9{<2i{JnI_vl(W>3+egnhxfJ#k+q zH!+j8FEh^CA~QKRFf%g_2~Em&$i;6kYEPJaYVIRLU~8t@ ztCPQg(pXi-ET4G<9?`Ta9gQOd-dUT_s=~6`YiFtqz_Huc ztE)7s%Xnv3JNy}?HJwaSpZsShMuMpii~mb)BW|&zBDe#7{G1X7xJdokRO@HPzRISu zJJ&MHz+hNx)~2<8vn&ZgclI5*WQyrp!|q>kj_`S{HkZwxV1Y;B4qSfrB5t~V05_j* zz->@vM{xG#%%~m=(}i^t(_pn~N&mj=hy=#JTe)Fzt&dpIyi-H8?j*N+&4IE$hr$?- zvY1;O|Kl;0o`<4+8v1KEF0D#`?5F;3ji)&-4>m+__&GZHc_M5OTpKD`{4Cib-Z78>HB;0jZgI?i!FZKRX5)j9UYECmRIv1hDmjup`bh zJHa<|!y2%?C=(xuY+M64zL~}Hm_o40Br{keA*18Kvv^BCz%OmT+|~Gu6NSxkS~jga z-!JX)g7r^SIkUI@dkRZE+lU~w7A}s_dXHf4p7%yL0|=As6qoOm{$g)2it6M)PyUl` zG?1FIa(q!w5c-{dqIRIIM(xb>`%bYNrS3oHJWY|hz@O15-iUV$`8`&9XAX2v(ugkfjMH1Xri}> zsw_*wVyB3{?8V8tk;-4mGpb_=%rgCDA0sB1CbU`eii!xPi{IiMI23|KvQ9oRQn|A6 zS(c?&nUzCoVc95c-qW~gPB!+D%D=4oB9#t%TvwGHe4XVKsdR=zj)(Q#!XuUL9&v1@ zSEO=Lq|#{dmbXhHl}pXzl4(mV%DeeKkxG+%X}*7?G9W^)=pijIQW+Gf431PXLo|d5 zPCIGLNF_93vm#O%5ve4Vt$gBIp2b=dsazYWjEq#Si&R!dMJm_7tXQXTFH)HwsVso+ys%JM9I31>I}ZQR6Oqc2Nae|^MNYJ5Wk!ETD#ZtV%bo}?kzkLs z*I5<6rlxYnKY6s1iCOZ>_lb<$!@>n`>MuLDP16BW2 zoolyw#7bQH`u7paOwW(2B#4I8#gnL}Nf1QpLT1M{flDO(;ArR_h7sF)Fiqm=hrhrM4^ZXA1(_l2qih4O z%$B+j>-Vr{@Se^~LjK~-0YBMcJOi&(1TKUaP34vFuutbLPKyhgox^(r$1{*jAka^G z%9|&6I`3C&XUf*`c|?;I*@x4!9+>*?ckb223~iN5z+OlfG>S4^&TuGU0Jc9 z^=`xh88$p%+hAM};f541Gw^CgGUH`C8URcP9mpki#RcI(x~v24c!GSFX}8~(%~8xB z$Zba!_jp2=cbXzv0bj8b$yOA#hbhi026A5@m`944#fq;A1Fse*yvkB(@kZgH8pu^5 zt5nmiR2eGx2XB$TRacc;R4s7)1A-Y;VXIZsQTRzA3(%#*7Qa+0(1F}xBn8!`peIoH z2j7uf=#%07C{#Fqjw2WZr`d+u;zlO^Aj@!TfyFEw5BKdSAc%07NL(!rj7(5z-M9~+ z0yhcAl_X1ZBKU}-6GtYT;EFs3=bVX$h~IuXd%jNU>X`JTc<7N|5&>{g5fLkk2BInX z+s|627kNU9yq=srGU2wHEV2qE{{x5JeVfT-$FV~4XY$B|#|%oIxyx&^8|B+i&v449 z;|P{S*-06h@G7BPblF5{qS$}?xk%})^s^k2P_PVWYB6j`W{`S+`H<6JRHn4j=4z-J#r0e37_dN=f8{7BCqGpyMo6LVOB>kZlMTiM@!u4R$Az>DK~2fKz{ z19#En?12^Ps_9MNe$thTsjV@d7TbxMRNlyh51W@9tFE2?_LJmW#Y^V>%Nq*u`vRRt zAwe({;_oUzd8;7=;CBi91!73c?hB3x-U;YKA5p426X6 zmta>&E@Nj0wk}j*s^CM4Du&ZiSPyCaYv^zR)ldi< zZ>9RG2!Is5N#&+Gs)EKi)o?O)!J(LO6}Cxbh7N_qQqbvWECf>AK9q@GfW&QsGf+4J zDc%sLKs|9oAsg_KFb!A$X=6EVE3Op>jU{}9^G=sI6tc;Yi2aR=fV6o#kxo1Xfwbiw z@c^+O(pD{UJ5gvy9tueeCL5EJAn@>oaF*SGl=PBZNuDA@W631SXR;qsj_^r-Fl$8b8SAnnj+_cGks^oFSP zHEe74ZuYdTJ4@Nv&Fp4&=+<5D;q;loE8a@VSjd}Thx1-<-JQmx@`NQktKECGB#ak1 zi4KYk&*WSd?GOp&qR2D*zKf(H6LI;OT>N6OwwNvccxHdLI0Sn9bjQmF9zoy#i+KCx zgLnz{mDp8s@A9El5=+T0iPl}x;lCvblKYb2yGI5kS0zFnY2n?Y3#30KVbYg(Mfeoy zQt5FisV(o8G)MYIO5fO)kI0@#ZDf+Rf@LzSfozNHM_ZvtwiY_$OL|E~-Ow%nB@^}* zn=3xZgfzwD-eYkJvSPnN|I2awMa4FSOtI$6iBZK}#Vi%I^vk8b{}o7o`gAf=g$+_w zs1{D1dY~$Rx6f&lB$$iaqjE;?OrBw(7N{^C)zJO>G`az8Km&Ef_yP0^It`bvTWXIR zLql=&7rJH1IB#4rj%d1UnZ+1!nT6I*O&Is}#VoVXY{1+`UcDgh{Uf=R(7Khqf&hWZ2o(2?4=rD=&c+O2*^`mR5zJso`4N3`9+8vQe6 z0#b`j26Er{F-q zBj;P>03%#rqCP)_F#RkDqa!PQ9wUHaNw@L*4r6|3SWr`;LWjN;4ZiX2!}lc9sK?*+ zGCW-cK5w<)8ZR8U;^t-;c@w}?0k{Syzn(g_#m9mxrA~)kEw_h&l{ctvz)sgOD?!gN zfw+sxds2zZnI@3ezu+)%t%ZH;vyVc{0rOa=$$?35^|iMYQ;0s7anhvM0~7#o$O& z24J>TO?+>-FL@<-BY7wJFd6(!zDi!on4rvHjQ@3zrRN3;wh<`}nxPw32`*CNDLW`Y znlVgK3Jm|N!D#YSFFf=Mtfp?OrpHRD2^t{jF7*ZDH(Qsd$F_h0YPK(XC3_=#XVjbgqwG>P zsDW3DZuSRuia19+msepb2%m2_J%?^|!vr=$SLf5xqaV-0yg2)L123I-h!+A6A%{g8Icly#ymX^&_~G${gMr_tfmwZv?%P?119-s&y?_d_w`UzcOFRe7o0 zyj!$oU{xB3c}!oy&D(IBYQ$M{HT*!BGe<0x9Ft@ohn*O1i`&Es@rXEmy(K=o&s0*; z_xHe@g%vT?E)wu;;5#AepBn?*f3{av^xf#hYV}RYl{(XgKUCM9sf(%pU_Y{Nu;zSn zg9hzGI%?)%uwH{owMKibHe5C$!KiwQ{N2}&t)rB?)Y}AgEPdDa{#$#;>fg=*z!;Td zhSFxvznYf(e~5bTxTO03|Nk7&MAHCAwhVBW8RE9ZaHK87)v!WP+ln}{ECW}&(9DKq zh)Shtq-ADZ1!nVV0FLHWh}tp>(aNUh_afh)-}j$$pxb@5aP-!P0A)qCvpGczzkB%=G&`x!K#}`O6Cm8F6 zD%VczMnPV7CI!=EgDLS6H_7yYxhAk5NV31Wkmc2)_d`+8hBO?~mNGSPSY%SM9SZ|k z?YL%b{+Rbnqgn5E_061YU#|VuHU;&q%@t!S?*7&Wf3Y+!*Ot^r!vzgh31^pnZNyhaJ|qBETvk$neVfVmvkJqYSy02y%PNOw#)wE zaWUr(56E2fu83xjA)6juiO7$mKsKGgWrL}Oh03QkFQe}oiGR9Pmb-ju)*5S@8&;fU z!MqAGac57#!taq^TmS!b`iA8_aKsaIt_o1RQdh5OFeKCEjQG1Wn}l{%>RlSKiPo!L zQIFpiFPWuyHk9mdlY9x)8+C&``Q!aFXZ^q4jB=4cgHF7P>H6t6tFVT0y)UKS*5B5{i% ztAZDF(!3|rymzU_)7@=p)&7YWW(EdY(0u7Mzv+EMPg{n!EiIdaZ`QWBet3xLD%Yle z`a%J&BJZdLU)y!1f#up2^%Ep0H;LogrpAHLdC}EHjZ*o}Z#QAs%D%O^fb#vpUaEVo zn|(1A<1p*~&xz3~*2V9vWXLG2>=z0C zF`dJ!(!iH87B~)$+pP`+o%nPME6L{aRJ@(U%G}9pynHiS&Tme8@yFfSHM=M@AeA;V zlUHd1N|9^Sd|pIS3A+sBp`EFv;27+w{V89@YwGu@u*Q;@{Zvy%35hzv8+sr4qOcI_r#Pv_Gx*<prMBT2-aQ zhFcMyc(;wHSM8G=tqflCNR@iN{F+o*$+`Qi5RJDvZRM1AV#cPEOA{yg=9gk<^+hlo z17#`lmG#S(%uz-1Iq9F~wSJjMU64`5Ll8b^w;D+tIowg!!&Z)uu0|G>q+Xq}EbJcq z?Fi{Ud>>A?ZwZV$@U9WkES~j4$1K=t0aDgIU;NoHiHx&8&%H~xkP6SK=SW=O zX1--;hIawwwtl=Q;R$PE*d^;0t&(NuP(_dm-6gX*#Bwd4^ABCl|HOA$5#$F)9Addq z>cMl6HJR@iOpyvbrNUTf+@OzCSnb>D{gD(P70!|hXPaeRnkyB~tM(qNRt#_>Sb`t*i}F;l>T#Nel9Md!@n@ z_Lo$tump#>0G+>F4pKK#VWw2L#a=4hT7*AJk_xv=g;8|r4yjPEwn!?>kqUFc@_GLm z%_HrU3U~Rb&ysH~YRPQbFBKk;3J-$w5J`oFQX%-=L*PO2uc#8K@Q74+bh=b{Oe#Ds z6_!p&zlfjyT7OC^6q`FrLJ~ly(zoa!PQ$}2em=+9s1 zbJ1|mp+^I;T(FAtX#&Y~YGdn|PMaeH9RXUL1Tgp+63E=~N5 zh{=#2`PH}f0w1gsxdEshYDi5!35qsEvt0EAY7h8phKOc&gQo!0?=I@AZ+q3JsbEC; zUnJnn4qDeV7n)Ig@1iG0~s-lnGTbUwv!l-(((Oz6H;pQbVTf4yHSs zX!bKFoIRPH&IXH~Z#l~5g5Ck5nMu)WHUxOZ{IQXx6ya>_?W{HSq z&XQFkS5Xd7P@B3+#1q{E(p`F1G#})A#Glr@Pc=`ajtj86+o~eN#KgKg*!`K>k#3 zko(9F0yUzB>gC(zoj{_r-{r0HDN1mrW3*JInKE8UG&9rgR6;Ce4Uprsk3a*M9w^9C zYpu~J{WV0h@!D98vqmTYa+0@2+8b>B5C9mCGTJ6%WB9Rr7a zuIVs4!AP&2g)a(uq;p2>EJ%J~h&7S~lz$--i{xKI5-b9qA{EFl>ey5$!<<9HWPTuCE3j#!eVY=?KhG70RmN9+R2z;?TZ%owo?>Lts_80v^!up1Tgjm!ipB$Yas zdISj4{AOxC^%YQ|5c2^w-;p_D7dD@1$=nFU0^C9H&1wK@VJEYk`GW}-TQr6Jj!9#W z*e#A{V`j2<0kx!todF7XU@@j1l=5tNBX;5bJTxzVB~UB@Zvn3ohzQ&rUJLG|?BqVxX3#h-QoO4+FKlNt7#k z3B(HAi0Hn^UOZwK8!X0&*NeeoEBA|+iZ6getJ=kwQ{rKuR!@?>5zmu>#n>F#3_z9| zv5Pw^OOxe41d5}RU6onMN9?#bUpXva0aSdpJX9``gT)dIJ%aDSp~SID%o90TIbyda zLTRVm39^*t zhNv5{OA6Fs#_84qmAqFMtve3{iKo_`)O`giWdhQp%b$ac*zwuObWq+Ju}j6B28FJF zflB*?TtV>70zt|&C3Ilj2_tq}!U>ZJ`RPDy zJxbsbt`UL(hU_(=nt%f6g>6pc0YVs=(eA!|6WNbkNS-t|`yv^$gZz}tnY-gB`8Ihf z_3T`dfKD~1CQ@~Cg}bSd)cjhi@8TRKwG@C6vH^x{JX1@Z#k{pRZxz#(nZsm^U6o(O z$*NkmMmCyO6CeMWH)4c zWZkk&*H0MBRkCSv#>ML=7s+jbzx~haWyNyLYI&2K{^-;Txl}$P-wiNiBxS!mSgCwe zzE0_-%-^pZ|4JfLW+~g1tDcAU{Zu&qRG9j7fV_xP&`*WY+>Tl8lYT02>gF-4J2q($ z1V?%T&kTP8LB`*1t^0P1roQg|Q(;Ju{8UV_ocy23{%1~V^rDWV>O^(!9X00Lt%Z$F zYN;Mp(UJFCN8>hxW^Vujh;2q<&uiMD3*R8@Yx2<@$pN?kSBy#C7G`bOp~8 z05mTa#Bcl5YayY-*{&Ql8Z}29vQG`8E_TmuyWTTxVRui8Lwm;^)$@0tNow)fRb5$L ztF-Oi=;u1~kGk5n6zAO?WA!t>O+a#BH)QSzcq=*+ydl$dq;=}^>h75%E$BIFrkW04 z>8>8E8lK%&JqTayPBfmQMg@b<0IE9t%xCFHE9Sfkg?g&jwvs_8XVi0dz~)JH_hU{s zh~*->qV-v6s8w&xT~KJf2ii$}sQ$mfpFb7BBe%9s3s)cibJwHmLI+0^^8m&-s=+;N%+A`}Eb_J3Hubb@v0Pubsl`>kJ$De?i?< zn|Aol9nd2Mso)>PpNeQb$}o(M0KPnEUV(@<&;&ehiRHF^>X&ipJvqr8UoRQSI>HIZ zzI?lN-;D6gf8=HqQ=M;9-F-(5-BJG>q^W7@9o>e(K*3JWn6iyd#0>^3>> zubZFZ-C}0KTwE_wh+tcNcJ4Atkq(uLkI-<9P=qDq(pCfuj zLOwOBDf0e=L%=qJurWd^koJ~)25Yiu$h?-<7zRNTa0O>&dm8x zqMfBXG>?E=nhIqE;D`iV*g0ZGyd7@66D}Dti=aX8+xMw2t7RR6uX)cCCpxKnSClxZ zm+c--oewf#GD84(jrNbtYf^-{k^FLtQ`-mkPSd_l%#ATW2mRGfb2ZGTrmV|qh@(l< z6ljiuLXcsuO{4j)e?fuZkB<$*Mr>bu8l688RGzxy+o-)!9$lX!Z&GLLHZRuEMr^t0 z42uYD=wR3KH=941Eel6!ZAEYXob2;>-VgFDLAjET_7~oovaWyFz1Hc=R9wfGvHI#Y zbOb)jyUOc$CoHl4x%M3o9zuBdtrxq|X1mv*FLuL=G7S)+6T?FA!lA>PV^gcaztL&N zkSXiwU_!*`xSXx|Y>NRBri~MfU1~aRsIdK)=Mj&txNomgw_X$8E@6%PEMfB?)NhlFE>ql{7M!IqG@jr}m_>LDHX;nB_1lZg{-??Mxpm^G^+y=lo%!nnc&^TKN0xWbvOYa(cy zFoi@Yg0_^op1BQdj>XJ+W-AlwWWHnmSRAcyV&PXdMMmo(Th6rl1lDA^Tf1OeQ*@*; zv?)4)^;)t$YROWI)-%z+rK+d;%IMFpVvQ$=x_?tg#`UxS)Qv(n{PfqK9r;k3YlEEn z{cguomAd_JD+l%OoSU3=bORriD2>b%RCo8*SAM_wU8WDlTe8NsYpaJs-lE&J3R-t) zL)M3AeZ!0Md5*N0#-|LTLX|7)!X7Drk~2<=t_UL|TMDL$uYD{V27PLLXAcNH=xQk|w9lmnK9+Nug7@L}^n5M{>TP9K6yT zKW1CpLfS$5EnH4@@6Rl0;g4^d-XzHi-TcbS?@K5(bt=!0a(7%|pbW(HP4<2p3%yR3 z`%8&i;F>atzl_KTDGxYO5rVo)43H5!PdmcN8Eu?#nC(MDJ%fMyG^lG;j&MS>Bih$O zTH>%cVu3d;g+@#KH{7u${onBEo-OOVX+$(Gkw%N8r@FTA$dG3XXw;Z!S)IV3+2fOI z3W?(j*Zmtoi{BVdG%F0I^B@yo3GGc|(itt5_^DRGYpe@XeQ*q$7%R?_(87cKlVeU5 zn2nt=^t&l~lJ8hE49y<~8KjiQadvS}WT01LYov|(Yu%a;XfYq-2B5qdAZ!k{8qD^ zb@%B2dDEM7KKEWj-(8Y3%zQ5ThENltHRSI#!TiFgilaGqQnp9!PLx9Cw;Cu7l;dOo zRbyGO9O7W;13t9gCvMEma_tfpOQ$%GiL!#u@I*yScFq7#wl!t z8L1c!3ml6u>5alEaN3yX=`}?y%W;YoI7KW@u@XGB3a41j`=Y~hz#DLJig=tN0jEfG zH#&Q+C|13oWdlyJ@#Ennz?1#ZjEX<`_FgL8rE+cFJX|<B_Pe(_?fb9h3zmi(aN%r)vSK4u*PlG93mf z%UVu%L%!*l2v`(vOhz6frAYb{4!s$H@{w2I`9wN|eSkP(!J_Nw^Rbq|VXiF8kADz& z%|Q)7^68!6uJZ$^u};u)>=r^0A^pi#dOTq!VHW``noX}EWPlq_S=K)sJpuZMU_&m; zDxmw5(d3mtL3`)|@&a-tkO$~@z)%9z2V@c5g8Gb1p_XNp(7`=~018WcXC0@X0Cy8P z71}$ijNVPHqmE(joh6}9V`9Eg7X#^;#PnwtF-x;aUYD2x<};wYe=+Yc^9k(IY##>O zg1rU^U)&yc6uS;6KNb4~`wN>t@g9m1YO5=3%CR=GD^dSyIr&dY|_)i8Q;P z*TlmKUM9`)5{&TjmjX36OAstL1;jk4MX+D+2B@wK!}PM3h<4DIP=FPk2TXv2zVss^ z3`cZT^fHO@N_18Pi@|b%j$)lC6sVw$VqbB-2&mu&aklsg5Fxl9;#*=n*~_H)G}&0t z9?p1~6uJvEik}0A!XC>o$7O>+EwGVy$pYkHv4tz;E^;AIiz?;G^8C9%E$)*y%Eu{R zCN05Hl)vTCKry!{1C=M0V6kwya<8%n9Ab^pVARU#nwLoti!~E8d>}}Xhd~qQ6`-PC zYEEnN5ul>&b)PgLx|c~Yxb-@3-2tGMUeImRb?Cri%Z7C~b(4{oNz3OU7*m7`)QSQm z9H|C^6#Ec4iVOg?(hB<;$@jy)Oj@-9>xA6_#A=)by9s+6DE52oMXWgiEEY#5{KQ5Q zUM6ui6EJi_DNx+&gxv%!5Ttk`vXbCRewmc8kUXB8&jTv)5P22(G7xKU&&gHfKR~S| zQa_S|s9>>mYpI^pebkpp>(5g$Td8e8ZTL!6P$x3MVjJf$O_*^&ZOUUVVdkF!D(PQl z3FvWtnUsvfv;SlIuwN$ema!e!+u2~T6ft`PyA>Sbzhz_U*=D?#NvZCFm|7iDorKNJC^6R5L2bGxR z$_C|}S9?2^<;ow*yjP@sQ#9|CG|j)S_Qz{xYVvn!@ShIUXfia9HOoF7#OXEvXl!)i zPa=OETDMZic>AePpj)7;)VcpDx}(Ds>H2i(e-2q7&vX>z+8z>=$G)_Nm3u6zpv5VJvE@-7zr9hJA@mwBzGp0_Gvsi6EO) z8ce_u))R*8NGJ9amJ%)yX1Ski2eAMAVM303*(CBC!aVXl_ft3yc?RgZ$Ica>1?~3_ z$&8q}-c#xQl*M#Rjdz=k zfbx3=XSWBa$%4=xnTn>-53x%#5n1$98a+k*76CQcAwy^{H{j#$Q%?o;EIA$AObwU% zTheU3=m?1I|AzJ>&uK=&zoEUcjTaq#CZs!1K#3!*qW=_7`U<=!7~De<(3(tt2nYm31*Dh7E%{`)UD&Uw`WfML=N|cu4~+>CjBe z0t&j7@`M5xMR;)C)<)g*^x(q#BaB-qsE3rAsf?=0p-T(AFg`TYR@7?FIxjHh-CSTC=>tA`0VRNL$uS~vErMVYHzI`}c%_~n z{3ooyYjg_g+>&i4y-R>*JYkeXg%Hh7Jzo#2V1keNMW4I?NU;1=sJteBabi zqa3507oL|$1qB{!jPu&x|7q~vK!MXh?M+}9gnBv@klrvC!YU z(A&8%XwIRG0M|ow??OMw)4wn}Ag0hOsL*?Lq0iYAQ$N9>-wapuy2TV-hx$;)|xmh@hVZ_t=Tv#|cH z_XHH}R{>=icI~?}|2LE9ap9kn^Q5HW1o>Qw!1Kc;A5#oJICygocYfO8yOcJH(i;Q5 zoPnE*?B0Ms&5Ppti%{ikR+w`z*qjvmGrGjQ`2zyV`rwSk-HBkHDi3LigJ`tA^jS#R zk~20mnppwX(36BpIU5{&%Q_|KD)W&CR^W-^yhy}jc~Hpai6q~Q?!;w}gOyFnn_-F? z?-u^Blqu2((nL@MWSrMe!HNJ8=)mrl-7QlYu;u=a7u>*{+k$$HtLBVvXsI3}OlF;a z*O9|L^QGg^817lPcPgWLT<;5RjpO8A-_&!iy?jQkPwxxQfI3F+D;jWeX7(ntDk0g* z-Y*UP1r`EIA~9(92l+ekpOXSgp45M_mbTl&nIorMeixE)uXl#(v(cY|d%fwRgPi$)}KMSsz*uc0dOYGmEF%|!!Ryxy5pK!>K%pUL`Uk~u*(!hkEvS!c@6QU#u3 z$&18ul~J>wW=vP4B+JW_8N!*~sK=GG#q>i+74lm)PToP8=p+~V$-{2kYf6xBk@ACg zS3O0f=UzXUb2hL+AX^{vb28zDoPwLhx=VfTJ&QHz4Rx4m$`np!x-&;PP8rOdUMfQ) z$)?L7w}~7w5CZcZXtA`SZhVmbbcp=k6AGY*c)0D>a>S|h77k`xhkoS6h z>&MDr&$S^aV$)i`4juMkgZvk_-t^5l^!9qwP8)%XAV9EC5WY&l6BMOYT91hM#KRfz zm@}dmQD}w*rXpyCW|M|0y1|SWWr%i(j*EonM5BD{A(64z_JrSpC5M7N3O#}f zS;YY!h0)&g4h5|)^z%OCr5Y#+4lQJOaXn)SgNqobm_ncFhmypCqhXW>%!hjT{bHnI zQyAsG_$6phM8x0mG6$JY?T7)$*WM&wC?jPQezXxT5uX8`6ITP$x61&!@L#{lg9lTW zASY>`geS&KHN%OkbLq0PE@)yb?P~R788k{H7%wlup204XKfoHLG>ykkueTmQ1#zh0 z*%m<*tMY)bH>l}dY# zH-HTVwDo^SR|as%fC)%$(^S;6^A4kkp~Z^+J3?E$@)>Y8$uVj(8ovWH{taHD#pTjh zmm3=YHk8<-GmjYO95T*0i&N}7KJ4TZEUq6*eH4#ERSFjcIfc{vqdiwwdH`O3MZq3# zYP~3HeJwZ-8QHxz;G3knbSXFy`_xOH#=rBNCg>$QQt1zb2WU!zc z1#11hgy2AKy(G#IrW+k-1tEtIbx*F3c7N}_A zBY{Ss7obHpyFCoVFiX`yY!M~i#Dt+#9uw~OC^f*fQjn=Eq&!7WP`FUtU-Ep!|NCD&z2Ss*eb zGX_-^s6csCS*^S*=gaftI|w6ksDkhS>@lAa`UqCaID(%N$|nSola%Yo4+;B073;2Y zQ) zHBU9$s0XMPI)aX(qXmLu+**JkyTdHg&9Dq&H1!)Na1%KeaKF~*(xaN0IJ%?4u+;r@#b5zepIr-DVUu`{Sqnpg?qub9$ zpWz%?u^WcDPB4BPRz7CHxS8}Z@L%pCzA!ATnY4Aei`{Gj*3?E24bkB_=zpSbqG^KN z>*g;snI_ClyclzX$8~y^T)eSK>yGJXjxhVRV{L#HQ~-M+sH?Gg>>PG6TN*L0ArIS6 zoPDz%L>ZmzcWmef=zO;0{U5R`lLu)4stzqUoUBUP%NyjK=MlrgnzXYi&7`J&6ZC2) z7+MZ0`b{oeC(Ez)OmF71Ilu1-#7jrn#KWG=)bc2>Wm-~US8?A#IGTA-YLlaEhS=mrvK-g!WFikg z6@@olBYsieaS>7#^=mI`4~tD(rwxCBKV972t?N9C8oj&JFhfuRTHk;-*yIr`F#(I?ypi8d__sL}fUE z>eg!O@Hnsqeh%9Z^ept%J6~H5)5`>yV{5*=!8uDe2nS_~NuxcAzYIN!J0uE_kB8CI zl&GGRsgJAT6p>F2J6>iA*zrDx7q_7!HMqpruZE)V9}l5E4R$tEw_}J0jz?LKbNoCQ zg-`daYFn1>+27`o1CRYQXdH!)vZ4PPs=DmDbj=VZ9^Q(&WK{+BIi^NcLH>786U=_y z1RGgjVzwHfl85h%P3(@sC-)qt|2T=fKOW6hSa{|9nRav_yk&Ps#$IH!?NFYB#P*Dq zscb=+s{T#;1KZG=Tr{bC)vb6b)AGzQIGABN@ZKoU2Q~^0vpx()_+ zm=V_!*J8tXQU9Vo7d5%XXmShJer@RZT;$oDT;p?pFaxlBz=&=YY!u9RpYuKkvSIvc z`PGt(l1jPu^>96G*=#>~r_uEazha|L-PiOT*YuwnF4a$1^Uu)xKVR0RSJC0=-JsRb zS+fnILqV@l9?&bwE0jCr^9HmYMteD>c)x;z-$3qTJu(7bK>z7x}s`tQOZOM zC)13rS{W!ued@1I_6<)k8Y+i|-dGx_;*wLJFT{^)VF;|>i zo@4cvh8&Mb=(H>EzEee}e0no!q8Gz&UHl+%+$$&wVkUVT(I1Lmi+6*v1ywP}Q$_8j zPDg*3upt8-TD=9Df1=8o<-^B#rq8{7vT`DH>slVC)0Le#~^laLpwF#Qu2~5&-P~_U<+czKJplZkvCOUFn!}-pNB$ z=b}Bc@@y#VsJaEikOit84WE*v4HC2z8)trC2=wV}MeyhS0sYgM7 z!1Ttvt#cez6zJupF-y-oO^BLQAHCf)tM zjeUSEW?MmS{|u=m#Wo4&?Qf8bZjf9(OUMcAiY@wc^=<5~UiLSTF1z>LiyS^;hNy$y z+gJn@ouPhFM@*QV{8Jy-0?h|bWE*+eNtMQ~o;!+ceT1*;kEa;?n#0dK#?sF_tz~Wv z!@aJjv0jS?L`YnVg?OSEaswud;JzqM6W`4~Q>^!Z{`g+6y?VCup-S8>{&IrDg5p|U z-xxYzOYxD>>zY}g-Uul+h13Fpfnq9=jSC4utvndwY>%4%`2za(2bm`m3R>8=CYCu) zE(koJz5Cx-CGTr;k1z+6#4`9*Eo+Ew|74L^LRfVjb5aG z9C6_u>Tv|uat;UrT2aR3*M{yDp5hkJuQV==&cis@b-}2J$XYt8npu42F&_n*5V+7H zLlZ*M81t8wR`_149k)*<_V~zu)%B>@i%t|)BkNxLLwN++4-f-2p<~$q_#FNRXGx^G zI(Btt5}8nW))oKq`Y`k5I;PRbmSbuvv^&saC7EHM0g)`DiMqTM1cE$7q~!5Nt&4S>i&4R<+^dJoQjQOG3;2ZUcD5DwPlOVQA$| ze&-&BvEEpJr6Eb5q-UJs`dI~KH;l~?4_+F2=Co#9{QHe9<-u^d|+!qdb@@b5XGS#&j;ME3iqR55U(g~wv|4?o{$Bkmd~yc|IyO%lFrg-+S`(8C z!`TgYH7j-_Q1(19)p1e&-!g|m4Y_)W4^U?}Zsga*Rr^FfC34R}No8H>o66lcm8aA^w@-^!5swqowZv4^&v3J{ZcqIv z^zA<#&13yfojLN?>}S|#F=E6XzRw{fBdg_xQ1~)Zeh+zp^dl;HOx}cg)Nf=o|F-gc zu^nv_bdaO!%&baRj4)jPXMJ-omlKk(*Yw~0f>S9o?XJ^4|4qvEprF8%Ldm7c_{lpF zEIdghoFVE(2jv{7UsS-)T`oe0ZV~~)$P{J>A%r_~wWaHQ&H}HuJK?uGQEzwNM8n4S zIlt|%G?Wm|Sk_rzw8YfLT_Zdq#0BN_PE9(B5YlnzrtMuW4!`XY57!y|7*7W|^o2f1M<$kXC3xR5SRalbT+Mu30mS7MNASqV1 zXrg+n(xIln1?z%xni_9ZR+OCE+H`Sc&9Oz!#M0x7)z!HPBNy4>d(z$NWF5#&X5O@4 zub1pUXX)@{`O2PE>wlLg*J$k{UJ>Jai0j*l$u&PCK+kA$R(YbDm|kJVO;-{vIHfPs z+KH)XXtSnmBF~LCm&fFBc;#ul0^U(xHSgNm`5VH0q28)zoX!NcR@hUjJ<{@o4mt9Z zl$dOfj2VqHGHy#eTA<$@MZ>?|p+8)`?b;~V`Z(uz5^Fna=!YeZ_5rzV(V*XM2dqOz zS@~ce6LR7z3``yqzdUtL`g(`DXhtgvU8?<$8*1AffVX|)c3))MJ!!QiCZ?#(}@q!rS|k;fIJ4dIFU4oChB;g6^5S(86F@*Oig zexN_(nN5Cgwjpx%Dwr{Q&LC5P`$2K)yF{%MSUBOR$fMVP{@Wd>InekAFi{iJc zR2%ha%~#&nM>+(7O0{zMczsR1Jw6cMAaQLBy`l#l;o+it*7kUOP>y*}P9Pp%v?2Tr zUJj$;Xm=~)>P_X7`kKHT1zuiRl`OemQ)B&pUs_b=FjtVbiF1FQjUw~gGM6W2<&Q5x z^3 zuz~I!OY@2a#vqj64K+f#e=N=K1TDlbg|WB#LhuP%u=CxmlzG5yQC_*isMy=Kdn-lw z2DNYirdrP5CTU{j$x39MhE10-X zbv`5?l4Gi6cvMrwR5fv`da>sU^$Kv7ftgWLQfbdP&p21$y{Y^7>7F5{qA;a5k7$o* zEn0wk;S-i~#Ud983K%Q4Md1b)YNFQokf25VQIUY^|04?Ziv+DN#BjHu?&aLe;TA1B z*tQBU0+dtt1Y5RtTEwh`r;Nz?2@^jCKcsu8^w$S(==aw{G06#msa2izo%MF)H(uJQ zZ0+(zB?)~TXhlWB3RJ8t;cP39HwW>9cvONV|4};lYBFxo zYwBOA;@+p(<6Bf;(*p5O2Ase5ljY`d`E%IX^^*0HxnPwouK81etD;YSWOrB=Bj2TM z8#8}u+xC_D9xK$&H(gq?SkR8m`PINwF)x2P2@)3OOIW~Eu`K_H7Rs&3cebpBp<38Q za&E9z-^rR(FcC~mg+EU9&hdh9( z;*7&{IbP6#fWr$o(7}+yItHoP`n?N()wHP{UD{*%`NSX-)u3ir^IbIvi^b-ZP)t#_ zPm*?xctcmV_`vaq5{zpjSIqAI{#CqRd`CAI5?(BhmxZ8Xisrp}CH@kqfT%KzY_Ew} z_PeJE_~*tx6TX$z_Ke7I@*U6IAC>VI?+J&ae1AF$%Ps!D;M%Tb$%Xax2`Tl4` z&M$$jCn;wr`92}abuJ0YbR~2q>HzS>s#oHwFGqAJ-vS$NAX_6wG4Hr)RRm-Jz3m65Z#2sb5Wj6Vs$!#JKDbn;i}o(QQkYQdJ{l!LI&bHu6iqXl*;LI(W%OeU_{KGk3`kii6tl2Z*9 z1Au}WHYZiX%;lG;=E%(1AsNnWe#v_xogK-J%t!+I%Wifl8xxmt3FzNSww9fg@rw<9 z9rcsx%FD`N@c1QTh^u%!-mZ*2K$}(ZF7q&lGgLs2`^fvllVsQm?D-{lPeG8NhvvOP zkaQexwNf^Z$q+*UdASEduaq9Thifwir`K8}(YG#ndgo z^-E?UC&*WxVa$)goAoHR`n(Qx{Q-U<}~Xn7T-VkAN*Urn)b;9ur%ITh4*Pk0SqldmnbX zGALKjm=Wd;IdB>Zcrl0OQ8m5zVkOUtK8r97Azye-%Q{ccKA(I zMlK|ChiEIZlf!JMn)h~lT;@f8Guk_ZvBuRpJ`UzP$5!t9G$Gw*{Y;NyTXfMGY%>-y zy-Rpb5bCio7!hy+vjbt|#i*0=QIkaf=z%`}=&qtAsscb6$wz&ffUk8hWj-f=oXIwy zp`Njz=ngPXyf)6PpE^RN;h2UjV+eB@bHl`J9TvR$R)RSb1eb zb~=^I-@``^R|(T z$-vB=$r0BN0Ve5_t~l_rwB{q`4{8TXDJN$ip0tHlRa!S}a_-LlLZPrc4QV|LQkfv) zMKmh2FNRd+=mfQGWA8&3C^oAxlFoSuhpkIm_LG<#aZ5)Oq6@My0pKg_xkNt7Bb}KC z&&+cMz4k#6tl`jM0cf=!7Y?OfNnyuBiBQ6gl+@M>qd-zKkFk_(7y_%J%k^^1C}2tA1RFyyW!n1>UHW`vi}$P;nlWEQ?FnM zC4{XSZzV^hQ_?8|me-4*>qU(bx8N6>XXebz8R0hPK+QSAib}W=j%+Bym*Hi(K9@dC zSi?ZS|HCtKfwSSl3PW~t+l7=)`n_;p;PQPh+#jlT_X=O6X2hzzPvYq3AkSD8LwO-M zsm;4aTS#Bk=B2#gRiL6T(H43`*^Y22#r5Tut~}Dylw&!oEWFi!sifH@4@588kL8S| zyyRF>X--r>Y8Z7%Vr0WQYIL46ppyEt(h~gZK2Sq17E`0sjuM~Uz}7D8ZQ=KBhli!R zjgWmO)ok&W`!wW;lp&bA=<=iRBmBt5f8f(w=C@u*|0g{<;zmmH)s)2R7l>}E1vl!G zUdJU|PPxc8yORnDVWmI|X8(*ujz1hkKBAQQqUC#PmUVSO(A?wsnC+W{=<9mBUg}vM z$ISV-5z0mg&zLftPT`oojH*LppU< z*^;-^knAG|(Bbn_L}I(}$csBSF6*pyKwLiRHIVDT7vuLyQLx5p^S904Vz(Y(EFgsY z1h$*k^KaHCUrH$nyppo%N=j;ys;&Ixja(0II3(;}tL?e)L_(;%u9vW2cyB#w8=R4q z5(h%p%PGe?>RoKTtmDiQ36$|dW6fIaE9&?h>3~hMKCl*7TUjHceOp>#w`Ba{2{wt) zury1Mv~)-k*@#HRiP+vxjsvvQ2GRN3DJ$!@mf_$ot{D;`ZGO(czQNtSlr z!io(oKRIJd$roRp^r0xo5LA4=)rWH0af|m+&oc$y&Vy$Ud5>_zs>R?}YihkC8_qR* zABxSbz2hy*t!wuVVnKV(cX==Klzs9x>9*>$Fq`rUd%pG8OVoq$Q#wZyyT%7UK{+fL zmW~ge_TyL1mr!P8<9McPSZu-W;OTc?zP)pp`4LFBzWBkXSDCLp1C|hJPi*Ol*6(++ z$LW@t3$%Gn&uFhHt9r|GSW9PpjgOkQaW%C4O?=d5ee%+>=P`Q1z;*qci?4P;hNScZ z%?~z&UUOZ)kF{CvRbQzcNtE>>Q^HnQW}Zl<3$BG%U1GWS-|luDmfmlD_BQfT3g`NT zv0sTxjVB}S2o*qxCMF=85#jC;6O&3Lro;*{1kezCyy@Ac`e5=>66ftLyNX0ydCor8 zHc9z@<9`NU{CG`)(7fM&VoggEe-#A6W$J0^!dJUyI{225_QYamllk_;i0Xe;If39X z;m!OXZxRY@nvx1S6AI28Da&dsO>A`7cPY9#w}kox1tWB`rc9U4Hqoh#LK{gtrsI$UHLgdy_>anNK*C04)R~nUprcYr%j3C9)Pdi@y7d z7Kqknf-+t|5k326l1LyLHF~=%f&d{Te*@zs>bGc|m?-uXLqXyg@j7u9hyhN4iN~8_ zXu9mJ_|&6U;z@NK;yJRsOGHF`WOJN05Z+R2(zL^k1yzDRK9{u~8B>g>uxGNDDKR#3 zjv&f?N#e}$J?G79nxMPb=h$cRKKZDvbntj+D?fseK-f$;qbmi|rZ)&iDu8yfd;Ip% zd))F+NdOh9L7eV+@FU>?&YWB2eT;QyTsIk_enRb##h zjh5hiy4Px$+HXDcv+Z3LxJO=7#bvxUWQ=EGaNr(!mxb;h@8ZxGDk+<@tnW()=zlZN zN&fb~=~A0l&eYfb+r!E3}D5cQYx``C@-T4F=9wwX4gB~&GAZDf9nT0SK zgEwno&&Vt@$i?8kek}mbmmwJLZ146$+(jjnShb5tB@J`?a7% z*wyt9Co655GimIQCyDagD^zkaY~4_&eEqv8uZDwv<8C9}{}mlGV7~umlB3Lj|G!MK zJvF$0OQuI3HL^StPp=}rve;G7wD7oC{2%=h5y58n~&U^ntRFnrlJi3$% zrE$_Y)~N(M0k3SMa3~yO&HXer!zwtN|EKPjm;CJZA;QEN)R=*yS>N1yU9uu6`gu<%ak_Q7?QhTibGE|Z(y95) zJtGd)TV*&xun=;&C<%glF9jP`I*qOXgp(ZTk2JahaX9&;rdUvY?q-?(brtFOz_jw` zs)0)`S^D=td#Smarp~>2%DDP^vbtRbiqxIP)v5{5_IsiFdZyjizipYrTNQhya}Hqa z>zj9GGIj+bZ(pUmWW7rNvZ1=yJ8yXy8YW4QY?SPj9Nu13*{qa+8@o4-dM5c0yl5~J zA(KW)fnG@gQtqCKgvlpJ$)pJ~u<@n&NBxTtrRB^i83%$bg*|l>BhO`fUY|VMbGcQi z(68$LAOn4$ikKa5Dl+OQe)VYIxX+q0qQQL28tQmLxFITNFlf-P*d$axwst$G$cVdB7$>JLu5 zlBDg(1YW&U`Xx8XBfjv@-|=VBY-ZuTdM}#QGSdl}<=R>;@)6muf6=36Gq!t>^!&En z_3yBMG4`CrgV2Ib_cy3n4ievodgsmOjm#4^X*F8hBxLdt38p3KX6jxSG^GDI2xP9{laTEE>zXNczCRb{TlS0I~0iNH(sDukhtx%TopaTmw6HcF4s?Wu8gyWx_Sf^{%j6L3~)5mz;a5`O3<5k&n&pGjOjM z*ck+28?(u5I@_K7Ba98}#B7G`|83YQVIN~(WZ!0k{{ZR#D_(FTxZnnN3->j5{mQdZ zDX^tS$_4tD{49SIW_^ds=lU(z1hpQm|D zvvKJljSwlDvmv_%RRyaeh3ixxTUb?BA|z-p3g49#fBP*1XIB`?2$J_lIEuaT?`3wo zseWazNXh$OUXo8w6(5p<^^%WAqdN+>?eE(ge>}g41e{5MB{a>_w`L~1Nf%3>^}UVi z-QV|OM}~B~mjMog?KmU5awT?o=-%h-sjz4V=s2Hi}ZY+n60D6U4i{a84@Z{XM^ut3zw~Ug(kKU0kb?kq;^jZw= z($i2ch75yzwvlamGbUO4s-SfWip*M!)5Beo-yOm^-sr42h2GLz+@j}r16gr%?v1;( zY1)pZ)SjNrHxY1HbOylv`*{sC+nBUjy;~hA`~^iC@c0zx4SfvZl?%Y@tiZud_y%vD(kK zRU_Bo@7j-gxPg)S@4xfs6JPb#%%=ZhvG$aAzx9(Y=#Us9f`<>cw4b)iKj9qyJu~os zCg^!bkt?&7!OO4@5!t|V3?wN=MU$9YlpBX;BUz{~hg9FU6v6y{hrQzBgv7vwnH8Q;?^A@C$o0yh+{7 zNvl#n!;bWu7A;gnavuk{BOU2>q9XTWHUgL7b{k+1tdH4*IZ>lM4g>qz9v5o#GHbv* zW@94@vi1gHwuQjcj>tM@V=D_XXNq8-x}cHz()TIv}u>*B3k;= ztVO~AVU;Xh*tQSp34ZZhc1Yp%YP2E@4Z_wR+4->bEj%EJlAq!EbthFnu1<8W)=cQ> zaH?ns3BUDvQf&3WfjYF}+<^DXUTnaPz3nlXprL~vx9EAL#WF-tyct0rc6#UBq{#A{by3S=RV%(TJVo}Z# zIKA7RU&JUJ8qM>+tN?e9N75G|&lLj-oXYeXmk!p>Tu^(7+PNdR_lyHu#k=t9d0{&C z@RE$7bHJ*mpy(Rd`HVSEoraM6eu=eMdHJ*aPnw_Z`TsWhE>46o0sALG)a za)xsM^;~4YBl6vsg9nuM=x`#9343Z$qmdqVn@Q7P`iJ7!7)eK4yS%4#FPf(n4b@Cp zb|aEL9wvP#OUF`J4h51#K?_DKs~-qK}Y<2nPG%{P;< zO9kvQ9%GL=@z+r!F{Fw7K5Mvlx~E`Wu;+$?S^ zrUhE^_F&-^GbfQft2GSMVEo?Bz*TeYYVNO_<55H@q*64nhsa>fy`HoY%i?>q9@-F% zqR*JXn8R4eSh9G@3dY^zV6}V-N5m**R5H#pZZV!P21c@>M7CZ}B~1QdC82PVfR2=5 z>_S(|-MB#z`jpA7zwuHxOc3&b;{9d!c7^XD`A#S=_0s z;=2f2`BB1tmSgfk(V#asAHyGAGwiX=k0@T{;|_(=E;&Z%XGPRX4x=s^*=Ps??u zh%ELYClC(_Fwb$8f(pdy1mbiKXHy7V4uUCzIi5$0mPy_ku9n}?j+eg$yCoHWR?E*y znkA1U?U{peEPAgn&u(VB zNm`Dc*tlx$tv%y3!MK9x)B>x^vXOqg0U1tFZmO82a8~#!0-U^^dIEsitBvvmds7l; z{2G#5Z^au^-(TOZ1{VzW~A*o)M_eZ z{9RcA+XMUlxGO*0c=3thb+GN+DjKT!-SpzQn`O&r#<*vLwR&qvskWnD7&H`3Hdygc z^!M|9y#O8#UKo$hIyPfLNF1hVo;B(PwF7+Yvwp~Yp#N&Jp0{RMLsTDPT`>3B(JhUe z)jfI{Jg1(~@#h|1?VW$yP}=)p^wr+&kz3AYg>Yhh0`MG!*l)Z=Cp2M8v|`>wvI>kGco&}Vsnrj#;M z$}zducdg=S-e{L>^CiNY?Zr%IDxgC)WYz!6~1u$T@V^A=`-q zEb@TuAk}5!z>05)Jc1eF%L8Bg=-jwbFA{kiv%xh33}ih}b_6$E)MjH%T=-i}XQIPd zd|109Q$lqWelU{EO?o%lCp&FpPv~aIASxHy-q5#excb6`Ar8J#pbX5lypLaltU)*? z?yJPtDmKbD%E57Z`;Cr<*qFMSx*GLR0tuHuGLETQE8iiFyuYGjkT)LqHHZ}z{`bUo z4O=VVF9uf5YLhjj*PLS39%h0q7=SOt-Ub{@<@q;$%@k@ zGfYWQw=b5=G$pNUE@>JBT%-FXmZqd=ZOPUSX?y>k{Mn|Yn4cx_gGyj{bS~bMq^7E= zR!ba$=n7^=j3|@0f=+*7+dGMVx1vqHV2&y28gdPxnUYrXD&0(~)}&U_)B7$C+M1G5 za<^C7{nM%Jcq~5;jvjT;@Am9vI?g#azvf6tYwK2ZGysvXuC4~;?5Z1;Kmxh@>&#dO=?Cd6I)MHSgNCLY_Whuaj+`gK zPdO$VhPFMa3t?@4Q@4i+$vM9V2k53aGi2O-6hRSN<{q$XYSS}T;hd)9R4{qBL(_0N zxHJLpMp_a+-M1Ei9@SmpT!)lC;MtHI&rv&>Cc`pj z9E}3u9W-%kOO}jQLu;gMYhf0H5&J1ahPXAb*oraYc?cs$7N;}v7^QGAvG^hb+-5w3 zGOHMaB*U3(_-*DE|62}(Qc_$92`!)o${+EM*dxU0Z7nB@!Bnm_m%$aco-ZER$+mJ~ z(8l5s7sNKW*j_xq1vtJbU)!F-paX|Qw@Vb!LzHwd!Ll@oL{#~7{b1wEPe1S{cs<-E5q6B$#gXr1d zT+u6xZhq@787E;?=^vFuH-EVfN3Pjb@1bP=fkRoc6;*UubTjUckhoHoRJ8%>QG4Lv z^|~s371Tyg;Ouo?)hI=DGie-EVW)UlZ|AGf2~!j-QJZ~{qC!!p5VbixQsCbyenaIr zU1g(UsYGp5r+C$R)efkf|5066iQA!a`K&TfPgLJ*TS#1}UZP&99@o7nN4-Z~rDlb7 zFTSOIqW-8p)a^>p;;C9Y?aOYrrP@U8CaqOJ!Z@r|XdAR2`?;1Qc3dKY&Oo!t(pKl8 zTM8A6xK=0DmFet;-7o3x=(=^RO~W1lGr=sdhG9={3?GiI!SKdjyRmYt7GoPzy*sft z*iWp?*k>AH0YQusx{ZBf30Z_~1Ph1~JVm%lxJOuH?mtM-Bb$*~wdPCy!-@Yi4-k^^ zQu0wUY8}`@9vSu7W=&-q)5tVB?Vfc|C~Xx@yn$xs$~j1@rm1KvT!X<2+85d=#!=VY zocRnlMi7Ig-V~a)_@KkXuW5Y)3-ceAGcNYxEyP5L6vDzYJ|r!g+SB2KRo*!&zc}e) zURn$?mRg##g#;`5UW3KMbi*c-X3``{(MKChYRK{kV)wh?s2)@0NN6(rGcnU=+9*~i zlSxU=DRUX|tuAvpxZk;O@HEalqms%r%wx-U3M*ki0jAdjQT^8yt3p;pTz)~qihr`#U@r!Re9Am&)GbL zQsO=AP;zp1T;j1x#lFp^%~gjpKQ&fqESqnf7*qu5)fQC|Rr{UBd0(7A%Kh&Phb1FT z0U+U1n-Y@4j@GAwq{~N}V!x(AroO5^DJa=P!j`j37nkgJUcUO~pQ6g5a>xsVxUi~p zi}tH8J6||byX;k=>*=c8cgGz@KR%B@Z%ZNTTY9;Cd(C?KC@~YhWx)2D?KPH#yQ=!n zxkx6Q3xTW{{(8v^&Fq#h+VZM#pKO}JpGQSi+gAGN`p?ydeb5S5QTTLCPEoQZC&g|` zj;ikyYQUVmt@Y)H3)?(3IrbelL3=})i!amQ>-Lkgc~5(NnO}w-kk<6QnWrXgHpZHh zCyyBZ+3TR^*QCg_+lkk(pIs1C4jT#nbwpJaetBB@bFN<^qgVE=cO zE$b1awU4DlPvArI(+A(iGT}dCzwtw=oI_<@3$v2rE?)e-`NOe+;>7u1Pko2&^@rC| zCw%(<3L>K{8>th{Z}7Waesq3~FB7%DSmV=|R?B*lHf)#w%X!#0I`6-U{||xL^By3n z>tJeSXp;?cucj;=_8E-s^SW{)vrTDBggv`Pb(?)wsqEekf3*Jv+e$`_ z;Mr$oe*i9J6#B+?TS)4=WNV#n!=enh+_bUxyJEvEqgem2c}};#Y18R2w%#S(hOV-) z2U+fA6x%yC?m#e+gj40rDLj#y{;U1^WxYyC~`NXGYiw+E}N>(BSz(t4j1?{)phuoUJ_ zQdlbACgjVy{DxMu1;uyVPu7RUJIsi0Q!+2rXV%oeuV|p)Q4fqb7f$py-dNsoSN&W) zpvGx;pQLChwptJE(#NGIs$Ybj)iu8XRGyIYUz3+HB!SSe9(ODZOTZ4M?H}BqYz8l7 zq{!vVJdQ;effJLE(!tVij6ZR_-s9hV+v>6VSS#Z-_V>rnk?xq!F5}^|EiaB#`L-B= zw{Q@^O=bkJ;eW426VW_mY_=Yimp}T*`nfnjO{;;8tEzRL1mwD~eG3J8e-c!NR9-J` zER}a`CXTfgc>|w4h&y-xH^JBh!R^=Vf?ojmd7wM8Cx0q7^fE5Y=nN9l4!@Ca=VS~)~kcO zipSQoI&3e}y>8lEq}x^6DsRy}B+>L5dr7pd(IXqWK{*qi#(b!}r%?ufLSx=IvCmzl z@>Z}@**zk5F}sp|o_%Xc^+`-(wcsG*IeWl!cvU%L;Bb=cZu62R0v8LiJ($0r*ft6a z6c5P9+k?5BT-$KYQIDk|D}#7}LAWqZTpBl*Tf#jCD;Kx9;2HN57w}DzDLK&{bCaVV z07?!m-HUgwj7XY;BCssOlL+t|UE3$ui4W3!CGG=w8F7 zn5A_1Y60&qN3WCT82;$}>iepRMeG+KEgmlWY%93~V5B__bBI(zD?vA6Ud3#P(R{^Y| zyef9>!>X4zdaE|ae5wM@#h0t1@Bfy6Z=N-{t9%v}_R5L;(G#}cZ~Q(fI&Nfo?&_%6 zEJM|)MeG_!s|z+BcWgW#+d4|3-_wom)4gn!4mWM))p(y>QxiHwcdhX*Gk9rLGLhI8l_D z7kz3OCoL#wZFF$li6Z{9A@GO<8GK8F<3L!}E0a`@a*DDjF*>L(HZPhI92C#tgP8GP zbx=?ghY}ssN$Q0VzL=o3KZpjFlV|c)EH857a3?sIwvCy8er$B-6wN&d;ropsZ(raL z^XN1cWbi$1OvZ+*pj+ayzG^LomG#~^2mE*e9Z%~{4g2x%?{LkN`oTDLS>GJ>!q%U+ zL(~iF*?pjh5u0_&ZCT$wr z8s8_n!;-fs4ZQ1pQDfYtB-(Oj4X)y~^qLe^R?5B7cTCv#a4&E29*c+at_Jgp6jO4S z@(kk9F{4X4)9+!OWm(DWth(NGt1e~Lyw?w{yOfbs+IV|~molxQCvI(*QZ4#I1b_lUz`8DFjdVkoa^szx z%35ica&woGU$do4DGaSax|BIx%G@qx-Wah_taNLaa@$JgQu_@05qj9JE@feta(9QchbEbdb7(SI0L+NCV(QtnO6+~1|-9I$-VmBURx(xsHqOAz^#l3pIgz?gT2 z;p}_a886*dX3?fY%4TR^coiCC)qig`+p_G9jgTccqeJw-s*E;aKw~cts|x6tETl-l z#mxp;9}LFqCiz3R)}1e#!5GOY$vTPty3WpE$kn?h0s8B5oA*O@v%XA!T~%|B1Pn?1 zp^WaF4e8CrPyus;RGCQjc;s>B56IO6(-f`+?_T`JK6Bgg;v8^?0OvCb{dG0WHptZ* zQ~=ikd4s7+t8iAi7R(x2p#mfPGq)WD4Hb~9*8&$oOYb`f)-zVS7Bn+$)W20A6iN?d zy_%&y2-TNPkgcAgeXZ7C$3YCV?drK&7_^hQL_1NNrgbfN%-o{|E43G(JoR<2)=`Jk zwP`>vldAiu_0+i*lu;9Pb~>;N$^=BA+oXE{RX-DagJ8WWm}|ix(-p&GJPZa+BZ)CK zOoF=>{AAu4$%pHpd}yG?QV9zQFet(aCs+^!1lIxsPC4Z2fhH(NbKXFP>lm_YfiVXx zApax;LrLOfkx}w~G7M_QxeCF0J#cX{M~?>XL5{p@!4;|>&5V``6`*pY5Uh6&N=r@` zD?b;`A~qNW&6=$I zTsgVy09fL*@}n?0t?UwZKa{q{+%C45&Rtk&7s@4bH$Y)eJP1qJDySS@z)9gzeAdE3 z$GQA3+yMTu7ei1Z-URdaS0fP0OLP2%;3(0yjgbNE7dJ2g`ags1wuxOWXnNSJE zV&Vfx*82{X>l8_!&`pBN7P#>w^CkI`Y=J00Q35te9!T0Ws(ghcP&P%@rlB$&Wr!?7 zmMvfjWIi&n94hywe_aT&1s=pP3XP1W$QF18E6f$^6s&B4*M3OWy9SrMdldN73Vl_! zz-P8S?=|54pkQPkOjB}8}iICTP40R`$X^%*q`7T5vF zdSBrZdy*FaQoUH4EePUjt+aViP&vmSS?@Mf!Ts>)B_`>z1tIo2OuHP4P-3>uODBUW z>;?quz1G2COGjf5b=Fw6U|A4`pNeHdwR|rG>s^6@8vY!T^>Bo2L4+l24G{Z66`4$M zA{0Tff_N5^^&UYL^$UXarjuc?l}z$jay&U(z}-&9kJt`m3!>E!toIoTDsKX{z+kI3GCUZE;Zj091HY5;3aUgy z_I<`YHVl>&$ezqz3)SjU2-Xu{f@;k(_Hj1gW($&uGr6DG-cY5i<~ne9b78R58t!IT z7S9$yiXOg^JB^<$NMrDg__0t>)3@?D{8Lb^ZG&Jv@gP(gra~>>S$IQ`NsJWE5(*-V*+wx7+-6}^l ztG;b(xY|N3P#bn{D_7&!sGHP*-P_+lu-+JLX*YGp0_{(Au=ZJZL6#QPiuY@0_V2u^ z-KOo)uI}GO)YIM5&eqlR7y9YUbg4SlkN(|KNY*>2V+>2WboisXKf0~MMP%%~&K+wT zrb<`AQ*;4lYFu0m!Fu8jEYf(-7fgjsB2*Zc5El_f5x9hR#-+K00Kzc>%f`H{6_WM( z3G2=G63O_d1bgyz^L@+6GsxLw18WM2Du;IV&1AOKfj$V<6OX3tu|7DT_MIF=dt!Zv zm_c)+?WIv&4_}60z2`JmqU#X^dKXzT6s|HK27WvvneolFTmr#*XBn;ma=C^fXZ&J_ zeOZR6;V*L!q9FC+7Z9Cp^xxVU2_7?~W`u-~~B+<{pXW9tBKm`(#$=Btvu>Ye_6q{Ma*qsaNLF z%TzF9nfM-akF}No%)7if%>7GdVS8FVU|H^;P7K!Cswbc*5&L(z{5=C*$>Bf-pNbdy zBq{9pB~_58PbWGtnTZqrkHL2+2!s6%U<9v^OJ?e=URo6rzyx#(CxAKZW$E$XwPWOV zU9Z)B|2;g+4f^+X{T_qm-hFosv0{SY_OF%jfW`UBbCp6mRY*vQ&D7U?8?!sk(;!U z_rPMWLukzDVA!c}C}=BllYT_n$KGr1wHsHhX(udj!s zu8J@B%KYi^QRo(D?$PS$xVFK?|4#%v-^0m}{7pF$w0&MK6Rb zKg;;hg-z+^B74qw{i9+u##AYu7IT_&nsX}{{9*oq&s@x0%9Iyo+p&R-(*nX{^{Hid+>uPRhC!MwpU!Bz=ijRK}bc zi9P-FpXgR5Ghl`kcJv!C)`T)Hu|MtE%4|ySWg1a97RjuzKg@$cEI$gT=T=yUr%7pM z=j`K0|K{%P8GJ4+EA>hmQ<0VllB&}TAu}Hb4Ugb^iu2P0 z&D+u8iR^&5LW2P2@&yTh^I*^6NDeIBYK`*h;y~(=I8`^@pJnha)N{0bSkSs@F}X}3 z57={dFR>31@=7>P%wFav8T#?8;~M+0zW8^Z3g-N8-r#JGr|+CFZ_jBwO1N`We>`?; zO=%LnnuucPiV+IfdosM9|M>SZ{!VA-y{k!U=Lzq1!v9UhFJ_83nN*%hDVs;<`@1)V z&-$C$Cb+gz@#us3FuLjHkwAzq`+`t@1-WEd#`_8*)7stRvJlmCpYKgAvM+*u2aRyG z1piAowm{t&+R3yiSe{?NB$hvOyk;71yn{O>FP3?%0MzGCi#eNrEBH;mWz3iSUX};PhGK9#ZTP zTjX^rs+gWpY;8T@%q(^>u^wRh7p;@JtAlb6SjG>$mfw4O_GRk}9K5|T!R2M+q`jUy z_k8QGqVG8!5L}a%c42KsOiQ|925_XnSUUR9m8_Ui!7pkRU?@9&8P zdHZ8MZ-1DtJp0i;%ri#)8jt?yMGhikl9@toL;V3r4glgL!Lu^~!)BEQ|chRNoc92K9fUtGpV0}2)5Dqq~c$LlR z;b3z($dzsh2g1-Zz2P7SeiRP!rpFm2r*91h+qO{GneHK7Cxz__2ZiBacQ}y1@I~Q3 z8V-uX!5;Uzu+nf)77q4?gMHz^bALEE;1b%)YvLRU2L`f*neu@qgmbU7BK_wS5VGLO zqyq_-VVo?7m1Qk#?i?PMROS%M6osjJVIs(&AJmJ)D1u`OO`c5*++dVJ1ZNjfI*qPG{rAjh$11v zt{M8I-d7w^SS$_fy{6c%=!J{mD^*{mR?JZ)L_DeSS4~g>K9t8h*{V;f%PNbd2pv3D zRjP*J;vR&e{-E+u!=R(-32IyQPIW?rG5w7CUt{@%2on9Px?Vk53xlQ%F4m4%$|poj zrsrt`wct3E9evxhvvfmR*h5GMB;7NugDxS$lD-@^yFxGdgowFxnQpbN5iVNOU+ch# zk$ge~oonT}3DVA%u~&<_R0f?qu;H@+|8_6}f=? zlAL0lL>xuyAY0MutXBunCehMqtl!paN@!f#MHy#H+4@2?e~z$Lu-RXTp8%PxKLvtfVU+N^5G|x`c`U3H4hy#x z!nD-~q1Z!muTYdAv4w*GW`}c#XW&S{eaVW$xnCvqlF2gG(ZhL*Wrnh7+55xdJQ*G$ zRAuz){M)ip*(ceCYU);!;+f1rp{m}t93of6n-!z3ZI>xlD;gC6*LDzJD{2%*s*-C3 z)~X*0j*9j4+RjWBL$yyeqixp}6@IHqt4eAs#HrgTX}PsX9gdy-iZ2j#P{5 z)Nb8HkJJ_F-|GBsDRH{?otmY++g%*5wbAa-vc~uC`A54RLK-6aOFnDy*R>OM^8V6= zIs@HG-P?X@S&nXru1ZH6-g`^8N2mW$w{CbJ0ehme!>$dt4idv*@n3)$8XY){C1MR2 z%is9mE68cU6N-%w%_HEyVQj)<@bPP~QcNCvJJ{3n~bDgD?K^Muhd%PF+Z*2z_ z2{7j7e_O++`lDW&@jV|VezIu)VD|q?19{Y+Ur4K|EhXn*c;7kQaA!d@1$(H9td3xza`TUI{}(--eU9)_G#ZP z(xI131sg(-n%uwHfYIY;g-*9MvkRSTTS_gZn(VNh8W1{(rLIB2=c8%XT=dYH~mOcG$?GJQyt7IU`yD`?MV& zQkXtAtSi9I$HoO%``9>Ken@c|6KxONA5!S2#zeCoQoJ5gtbYeNp3;l<^09G#N_01f zc47SvqCZ+oV2L@CJf~lX{38pI1dkkUfe3a%c#1jeEZaj~L{)tb!2*KeymlH`d$~F~ zqdFQo*q@80oVpU7SRGAKM90@eC(&SyK28JyX#)(a>} z;Bc&fLIFG>s^P`V1FNf}W3NP0)X~>@1-D~Ybwsc2js6sm%iv8TtZnC|f(4#QYlF|O zOqwrSk!m^RLIfUt#R)->ZkzWu(Vp>h%zSu@cg~zj{b@cImMi+r$^vN^HkF!OF{hM- zgN+~S!~RU(No*#{baGu8?m@tGuOd8g!5@O*eKcI zkht^foSbcwJooH;ZWE-Itg}p%{F#!TXHii=(qACjZLxi>17fjAx=1=hLb)<~D;2(0 z)R#;n0a}`VN<=pnpyLWdi5u)qd}f7~QXM%HTr8y2$(u8+f;iIzsQJ=3vH;!738M2ET(sBSU=Y zE&_C+09{m_Y2YeA-2~_tQWa@qv|e-}m>dm&6}6Mvoa24M)PhcrrTYueB?2_ylmHDB zplkse1S7&P5-dPN1Zb!Lb)s{Y3eX|WRBE^YjS#@|uK-;kK%)fc%Bi8J4yN-2Xp8`j z6`*ky0yO?{=u_qvYLWn54Fj$j$V?G<@C9hvDVvhD0yIN_W(v?O_{cf|x_-C)Mgh9X zPk?3%(9Q72;cXG1Cxr(%0yIZ}<_gd}s~PtB0(7eY-R3Q2h{1}S%QZ-YPlKdE(_r2a z*8xs<40X8lih6JMjvEXc)P4n45MFl?!4NO_5A&hfp|7B8(gDdhbv^l{_uuRNW)sz5 zu6nl9-z$bTmxPJxj~8}0fL-_c$qFbZdH%h!ZugKH(C)0W{3f6NI~Rf+J7FTT0YZe>%5^H6*g1npaZ+1+%2uvZP0b- zY;KpPgD*OjZW3m5TV%T!Glb3XfZlpQnu`Ts$Kc`-X)6Xwuzo0uI7Grz%${I#8yu4^ zBg`OVLzzuKLP#Qj8&IB+_7RkX(PW$3b2(r>`8y#9%2G=kvYLF54EoPIaxRneVXfKb z_H`*j19!=mG@IKuq&~FqaOw&M-Q&50_JMYR)_?xCR6~=~z%RHeOgCq|r7;;cw}Ut! z4uajbL#dITW~^hV8NlZD6X_7+8e;<6=5{#Gg$?xCQBb~+irD_JgbagT3lp#Eo$kIiWtQexa9a;fj^+Cg}F}vut(4+NHXles|(V z*vWTTH+$HlUbj>CN{34w_B6!q>*itShF5$E#qen(1}cW$rSR=_33E55`aHvqV}MX# z>^qb22@`u0I*k2R6C4P;36sqIi8X}HgiZq2e8~?&BVihub<8|~K{g`ClKagAx03N3 z@+q>tHM@hdM*iR?7?uYmA9?3HZs z1vWD(;t9J7(y+HjMG~ppk8Dq_I%-8C*N(f3%bJi9rQmMjKHx^Bto+8sH*lx$D^uV# z0T0o9A5y5%VhHIw!M7Fg?(oa_VjX{@AjU-4&36>m3u1}kLJK&;U|1MeE?gsQ60!md zmcB?eN+ss1-d$Ups|rvZQ`xj-5L;Cxs(#h_woIb>smfl>y55$xOg%%L ztv2XhcSMa(f<4Dey4UxqmFm&jJ>Ap|^R?gALE0zX8#A1VdHnBgO zi0JNWEp>|i%|5#Ex?~;eTfab}i_o3bxejm9=uxr=^Lb-7s(S@K-h$6f(7K;e}gh~QyfqDK-LNVb3Arll`oByd<9?iw$W~>jEpX zvl)-!N3*`k@a5GcS5yRx9tZ)E7UYNm;d+fUOdfa4tH|vrVt{Z;RD1Sqto$PRSx``f ztH@8iUs3>{ai(OxD&~ZVM%4OyJLhO1u3Lp!Yn^Y!Iq5lRdc{v$)sIHVXJ zVO2Tpuq;<>KWTMt1jtvhhE+F$QEq_n+s!}e@_XYY=`6PnLdO%J%^ z&}exB$N2C3`ln$+GyF?l)wrRpYDXhHzHkk(tf!M=ElnlT#Qzm!7Os#vnXDp|k z65k%$5&d9QLc4VB`gU>Wz6ZRj`>Q%qXMzP!TPKw+xijD4?(Wk5DFL_f=%xk)8MBls zMWUZJ&pCZ!@##JL7D>Mq`X2qlc%Ppt!}_pA(&QWaigRFR5HN23x#O6$b$@}hQ#N}x zBBeZ*h8<6%##MEn4XfB%u?v5J>I*ez+;IYyUiJ3_FgwBeex_>f@3G2wtgQ5}uHa`u z`q7e#Z8=RnXG*pM-zr!$9PAjpsC&Bim~@h~k^x^=BaLWY?^unw!PC|Dy3(TGAdqGj@v zOEseH4a>tyA~d2%_|OWCC`uz*SyM;v4dZDEuP<$UUNj6q!F!#-~5`b zuTsX>@in5fmM>vzHKGiSC{rWKf{(1zh}LUF8#JPg8d2#cjVN0q+6;f5hAr@m3T+xR zq8yDV7d|hKRhh35ZPkdjbq|8hS83D>&AwUN18cq&Mhldx@}^B2XMKybjG4`$wYRG)ud9?EfCMd47v;PR1?)n>K3aaWS1H&gS&EzRSEI{rt`i-1@<9Rw0&wfZHv{yUY>To7UV-& zj+}rQy}M9VB0vXIdgFC1a6Zyehrq2F2K@&S=zMf?xTr*$bU>ne3uPTL2Gi(h7z}z5 z3C7If{@em{u=}w%3|xb<9_fLZJ$*upRTBbc6NWHBThSt?>1H+whh%qYw>~#<_q>T5BOfQW?3nQK_ zqO-4f@xn&X2pibAr7U6zo6Ek)W<|L_g&ji}o3$g#V+OaM?Zs`6@=W65?V;1a#1tgeegpfQoZXvR%>( zMKDocrk2c+J?#$hmra0VOxDxx&|+DX>^xiwdo06O%7&p@N>O}}c_^NCQix8)=_*^Q^T$)Ep>ch?!aj1Y^$VkG%pJtXeHAsXq=j zo550ovOnHehd0%w=)U)_DuRg2I-T1vHQ^CNWd7FW4<}B?-s!|F?Cx+INOD|D$7taOS5pc4RN#$Fm2w2INEl8m)+mz`}|(7=P%zJ;p345=Ng~) z0C{G5J6B-Q*sa+2da(j5W*xQyOETSc4;Zihi%l{maPq^>NB?pt!>&Pp8_x6)Z$Un#jeUot}bRbftKk(fb4!l+~=`{V2{Z+tg z^)Y>8NQ#DzX{H;oL?H)USt!;P*4q#wpU?7Pm9cDNQ||!hjP#GJgjj(d=NZeMb2By# z7s$bL_Hd9X2TyaNI8qL6O-lM8ry6t(@=`Ju^D*NbU;fjSLvegJei45`4l(mOKaKyA zADNT&hku`+ZYI2(bJ$CW6K)rdIAeiPCJXS3&thK2u#?w!qH zi!e5#3=y_E_X0?Ocq9V0r9!o+Ni<7xwmQ#6f{>(dk_=Vnr$|;y#1iXU1-K50Q1V_9 zf2(l1^ofKdr8V9v@|T)QlcZ2r@kuErLV8QOs_U3idP%A!%k3f_UnCoqu9fw7o!BK? zE=w(tnG9ITZ^#bHUdf_foWlK<-IWm(RRgCz6f+gu6g17inIj6O;)=rc^I5q9b4D?t z;D0`6tbU_dslM}>C}OFXs1K_3CQB;STy^>bb>O76FzP+KX}Ylt|OaVM|50AJY7c?fvIbSCR~FFA3dwlF?JnUuR%-4 zyWkx^!Zm?nP3S~4dtA$P#OmOvAn>*(O|$uj7D5XVI)NxTIO?upj~(t0*DzO(d&6b& zXs3BV5D$9+MuVZQ9tHOP9}jeRN@YEj0`%z#Ia=#!9QqE~@067eN-&B-oz-X|bW$A= zi{h)0N<;F<<{wqa&=Y5nOnof`0{L9~8B(8CshI&22atcv27v7w(M*G!?rr}IWi%V% zZI7Kr3D^9qT80SM+}4ms5LdPQs*qPvKDhd^a#xIPv(Dv_G2)nx7V+Ciz*odth`=6; zw9~qyvC)}^Fx>e2j^>Vrq_;>%6&bEE(p@>mavfRy@4TyMgoXZQouzI@2#YP?$JE0R zou!Mw&#gL3Fevs|YBpj9bXK!*ayvR6-3`M6_^bv)Tuk&K#t^fK_tRW4)(6Mj5YA#} zaSTyEYrlBEIGd>7E^ZfNh!7$Up|uQgTQft8L0T;n=P44u#b#%-V@!W{je3RzWy z@!~rsPqQ;1ANDlMe4rr76XCfCc^kY@{RRP=01a9@Tr>Zu zXY#0)MoUvax@K90=g6pQou`9Ay{oZr6d&kSwvWplHyj*=!JHhj2a!JC93dwS#S3s{ zm{cy#^)tnB#fa?~We(uZB#zkrq97SK#s~Yv5n~4R7kHY>k$Q^V7%gRi=C;=&G&Ys* zSZ4SNoKzdNer!$12%5Zk!>&V~j)*_x%|EZAp z@TpsbjNd(u2rOc4oHSxLv2+PqP?}w;5&Jpo6KgU=1Khs)4GgqSMjWP5DX0RB1N{HbaPap7E zF$>qkfDep0c$f`7HWuJZNW>5=W$3D2#KLe5+dF+xxF+m!Ksp8ig@>ju4%b8=W7C&Z z8dd4**muz$QycV4G!CQo@%q0;e`}V8YqmeQl1>WO?6{deu7YB!?xov@Yj*ahJA`Xu z4F=O4Gnq#jPT`v8i023$=Vi`r_Ab}aHxU=8Gr}(Gv9D1fo?X%Ma7}`ld(nz;%{Rn1 zgd6x)=vNu(uMF4hjwo^u*X&uxE!swf_8uq-7)?G}HnhK@C`og|+24iH z&V~+1i!P7yA3Z86wTDul7ky+yf*Eg%PHLdEv7#Af6Z#YScKX~aNC{#A7s{AdZp}U6 zM02LPa-mG8axX4)GK*U7&xH=JFK2O~`$smHXCseBm+$35*^d&-4{@QKwDLkOl&d8y zcMWT-!NdtF$v5m4axlKj1~(?eM`K*_(B5YrnB5_l6{IkLUabf#5)0y^vB}tM@C=9$`2+CD zP4QbAPRG0B>3E2Z4{p2=pN>CekdcOG*|R)Ypy<}LDApd<5ddS-ssW=M zk^{IWZ5(jQjXA-M8EILG<+SY&wYq~i{Z*F*D8oN#UrUi~Q7GU1f6Jakp%Kkth&E0i z$Dpww&5Z;3aw@^AL}`}%W&AaKQ2%n;PB4kg1F$h|%H#xk3gDeIKp+z?5C%8)ra@F; zfG`q3Wm=Z-l<=~U7ToCgP&gn|3z@f^3`7_UklD_>H4Ns#p3*FTOQ#q&2nWW3B?rsW~KR85JJ?U5Y;pbw3!m)(&)li5bm#%0%f<)eQe-=KxjLtww4EHz{kO%bxkm4%C_fHwJ!oY3u}o5=eB+|b`y3dKy)Eij7`4^ zkRNd5!Ttn*fiuOE@KpSzYX2$Q(JXx0rRso7_*6C5i9B#0E)#4^g18z3;fyE5uY#Y>L zn_zo|y@rHZscUY1PpV@{zT64T@v>S4{}o^Z{k2wP>lKT$6|VCb)9F~k4sWf+-dD^^ zMqKw3(RQBRFsaTK{S`-m?k;k* zWbZ8$EU*koOyo~u!~y>NMKjI!ETEeISz!6ssvX*{ z23uyk-Y65Hu(V^T4!iO;IJS}cNV9E<2IpICbUYrC5E2I{sH7+_Th4cj#=p;L`cE~hapucR=kM}l`*W#j^;Cjp_eE`{Y=j?OnqjPWf{XM`}ooP zxr@_@si_rAaF#*hbfT-}gTvfEi^C~XLh8<)FyMSU{FnKxPoY5nuaX*5{}Oi%D5+8-m{DGb zwiO>NXh>t0U(MREI2_|aK(t-m`Wi@rb+i<7M&2H~oJ;esn~{(Uh1!afEqUu3riVTv z63=v(_hj)Y2Y^g^|0iM%+%YAS?y8gWfqz$-RKvs8z<;UTfY}XIcMxkGl2l*0m$uyirj#DCh^m4G^-CQ-M%bZ4~y- zJOWd>GcIqp*;m}YTZ{_-PRVd_793mGx~|or zA#J{3D7$T0?$Goy0Nc2L!u@R@v^-Dg3g)3qm*_m_ zYu&c5l=k0oOy{>sr=%K({du;IgnrtK(B(e|T?dt(Abv8bX8E;l@6;aM=C1#3FiY|$6iBdQ3{V&m3|6a=SP{GJ`Hy|nE|YDq0&A~7U!L{{ge`$T#*E8G)u zhw}&Aym*Rf>f?%wFB}RHfw|Py7Zd$ujPRA$^=@9&s(Nm7Fz~wA<73G1W}4qH6dRvD z91@>D+>mx|_ec0yHG3>YBJ2vsU`u?Y7 z|0=!bjW9i)D7{XX*zV6;wyE35Ze-A7e9$&JZ$hP_R((==N9WnuLXIy&y^*h!%l7Bt zzg|)SQdxff>itO`QMAA074~(%OR9#9^B#@96_4Ne?nHsu)yVj~gbawVGcVdF79wz< zNN{=bBaWpua_Rst18n%8@s9{h%Bx`P;zNYc?&w{4{o(d;guw1ym;J+_!#iT3n0&&n zykdqpAj+SMjO_?|9>CslVyQ`R`uonDwKhrXa*Y11EAYlRQ*Kfb7tD|dTe0~c_R5o} z75e1KX{d4X982w3JPfbU-!~B?*3&;a4()Ic65pF!H}TB$HXLO6490x?LHmiqGV~Vt z@h^E{wIQtS#@%J;9Z9wmmHdVbGCzym#SLpQqO2*LDSHy#|;Dqf*+jwk{o?| zvB9buXeYZsqqnx`EpY|H%pu=^GPHo|UpsrFp{al|_d|WU>IA}cLlM3b7r2Y6rEgY= zGfyA4yl%l|^aMT`KiuJN3Z=ZUMb z5j!ezG0sD=fleIo%(#Ec<12AHS`0#=^(}r7lmz~Od`~4Ve{WQ4n7k6VzY>Sn9PqEi z@wwDWoS+hyR*74DkZLhYey9?cxj-;GA<&V#m786O%c;cWR^ph#N?aazc_pp@JSgnY zDz3yGtHd3z#2KBa#GS0fofqKUGww)E%(fwEEEHVa8k+*h{5U7P$bHIHB5{svy_4J=hl+r!TofVh7poh2R z`@l5tW*PdSbcf7E26a>x8yWnSl66!%po6DUoH}G3l~$1@vMDiHMCLs|jY$dgUgf(DX+^nwIUHq{CyfiRIso@}yXc#H%+=|BU}J`G?>akSgMZACsX; z0Zpg}*zX^c5&4IOfx`4^03Eu7CxjZ|&s&bTDe}9k=;tk`&7y^XpG^CC%ehn(3*^#2 zZ@GLBVd_PClApJh*-3th0s$bp?grjDrvX}iTXI;EJ_yhXw6t5YSo-sp8*ZI+4j?H1 zytT4Wx>b5zN~3nUzmQf)|46gC{vpbsf2CeBSr?_#3OHyN%DyBK_?;ZtOvMWTsb6KS zvh;b1@&TH=0s|Pzp9VZ|=?c2yg2Lgm=R?IYg<3(|``ODtJpcsKEuX!E)ffwPihA1Q zsuFb!U?{JjB(8p^u2WBkiznACg@35i{oz-WK8Y~MU53r|*5aDsOjrr;&|8PXK86=z zX|;O3K3F5*4EkMfeLfbm1yGd9ru1jnGVE{cAyc9s9{&;Rf$uV9MB(l6=|}K}w*J-l zJ$N~Ovuyxw952NilS*v^-ALMip-lT=%SoSNuOY-xA!`%sD$6~V{e&fErT=85$A+15-m|Ejhq2+f z2o4EQlnqiME^(4LG7c>`C32K=i!+;Fk`lF?kI@1Y<##FDQu%8ELwRWqG5RjQfd7e~ zn6rJR@Hs!-LD-zLgDE5k_X<&fk#a`34N#PQ&hC68yds(it9?cD8(d5yQCYsc8^GJN)2V_x`=z0$&j+mvf-}12V`qx z>7_E8f#gnEp6r8+H?R*kL-AB*r)V13AD~zO7|Jxn=af^5NDwHu`tt#m0&`h`RtrD# zt<+WIm-N%cK75xz8e5a$VF0YiCoGW{qV1PIEs z<$4)C@LBjPoT_(dE*3KcyJPR_Wrkv{0YQ1DDKYCjHXi#B%QQXw1q(RK2KY0kN1X8x zJ{bST^eApWeign1zr;4X9iIyVdBektjOZ7zd^F(D!!b zDM(c$6gkH|e<4{zO7|i6xfjHeUBQBEzHcF}p3EmdBZv7G{UYBXfyMs;W%{ja2!oA z#Yh>B)4~nMmovV`M`oi!({~?6XEG40((^ME+~|P>ZB+sm5VMVkpGmBH-a~Dsgm%|rlP$;1wQ~>s~>HsNFJ6%LzM}I!0I?1$XdXwdG zzaxjUP_{OL{}s?~%!9Rt0CRX+qF&R+{OKXbP^tR1d4D3!Yy{d-CxT9-8tlzy%&|$^ zTo6=%V&`k0D`X>L3Ze=mMb-io(p#{rSb)%)Z6nZ197+Ye-~k@UDR@+fn%8>_Jy3v7 z+@1RFq=M_z!WL&NKo>nrpHpOXj1OW)2sn(%tmB}iVe$BM&vEVEW6Uz8S6ZkfzUuq& z!x9LA@DD0QluH^e&a+8N7|Q=s&LAkZ31&wNP97V{ds~V~&=qS+9mhW&ds~Y9_k7Fv zTIrnewd%&g>~!5oHD#1=$duK{x7kf1`bP~=f)>8Bpu;qDCwiv=dB4Vi(RIfum= zm<+0yg1d3u@w?OC;TFA#AC7DJeISy!s6!esguSPO$vK3%HWXAx6NIO$)(R_CC2t@| z^^IFAh!pm}u@(q38{c4#XI{*xR5>+dLMrTib3y9F@W;-7Gin9qf~?{1hq*t86Hp$d zx)cg~E?f#M7{J2+D?H_8e^(ncr2bDBTSLnDSMs6pMl$sj^Z^nTFi)nIOvSLJI@cZg z+B!D3A~Pd|@t*rXGVw_=<=rNm*%KrCM*eTWOtdyUwJHMZeN@h3MnN3AAl*C_KMnB` zO5K@9NydS4$hk-q9&10dtFTn{sI05NN<8?eOuPlFwDaoXhjBHeZb`+39>VpcSk{%%*MRgYY@r2_OH|J z4N6rjW{oJgd)a*%r?n`rf6=}b^Y0uRF`?v1zSW^I#6$c)H=ymk-A?JE{Uc7MIP>owZ1=gG~qO(fG#_p$d}hvN}}!Gc^% zahf@}EJ1aZDng|yGtF9HEeLGe_UWD<5R5+NkviLt60%gY^qs_M2*U+VL3MXEcQu)5 z%^87hnBRaHb24qdzf)gYYi(<-pLtp)F_YLhSRZgBD$Bh0{iH$q11{n#68WDWy)$lP z`Ky}Uc96>@V2);s8(B=VCNwzOEl9P$Zr5xdvb?3n7V^Ar=XeULdS&liYv0j`nJ8rPfis;u5n4%8Y2cDCYsaZujDS4KyGRmv6Fjy_M)GZGX{ zN?syI93?z#Em(5LvQmZ1%RUog_ha8;R+hPq#&89+)H$e*=nSFCK$Bv&g61ydi3pztZugoztrt=j(QM z>v1FAki&HcNKCtKSF!vL#i7^Xg}qZtjop$tCC*RnXs00iOLikJ9sBJAI~UwMT~=6F z0LCgXUOoA?-@Y@lukh{JiVBgVuX{j1K;*NUgsP4H34+kb#e}#I-SJC?yE!jv2z@nC z?WJ#fnS>WLiSp82-8BSz0yBEJJ6sS-uq5nyUb+GB0zY(zFEZP{(O>s*S=3-%tfo@? z>ciS0xfk$)TDs<9qfygoo3b-6vWDl~JcXgW&qpBEd$%GHp&GIcGZ4>yg!Rqz7$^UZ z^yk1ZglDhwI>HW6ZSg#wbA(;Jop8|WR;-ZjmUxlQY#UkeN^3`NADuC}Ek)MVzq4~} z7nE_AS#iAcmUpkLGjgZQz{fK}bA(-5r|-~G5RsMX1?}hqUO@7NvVY(#Ri&zVL9N$0*Y|a0`Fl(TgGd(T+ z(l0Lh>NFRzq=906G{QEpfwH=m1a;UqP#hX4MeY!8)VYD;!g9(aF0X2!tZ1OP)z-T= zQ2xPrIn5^GpsWpRpsZ`4jB*`t5M5-L$XMYIZ3Rnw zP~6{*8#JzUgAv?7+0+2kDh-q^4U~`u%2s@lr>NFNAH1?1foDe!6kWJOOk;ByI~pi4 z+D@@c1nHaxN}N+)JU9c~JZTB^xdeg&xDLc(ZvNh7`i{f~%Kiq*i2VWo1`7XNegj3& zKuK$$EIyd6HKc#2fs(ma?$Hq#+IqA#yMdC^K*0qUZY%IkOZ19Bj3=GdDBO4;vqwlvyN`@ilthl5YouE0{IFr9lxQ_VxP}z zNTnpmS?6SJ2k8l+0LVo~zJ+@s?^zE&CE1akbDCY*jcA2-;lnLa)s>YMj!b$9sH6q7}mLn4yDqab?ypE>GhO2 z`hD;#s7~&Mt#~|x;y6ya$20smkQyk^4@Etezu;7G{(ytf!CE5!Uyc{wNjES*n(xSmvH^S{ zm++JMy#T$ILtpu={CPqr-4L<65F=y@LD9GJbRk`M0UT^C&Jse4L}S83QD5W+q5+|c z2oxQa2a7B~pU+A6tGons{Gbj1f6Cv1mfv)VlkOimv{dp#wD_s(k4d(C>57ovnHXI)Bh_0OzUjvX4>^nUn4U z6%+-Ue@6f`Q&ofJpIiotE>w-nq%vd0k{3%_2$urRj1bBHj_7jbHj?k5M!pGmX>>AXN>lFlUi!Y>6}%5`wge^v%{Ig|wQKE++ls z?%6>S0xQf6cQ4#@@)Ht?yvo`)VZ_bBU})&vIY0h(1bQ z3jon)7kxRfv&?c|dySq-Pk#>3y5ID>bOI~O-52MWCv1}9ygpXDCt#D_T>0bt_x@x6iS zD9b&lji1AR%Lm0a=m`7xw!$p;jebJRd|?7W!N-MRKyd_$ZF&vN43MHM_sy1~5n=io zfVS)uEdz3+EcX!HRnY;_Q-HSq1U?1}B%m0JDw!dPlw`SwW=SvslFIK_et6y#mchWqa0+D(jXZqwr#J>Q+5^{if)l% zj>?7r+CELuBePb3VmsC=<|^U=iYW%x1?i0d?R=#;5A#=(HEcZQjc+4+sAV7O}<7q&`28t!$24)3=0PRDQy7B3Y zNm=gu*OBIs;s8j&6#}P%>i`{iL8>7AA%S9iBKcpE7g^?>8coJHlC#OPeFYM7GP#!= z;!8~XN^T|3qnG<0bf;tJ>1_HZ-}H1koqmDt5R!p=NS~rS?+rO*z#5>tuxKqInZY21 zErm5LHmih%iD7lH*2f-x$EssZ=M={hk1XZZ4cKfZ^sD~DJRCA1eF z5gMK?tQPJOrptw!&lZgfr9xv->DgkOn@C&45`8#(EKTGqsua=es*m3n6^TBJc2}Rk zNuZY^C&}&V2jWc0wEYBwa^Zc z^thDRb*@R8A$={SMR$o1vPV)&nWU>^wG1;$wo~@CODvRal3kU#Kkuh$cTYq1;k3Jv z5bRf%vUT2X&1;xiclNH8rLTi^ zC}uoIEDd-99J!Ev(a1gzxvi6BPoS}Ox5=+ZCi3)xer-95-ginKEjN*4-Xr_0uW8G@ zUbj<>kHVe*6Wj>{hpa7EOeoY!t=?{O<(+v$EoSfj*Cc47H7{4*Q2$)6Eq?%Fj4hF|?wtLOgYJy+!Gwm^Tmn~~3;3Ah3^qZALhhnzWRA-9mbjBb0< zM|duu#7;h74qKS+be{EDt~2Ylq0gYh)GTWh7) zOoB%Q!ASx-wvJ&I%Qg{cA0r5!&!Anb+hqg!r@ba^<#`wvkAaWlW!;1a=bovHt97HRjOd zy#)eWOQ%`JXyS*OF#;yU57|#Rb+X<5;zY-HW4SKcqOW_&njus8)5_InyC~i1?v8i@CGzxX5!Mvo)7l4ZU_BMK0|VM}Bm>!B+J8!3Nv!KjwUAHV zALu{y{CU4d!Fm%413rk$=>akYcKgew)dikgO@B9?diu%t0|({IHaWA0Ot|5~AJyt{ z&?KSt$#9ak>b(E^R((~AI}rit(bkzGjnpTQOR(2D$;Q9-^SpE;;OoRW+9%36Lqn4eLNyUBiF z2I78im~q6TK9Ss@zL9)w4o}}i4o$@?gLLH_6U&;>O5*4KR5y8Dw=?l)&I4vI)1Czr zVP_&wzf^u(#ijK5%c1S8eVewev2$h)pRIU)@8t#{n1K|6<4NekbG^(fqT3?KdQoBV zKiUtN6C$)E;9cSA)b60EFex`VPd`_#y#)n1navN5RxD>pgr)tt8X-Hiu5ZZu%W7N8 z+Qa3nlP5f2u&bzrRDm~Mw(Mf0jCq^Pr{w)*0dQ+{W3FC_zjo!{4Y}PuLssn6B(xL9 zd%K&wRDMZvO9DeC@)we~VB1|+Y9d`KrAW1k&L&)a{bs}AuFQL%H=UM3)l%uL+e6-p zmg>)Pr0jqKikRjy5yJ8p30Q@!U9y)!Xz#^Wyt&G*;G5mu{S7h*X6eTqt+e92l&uTb zMz~Bs)vvo>bpbI!)GtPtu`U|JJ1cm;lFZEL3nDK%f9nY(EPD^xEG(Hwd|M0iiy!`h4h%Pb3m7i> zGYy;3Ujk=ULEl=t#T)56==CNq}F1nBJ*KG+y9$+ zKvo()d2fVn{C6|<`;(Xq9d-XZx(f2?-#k3FK#BJ!ols9tD?l3qvVi)f8uEY1>lPnL zhH?eD0w)L0e9wG-0awnILji;4L~~+BkAcQO6O(pHT{0C+(v>{SeH}MFzoe3o<|GfZ zR9UJ51}~g(%IH~h@uE{qT2+ISPtT=xr-Bb@m%E*e{Hq6?82(pgd~_1nLy~V!LW5@+ zR5nx`b}KR+U(b24v!C;Q^f*^*gk!!ZW+tDo&srl~6(uJG4A&ucbkEh7`3jGA?6QQ` z;gPJl`bVkOn&VtbJ}v{=jXjLbx{xVikV=o2omhV-*DuiOWDCV3GbKdkEgwH(4c>epOVhzdRZ>%ajaEa^?lxh@u z9KG@F&cy49i7`p%AwXp94Hz~j2{%}4yyY2kgpKRBb%?Bs8S;#Qs2@r249mquFw-HQ z$xmv8y>p>g@R#37yVHboXC(2@p10O$UFCFgV1fN0=L-h{3b7Fjz6*cqUNIG^iU;ZG zZf%MDO#Vqebcuh9FXOBDV|=u5j&QLMaub#bS;D)*jk!fR>xB(MO1#kc1KhfUnjwcD zO}o1bvZk7f7K@gj_aAu6`p%mDFD6?Q&kDC%&sjQp6=_o#02z7}Gd##EWjYr~Fcl7f zp-6b6KU!r8uwA_tnB#^u@hVV-EW%9%A5y`{H4hqN<+b>&Ef0{VW-nMz?tkXoq ze0sg0b)&Saw}`##`c5N^TZM1&GC6)O>}e6cKkM;?}f0YmAhWZ zV*eb$@bbnGh%fCY8B@fwo|79!yrPWTjJWwT5_HzrC{GiUwW5KLaZ&{pHK-jlF(g2}{?T;O7Sn60+H|nhcHGpmp+f z@-J-)jY2cGXM3k-4gSwHunilr+el#A zN13_k5~yJW`#=IBQLBVhSW2AFZ~0S8y3$w&)A3#Yo}@_ zGB+zD+rTU(?lBV0d*{IG(YnKY6_Cx&lcttRbpc<&e9a2ZI?mQ@A8^~RaXDYwY->5E z71d9hsfY#5ipRibcvPXKo~^c0kFQWmZ*kwf@z&Lz3Kfl;L7`F>z(O#j=}^427N#k2 zSv;lOLV7$1Q>NoZ zp^hV)sir@cZ(ID(|4rN`lMY|I;B5#fb^R>RA91{?3J605b3$Ww1x(87XDmS2qfpIM z0@=VdjBL;oRy;a=-&ivhmoavFaurcBfxH1ffL~1@rVo!cQ@@NUz8_?Nfgd(X`PZHRhQXM)<|<~M3NV~gM5GVB^`)@HC4VOh|Ie0T$I1pm@E9@6+8Zf!Cz`NjAUIn2y^$qqA*Jc368!F7q>i+qOdyMlwn-9)=x1P?zmgzE`X zl~ps1zs^NjVV|XJk_NzkMC2nc2+0eY0>+fbCJ2+%v2 zPB*1PBs!HIK#!#FrXL0k>FU+!Rh@*mPC~shkZ{MlCj&`spZnG`IX_gA)ZTh?RV&nL ziDxF~n~N*z5gXdgH!(*lE(S5zedZ^&fF${MHwRv)D6{=esTmR=i0gw%E z3IAf*HAH&E^Uk!g^L3aUz(x=_A3XZ#qw)ZwgNiYJ_q1ZkP`twzf%B4~9dW5n?>$=M zg~!y#gwlnK-oW%~ar2SbTUj}3k-An5=~&kt>=YL+8h={aUE5uY6gU)9$LALaG|Bl> zF_R-0SgO9AwOH!6LW+akZf0TEp2=v!uiten_SlHvu{aopV&D{5IC&Dpe3^?EcXm)) zDr!7h$$Hp+7WmgUgN874wTvw%>Sae~=3ipOCTA zMYo^cLqDx}Hq*Et8pERS(Di5NC>L!13cL>V@g!@KI|-tb*d!h)gY;al(Hzx{eFDi= zK61Ue0~leBUh#BIuwA$GsKDKOM?(4me#kCo&6{&Z;GV>pcJu}{} z`B#5tEn!mFMEDNIXvMC{>wj86r&y`}CjB*e;4_)xUoPFWyl8-0+z68E=4cpTbRO*v zO@l<4gK}edS@E_*8YxZ+*eohirPUjVkB{I}h&>3%6<*Q#%jYHSFZn6vFwuoq)Tr+d37o&p@RW zcdU@18E2i68grn!1|q_I6)f_&eSBJ96JtwFy>w8UkL=g|j#=cm0RdlZFYclSZr z;y88>`_0p|u&I$UVmMdI0W^u9rO!D#jUhf@zf2Lq)n!Mt_{`{Hgysn~rE&FH1lE$%@=i}pQwpGQ1My5i%19pivb`e@pby+H1NxY}v z2LA#76+iV0|BB9(6v+p@|$@Vu~5sQgcggb>XVK}>IW!+*Ka zz$Wq4)abEQXBoxY^MVe6_MT&Nd4vS8oI-#%i{|?UJMjril6Cv2t9ugyU zDAwi3^_qIc$%oSxAF7MnG=C(r`CHkiX<)RTo`6f%apWL|k%&*&$(a*pO9HdYZ=aN- zQ0p~MuSU*BKyi zhkmU@)1Y~2GYuaPJi1l>;qK7g%OCDi`<_caNhT#&De+c-gS6!ZVb%3qzrY&4{r)iR z(Bhc~-h^)tjSwmisR-b@u{oh}?5Q+OEV)_=Nu_e>8|j2}nrsHyTIMc;=rXp9C(Do> zmtBdTPnQH=Peicq2ykK9@|nYisR3gRO+YJW&1*%wJf^h zsGeV2bmaC5kEiQ3P={{{BU15+zFw1~5GiUEaqWtJ#XH51m!XEb7^S9WraCWai8jGx zX6CzgRm*bq+TpKr%HYA)iXq=rI10aFHsZoi_=h$k@BOf+BrZIxm?F3m{yX7;zrepimNM$^Dj5kIQ@oD=9q?*} z1%^U3w1or|op03RMG5abuuSY!MC^;xr#_yX;cb}_XO{n`Aa3nc*7e7E;Bt>7O)anI zOrs!7%8-q0#YvaUrNc;MT*RSJy?KTk4j~bERFE)Q_;%VldsCz8G(xd()~srwHJ-4I zz8W9yk65~(w2{5e!8vW61M&EcFamFuZP^oc4qjx6tO2B6Wgq_Sf>gmTeCfrvgIV8h zbLrJ_=TewszczQ@Dw$d$+?%!jtAo{O;ag8q5Gk7EnM@+y3O-AckXp@L?wVWcQx7Zm z{vd?Uk4sgdfw@lN(ZN{hI4O&4OolH1O`;7Y#{-|JW8^Uj)I@$neoY=BBk7>;NOz?N z`q1CCdYz=$<9fV*w*=0SCsXZ_J)V>fSBq{Yby1w{?-qx%H2Zo#Al+iNI+xKYFP^aT zyZ#M_UeO!7p0JTDL)Jo;EASrpy@j=FbIa7G^wNvx53-g$F+P^qeGTdwi)z2ZT04BO z+#nc6JSTfxy{AYM?vJw;gnzi{VN@C5*H8Gt7$lw+M;@&KxOi8ga{HZZuiA_J zbCEUus*U(~Q|&cWTlqEUXWO%D*umjzhVi45juasamlPa1N>i!$LHN}tzlxleAXM&3Z{pze?K8^$xAa{ ze@{YHX~O)t*FgD-p2O?wCbrh02HquX}gTkDFjbUoLqde@a{g zI2--l-vYK*l|D50imEG#A0)i$M>(=TJ5|ixVc`i5RVJO4;2t;e@ z<5bho1Q`fSLxT(2)wN);sQ9AxiRDLRVu2H8$OwEI&%Ck+&B6E=Vm zXYpx+f&uOQmQ4TI8N*EeleP*wT;!F?3+kpDCT^!M{J4)h$S%cLiZdY0P!_5)d1xhL zC4*p2XY#XEGq}BR&@ubBt%P*JGX@Uvhuy3(I8krJFnGcuKb`PVO|G@}GP4CXDBCf*uc^GVq$}S-v+AJY^V98O~GE zZs$k7FkDk>!u>Aa0ZPU^>WDp{#o;OA_9QUkdCK;@W&(7f1R@uBUK3ZU_Db^`#60DG zp3;ZcdVr_opVsFo1w3U%8c%s}B7KAS5Ko!ux0*rm454OGvw6xKP&1dO6!MgLJY_z3 zP{30b+6@)+l*hn>s+C=5P1hqpql2b>puRlzs%R-6Hl1>vok06*V@ZMyQA3QoD2&3?OOTu zGr|d>!(qh4{BzKh&&cQ9-Ni7!Npwi`B?+>r@D?VBx&X``z9?EPfea;IlBOArh>()a z00|jTvcwCx+}j^1WVC{8qG8ZWIr6r%QxYMylYU7$&7e!6c~YL#{z!%Vn3OGT0tmt( zUrR4akurzFxpE7cS_-X}*&k`v!~kK55FiNys*|P2o&dO1{|C^Om?}U~!o;NP42YWk zlH{hJset?ymlXC#q>RUklVH~X6uql5QY#h9)%Hh<&~t&y2$Zh=lJt;K281Pd!9f`V z`UtX$X2SMI82a}AA6xGomsJ11j~{S^Ex`5!G+Snf+tL^+jx<0)%QC=KRt7k_tt`N> z(lXT2$}-gSwoF4y+l7|e4oTYsv}_yVsJmh3`y%T7`Tgz$@ce=w38*34Q9zN7gf7 zEP=sAJqxnI^`PlEQg%Np0q26t!GWP)S+%&$xDIgf2kR>ix{8}ZBxS>_MMNuNG(eCU zKa0)vP(7jz_1t_B{fbQ*Pas>e0xx2{~K==0W6q}1>QDVBcr^yvS z_g;W8xdQ0k3yrP-CpnGo?PYQW(7nA6%TY#G0Ns0$$rV8NhL8mxky@0|7eM!3V)6xmVGNTmfbPxg z)K+U{7J9lj%j657dxv67z5u#+n9&#TR1b!+O}+rSH^&!78GQkC?{JeZ01S&T`2y(P zODCaU!!mC)-FunI7eM!p#F%^mbnoRxUw}0Z3|nFH1<<{t(s3xGFM#g7(&P&O!?-42 z0NtC%B2FdBQi*hL{$F1}G{)o$=zivIVR+*#bHf34*`20AZ70 zw?JmJ1&IFI0+KL)Z2`$fTfhY|%{M3Ih4`2lA>WmgIzx`qiv#5Mb2hA%yUFG9NyUVJ zPRX~(AIf>fY2UzNNH$GTS-g>=7@>$&d@kOE*`WvpHdNP|&G&#GwNF7yuSp-L)G0ib z*J`$`P@-ljCCcHKw;ollS6)}LE)&Eblnu(!ssooLB-Kx)jHA+CmZqtEREJeF?`B|B zs%-FBo_KegrCOt!tESc8m4&D$szvG_cQf~?QC#&oHSNXrXX<~|usZ7nVTX;jM@`qZ zz1W$cb6KN~F4-bNN-$|h4zSxV58b;=kKX@P6 zMqWa$B$Gl2id*CY@@H~dNC}qloGf!?s6xO7%@%CXESJ$flu?G=^2L-HOVZ$k!Q7bc zTxB4<>*u)YFJ33Ebq8$QXH`Zq2M5%kAq@a4wruazGRk?-kT#d?!G+--Y6)man;H)E z7`J>^-|`*F8s+jCG^EXBw*+=mmvd-kRI`cf7#4}uO-0@E?H#Zyqb?CuQUBLEPC0Nh z7Ir!qY-Tje!>ccwYR4DP-20q)b3LUy^w~#Hkw#|T2#8=#_)Ptu!(%${|0>cxQ_Vhw z&x$FdW{}EQWuPLh(%0mgH$Jeoy zVur5&WXAqjyfk1xtO9Npz*7#xrwk^=hEXoRBeiqA|FAVdF_Z{ux8GLQY5vvdP&VRf zbemRqChTd`8BSp3|8=8X@j+e?(9NhkaB3o;&iwV6YSL>!+TVH&7H=KoC-|DNIf5nA zQDWA=iz~U2vY8z#Z;ZX=d-DcpM60B+r?3uWUXAXic2kc;Q%15zvVx*}s6Eum=v4|f zzKj(qZwU&Dljf|;-*$#&HD=1btI=a;?>iFhz<1zFf}*#wwz4XtuTZa0V?w8xuh_RL z$vt6THw|pwrMS?9`jeSul=ytmh}PlzeK!>WCH)p`oPeBIJde6u_X>*VmCL!H5e@Ra zmhVutf$6w`>DH9%kt=aOxnAf1kv1?%b-6AdA?FH;YX!v#@o95lw zo@$?0MZM(*SSnZ?Xja!ZkC3o4OVM2E@Q2 z84c=*VcS1mTROTcfJ-${Zux~mQE?BV+^g>`kgF^+s{WMCH01NZ_{wlwT&vW!V~jfh2+@Ih@^=Ig&;HRCKv;S!Na&%HP&a zonGWoa3tEkASjw!098h>D~Ji*SkO)LD>xInJ?~w6>P=071Ybe}QhTT@|7!I1gF)XF z1>7$|arug>@3i}eTRonAoINAM&hboTm4Y}Z7CtOk+2PFs8uAfVi zB!`|_9Z(DEArk5e5b>qvgo5H!6^45YXH~|9*j@iOi-?cm*brNSZh`x48Jl{9huqBG znO$(pcaShhc#bRQ2Al!^xovpRZcSq8s4@y>UfoSi4^_jrp0dwA&w-yceqr-g)}-cG zZr&VFiiR=Al~GuRw{2A5hd zX_^gtTGM8i+Prj^+V6QRjhJn4sg(w~)MmKUZYzoXEZXi;Te<^5`ZjhvflAozQkzrd zQoF~cR_;=p3;q@OAm62SZ)JUfOKlSTE(T5QixD4 zV-YIOW7Fq8oF6rN>OasiPJ8OPmET+Mb6<0_3TvsOlZDi!Q~R2%+LCcLf|2gy1X={* zdUVG9+9{~1kRIKT7+5S{+M3^aCc&jusFx2LZfyKG>%H0i;8~ z6Rwhfh}?bO_!JKfQ+!;OSn)=lsbDE8!`UQAs8|RTp&ugW)tyyjD4r>x50N+To1Wu8 zE*n?pr-U#-6Z#=?hi11j0*FFCL_(`c?SLzO1@LX>WEJ3wi&P&X_qR+3F_c-V%5V?~ zcMNdFJK$m(P>WwsjZuT4=_EHb0!TwYM22)PP(x4D6>4FtjMNOc;yZ8=+Rq=MeW)gC z!B0vG)dH@#0l-|+L2az|GC=!CkPdJ~bNz?NF^E~95pA&^3_VO*ulLmFgNy$RCg~w8 z{6a5mEhqg1ToDh0p~px*@Mw4yfYpGz0j_uwz*>?9aK%A@>PgT<^efm4{UP!kiHn|# z-i8K4FOmKQT=5pTxDwlghR&g}xDS!dBo`cvUJ4L&gR~h($0-23LjrLFIOq+4Z6qsV z2hM@`A+m!6F^N-%DF8ku?FU@(A`!Yf_c`e$;EG7{-MKoF9T{-NKmcEp){))Gxd0KI zjMY{hq7gMv<+bCCzsoLsol$)v9iuN|jeGJ#wZ1pzEBa(|UR$I+a z^fWbFt=&RcV63(pDOkH@p|ROY76y=)soAPJ(Hmo`wyI8CWd6I^3aU=DO&uYgCf*>{ z%#2PA6{8G5BBPl}HFaB6ClYAJaw}hXb)t{4+e)?zAYW6rRdu2t##C-qok%xzThXc$ z{kJKM-B#6!0k;$=W4TpzVxXzp3JeP}mRqGOs}mO+yRBr`017sBTU959U`*v!)rm_? z-Bw^2<05d5YgN^WOr#oREVrsoWSP3Hz_3tbxm7*56lUzUlKlXPZR)nFPUK)rJzxM+}Ld;bB3!ESA+u{;3fc~ zFs5#+>co|%YAY~|YmYWoTU96WlF%q)w^el_-&Ab{hD95@t!Ch=6Jw0kRN7~*{54q|oU>M9~Cm3R-J1Osr6k0XO&Ydpwiz&LIrs7_49_z5tA1VMk|hTVb)K`rQ8-||m8Fphr} zNVlX-7Nfcai^Mm!Y~+jQi8ICM9Kxn!z&L(K9GY(@t zC?cA8(4oYMh#JC$6Lk)y8;QQeV&W{%2Q)o?SkDZM9&c3H2acltif{c4`(>wF?kIm2 zeY+*VNoJ+T+mR5^Vz#dyZ$8(>dD~Py-svg9azT2-XU1d) zk_+02J<;Fg-5g7jEZtR4F!OYgkwQt9B$Tda#<+2Mf`E0KfJ91R3Z4n9&^BH06wij0 z5QQ@E+Y0RuG?xFfLO-MQS<=3eNBN#7zh}Oio#r?JO+u!Q)Itz1bvT(~E>TfI8QQOL zXp$La6g|L4PdJLbM$!}LH)g^ow`3O(W73T!Bt z>vv;@?boSa*JRSCQM~4G%Hf6sCUysF_YMDIWOrQ9eZ5$HjPpi53z{9Y)+dc%>8c=g zP+!rKU8smxG>G@e`A6v^*T5UL@SlXV%^$S3$lRG`(GSI6n`@uy?ny&oE!QA0owLIJyj!IB)%Ifzu1L?P`K z`ra2h?00lbhMeWhS0ZPKy5F(Fp^oSCIO&y$)**ENu;0%yLFXln6cSA|f zkDtu^R0Ca*uW9IzzuDPs56j<3Y#SgO^jbf!(T_nr#tlE+o-{OG=88pk&;1DQzh$We z6$N?NW#@_1o*AzZuMxN57IMHN@W0%L0xdG^k&e>iF(G;9>PD0LsMcO7!J;M9tnus0 z6{Jbsz7kOoX<8ZFfz#tDnu(=0dc19wL}o{eokft%(c|X^>GAd#${qCho=#%(3=Rpr zMd9=@yqr272wN4_4t*| z&AtY{9v`j8kBiacWA*sBj1B{TH>s*5Z;c+mmXwk>vssX>#|z)NB!Qa{GZf^o$)ij1>5{#V_i+m7l0v#GWP`&|b(m5c1pUL`{vVy3%xGI<;ezG7WZ;{wa3`GNY?$mZM zOI#&>>gkpT-4X8>_kxSDbz|f&#qM(G$$|)Mq})!vRsLkb!=_R>v`*dv;Ejq3xvv7F z07G9j5f$I%VTvaUR$(_Ns0yeEKtbtc#ZE;hKwd3SlY*z5rz~_!#x7QlR|=G1=xjs2 zGD>+y`DDRnkT?gG1HH|Y1!627EcJa=PZmJiu&Y!~s$BpgJ5Q=Ms-XJ-?!peL8da0j zPZq>KfWD~?sAJW4{@sh+re3111Qc<>e(WuEf%-G}{2?q>3q4o6YM(4nV3%rbwdnvs zN3ja+8tpXzE3t2Yga#U}f3n~N)qHV}r!!ifN?u(|MZxE>(r8uk%f2LAx?I(9nxJq*#%PZr$9#-Sa7g97*&uuwJn zA9NeKYj``hAAJQq0S9#re}r9tv%syybq#-pmEusrxC#JWT5!3z_qg;Sg6l})Bb*~K zeaJ10IGrf_2O#$%VjS@b03Mi5Vl~l%oId0^o7_(fCezY~762Cuc`vxM@C+FxB|ino zYlwVLjFb}_;kkP@IOzkEhHV~Fv_^1UDC2_uc`%Y9=><#Fw~GA!6O%01+H01!gz@0I}K>hZF-~2Q(BqLD{8Ps7xOUTd73NQDy+du22eTaA(yor7QxVh)pU#)e!)eVwzODRowtBL#f+U^VDEiBttzJh_lj%mKUl~ zeDwu@R=fZyMF=ez7BxewR|f#Ja;?@)E0Y7nJ*C~EeFy*#^G(~Vou*G8;#2e^^s#y{ zEP97NRDS|oin*sp9n|*$6gv*q={@0VLxi{$@GMvY4<8kO6kZR@uEVTRt3JRD@M!db zQL8Z|^iPZ3lA-IV+5$?w{LgGFg z7k3Uvb6Ecj_b*NcO(bkF7pS?j1*a0X zE*6Xz$OM9KiQ;@gl;DhjvPFV8~YzGB+FEg7rCPU2nSaXH&gicuTI z_r)u6WP{>H@g(`t973j-e3+ak|B$nNn|z5}Rw*YH@3;ljho9wX#XB)r#dEoZVo{70%X)elwX-M!P*sP`(G`p(^b zacW0(mU_$!LP53qA9b5L@qX_y8wl|cmiNtdXc#U)T<|wTG+P1!=Wo8+#oxRh;ZlfX zPrPTo9zo|duzp*OQ;ah$leMOX8Xpg z$20~a<{E;qfr#sxP=txBd5!^EQ0?!8-z?1kiObFb1D^2#6!5o^1qd@_5FZ9DEURbP z1V)o==M*A^eCG)-LuMHTq8iL5XLAkK-v$vvj&kii4hDl)By;IxTGgInHf2r%dlRLc*{#R z53B*lYsCcdtv1OV+sBR|JN-ila1KQL_p0*=qGC3sL$L$(<7G=ZhJEq!_h5J*V0p$6 zY}kZ2T%U~}rkpJ48v`41EM{VB2$yWWnNiTu-_${9Pn~lJ5lNp^@u*}0z?6#)Ml0cSbPw6C1d^YzHyl$>k55VVy(vD z*q3a^&SP6UJ-|M|O8Ts4VrODYZQ>E};FmMSoX1}4vSAm2Y75d+XUpW=}xaVuIo(uebWiL%t;!jC+OljnPf!PhgF} z24R~B#{9UM*cMFR5;zb>?BN_K*s^LEkVWSpyYn8o5?P_hUnAor9<1b8kD4a(CFgmi zdpOtPc8|wD#$Bmi{JQB`Y!+gz>#qXyJNG?B!Yno%auS*0e7`T^TJh*?)G+=*NN547 z%RwEZHzmoH#taoc5VV6f3}JGta5#iWSUwg;Xb`qzOYOc|Z3(;)h&a&_h*(-RE90NP zgzmQRQvB!&!VDMHFhn5o{Ze|)pf#{53f_|PXAF^(XZ zjBkr|5+4kniJ&0NX4wiSNl9}G_xsx*g_~++C^6w|VGPmijAAFT2s}GTuFRYyy=_yF zf7^ywrnMR2*ljyWswX165J+n>IKpsSsLKmjG)Wpo7I;2OCx71Kn04~=KCi5kFCkEA zLcT?Q4nzYGcy^t^fZP}Xj7ab<0daE~AX$e2wK7g;URSLjp0RNRcN&+-l~B21+&Jz( zAV}vBwI)`qC-jh&>FRQy z-oX47-ruym0Br-G#wS|^pB^S)Pm)d-jC2&VX<>MhG*YlmuvI|G6_g3;1+9X|f+g=g zz6yR?iT5KNPdiN9(glYH9Dp;DKR;Of=Cb3)d0E?p7GXzf9|)ERg~7tulGSv0{!Kh$m$+F**nNFlwP98sxRItv+qK&MDJQOH zrsUA1(Cyc9>4B#8Ru?mc7E4P{XZ?3OC)ssv;XRM*qwzn+LLVfL@ynMw$uEHDbKU)H zM~PY0uN@ZuAM(Aglu~b5`n5$%(2Z9%zlu1RSGTI@@tTJ5)A2BQjRKLbu|GAu0s}f? zYGbyAHK@!{AIwi^B~LD68ZN3BYOTs};i?%MS}nD@)!{cyx_9cFp~|e3n+Ps^`lxi* zt%{b-Wd~Z8=RP8{w7L8`cuHScR%XCiBH!apR>FGRv%mL zs$%+U<~V)}y~pywmNoO>dc0zCd>=P@v@>ZRnNC_J!3n&Sq*YIc zS4_WR|F7+$OW;&28VQB$?{Au&k|}I|?@%$mJ!Ek*KbaG^9g`9(#2=|$9W3PFJG+vG zbb{_KK^Ok>brKN1-f;r_x~juzeLDqztakN~E+%QS1aIhiK?3|bSXdErL-p3m+j~MJMVhtARX|B0Yj59wy-~ zFDP1>WwA42c!ebN^FwY*rhr@f^qG_da$Hps6_r%9c2 zp~F_Q)PL2X?(5aDaf{S2ICt-8oo-SSr5idJ1kRI6^K&5SZCzf~6vevFt_U2Ll^PB+85 ziJdO})w!lsw{}Z&qHOFqL90&qSeDePyIyjnwixPl1mqfgkGeFQR^7&vrB!vUy7X4v zDh+!hfB3 z`QU@SZUY6ay24i7e%?O6gRQ!v2=lhmh`b}MIt#^|`qJjt8tJJAV#5(GG&`YcX;$T6 zCZ)mRNR}l|0g)76S}hdi3ZY_P`!l;>1@tKLl)~*$(SyATC*?125d_jdReVzTDF?Qf zbQ6?~N@zELjt#4oo0RPUaT_3|a*1lPYGC^)yDv%<5U@f6+Y9&-)nZk-%Dw0y|GEmw zSA7H!>NX{#gQ2B-jvBAtsCF+>bsko)QbUaZj<Y^%AXn(N%;< z>!mHwLheNkd{Z*IdyxwP)Yj3z^?$?io~B2zNDd(jChbe~*I{sJyyMaE=wZw44TPGm|( zcQ2YGs$@XMWOVnUX(CfHIv7e2x&BT@cQ3LNrE~qcPzl$)XpYE~jP73KAc9QE=#(`i zkue!PRRB@exQa~4=#({{BCP;rOh%`yaj_MD7Wj*ULkO;G#IE8!0J+tP)5Wp}0J;AM zZuV2fih;I2Zwl>GSR^>Z&N0EaLA(f zih2b!N*Nr2sxZloCVH$X6P*x6i2Iv~9*^MOVaSY`=&Sx_qOZpM%|uTyW}<)R(qxHi{$`@D z{iA-i-m=c5eqOePkoY$fef=Nx^V=3^QD}mznSRCf7H)G#VIEB zb6zna^=~Hn29d%`Av0#8|MNE!J?)S7xu$00AMNu%&8EMZ=$rp&pEE9}o3zh2FB7)> z%|ze&NBbOcSNt~FtzoaO*RZYmE(4+LiS5j(m>VlTviNcBEVJpc34C{c#zz)P!~X8t&SFbznN;|^ zf~AVQx&WFn5R~JOogrUAL zk%P&3p~wkSy({ z;H2X}(>zfFd-GX-75sZE{3>oLG;Harir8cPON!f(%+y!K>t+n>y~H1Lw|sKO*r(-R zk|1Z1vxu1_1K$QtY6cDM)(O#5M%RaCxKFA77}}p#-k)a|U5}|~XT}fg1>4o9?0gm? zIs*`IqXpSFo#%0aNxJZc=@tW0rm5Z~^b?S4a;=N_luvT4$A!LJXG@6# z?aQTYu8pmu?X9)iB4@R;X8%k}Wl4EkTIP@51HB{n$C9anzSFubO)aGf{9}Ba)JVH! zd|P43$(rL)e6NO|-S*dwwEJVIkHNLzMQJVTmxe=ufVi|%xb2*3^4@HNSA(eKL%f6x zTA|+dpU-N3%ldgUv!6W=V!ez>hQmWnJm0f6QnephGy2`qMFU|PPN))!gAxzrZus7a zKRJ#Es@wi+OjYKtulnAYRFE4#zD@A65kEhs7Dz4k<_@3Pb|D6e;)9%$SU8oF;JUv( z%*w8>owXFTgZ}8RidNossd*(KLpDbh$7&CK|D0oWDbA(P{7ceszBE2|{5ocGpDMf# zBE^jEt~tIuCLzwXKopn2N6g#0>P4x#_}M{n%dxn|#GfwMT2}4vgbe*u3MGE6Xs-oD zOpyRl?ZlBtq1e|H$#tT!=v3FkbKM&9sMHrp>N>MW$uBgWN#^4RSmxcS=Y_nCymlsN z4p{Rr+3furi~cT))MLDzL+`()x)w}B$tP#vnvniTNw9A!GtaBRsU~cfBWH78W-~iA z{JaQRHEA1qT2k~J-YehK?b#t|sWo8}8=32z*0~^bPs5tSo5M$K%*;SEn!PUmS=?uF z^b3&>I9Uj6Yrbh4QTXpy)z36&d!EnFNc0MRDyOA13fzvMIM&4Gf*N=J&CF!|s#S~C z8P2&x{@qko>h19O{w`?jxA&`fzxulnxNlRiyYFH?ThzUQ(LdhyTK3{_q)8An)o=QR z?v*$p?%IUiE$7ceskdrySkQ{HyCos+GdcpNn?T%*d(HN0=x3jmb;Ff+r5CAX7nkGq z=SC|4ifsQ;4mvI$Q8aEG0j8<7mHEy#@#^5SN< zvDQi)Cuwr?Ru$y(mAR?01-Z$4a|Mu4;%G5^Ty#bScu9rZerl(_f?j)Lb}>^udN9|w zMH|a3e|k0S(sL+A3-dx>n>68QmM-TU0q~}hA=YC=4xfa-_fI1??PB^s|{B?UTZEj@x)pay9PVEXCGBSoKUrJchp0&YhESd^ATpaaRWE~? z7tNQHJ$z}2ONzV+`yXqY4^1e8K55=}9MiD(z7vrRP}9Ux=plK^Hg7Nef0S-^-b}`l zTP4>X9$?!QL9R`rsiW$j{B7>%k7emtu4=|*&I(RpLD7!vwY^M6EpJ5 zgPp1s<<6&Ss>`c{t03s)`Eq6{q--r8yE4PRVbn2A+@gRmxd#LCx`W8K z_j82B+a!yuv!(Y{vvS6t_s}Dte8(kklCtJ;*1q4SpQwOMp=U2nz^2eMi=}pNoV(9@ zbvwPOtXMp~o#Je;OYM{EzwYJG2=huJ5MyUOrxDEG-->$49mwjkf=+jqU}Pe3vVZsV z_T+?7zo7Kxw-QDTE_xFP+oi_*n*IZ$B3ZCDX?JU3X6bQlgSPRy_KEhRc1VlX6ZB*! z@#s^()6cy0&=NgQpQM-R3-!nJ7xZ`Z&`aQKLc(j{neZMM_iOnOG!A6dc*0wksYqlN zjiB;E4BPWkQ~Db2g*W|UmpayhQlnO>XFU%?Q`JrfmMl5~owwEOp5FedV!Fm!X+~~C zfnz>!D9AO#X}Gqywq`FJlr84r^4weskCK=FR1(kPDEW)Nk<(N2$?1`=MLX)tq2Ba` z+xXOPO{1jgA{=p+9BL>Zh2D9pznsh8x{T+^bp1JgQZ|u8F=hq9AS;MWxfEFggWUmm zin_3ZYwSX~Z_nwn=OC`yN3>_(i+Lk$Yq^M4UuW}6@5POI6f@LWi+EAS0B@&=Ii%#I za+|a|2jQ}X+g4w*GGBeY7di4F0*BOG;;rhKqj zllNZ(WGS8~o-6JYT-nFae8^nh0mDb4$Z1Y#fpFbNaZgb+V;5vudc5V&3FXFz6+!o* ztUAvJDSRs)pE~P>1ILYHxsL(Ed@6&#j@us!Y7<9r};c$9pl z`t^>smM?qUI9LTlP@HyO*g~f}aF!}oE8fk5zU*=iKLj?fDSQV186qJVVaB6v4YVUk z__11_K`LG<@>;ww7VspF975f+&wta_dfYl-xUd@bdmcTs!f1LoxV;9&bVp zOtrE(>8XiR*%S52K150@XjjFQ4A#{9uwgn%js*ZRdKbtCk)< zvlR2v`MIN3Lep-Y(<3@6u+@)~gTI+DsBqb9vD4_cv#l*-=6iQ@pyY0R(rL;xGDIX( z$zkL;vcotx-|gf{{t*7*3GzGF#}CKCI`79X5e&T9uQjk6V-&1oChUD3L1ZQnXMf^= zUYwNz=0gRSUL7Im*s7vVUFdtHqn*_;(5~u}k;1nzR7#=fdy2uQ z2BK0qqT~8PLYfb%;%i<*rPRf8)lW*) z57}>B);Ba}#e>lEoQ0rU+-dSys+o-;e4Pd{f;w|#zqN(UAPZ61*TAYAj2P>KI#8R1 zz}mKlBA;;Ck4mjao=#bkkFhaqN-iEhqE|WZIob)&R%7Qyo^LX2+$IYEnMnSnb4$Nrz=?QlQx z!eqKxEfZ|ZCR1m=EUYtb%W`zU9+h&qwuA&?g7)DzL+|-Ez4c=RB5VC4vYUSB3q+Pu zg|{*d@dlAW>3nF92p@NkY(8eafehtzQH96q_G$KMpk?=E2ARPp zqZC_;W%ZSI=bjHeY&dMF?3>c&doRhI`NFs6>cUJlvYxa$ei5iXIiwjVK&03lW6s?C z>!8lX7~cn~J|L%qI;Tb^)t>28WzTf@0QuQ79UGaR7v?ZY-l2YwvjdZQ@}Q0exh{}6 z+B1ETm)o|~aBeo8=g3G_JR8I0=iWbyuD&Jn$0^bEVUUesPiLh8v8tpCBd`%<#O-;Z z2T$fTSHJ4B59q{SL6($CNuKBY-3I1FOjv46g6yX?Esnh>HG>io>tAd2{?|K6wgRwWHSyk zPBI!9_ZhDl$G$L7+{w$F?V0WoOnOiRlV;uPkid*(`H@4bVp%?}q0W4!rz_L7>PCsL zJCk&y!~@+(L!uj9Zj`L&N+R+^KWe}du#9_OohQ1*ea`*Ng#^|Dml*=LwUWoy6{=u? zZ17j&_IJNarLO&4)3HUsypd=bG8fLV^p~_}6zH#iS=d}6aQ#=-jfchwua+feb|v3g z*D2^1Ko;T&;yL1l;t(-cED~?qjL0b;IGE1rZ&y!b-G0^CO&R-SdVA$y(1U^0O2a(# zTZzm-dS7X%9Gv>ZKGP>B?+P~#&^(W+e2GW@p}YQ=i6urR1Wz3KhD-re=ok}|DUtO* z+%>4#G+wekrc`YSo$1?Vk?PUb_^p3TZReaWb6UT(*}E@h zee?2y9!&F8c!75~4H8hH>zUD{$Z0K3vZIciCCJR$eN35KWZvG~<9X+vPk`G5`yM+%V^8!TTg1iRyC_zPe|<~+?N zOBL(g0n+%94mg|!lDYm{hu64EZ@2%ry5X|B6fcdV!-%i*w2>u5+6x(Jr~8_TkIwW# zm%br-Z}%f4_rHC{CcbDIC;M_Acjap@baU`4Zhgm|hKciY21!I8B2+jl@j=l|_capY zYg{=o@d0Eu*o2!){6JhnJlHXN) zkAI7o47VK=?Sb;e<^Ra2`$=cSpaMz!X$wTvKyvHs;EGvU_y^9JKJs5Lw(T}XIF)|` zkNu|XE*M3jG_D4*nfCPCDLZfQLoaTZACN;;@=Nk9`9Tj3YxXEg6sHur=6o5o>(I28 z{|csQ?BTQPXI&ywwl3HEj+Hz^mw?+iLsfe7!=z)>n5Xv2|GbZ>RkMppQ*o%p2V~U9e2cz*88u~pKq64Ju33MAcjsZM9M`_z|T9DJF z?->*RV!AZuY+rLfJO`jjg$z>ItqtHa?6` zk&EUIJXwd(t)C~EuPTG|&>?aSSw+^6BlUyit@>O&vh1Tgld<1_LtO>qnCd1&@{G~L zfEie>E!UOnAN2sq2Ngu1%rOJlbpGX@<4XSAC)RAJ!wPH@4rsej`+AetH2QwiXGbaS zEQ)0{za1U0j@A6gv^~$|hZG7M4+b+Di`PLl@stg97ZQ#=Y6CXHfq1hGb&z%Pe=!^C zkjchpQ!nunF~k!miDlwKknP|lzaxGrhI++FxiKL9nEsC9j()uylF0Mr3Oa) z*)@PMc_n;jD}}xv)G*7hTtyhNj@OwTI_ZO~sft@gX;nT}eo+1dK@lZ*ATRY*g{$oS z{k4s`kmbN$YOb%giEhgyoI`9zK*tSo^j=#`aOcD)4R1R`5zy7K7tc1$x;g2&MbO~9 zn~yb@cJPa1ev&Cu@z~xUHWW%UA^#(pF8&>XzwRL`#+{J=%-OY-9R3`YjOP*d(=4r9 zHJ0P-o_9r(_KfCrs{n!i-p~Ak9o+FMM3XV2gPc7}7 zggI`|G<=zJbJDiXiMfrzorHqT_3;swo9l9f*eZPM8Jl9fS&Y3#j{mF9L(8oLL( zE#kH<^U+ldkB~6>?obZ@E!ov|FA*%)c?2=5gw@3AV)bCd4MBrc`?xU!hz)fc>bh81 z9-)~>=)q!3z?X&j?jSkAG3pQw0w`M(YbD+ zxgJir9v6B&%O;vTh31m-tPt)=8BTK-<+|PObqdILyU<%8#gYPsc}mUg(4DU)v%_SL zme!t9y4}@Xz2y5liaVh*h6?>zeS!Fy9vmC#u|K3qk^5w%(F*NknP>R70Q2D7z+83+ zXj%~|j?&7h$m4z1nDR4yOe&K)gj|X>Uy7yM__&wfJhhsznvlkVCf=W}nBtYw^f9Euef8C^d)bh)5@uFZ<{dX5c>6_r(Qi(;)TtPih4K-{DCb|@CF zw%!pW)9S9AK1_n5Z`Ffy@uQf>r{|zpv9IgrPUApdND{tphM&}dHN6jKcu)1cVxuC= zN3l*}Php8Dmem@kW@nqVY`8a-B2v5 zD5v?NVOzc|?~Va7Z>u_f)f2@^sc&9@Vx`V)YF>z9ZMfI$g<|dMytS*-8^ua{*Zfih zZJaUKJjrGgvSXa}W^@O>bQ_dDwPPtZ02zo_Pzv4L>eeB!5&LvZ5_(o274&?+}uQ zr3h;zHpkil>wxVog%0li)G<^F<$UWHUI$IuWBK}C9(3MpqBCLI#_5yqLy%5YtoZJC zx&RvA>78k#pEtu>AEFQVnxM}>h5jc6E>py8y{29d*+PxC_0QhhHkn;>zvf{%mhu1E zd+)d=vVZ^o%uGTR6RKDf5fxDkRd6i{)rL|8+o~iKK}A9pumOswYe5w32q?IA6j0Z) z8x_#?v$|NYtg8kP3r3d-RX~{Edjbp2F28%f<#8Y1f8?<*cjlQhXU_YaGiOelb1-6T z-92juYC5I&2D$s5tGzjl{uXt<@c}Aw7{7ojq1G5T*J^n8X@T!j(fld%r-pefXbgh+ z=qW93!xJkh&0!*rHYY9aH;#t49{)9`k>j4n;aR;gFy~F=X;^KX1II=YybZi1d6~TR zR&R`d;{Asgl~)aT0H5ON3KH{13#{G@auduGXl&1mgySLG1zCavd6xya)f;}f;H}`t zJR~%W9U??yg%@(C2)!j_eSkY+(T$I`}?=FH^q==eml;+tx+5a zm|B>j?RLn~|5n^vwWggOjd>`*BgSJB{J1xx0X|YS_CxdD>J`xIBrf#xt>G0U_@Okv zqi{H;;FjMrzYlPP#uw;Fc~UE>Z;e}lk93I?#lhk1f`igCQdmT_MqGg4Ehkk=@U6MC zaZJMG1kVKUbX7rk!uo`CfSU>~C7?SAf5KsUK}P~N)g%=>%_(qAotwH84$l^BOFf*5 z&cWf;f=8)uQk&uE*8(&kYfRSUEZ>^P1(K|&tc_V{@BXTS<5^d-?q==XUt3U{CBpLc z^Y`xmQZO#x>dpOMYq!#YT5 z+4f7|r2o{7wR_7rV&L6c(^qgZz5z}K>%)RbdTH6;O`x`(;4Oefk&98(b>TxH_%@>s_I@++pxWKXd(7}i zUIa%o6JhVSTsWA;z3uUbhXRf~`ug$xto^_@PhZ&kE#8l6_d4XKan|oT9C^R?YxGl> zQtd-$n@cB3XTgzAMCjfOm&d~+49V2I9O<_68hg{*xwbcu=lrzTX_VfuTTV&tKR5}D zM(nvBV3ii{zt;I3EVndeXoo}{?F@t%j4)2i?jR|3=V+E!0@Z?>M5pBx+z5|I%P|az zi5sLI>Ejfkbz|SsUkh#&+}sy(a9_xdp#*C8O$c4Zzb=Z~LG^pQT=G!ph9$f(O+3iD zFMJ=p{U#Z6U3kzpE+#EI^r!e}&W%mpCPp3F5VD;tONY=9uT34n)?ZwrvfMD2ypi82fnbciiingG5ey-E%t@ z{@A&8=upj;YOF9i`&^t;gfRPju|aHf;hM~~aU&+?Zw`A4UIK_NaL6?d$u?PL=&!*12sjLZdQn7Nj0l8^2DC zZY}UvN1CNat=t@Amd4MB?Fd34@r7^BNU~y1$REeudVDXJttff?WJF`}vpTs=RaQ*8 zsCHj)U;cY@^{D&70Thf*FNKw_!(LEOd5cDo$H`EXFcvLCQAq0;DLVKxJ>giwz7X{X zS7YWaZ~pSU;WQ+IpXKx5zm!{Z@!bcy+J-Q$E-M6rJ7k&JtsP*a3eD7Xj6aQxOvAk zUg4Xe*oj8%z64v)~b(I zi!i&S&_Dl0h&F;~=A7`{4 zkB+*M6CLx@?cC$%O`0IgQt0Vgd6hC0IrgVNQkTO5yrV<)%m@{TJC1ccUlW;$)!4ro~oq|n3iEK;Qr=oGFlT#W2bFODCXrHj0QXUz= zALbTmqV5!Ff;qFxbu%9#vt8`U!Z*6r1#u^`l}8R|f9MFkm~ob?GC;# z#34T5(C+Y&i$)|yK0VKWdOkW*EkZ5gd0p@i&o=s*CB8cDx181@6P`(*r&IO|E%e^HS&)t&LkE42XK){weUI1XfdL z70iX5+xCbZbV$2B;!GU zAh!A-UTbMpW@VQB^s_YQ5m~P5y!MN_$vaBe^?3>=R2M9dD%Wk!F-xQJ6Xj?>=MqQn zjlangPI|xhKaTJpi}7IW==|{PE2cMXKA+Lu$G&Vp8ChK%NUax4yCf=ETeB(T^!F)B z|KWaCdp^&;ih>q;`=gj#G8!GPyHP(EKC*pD)lwKIbBhQzTZa$2d^Ptx`@U+gq!wi* zjR;ttP$p^C56&2|^o#;kXJ#dhjo6pme`LeEtSz~k|LORYb~|_6t%obJ*WdW-@X!$= z(bb{KID<^hh><$y> z$;a4Jj}YvbE#clLEa8D%>3G~@$et*=6RnS3f3FKc7S`JeEq(7F*;t!=X58@#$5EDL zR-D%+{(|h+T7B$NhJ}3pAbQ#htzwUJ15%%Yki7T*<2Qi#YoYJgQ zoYDle0TVo5d&cUogqM0#k066tCmeQmOg(}{pXh&sy`B5_t}HX1b5Jg zAm`sXc?-+J%5L1AJ^14<=u{a8O2&1AKgxW|4CV1%pDShT| z4fv+vMNKKn5kXctdp>)gT%8EtUoSmL2LE0mnfiN0fY+aoA|Jjw+RVQuo_;~OLaRzz zMCw<@9wQe;--Mpp@S?ilBGNbL7c$DMN^+76`iVq0>LZ7zryfiFDfK_8W!65H9o31J z<9EDv*zr2)*V_wO5&68&Njj`n+I8P#oxK&I_W6eEJtvW{k5$jX!b zkyVdcp4gt`!}5WBU@jG3HI`zq)AB<7plglgrHxlVU;GZcj=3~fI_3MEp_*3Y&p*=l znj?-!b1|;+`me6|1|m8p$CI-&e1?vr8n!b?Co!+Tmv`f^JNbX+V^hU%*yk?8z06uREX2bL?K{1Q_iE@FJ9_2$gR(O+4SMDIsJG&-DHJb5^qiY3 zi*>ca>j-S}2;^O7Usl+7kHiH(myHnoP==O`x!;%sb9l$fq5rDnz98E`&>(Pl`D^ZH z9;Q5s@*=&JTEB_wj$k`%urFp&yXBtg<6bJYsG_172R=K!8VP%?OrCO(=7jg<+KD@2v(uh!R)I%9cHO zQu^hd)d84*TrF%8YIqFr7~@d@o2-8J_lWjr-VNJqw6zoKIJ-UaJTA?oJQn24^johx z2X~hcL`7Qo>vb#fX@{o2-L(=ooE^QAy>6u;wr(Y{YbCa8WtM-iABy+e>X+$vQTnU& zk>8ue6=@Z%eu{a!A_htiK3iURl;X@<;^n$EY##6aDV+Rqa#}^&UzLdZ%U!Zux?1W$ ziHCbrffQOvo#efio`%WX{S!tfG}LK0CHN#v;)vZPKAa^O$``F+4>+FM$M$qf{koMb z9)Z@aEY^dMh&Ycq?>H?SZ5|rT6Yv~)CNhoGSl$-iK_2=(O9u0AUh^V^>jaa9qXj5@ zm(!@ex8@3#3d&{G&`3k)1;v6fLUEa=P#bnUK3;}C%I=m031fv@ga;>wGPR;l;bojVr(ZDIUeXF&n z-2Q3$rOkwe8_Z5DxE|9H0B_)Gf7r-g5u>xSQaj@0F12eVW?g_dDJvy6T;; z?1w)}uiQ~Z?5||2J$a2CtvX!wuKEtFFqZ9mYF9+?3Hzqq1)1`YA#W#DKTF=3KJzWi zk_?9FR+&3zzJVQB&m_o$lZ--=_K5Q9`8FT3jB~Fy%#e+2m{Hp&|I%mEnf~@othVNH z&1y|`mXDvMutuW_cwZV#iv)51(nz8cnFo+G4S z`F)r+P$fKY;d;fX`?Zb&*&oa8I|kK>IZjA|pdz*$1*1qLrBDnCLxIS7Ss!j_A8w?1 z#i~D@&I$c7L?pgGUujPOq2uQ)PzS43{bs^jQY>Gpj4 zw4?dvuQ}&;Ul=GuFt0>5Gq6dyuqd@+S6J54F-H3j%6zeWnfYY-i@?MVXSG*m_dy+q^pG)D~2SFMb=ua{7TQhC!U|iMNxGZ5V=59Q!Y*C1xQQ@si&A%08wyvsyjt&CZk?b` z^{3G27T-o;qugzGfxB$6j9rWR)lLu`ll>%fla~ne<>)tb$avuGp6%H3QTVec+A+}jj?g&$ z#Q}cC<;)ofJ+0bali2qe{Ut2-$k06tcY8Iqnh)Q%vqZHm26YL(7KL$=W{Tbp0k$VD zUAIj1Md*0*iL7R{cb7 z6?K&FBH$~R!=I9p{kMfoDC6ll9f!hpQWAG})}YrGx4(0lYeOwY;dT&B%t-PTOIX?t0J z@3(h!F!7RJop#=*8^7zeBTcvD$msC!v4_vYK>er0)nN}_dafUGn@a zceMJ=b6}bHq&?6o)pNR?gl;G8z#Wqulgv$u(u&ej{juO-W_M-%$JWZ)oYk*qT50NU zFVS-{I8d?!_fPXr6PcTEeN+9<=A6xO@gDelNurr|3)X_!6%aRw8$Roc4s6v}!YY2> zo|`*c7i&Xv4@E*f6uEf7qDA91Jk1|Csb|l%KsF;E+SuH;{Upw?J(Xyoo^5Nuo%q1! ztn)(`H11TQ`J%J2FVKab&d1xw~<-Z;1{F;K@kN>nH`FMK)Q>P`PW3Fv)&%bLluY1N-cN0|BA zM~@xde8Za(UYN1_$Gy9_BPYgbyc%kEVX;G$a=5Q^e~~0KGAKNJMIWwjAkGa94-daq z74${qJ0?6l>N7w7izrBsJC~3At1I~G*#VzT43V^^bmuhggM`c>^_a>Z3xSDV; zVfzx@0PB2~=C!5-jU6?|au1GA4YW-`wz`>CvWYIU3*<%*KG^)#$o(wLw9}jE;x%Sa zbLNeH^DA7uTzoD4KBY=rKex5ZV7L#y64%tOqQJtsLm{EN9qWo*_Z-uxAKaA4Bh zLW9#mm~kZTe+9jc%1FV#`=Y_8wWE{!fFkqAQwvdG@ zilp_Yg@%HWBU<&Gg=coEigT?c;)-g^T8*69f-{E35vUcGI2htLo8#o?V6G0;Gs1w3IqeJiuN6>+_dOQ>7>;@PtrDcu)9h#RtJ`p}xoGSfN?M zcM-==9)I9OY3jNh<(6Fkaqk|rIkV!!c;RQ?`<%>5T)H`&|Dj@ON_g;x$Z*N63Vu_C z6svyMG$Kpy!iqDE`Ra2Ff_bTnZB0DOMoL~CU z$tfa28Xa!$rSH2TBIcRXtogGgXw*W#qvxcrDooXt@exs3i7zYtpL^FjI$iRLoaLQ+ zzOr(=SM-Z2cF@st0js=IW9~m4S|^ulDCNYP=`Df#0_G^`tx;VzQhUkmMD>x+FB))r zJ!gmQdylv^Rt--MT(B(+409c8um`DTR8@kSrT*wp^X;vl|9>UTf9vs;<^UCOdm zrbMOLKq^3LsF7i)v5VjD3UANZV?%95?5a;~-r0nbP@nQsD-W!??O(S2RKLlq5vqr8 zLN&xI9%wC&>{}DO+_p4O^dJM;xL z=BOysQBR$F^vXy++w6wziM{A}TI#5QH{A2?4!_^HcIdzx4M!W7Yer0Qq3gH_`A_SG zj=2vuBT8q8NaO@nl%p&>8|6MO&#iosce%V!&4AUfQZHt4xHx8o)>TVZq9^}=@!W(~Z)=Msi86O-tjEfu;u3kWWZe*eNTd}lX-&#N-2!N;>((uhio zJ>Uc0l7`<`Vlf4#H^u(7*tOwlj{li1(umQ;iPr`Xa0Ig+4Iaqs%m)l9=o3AE)>X^v z=T}7u4G(3SwYyGnN#3a-QW~iWq3GZ*mo0vwGGGQ5{Y3^9_p!aFSL8zJr{xu;JTEAsQ-n;RcZi|RlbkD?0#}Tdg6zG_U=JyL& z@Iczfa|-Oc+6S|LH`qQebOpra+7!^}8cbchp+BK7b zKU8O%*zc`Y-aHQNsR!I6Mbfw>*B`xq;gmk-CUi`k*d-pZX!X`aJ7kr}w{*Uq;0lY` z!3*Jag|CaU!Xh}^*7>?!ZAGJl^L3m36&A=D#f7wyvR<#u0O}VbWHkvHoero8E zB1dKE=bVzMv+s*S9_%6{5=+mt+0qVimKR?ih41lB^D-M0XzxWxSXaGjy~3V*+63H= z$j!Q##os8q|FH5DXRLF&SZo`Td@kOm6U5KfF0!t03**#9l!M*aN?vOofV{uf^>xwHw8IGK~7bW)8J&ff}Eis-4*0aIGLp&Jrty; zg7ktDZv{D9LHfWE{5MBI&Q*}}6y$t3S)d@lSC9)8u#Q=<7}jGzN^WRB?dXB@*J4`?gM z5-MdPVKI|HB`}{IIa}Z?zr`|KIg3DAkeH~ZZUUNz`-;bMHbxxMPXHFemF1_Q7qtkbOSf7x9}BKUta z-yUy+fO^9*t^boh5nNOa{=`5yX2Ef%KZa8wW54WRy`YRZW__7w|5d15!H3h}+ayl{ z_3icz4*oa)XnzI`wZ~^L{P8tZkW?N0h>G9We`#${)*A-kP_mrVL_2lZ>bdF_Z86x}#*lXn zjf8?Ug``71#_$aHk$-uHJ%eAcm-w>x^}Akw&V7vgx(y>JzQ|3Lmni>{BDd&Uua&iN z6Mqpp7|PtVI(M|p6;3xYDBuu!Uiy86>bjeF9qI`bfmmx0_c68wQ`bGGhn>_b)Mpu> ztLS>E5kfnmOl!k%ZGF|}lKFwwmxUh&-)S?xEL64MAL^JXhG<9m+6;YTHR83wR6)St z(TMk!eNe+VjjwO5c5Jf+DLi12YUcSx6F%8Gsi&=XPLE~u5@T7!XmiE<`Dz^}_1f?O z=k(YwP1rHd(7RC|lr2tW#wT@Qi#)AGUzc2o*c86>Y|gnRV}SntyYvy8+*g+&zf3%eRbWbZ<@wCCL6lCAZ=aG z8QO604D+1P#&&ht*=prECDv-NYl^vzx~?sH;G(X(!Roa~qlda*e^~5|HOcRNeb{2w zR3TlVT{p>~zv~O96J^GY$89cImH2wTA5mmm;_E+ze1_~_;(lVI5onsPXOz-X9!Y;0 zDd)~a?e2PF7wB)0ptZq$#S*jvjWzc_UTXQX!_U@uvGuH%7@-gw8U{J>#Q|vfSrdOL zit+Uf)Dt`YzFZuLEP}*yyu=#K0_1E2{!Bu0Yh;P6pxBJ}dC#>8==)tT=euBTvGwK; zN>4|1UGmMc=Wr5Yz^a)cVqIo+3MW(@O<55J#}4ecg6ykdJiy1?=56C_ zrDa60ILO!2H9%>pHAFljN?mu5MeOmx(;khGe@TD+dEVVvmK<^K-Mgoz%N^;nMO;%? z@%@mY1KE~u8+B^Vvo$rItku?=1xA)Yr5MTKm;7+qdr~B3LA{?l7ERSTB?m{dQUS%kae8!(Iw1 zgao^T5N4jgH%wdi>9G1?n}5D2!DaD-?R7vP2o=se zXN?9WhVPw^-`3Y#kNfWwzfPB&G5N(t(|w3IOlj%7EJz$0B!*Y+sz1{ubH+r8wHB7n zRa!1J5l4h@#bKo#)`Ymv!qOYwK}#0j5Lty6o222IGsN75r9P(qnv!t7*fDZX@@}!T zq||jrjGs1l)iAEH7B-M1$?1u8O^JyH4^|_`)dpw%rc|y<7xEv=qIeC?zw51M&-e{N z<+EytI5hZrVA+^ROspjim7}!q;$N+1iM40*!ZRhy#n4j`B|q_q<#0|O_vg)%}_H z{+Ne6P|lLu721-Wx6f7exkzu|P@5r!FE@3>oM(Te50=DL25`koV*|sB$DQ0Cp#SWT znSB4SA>t)YL&O1mu}S+t!@;g??`3n|?$%_z-AjHy@b}>nc7t8)Fz0a?R?zgo1pm1} z)57&iect-gy1exdOit#lXFYFHd)}n}yh-Ea^Cqq5P1?_!`aEyaF@N6FSKE-#G9pUr zOd~NHZ?$sA*!ygK^BgehK3|aglTL{y?`QoBTPCin;HKy$p&t%S-XvJc-&%m8Ut4S~ zz%+#jZCz=`t!K}_$l|>jNglp1iZ{Uk&4`&k#Q#D7FNXJPzcdIis_$C>ds{u>r5Wm9 zsOK!?p+SN~o?I-lGmEg!|8AXcK6l%JfQWzyhxLc*Or7)&jyKjzI%Sz+;3T@0#!lLA z!*Vk0JHc|WLv+%Nm@(0kJYRRdIEw2ZbpB>^q&1I^zEE1qieq!nq?X817az}AeBAnh z;*!~PD&6M&qp)fb%6RXvkzI1`QK4W7zjYGJwd4^>yqPYc3e?f6sk$!Kk&T%40+o|h&(DtwT7E3$f3&6fTec_Wdf?<*(C z1(<|zSbWTOUt(> z`9u~^waWUG4JkvGWlm*2Wh>=zWj~Z1DmzQBb+fFtx~vISx)~rJBcCiso^pTrrqmSq zKKV&`mHc-(dYM%xx2-j*HLJDAcZZ!6kYE1#+Vt9EuxI0cYG2g;Rf`a%N10ONsHqe^ zCukkT-$@;5KQi=U{o{++)YYv3;gS=)_zgF{h~(uMJ+hdZok;4 z{i06$#lAH`Y+}$J;(fs~BIZ^+XDbI~awaC+;5_2I;mn3rRAU7wnJ46}jvXm4;mwez z@uV-%#uz%Rb^?;eFMli_FGnqMp}<(4BzLUMlkXRt5}=<2Wr9jUy?`z3Cmbc5AVf32 zGjI@kH@fFaEnLhvTKfh zh+cNBhNoI~&5s@&LY*^^`b$TLoxb2Atr2_!n4)CCN z%Gwq;*!jlc1avOpW=6(co-J!Hn`&&WrmQfYotezP<${}L?r z`e#1+luzaB%7)48WK(4GWy@vBYh|gIhiwyO$aS0b}=}$6S|Flc%q1JCTWI6MBEdtVH1%e1#|s zPYgZc`7$D4RV{8U-)V(x(T--cO!rRhrLtfHJ;QxDFLF=`_n6UN(@(iiA7o&=VVh&% zK!~2clZ@2hwV=5y+&W=Sua=fdefLqq&(^)=M}~Jvraz8 z1b3dDc#T5-Tcg?^2@dx2d$>STBs=JPU1Vh#?woYRsqg96iOY1O zypHLP81voGf_tG}!qk7yn`!rFJFDBXc8NkcDkH#mvhlAMbR zuzh*IXj|&t(-?C^mz!%4Rj&mLFBcr__dxfL9YhND#1Uzu>mmAX7KXyNlX;%~@9)bC zi#i~epc8p83RtA~hLH!yT} zD~2ASJ3z(^^1}x}%U2(coe;eAkinHhL@~4kSHiI;bPgfp4rD&G!a51<&zfu3@JB#~ z=s@cW&O85nq1p>=GiX1Vy{|VM1dXQ`6g0c&hF1m#Evk179`70~FqfMna9>AkI8mqc zg%2b6ACyaUD%vdAACw^`8W<*^TV4v1CI2!CD<6ebwOo7sd9D%ei`Q9Tn)y1f+A*G* z#`nkw`f2)Dur)>_mwZfDk2{#nGyI?o9>L1a$4+6#S#x=3w4uQ=TFVIcY*MOiGbqM+ z+=F`F7P!_igTZ*wbq$UYe$|KnzMd39r4-{9;}>-;*f$L%#q5Uz2eTg!C?3@QNKe}w z!^CEdy3vNk>>(p?FAGej#p=(tz^9tCMq!SeB*7+=#3p5i#d*$7Se&egQ`ve@>-A?> zBiw5NZ-meRwy(hu%)20iAT1mb6{%`!gd#Z~mLUmiAp?+H3Inb|6gd+uo&AE6f1$<^ zH9`Tq854?ap)IJ!V&mQz%M_zMVS^{L5fu-u6n~gFmlOJe(&LzN#&HrqDA^Pn!!dO= zoQ;T$$D#BmmZcLgX<6`)vH{IHRPq2m`+v>xYW2T@a(YNqzC z0WMPTzMcBDuz)#`TFxO z4s2YTjkCNEjuD*}c7~G*f&0aPl@Uw-cF(G8T|@iabpe5Yb-_&JM+YvrnS>0rP33=L zMVrbs#bOg|oFJgDtmg(kD1n|Q5R4!+6ID@2AW>y&J^4$w|J?zaqKY_q5V#L)A>)w} zuAw82GDnqi9HHwP0yc(Ge1y#SklVFcJ-MB>#TyNlG?Ob4*g@YY6%h!h?*uoJcA4H~ z2z?_++YpH0FckB5+S0edp=#E78$Q)_o39@#`Zn%}2Or>}kY^74tR1r*@Lm>Wt5y9|)Ng+i7A;-d##)n=u$U(84S(iX4sjjL8b4Boc zX%qhpnIlT*Dl@(^slvH74qexTm_wpEOcZB|aUg)UtK@>dR5a1~E6hhuc#!{p= z%9OUia{v#)%MJ?SxWbVR&tIwl(c!@;_K)FA}_iG^HQ=)$-Nt z&~uxp@veb_MX^;m!LQ3AC}xZiLhI;%{_!^$eC+-2Dd6g0dwjDWf#_aDCqxsU5PSR{ zkg?sQ1V|f@;oZb`sXfkz@%+i%Bp1kHAU55^V3|Fh2E?wLBm=nx1V(qd?$rQ9M?#?Q zx=G-2dwdEI`)*PWWE~L4ZsHPZkIR5qc9S9?wLq-8iRlUmq5s!zU{grklR;Qv_IM(Y z3Efvk1Gx&M$M$L+x>Ilp^m#6&2UXy>Q4i+&!JJwc zEl3E0{$VK!ctJMuRnQRy&|RWSVPH$rQU^V>uoV+@WMOvT!bIg_3iy!_r5Y`WY$jpM z#tpuagI-@9NgMQ7cFt~u`7_8*)kD{HkuTlR=??dzCzUnBcXjj?K8P0&OGO2N*CSM3 zub_toRzgp(6nX&XLT_?A>D*3+X(Rg}1ifbn!KQ=I``zg~-2>MMvk}1(#&zxC81(VR z!@Xjm`&t_;kJLs9;i{pL0E&FPLDX-#YbNQTkx(>uDOyF5(FB5?<+*(1*iJ_3s2rQA9J_#- z(2-3~&|8WU0uU@>sd5>Hf-n@VjvzE&n`aB=(er@+jzPM&_UrR;wE066Buwz_3M3sw z2_1PskXZ2;4rxH=lO6{i5HZW>Tm+zS z5G*!Og@gWyQvC!8iG@P|7?)W8|6c+>F)yJ_lK*WIQV&%>4D(_Jrsf~i@;-&Gw z2%8u3ivjaPF$CXMclj&&Uo>S=C>w{nY13B^hRZuc^_}W!MyPtRjF0Aa22>L*(L_35 zhm)Bc6eI`4p%;1_1EY#<L`#RU66#0FiCgp&4sXZ8R~`}L(vu6PR?qs zqu+q40K(02`V)z-U!>}t zAR3}jb2O5)gQY=84ka-P*X)W4jsK=xw1!~AGXr<+^3D;GIvTaZ3x&>U%W3a|P#i_N zB6}E$r6BQP0J{4XK@ZJ+eNGQ)eSJ<3mC@A+@SlFGBy_&^E#am;P_BZi5}*fmxuk>l zFKE*nwCxSjwUU2bKCU-t-y3x34UYdegz4)5At!^GkmKmgNl#vgLG1x;Was-w$5WMZ zooVk(KgdDwWY85UIsJO_?9F^@)QhFos25AEQ7@KSqh2hvM!i^Sje4;ZHuL?rr8X){ z{}H7&s<-REAT#Y$sch4mnKr#yWYe2PHoaM7)0;&$y;)?_n?<(0S!COrMYf1(kt&PY z{v(Z4X4>{{?jLESGILySW{&I4 zqH(=hG_E&`?0d7wzBh~Pd&_n9y;)@6n??5jut;Sle3#0II+dCBy_sp>n??4$S>({0 zMGn1Llj;_9h#{D&+70|pSCPQFb zIpCY>Tj-cMHb}e^dJX{BH^`=$OvHLjHtGFI`uRhCB3wI}mhphR%Dl0nzzP z)#1_^K)R--s$9~k*%fv=%DNgx|A^JjBBa-JX*X+!_8MJ3<^@2U(&-0P=&tlz^mk_D zeX))Y>Ydf4&c2g>c=T27ZHC~xb1{`dju z@#i$Skpdaf?WW<_ej)>iSvT1SSN+Vm$|t-Xy9dO%+s$ck!(H{Y&*k7VAIQjVH_uMA zV^e^Dv0dR|oovS>K>Bx++|m1qRX~PxlQHn|!9F1L1j9}%On=-@lmapDCM9t9S|B}k zJp)29$VVWY)nB_|;RgsFkfGiFi~%A7V%kmk5W+wpJs~WC5UvF>xZBM{aC3m+#s~Z< z1kz)>4}|$Ske)CngB#Ww0`a>2sRo~i0qL>5ESU*`nYiT#8Q zkRH2iflL6>W0xuTBLUKr?#XbkH9&eocpAu2AYa)9%^!3wZ z48)p2#sG0*kU@}Jyn*!O7F!^}4B`%C4TA&%Nn?;?AjcTw5Rj`3QUv5agWLu3hC!-< zv@!^5Q~<$Q|8)ol0WoC|7V7{p9!O7`xGss;aEeui(r0<5Wtzel45W^T`5D*6ju>~@dLEM4(Ge{tiSO!T3vW-Cw z0m)&IA|MwT7 z1}OrvfI;p8kupd%kYom7Sp*RK8DtQUvkYPjq?ke6fjnc7Kp>wOBpC>v^0i%ufb?UK zA|PWJSs!fs`}IAs{sjQUs)f zLGA+4-}JSm)j-S`ge3?dCNan$Al?jO3nZ99+<~lN5I(${(tz~5yIr89JprVr{u2mS zU1nT05w7|jNKfr+9$fVv2t6R(S-Y4AZkiZwl7VnHe|=RTly&Andg?97aIa}VjJn?r z$>7G1;U*WzIv|6(-4tCvL>vG@53f3^YOrIVTs;h=r@ra~q!>ug+sYK)gCBsF~BP+Vb^P*ACweAdeWN2>kgANKYKz1;YB_Yf=ql0E4iuw_}z} zVzHla1Jd&*3WZb-1k#f?Sf|^uXdpe|DF;haf%L=%AKdI_xG8~HJqx6#p3nf~34@rP z+)s2c$Z1HO5nI1b9a9M5R3JTdn-_5RARs+=FNdp^GOl8=4-i{{^yG~(K+XX%?T-0C zXepEf>8WS>fE!}l*KSic2ZIa(f^Yvi_nHDxV~{aGv>3z|NM8n-2t~|N`TB^kh?$@Fi1I&#SHQSh(Ci=16jf#AAv0ECQ#t1damg{RJyN? zE~nTaHIO<;14Ivg)9*-a5Z!w~&yJwq^BfTUCeQ`xf%HN2yNhm-(eIvqAi7>bw|nWD z0{xDl-`R9|NxxI*w;CTrzX9nIlWzOcB`{qs)9p_BO-;Wc=$1X*njQ@r1EO2IbW4>k zo9R|0{b?#aJ&o?mq9$Uas|18 zrhuk`rh%q|VAXNeG=`b*|5+dpkSE9s4XeTHQvPTO&^yq3Pz~qClB9@GG81T}%0L7zb_pjJ>D=nJSF)B&PE zs)rx`=WFz)36>#+X*@bG05GA~)kI;%%l~#A(`%HgJ%0Qsfpl9{tBIETEygc@y_%@6 z5iBaInxv!#i;2K|8ZG)>!=t;_N@dfZ^Vi@!)(0g7C)v?nhU?}+l^8smY=MW~Fv5r1 zBNL462)=M(*-CgaG1`otKTgl#|Im>L{B^mu2rmXRXTh=e|ImH@&%G7Fr7TzgbtFWc zJsfw2khy>=^X&gkOu9nY`an!>%lp4us1>~VANr$1I1ys<03(E}OJMX5^4(AMWa_py zwfFNq5g2BDP(@(94E;m{4Z=t|9T-j~E&h$E&Fu3Tt~dzSCM%g7;3E`8-B6lhC#JsTr2WvL$FBoHl7i__)e}V-$Tzup>*aS&qGs(ONRar NrQ("SELECT COUNT(*) FROM dbo.TagPosts").First(); - NumPosts = db.Posts.Count(); - NumTags = db.Tags.Count(); - } - - public void CheckSnapShot(SampleWebAppDb db, int postsChange = 0, int postTagLinkChange = 0, int blogsChange = 0, int tagsChange = 0) - { - var newSnap = new DbSnapShot(db); - - newSnap.NumPosts.ShouldEqual(NumPosts + postsChange, "posts wrong"); - newSnap.NumPostTagLinks.ShouldEqual(NumPostTagLinks + postTagLinkChange, "posttaglinks wrong"); - newSnap.NumBlogs.ShouldEqual(NumBlogs + blogsChange, "blogs wrong"); - newSnap.NumTags.ShouldEqual(NumTags + tagsChange, "tags wrong"); - } - - } -} diff --git a/Tests/Helpers/DummyIDbContextWithValidation.cs b/Tests/Helpers/DummyIDbContextWithValidation.cs deleted file mode 100644 index dd1544c..0000000 --- a/Tests/Helpers/DummyIDbContextWithValidation.cs +++ /dev/null @@ -1,85 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: DummyIDbContextWithValidation.cs -// Date Created: 2014/06/26 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Data.Entity.Validation; -using System.Threading.Tasks; -using GenericServices; -using GenericServices.Core; - -namespace Tests.Helpers -{ - public class DummyIDbContextWithValidation : IGenericServicesDbContext - { - - public bool SaveChangesWithValidationCalled { get; private set; } - - - public DbSet Set() where TEntity : class - { - throw new NotImplementedException(); - } - - public DbSet Set(Type entityType) - { - throw new NotImplementedException(); - } - - public int SaveChanges() - { - SaveChangesWithValidationCalled = true; - return 1; - } - - public async Task SaveChangesAsync() - { - SaveChangesWithValidationCalled = true; - return 1; - } - - public IEnumerable GetValidationErrors() - { - throw new NotImplementedException(); - } - - public DbEntityEntry Entry(TEntity entity) where TEntity : class - { - throw new NotImplementedException(); - } - - public DbEntityEntry Entry(object entity) - { - throw new NotImplementedException(); - } - - public void Dispose() - { - } - } -} diff --git a/Tests/Helpers/ExtendAsserts.cs b/Tests/Helpers/ExtendAsserts.cs deleted file mode 100644 index 8e85c05..0000000 --- a/Tests/Helpers/ExtendAsserts.cs +++ /dev/null @@ -1,111 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: ExtendAsserts.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Collections.Generic; -using System.Linq; -using System.ComponentModel.DataAnnotations; -using NUnit.Framework; - -namespace Tests.Helpers -{ - internal static class ExtendAsserts - { - internal static void ShouldEqual(this string actualValue, string expectedValue, string errorMessage = null) - { - Assert.AreEqual(expectedValue, actualValue, errorMessage); - } - - internal static void ShouldStartWith(this string actualValue, string expectedValue, string errorMessage = null) - { - StringAssert.StartsWith(expectedValue, actualValue, errorMessage); - } - - internal static void ShouldEndWith(this string actualValue, string expectedValue, string errorMessage = null) - { - StringAssert.EndsWith(expectedValue, actualValue, errorMessage); - } - - internal static void ShouldContain(this string actualValue, string expectedValue, string errorMessage = null) - { - StringAssert.Contains(expectedValue, actualValue, errorMessage); - } - - internal static void ShouldNotEqual(this string actualValue, string expectedValue, string errorMessage = null) - { - Assert.True(expectedValue != actualValue, errorMessage); - } - - internal static void ShouldEqualWithTolerance(this float actualValue, double expectedValue, double tolerance, string errorMessage = null) - { - Assert.AreEqual(expectedValue, actualValue, tolerance, errorMessage); - } - - internal static void ShouldEqualWithTolerance(this long actualValue, long expectedValue, int tolerance, string errorMessage = null) - { - Assert.AreEqual(expectedValue, actualValue, tolerance, errorMessage); - } - - internal static void ShouldEqualWithTolerance(this double actualValue, double expectedValue, double tolerance, string errorMessage = null) - { - Assert.AreEqual(expectedValue, actualValue, tolerance, errorMessage); - } - - internal static void ShouldEqualWithTolerance(this int actualValue, int expectedValue, int tolerance, string errorMessage = null) - { - Assert.AreEqual(expectedValue, actualValue, tolerance, errorMessage); - } - - internal static void ShouldEqual( this T actualValue, T expectedValue, string errorMessage = null) - { - Assert.AreEqual(expectedValue, actualValue, errorMessage); - } - - internal static void ShouldEqual(this T actualValue, T expectedValue, IEnumerable errorMessages) - { - Assert.AreEqual(expectedValue, actualValue, string.Join("\n", errorMessages)); - } - - internal static void ShouldEqual(this T actualValue, T expectedValue, IEnumerable validationResults) - { - Assert.AreEqual(expectedValue, actualValue, string.Join("\n", validationResults.Select( x => x.ErrorMessage))); - } - - internal static void ShouldNotEqual(this T actualValue, T unexpectedValue, string errorMessage = null) - { - Assert.AreNotEqual(unexpectedValue, actualValue); - } - - internal static void ShouldNotEqualNull(this T actualValue, string errorMessage = null) where T : class - { - Assert.NotNull( actualValue); - } - - internal static void IsA(this object actualValue, string errorMessage = null) - { - Assert.True(actualValue.GetType() == typeof(T)); - } - } -} diff --git a/Tests/Helpers/JsonHelper.cs b/Tests/Helpers/JsonHelper.cs deleted file mode 100644 index 2bf617f..0000000 --- a/Tests/Helpers/JsonHelper.cs +++ /dev/null @@ -1,129 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: JsonHelper.cs -// Date Created: 2014/05/31 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.ComponentModel.DataAnnotations; -using System.Linq.Expressions; -using System.Reflection; -using System.Web.Helpers; -using Newtonsoft.Json; -using NUnit.Framework; - -namespace Tests.Helpers -{ - static class JsonHelper - { - - //public static string SerialiseToJsonUsingJsonNet(this object data) - //{ - // JsonConvert.SerializeObject(data); - // - //} - - //public static string SerialiseToJsonIndentedUsingJsonNet(this object data) - //{ - // return JsonConvert.SerializeObject(data, Formatting.Indented); - //} - - public static string SerialiseToJson(this object data) - { - return Json.Encode(data); - } - - public static string AssertJsonPropertyPresentAndReturnValue - (this string jsonString, - TSource source, Expression> propertyLambda) - { - return jsonString.AssertJsonPropertyInOrOutAndReturnValue(source, propertyLambda, false); - } - - public static void AssertJsonPropertyNotPresent - (this string jsonString, - TSource source, Expression> propertyLambda) - { - jsonString.AssertJsonPropertyInOrOutAndReturnValue(source, propertyLambda, true); - } - - //----------------------------------------------------------------- - - private static string AssertJsonPropertyInOrOutAndReturnValue - (this string jsonString, - TSource source, Expression> propertyLambda, - bool doesNotContain) - { - - var stringToFind = string.Format("\"{0}\":", source.GetPropertyInfo(propertyLambda).Name); - var startIndex = jsonString.IndexOf(stringToFind, StringComparison.InvariantCultureIgnoreCase); - if (doesNotContain) - { - if (startIndex == -1) return null; //all good - Assert.Fail("The property '{0}' should NOT be in the in json string", stringToFind); - } - - //otherwise we expect it to be in - if (startIndex == -1) - Assert.Fail("Looked for '{0}' in json and could not find it", stringToFind); - - //now return value after it - - var closingIndex = jsonString.IndexOf('\n', startIndex + 1); - if (closingIndex == -1) - throw new ValidationException("This only works on indented json, and this doesn't seem to be indented"); - - var result = jsonString.Substring(startIndex + stringToFind.Length, closingIndex - startIndex - stringToFind.Length).Trim(); - return result.EndsWith(",") ? result.Substring(0, result.Length - 1).Trim() : result; - } - - public static PropertyInfo GetPropertyInfo( - this TSource source, - Expression> propertyLambda) - { - Type type = typeof(TSource); - - MemberExpression member = propertyLambda.Body as MemberExpression; - if (member == null) - throw new ArgumentException(string.Format( - "Expression '{0}' refers to a method, not a property.", - propertyLambda.ToString())); - - PropertyInfo propInfo = member.Member as PropertyInfo; - if (propInfo == null) - throw new ArgumentException(string.Format( - "Expression '{0}' refers to a field, not a property.", - propertyLambda.ToString())); - - if (type != propInfo.ReflectedType && - !type.IsSubclassOf(propInfo.ReflectedType)) - throw new ArgumentException(string.Format( - "Expresion '{0}' refers to a property that is not from type {1}.", - propertyLambda.ToString(), - type)); - - return propInfo; - } - - } -} diff --git a/Tests/Helpers/ModelStateTester.cs b/Tests/Helpers/ModelStateTester.cs deleted file mode 100644 index 8f3068b..0000000 --- a/Tests/Helpers/ModelStateTester.cs +++ /dev/null @@ -1,102 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: ModelStateTester.cs -// Date Created: 2014/06/10 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel.DataAnnotations; -using System.Globalization; -using System.Web.Mvc; - -namespace Tests.Helpers -{ - static class ModelStateTester - { - - public class TestModel : IValidatableObject - { - [MinLength(2)] - [Required] - public string MyString { get; set; } - - [Range(0,100)] - public int MyInt { get; set; } - - public bool CreateValidationError { get; set; } - - public IEnumerable Validate(ValidationContext validationContext) - { - if (CreateValidationError) - yield return new ValidationResult("This is a top level error caused by CreateValidationError being set."); - - if (MyInt == 50) - yield return new ValidationResult("This is a top level error caused by MyInt having value 50."); - } - - public TestModel() - { - } - - public TestModel(string myString, int myInt, bool createValidationError) - { - MyString = myString; - MyInt = myInt; - CreateValidationError = createValidationError; - } - } - - - private class TestController : Controller - { - public ActionResult ValidDateTestModel(TestModel model) - { - // ReSharper disable once Mvc.ViewNotResolved - return View(model); - } - } - - public static ModelStateDictionary ReturnModelState(this TestModel model) - { - var testController = new TestController(); - - var modelBinder = new ModelBindingContext() - { - ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType( - () => model, model.GetType()), - ValueProvider = new NameValueCollectionValueProvider( - new NameValueCollection(), CultureInfo.InvariantCulture) - }; - var binder = new DefaultModelBinder().BindModel( - new ControllerContext(), modelBinder); - testController.ModelState.Clear(); - testController.ModelState.Merge(modelBinder.ModelState); - - var viewResult = (ViewResult) testController.ValidDateTestModel(model); - return viewResult.ViewData.ModelState; - } - - - } -} diff --git a/Tests/Helpers/SimpleTagDto.cs b/Tests/Helpers/SimpleTagDto.cs deleted file mode 100644 index 62d4dc8..0000000 --- a/Tests/Helpers/SimpleTagDto.cs +++ /dev/null @@ -1,56 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: SimpleTagDto.cs -// Date Created: 2014/06/26 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.ComponentModel.DataAnnotations; -using DataLayer.DataClasses.Concrete; -using GenericServices.Core; - -namespace Tests.Helpers -{ - class SimpleTagDto : InstrumentedEfGenericDto - { - - [Key] - public int TagId { get; set; } - - [MaxLength(64)] - [Required] - [RegularExpression(@"\w*", ErrorMessage = "The slug must not contain spaces or non-alphanumeric characters.")] - public string Slug { get; set; } - - [MaxLength(128)] - [Required] - public string Name { get; set; } - - //-------------------------------------- - - protected internal override CrudFunctions SupportedFunctions - { - get { return CrudFunctions.AllCrud; } - } - - } -} diff --git a/Tests/Helpers/SimpleTagDtoAsync.cs b/Tests/Helpers/SimpleTagDtoAsync.cs deleted file mode 100644 index 60256b4..0000000 --- a/Tests/Helpers/SimpleTagDtoAsync.cs +++ /dev/null @@ -1,59 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: SimpleTagDtoAsync.cs -// Date Created: 2014/06/26 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.ComponentModel.DataAnnotations; -using DataLayer.DataClasses.Concrete; -using GenericServices.Core; - -namespace Tests.Helpers -{ - class SimpleTagDtoAsync : InstrumentedEfGenericDtoAsync - { - - - [Key] - public int TagId { get; set; } - - [MaxLength(64)] - [Required] - [RegularExpression(@"\w*", ErrorMessage = "The slug must not contain spaces or non-alphanumeric characters.")] - public string Slug { get; set; } - - [MaxLength(128)] - [Required] - public string Name { get; set; } - - - //-------------------------------------- - - - protected internal override CrudFunctions SupportedFunctions - { - get { return CrudFunctions.AllCrud; } - } - - } -} diff --git a/Tests/Helpers/TestFileHelpers.cs b/Tests/Helpers/TestFileHelpers.cs deleted file mode 100644 index bb2080b..0000000 --- a/Tests/Helpers/TestFileHelpers.cs +++ /dev/null @@ -1,108 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: TestFileHelpers.cs -// Date Created: 2014/06/27 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.IO; - -namespace Tests.Helpers -{ - internal static class TestFileHelpers - { - private const string TestFileDirectoryName = @"\TestData"; - - //------------------------------------------------------------------- - - internal static string GetTestFileFilePath(string searchPattern) - { - string[] fileList = GetTestFileFilesOfGivenName(searchPattern); - - if (fileList.Length != 1) - throw new Exception(string.Format("GetTestFileFilePath: The searchString {0} found {1} file. Either not there or ambiguous", - searchPattern, fileList.Length)); - - return fileList[0]; - } - - internal static string GetTestFileContent(string searchPattern) - { - var filePath = GetTestFileFilePath(searchPattern); - return File.ReadAllText(filePath); - } - - internal static string[] GetTestFileFilesOfGivenName(string searchPattern = "") - { - var directory = GetTestDataFileDirectory(); - if (searchPattern.Contains(@"\")) - { - //Has subdirectory in search pattern, so change directory - directory = Path.Combine(directory, searchPattern.Substring(0, searchPattern.LastIndexOf('\\'))); - searchPattern = searchPattern.Substring(searchPattern.LastIndexOf('\\')+1); - } - - string[] fileList = Directory.GetFiles(directory, searchPattern); - - return fileList; - } - - - //------------------------------------------------------------------------------ - - public static string GetTestDataFileDirectory(string alternateTestDir = TestFileDirectoryName) - { - string pathToManipulate = Environment.CurrentDirectory; - const string debugEnding = @"\bin\debug"; - const string releaseEnding = @"\bin\release"; - - if (pathToManipulate.EndsWith(debugEnding, StringComparison.InvariantCultureIgnoreCase)) - return pathToManipulate.Substring(0, pathToManipulate.Length - debugEnding.Length) + alternateTestDir; - if (pathToManipulate.EndsWith(releaseEnding, StringComparison.InvariantCultureIgnoreCase)) - return pathToManipulate.Substring(0, pathToManipulate.Length - releaseEnding.Length) + alternateTestDir; - - throw new Exception("bad news guys. Not the expected path"); - - } - - public static string GetSolutionDirectory() - { - string pathToManipulate = Environment.CurrentDirectory; - const string debugEnding = @"\bin\debug"; - const string releaseEnding = @"\bin\release"; - - string projectDir = null; - if (pathToManipulate.EndsWith(debugEnding, StringComparison.InvariantCultureIgnoreCase)) - projectDir = pathToManipulate.Substring(0, pathToManipulate.Length - debugEnding.Length); - if (pathToManipulate.EndsWith(releaseEnding, StringComparison.InvariantCultureIgnoreCase)) - projectDir = pathToManipulate.Substring(0, pathToManipulate.Length - releaseEnding.Length); - - if (projectDir == null) - throw new Exception("bad news guys. Not the expected path"); - - return projectDir.Substring(0, projectDir.LastIndexOf("\\", StringComparison.Ordinal)); - - } - - } -} diff --git a/Tests/Helpers/TestServices.cs b/Tests/Helpers/TestServices.cs new file mode 100644 index 0000000..ee7c7ec --- /dev/null +++ b/Tests/Helpers/TestServices.cs @@ -0,0 +1,48 @@ +using System; +using DataLayer.DataClasses; +using DataLayer.Startup; +using GenericServices; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using ServiceLayer.PostServices; + +namespace Tests.Helpers +{ + ///

    + /// Builds an isolated, seeded application stack (EF Core SQLite in-memory + GenericServices + /// via the built-in DI container) that mirrors how Program.cs wires the running web app. + /// Each instance owns its own database, so tests do not interfere with each other. + /// + public sealed class TestServices : IDisposable + { + private readonly SqliteConnection _connection; + private readonly ServiceProvider _provider; + + public TestServices(TestDataSelection selection = TestDataSelection.Small) + { + _connection = new SqliteConnection("DataSource=:memory:"); + _connection.Open(); + + var services = new ServiceCollection(); + services.AddDbContext(options => options.UseSqlite(_connection)); + services.AddScoped(sp => sp.GetRequiredService()); + services.AddGenericServices(typeof(SimplePostDto).Assembly); + _provider = services.BuildServiceProvider(); + + using var scope = _provider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + context.Database.EnsureCreated(); + DataLayerInitialise.ResetBlogs(context, selection); + } + + /// Creates a new DI scope. Dispose it to release the scoped DbContext. + public IServiceScope CreateScope() => _provider.CreateScope(); + + public void Dispose() + { + _provider.Dispose(); + _connection.Dispose(); + } + } +} diff --git a/Tests/Properties/AssemblyInfo.cs b/Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index b722a8d..0000000 --- a/Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,62 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: AssemblyInfo.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Tests")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[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("edff866f-292e-46db-9cdf-74c70d23322d")] - -// 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/Tests/Properties/Settings.Designer.cs b/Tests/Properties/Settings.Designer.cs deleted file mode 100644 index f2bf076..0000000 --- a/Tests/Properties/Settings.Designer.cs +++ /dev/null @@ -1,38 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18444 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Tests.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.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; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("jonsmith_")] - public string DatabaseLoginPrefix { - get { - return ((string)(this["DatabaseLoginPrefix"])); - } - set { - this["DatabaseLoginPrefix"] = value; - } - } - } -} diff --git a/Tests/Properties/Settings.settings b/Tests/Properties/Settings.settings deleted file mode 100644 index 74f592a..0000000 --- a/Tests/Properties/Settings.settings +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - jonsmith_ - - - \ No newline at end of file diff --git a/Tests/TestData/TestRadio4 schedule 2014-7-3.xml b/Tests/TestData/TestRadio4 schedule 2014-7-3.xml deleted file mode 100644 index 05116c3..0000000 --- a/Tests/TestData/TestRadio4 schedule 2014-7-3.xml +++ /dev/null @@ -1,2375 +0,0 @@ - - - - BBC Radio 4 - - FM - - - - - - p021khy6 - 2014-07-03T00:00:00+01:00 - 2014-07-03T00:30:00+01:00 - 1800 - - b047w7gj - - 03/07/2014 - The latest national and international news from BBC Radio 4. - audio - 1800 - - p01lcbf6 - - - Midnight News - 03/07/2014 - - 2014-07-03T00:00:00+01:00 - - - BBC Radio 4 - - - - b00cs19l - Midnight News - - - p01lcbf6 - - - 2007-02-03T00:00:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021khy7 - 2014-07-03T00:30:00+01:00 - 2014-07-03T00:48:00+01:00 - 1080 - - b047zlbz - 3 - How El Valero Got Its Name - A moving story from pal Rogelio, convinces Chris to compile an anthology of such stories. - audio - 900 - - p021gf7t - - - Book of the Week - Last Days of the Bus Club, How El Valero Got Its Name - - 2014-07-02T09:45:00+01:00 - - - BBC Radio 4 - - - - b0490f3d - Last Days of the Bus Club - - - p021gf7t - - 5 - 2014-06-30T09:45:00+01:00 - - b006qftk - Book of the Week - - - p01lc1rh - - - 2007-01-01T09:45:00Z - - - BBC Radio 4 - - - - - 0 - 0 - - - - p021khy8 - 2014-07-03T00:48:00+01:00 - 2014-07-03T01:00:00+01:00 - 720 - - b047w7gl - - 03/07/2014 - The latest shipping forecast. - audio - 660 - - p01lc1xj - - - Shipping Forecast - 03/07/2014 - - 2014-07-03T00:48:00+01:00 - - - BBC Radio 4 - - - - b006qfvv - Shipping Forecast - - - p01lc1xj - - - 2006-04-05T00:48:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021khy9 - 2014-07-03T01:00:00+01:00 - 2014-07-03T05:20:00+01:00 - 15600 - - b047w7gn - - 03/07/2014 - BBC Radio 4 joins the BBC World Service. - audio - 15600 - - p01lchw0 - - - Selection of BBC World Service Programmes - 03/07/2014 - - 2014-07-03T01:00:00+01:00 - - - BBC World Service - - - - b006s54y - Selection of BBC World Service Programmes - - - p01lchw0 - - - 2007-01-06T01:00:00Z - - - BBC World Service - - - - 0 - 0 - - - - p021khyb - 2014-07-03T05:20:00+01:00 - 2014-07-03T05:30:00+01:00 - 600 - - b047w7gq - - 03/07/2014 - The latest shipping forecast. - audio - 600 - - p01lc1xj - - - Shipping Forecast - 03/07/2014 - - 2014-07-03T05:20:00+01:00 - - - BBC Radio 4 - - - - b006qfvv - Shipping Forecast - - - p01lc1xj - - - 2006-04-05T00:48:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021khyd - 2014-07-03T05:30:00+01:00 - 2014-07-03T05:43:00+01:00 - 780 - - b047w7gs - - 03/07/2014 - News from BBC Radio 4. - audio - 780 - - p01lc375 - - - News Briefing - 03/07/2014 - - 2014-07-03T05:30:00+01:00 - - - BBC Radio 4 - - - - b007rhyn - News Briefing - - - p01lc375 - - - 2007-02-03T05:30:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021khyf - 2014-07-03T05:43:00+01:00 - 2014-07-03T05:45:00+01:00 - 120 - - b0483p66 - - 03/07/2014 - A spiritual comment and prayer to begin the day with Sheikh Michael Mumisa. - audio - 120 - - p01lc206 - - - Prayer for the Day - 03/07/2014 - - 2014-07-03T05:43:00+01:00 - - - BBC Radio 4 - - - - b006qmpj - Prayer for the Day - - - p01lc206 - - - 2007-01-06T05:43:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021khyg - 2014-07-03T05:45:00+01:00 - 2014-07-03T05:58:00+01:00 - 780 - - b048033l - - 03/07/2014 - The latest news about food, farming and the countryside. Presented by Charlotte Smith. - audio - 780 - - p01wrdlh - - - Farming Today - 03/07/2014 - - 2014-07-03T05:45:00+01:00 - - - BBC Radio 4 - - - - b006qj8q - Farming Today - - - p01lcqw7 - - - 2007-01-06T06:35:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021khyh - 2014-07-03T05:58:00+01:00 - 2014-07-03T06:00:00+01:00 - 120 - - b0378sqk - - Stonechat - Michaela Strachan presents the story and sound of the stonechat. - audio - 120 - - p01k03yg - - - Tweet of the Day - Stonechat - - 2013-08-01T05:58:00+01:00 - - - BBC Radio 4 - - - - b01s6xyk - Tweet of the Day - - 265 - 2013-05-06T05:58:00+01:00 - - - BBC Radio 4 - - - - 2013-08-01T06:37:09+01:00 - 1 - 0 - - - Available to listen - - - - - p021khyj - 2014-07-03T06:00:00+01:00 - 2014-07-03T09:00:00+01:00 - 10800 - - b048033n - 21027 - 03/07/2014 - Morning news. Includes Sports Desk; Yesterday in Parliament; Weather; Thought for the Day. - audio - 10800 - - p01lc1m2 - - - Today - 03/07/2014 - - 2014-07-03T06:00:00+01:00 - - - BBC Radio 4 - - - - b006qj9z - Today - - - p01lc1m2 - - - 1966-10-27T07:15:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfnr - 2014-07-03T09:00:00+01:00 - 2014-07-03T09:45:00+01:00 - 2700 - - b048033q - 637 - Mrs Dalloway - Melvyn Bragg and his guests discuss Virginia Woolf's novel Mrs Dalloway. - audio - 2580 - - p021n60h - - - In Our Time - Mrs Dalloway - - 2014-07-03T09:00:00+01:00 - - - BBC Radio 4 - - - - b006qykl - In Our Time - - - p01lc1r8 - - - 1998-10-15T09:02:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfns - 2014-07-03T09:45:00+01:00 - 2014-07-03T10:00:00+01:00 - 900 - - b048033s - 4 - The Rain in Spain: Part 1 - Andalucia is a region racked with droughts, but one winter the downpour was biblical. - audio - 900 - - p021gf7t - - - Book of the Week - Last Days of the Bus Club, The Rain in Spain: Part 1 - - 2014-07-03T09:45:00+01:00 - - - BBC Radio 4 - - - - b0490f3d - Last Days of the Bus Club - - - p021gf7t - - 5 - 2014-06-30T09:45:00+01:00 - - b006qftk - Book of the Week - - - p01lc1rh - - - 2007-01-01T09:45:00Z - - - BBC Radio 4 - - - - - 0 - 0 - - - - p021mfnt - 2014-07-03T10:00:00+01:00 - 2014-07-03T10:45:00+01:00 - 2700 - - b048033v - - 03/07/2014 - Jenni Murray presents the programme that offers a female perspective on the world. - audio - 2700 - - p01slb15 - - - Woman's Hour - 03/07/2014 - - 2014-07-03T10:00:00+01:00 - - - BBC Radio 4 - - - - b007qlvb - Woman's Hour - - - p01svhcp - - - 1948-02-02T14:00:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfnv - 2014-07-03T10:45:00+01:00 - 2014-07-03T11:00:00+01:00 - 900 - - b048033x - 4 - Episode 4 - By Scott Cherry. Ian has suddenly returned, claiming he went to help his mother. - audio - 900 - - p021gkyj - - - 15 Minute Drama - A Small Town Murder, Episode 4 - - 2014-07-03T10:45:00+01:00 - - - BBC Radio 4 - - - - b0490f8r - A Small Town Murder - - - p021gkyj - - 5 - 2014-06-30T10:45:00+01:00 - - b006qy2s - 15 Minute Drama - - - p01ynknj - - - 2007-01-19T19:45:00Z - - - BBC Radio 4 - - - - - 0 - 0 - - - - p021mfnx - 2014-07-03T11:00:00+01:00 - 2014-07-03T11:30:00+01:00 - 1800 - - b048033z - - 03/07/2014 - Reports from writers and journalists around the world. Presented by Kate Adie. - audio - 1800 - - p01lcg42 - - - From Our Own Correspondent - 03/07/2014 - - 2014-07-03T11:00:00+01:00 - - - BBC Radio 4 - - - - b006qjlq - From Our Own Correspondent - - - p01lcg42 - - - 2007-01-06T11:30:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfnz - 2014-07-03T11:30:00+01:00 - 2014-07-03T12:00:00+01:00 - 1800 - - b0480341 - - Terry Wogan - Sir Terry Wogan chooses his favourite words and music, with readings by actor David Jason. - audio - 1680 - - p021n5wh - - - With Great Pleasure - Terry Wogan - - 2014-07-03T11:30:00+01:00 - - - BBC Radio 4 - - - - b006qrx7 - With Great Pleasure - - - p01lchhp - - - 2007-02-01T11:30:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfp0 - 2014-07-03T12:00:00+01:00 - 2014-07-03T12:57:00+01:00 - 3420 - - b0480343 - - 03/07/2014 - Consumer news. - audio - 3360 - - p01lc1qq - - - You and Yours - 03/07/2014 - - 2014-07-03T12:00:00+01:00 - - - BBC Radio 4 - - - - b006qps9 - You and Yours - - - p01lc1qq - - - 2006-04-05T12:00:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfp2 - 2014-07-03T12:57:00+01:00 - 2014-07-03T13:00:00+01:00 - 180 - - b047w7gv - - 03/07/2014 - The latest weather forecast. - audio - 180 - - p01lc36f - - - Weather - 03/07/2014 - - 2014-07-03T12:57:00+01:00 - - - BBC Radio 4 - - - - b007rn05 - Weather - - - p01lc36f - - - 2006-04-05T12:57:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfp3 - 2014-07-03T13:00:00+01:00 - 2014-07-03T13:45:00+01:00 - 2700 - - b0480345 - - 03/07/2014 - National and international news with Shaun Ley. - audio - 2700 - - p01lcjyc - - - World at One - 03/07/2014 - - 2014-07-03T13:00:00+01:00 - - - BBC Radio 4 - - - - b006qptc - World at One - - - p01lcjyc - - - 2007-01-19T13:00:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfp5 - 2014-07-03T13:45:00+01:00 - 2014-07-03T14:00:00+01:00 - 900 - - b0480347 - 4 - Cambridge - Town and gown provide the inspiration, as Simon Preston creates a new dish for Cambridge. - audio - 900 - - p021hxgd - - - The Town Is the Menu - Cambridge - - 2014-07-03T13:45:00+01:00 - - - BBC Radio 4 - - - - b0490hzy - The Town Is the Menu - - - p021hxgd - - 5 - 2014-06-30T13:45:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfp6 - 2014-07-03T14:00:00+01:00 - 2014-07-03T14:15:00+01:00 - 900 - - b047zrl3 - 17395 - 02/07/2014 - Susan's not satisfied. - audio - 780 - - p01t7xy8 - - - The Archers - 02/07/2014 - - 2014-07-02T19:00:00+01:00 - - - BBC Radio 4 - - - - b006qpgr - The Archers - - - p01t7xy8 - - - 2007-01-19T14:00:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfp8 - 2014-07-03T14:15:00+01:00 - 2014-07-03T15:00:00+01:00 - 2700 - - b0480349 - - Blurred - By Frazer Flintham. Old university friends Nikki and Hannah meet up after a ten-year gap. - audio - 2700 - - p021n8mh - - - Afternoon Drama - Blurred - - 2014-07-03T14:15:00+01:00 - - - BBC Radio 4 - - - - b006qrzz - Afternoon Drama - - - p01ynb8q - - - 2002-06-02T15:00:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfp9 - 2014-07-03T15:00:00+01:00 - 2014-07-03T15:27:00+01:00 - 1620 - - b048034c - - Tour de Yorkshire - Helen Mark explores the route of the opening leg of the Tour De France in Yorkshire. - audio - 1500 - - p021nxzk - - - Open Country - Tour de Yorkshire - - 2014-07-03T15:00:00+01:00 - - - BBC Radio 4 - - - - b006qgft - Open Country - - - p01lcfyg - - - 2006-04-06T13:30:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfpc - 2014-07-03T15:27:00+01:00 - 2014-07-03T15:30:00+01:00 - 180 - - b047w8k7 - - Excellent Development - Alison Bell presents an appeal for Excellent Development. - audio - 120 - - p0219rxb - - - Radio 4 Appeal - Excellent Development - - 2014-06-29T07:55:00+01:00 - - - BBC Radio 4 - - - - b006qnc7 - Radio 4 Appeal - - - p01lyjsv - - - 2007-02-01T15:27:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfpd - 2014-07-03T15:30:00+01:00 - 2014-07-03T16:00:00+01:00 - 1800 - - b047wb68 - - 29/06/2014 - News and features from the world of books, presented by Mariella Frostrup. - audio - 1800 - - p021np5m - - - Open Book - 29/06/2014 - - 2014-06-29T16:00:00+01:00 - - - BBC Radio 4 - - - - b006qp6p - Open Book - - - p01lc1zt - - - 2003-02-23T16:00:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfpg - 2014-07-03T16:00:00+01:00 - 2014-07-03T16:30:00+01:00 - 1800 - - b048034f - - 03/07/2014 - Looking at the latest cinema releases, DVDs and films on TV. - audio - 1680 - - p01m630v - - - The Film Programme - 03/07/2014 - - 2014-07-03T16:00:00+01:00 - - - BBC Radio 4 - - - - b006r5jt - The Film Programme - - - p01m630v - - - 2004-06-05T17:30:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfph - 2014-07-03T16:30:00+01:00 - 2014-07-03T16:55:00+01:00 - 1500 - - b048034h - - 03/07/2014 - Adam Rutherford investigates the news in science and science in the news. - audio - 1800 - - p01tbgxt - - - Inside Science - 03/07/2014 - - 2014-07-03T16:30:00+01:00 - - - BBC Radio 4 - - - - b036f7w2 - Inside Science - - - p01tbgxt - - - 2013-07-04T16:30:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfpk - 2014-07-03T16:55:00+01:00 - 2014-07-03T17:00:00+01:00 - 300 - - b048034k - - 3rd July - The funeral of Archduke Franz Ferdinand in Vienna. - audio - 300 - - p01qlg3g - - - 1914: Day by Day - 3rd July - - 2014-07-03T16:55:00+01:00 - - - BBC Radio 4 - - - - b03t8m6h - 1914: Day by Day - - - p01qlg3g - - - 2014-06-27T16:55:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfpm - 2014-07-03T17:00:00+01:00 - 2014-07-03T18:00:00+01:00 - 3600 - - b048034m - - 03/07/2014 - Eddie Mair presents coverage and analysis of the day's news. - audio - 3600 - - p01vf6q0 - - - PM - 03/07/2014 - - 2014-07-03T17:00:00+01:00 - - - BBC Radio 4 - - - - b006qskw - PM - - - p01vf6q0 - - - 2007-01-19T17:00:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfpp - 2014-07-03T18:00:00+01:00 - 2014-07-03T18:30:00+01:00 - 1800 - - b047w7gx - - 03/07/2014 - National and international news from BBC Radio 4. - audio - 1800 - - p01lc357 - - - Six O'Clock News - 03/07/2014 - - 2014-07-03T18:00:00+01:00 - - - BBC Radio 4 - - - - b006qjxt - Six O'Clock News - - - p01lc357 - - - 2007-01-06T18:00:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfpr - 2014-07-03T18:30:00+01:00 - 2014-07-03T19:00:00+01:00 - 1800 - - b01gg7g4 - 4 - Making a Difference - Ed finds himself an unlikely star of local radio. - audio - 1800 - - p01lcmpy - - - Ed Reardon's Week - Series 8, Making a Difference - - 2012-04-24T18:30:00+01:00 - - - BBC Radio 4 - - - - b01fjvry - Series 8 - 8 - - p01lcmpy - - 6 - 2012-04-03T18:30:00+01:00 - - b006r5ck - Ed Reardon's Week - - - p01lcmpy - - - 2006-12-15T11:30:00Z - - - BBC Radio 4 - - - - - 0 - 0 - - - - p021mfpt - 2014-07-03T19:00:00+01:00 - 2014-07-03T19:15:00+01:00 - 900 - - b048034p - 17396 - 03/07/2014 - Elizabeth and Shula have a heart to heart. - audio - 780 - - p01t7xy8 - - - The Archers - 03/07/2014 - - 2014-07-03T19:00:00+01:00 - - - BBC Radio 4 - - - - b006qpgr - The Archers - - - p01t7xy8 - - - 2007-01-19T14:00:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfpw - 2014-07-03T19:15:00+01:00 - 2014-07-03T19:45:00+01:00 - 1800 - - b048034r - - 03/07/2014 - Live daily magazine programme on the worlds of arts, literature, film, media and music. - audio - 1800 - - p01n47p5 - - - Front Row - 03/07/2014 - - 2014-07-03T19:15:00+01:00 - - - BBC Radio 4 - - - - b006qsq5 - Front Row - - - p01n47p5 - - - 1998-12-28T19:15:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfpx - 2014-07-03T19:45:00+01:00 - 2014-07-03T20:00:00+01:00 - 900 - - b048033x - 4 - Episode 4 - By Scott Cherry. Ian has suddenly returned, claiming he went to help his mother. - audio - 900 - - p021gkyj - - - 15 Minute Drama - A Small Town Murder, Episode 4 - - 2014-07-03T10:45:00+01:00 - - - BBC Radio 4 - - - - b0490f8r - A Small Town Murder - - - p021gkyj - - 5 - 2014-06-30T10:45:00+01:00 - - b006qy2s - 15 Minute Drama - - - p01ynknj - - - 2007-01-19T19:45:00Z - - - BBC Radio 4 - - - - - 0 - 0 - - - - p021mfpz - 2014-07-03T20:00:00+01:00 - 2014-07-03T20:30:00+01:00 - 1800 - - b048034t - - 03/07/2014 - Combining original insights into major news stories with topical investigations. - audio - 1680 - - p01lykqh - - - The Report - 03/07/2014 - - 2014-07-03T20:00:00+01:00 - - - BBC Radio 4 - - - - b00jkr1q - The Report - - - p01lykqh - - - 2009-04-02T20:00:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfq1 - 2014-07-03T20:30:00+01:00 - 2014-07-03T21:00:00+01:00 - 1800 - - b048034w - - Mental Health - Evan Davis and guests discuss coping with depression and business success at the same time - audio - 1800 - - p01lcmg7 - - - The Bottom Line - Mental Health - - 2014-07-03T20:30:00+01:00 - - - BBC Radio 4 - - - - b006sz6t - The Bottom Line - - - p01lcmg7 - - - 2007-02-03T17:30:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfq2 - 2014-07-03T21:00:00+01:00 - 2014-07-03T21:30:00+01:00 - 1800 - - b048034h - - 03/07/2014 - Adam Rutherford investigates the news in science and science in the news. - audio - 1800 - - p01tbgxt - - - Inside Science - 03/07/2014 - - 2014-07-03T16:30:00+01:00 - - - BBC Radio 4 - - - - b036f7w2 - Inside Science - - - p01tbgxt - - - 2013-07-04T16:30:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfq4 - 2014-07-03T21:30:00+01:00 - 2014-07-03T21:58:00+01:00 - 1680 - - b048033q - 637 - Mrs Dalloway - Melvyn Bragg and his guests discuss Virginia Woolf's novel Mrs Dalloway. - audio - 2580 - - p021n60h - - - In Our Time - Mrs Dalloway - - 2014-07-03T09:00:00+01:00 - - - BBC Radio 4 - - - - b006qykl - In Our Time - - - p01lc1r8 - - - 1998-10-15T09:02:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfq5 - 2014-07-03T21:58:00+01:00 - 2014-07-03T22:00:00+01:00 - 120 - - b047w7gz - - 03/07/2014 - Weather information. - audio - 120 - - p01lc36f - - - Weather - 03/07/2014 - - 2014-07-03T21:58:00+01:00 - - - BBC Radio 4 - - - - b007rn05 - Weather - - - p01lc36f - - - 2006-04-05T12:57:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfq6 - 2014-07-03T22:00:00+01:00 - 2014-07-03T22:45:00+01:00 - 2700 - - b048034y - - 03/07/2014 - In-depth reporting and analysis from a global perspective. - audio - 2700 - - p01z0ls6 - - - The World Tonight - 03/07/2014 - - 2014-07-03T22:00:00+01:00 - - - BBC Radio 4 - - - - b006qtl3 - The World Tonight - - - p01z0ls6 - - - 2006-04-05T22:00:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfq7 - 2014-07-03T22:45:00+01:00 - 2014-07-03T23:00:00+01:00 - 900 - - b0480350 - 9 - Episode 9 - Eric and Cecil have decided to take matters into their own hands. - audio - 900 - - p02128k8 - - - Book at Bedtime - Remember Me Like This, Episode 9 - - 2014-07-03T22:45:00+01:00 - - - BBC Radio 4 - - - - b048329v - Remember Me Like This - - - p02128k8 - - 10 - 2014-06-23T22:45:00+01:00 - - b006qtlx - Book at Bedtime - - - p01lcmpc - - - 2007-01-19T22:45:00Z - - - BBC Radio 4 - - - - - 0 - 0 - - - - p021mfq8 - 2014-07-03T23:00:00+01:00 - 2014-07-03T23:30:00+01:00 - 1800 - - b0480352 - 3 - Episode 3 - A pair of American tourists visit St Paul's cathedral to confess their sins. - audio - 1800 - - p0217xw4 - - - Trodd en Bratt Say 'Well Done You' - Episode 3 - - 2014-07-03T23:00:00+01:00 - - - BBC Radio 4 - - - - b0480h31 - Trodd en Bratt Say 'Well Done You' - - - p0217xw4 - - 4 - 2014-06-19T23:00:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfq9 - 2014-07-03T23:30:00+01:00 - 2014-07-04T00:00:00+01:00 - 1800 - - b0480354 - - 03/07/2014 - Sean Curran reports from Westminster. - audio - 1800 - - p01lcfy2 - - - Today in Parliament - 03/07/2014 - - 2014-07-03T23:30:00+01:00 - - - BBC Radio 4 - - - - b006qtqd - Today in Parliament - - - p01lcfy2 - - - 2007-01-19T23:30:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfqb - 2014-07-04T00:00:00+01:00 - 2014-07-04T00:30:00+01:00 - 1800 - - b047w7ht - - 04/07/2014 - The latest national and international news from BBC Radio 4. - audio - 1800 - - p01lcbf6 - - - Midnight News - 04/07/2014 - - 2014-07-04T00:00:00+01:00 - - - BBC Radio 4 - - - - b00cs19l - Midnight News - - - p01lcbf6 - - - 2007-02-03T00:00:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfqc - 2014-07-04T00:30:00+01:00 - 2014-07-04T00:48:00+01:00 - 1080 - - b048033s - 4 - The Rain in Spain: Part 1 - Andalucia is a region racked with droughts, but one winter the downpour was biblical. - audio - 900 - - p021gf7t - - - Book of the Week - Last Days of the Bus Club, The Rain in Spain: Part 1 - - 2014-07-03T09:45:00+01:00 - - - BBC Radio 4 - - - - b0490f3d - Last Days of the Bus Club - - - p021gf7t - - 5 - 2014-06-30T09:45:00+01:00 - - b006qftk - Book of the Week - - - p01lc1rh - - - 2007-01-01T09:45:00Z - - - BBC Radio 4 - - - - - 0 - 0 - - - - p021mfqd - 2014-07-04T00:48:00+01:00 - 2014-07-04T01:00:00+01:00 - 720 - - b047w7hw - - 04/07/2014 - The latest shipping forecast. - audio - 660 - - p01lc1xj - - - Shipping Forecast - 04/07/2014 - - 2014-07-04T00:48:00+01:00 - - - BBC Radio 4 - - - - b006qfvv - Shipping Forecast - - - p01lc1xj - - - 2006-04-05T00:48:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfqf - 2014-07-04T01:00:00+01:00 - 2014-07-04T05:20:00+01:00 - 15600 - - b047w7hy - - 04/07/2014 - BBC Radio 4 joins the BBC World Service. - audio - 15600 - - p01lchw0 - - - Selection of BBC World Service Programmes - 04/07/2014 - - 2014-07-04T01:00:00+01:00 - - - BBC World Service - - - - b006s54y - Selection of BBC World Service Programmes - - - p01lchw0 - - - 2007-01-06T01:00:00Z - - - BBC World Service - - - - 0 - 0 - - - - p021mfqg - 2014-07-04T05:20:00+01:00 - 2014-07-04T05:30:00+01:00 - 600 - - b047w7j2 - - 04/07/2014 - The latest shipping forecast. - audio - 600 - - p01lc1xj - - - Shipping Forecast - 04/07/2014 - - 2014-07-04T05:20:00+01:00 - - - BBC Radio 4 - - - - b006qfvv - Shipping Forecast - - - p01lc1xj - - - 2006-04-05T00:48:00+01:00 - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfqh - 2014-07-04T05:30:00+01:00 - 2014-07-04T05:43:00+01:00 - 780 - - b047w7j4 - - 04/07/2014 - News from BBC Radio 4. - audio - 780 - - p01lc375 - - - News Briefing - 04/07/2014 - - 2014-07-04T05:30:00+01:00 - - - BBC Radio 4 - - - - b007rhyn - News Briefing - - - p01lc375 - - - 2007-02-03T05:30:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfqj - 2014-07-04T05:43:00+01:00 - 2014-07-04T05:45:00+01:00 - 120 - - b0483pkw - - 04/07/2014 - A spiritual comment and prayer to begin the day with Sheikh Michael Mumisa. - audio - 120 - - p01lc206 - - - Prayer for the Day - 04/07/2014 - - 2014-07-04T05:43:00+01:00 - - - BBC Radio 4 - - - - b006qmpj - Prayer for the Day - - - p01lc206 - - - 2007-01-06T05:43:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfql - 2014-07-04T05:45:00+01:00 - 2014-07-04T05:58:00+01:00 - 780 - - b04807h6 - - 04/07/2014 - The latest news about food, farming and the countryside. Presented by Charlotte Smith. - audio - 780 - - p01lqyv0 - - - Farming Today - 04/07/2014 - - 2014-07-04T05:45:00+01:00 - - - BBC Radio 4 - - - - b006qj8q - Farming Today - - - p01lcqw7 - - - 2007-01-06T06:35:00Z - - - BBC Radio 4 - - - - 0 - 0 - - - - p021mfqn - 2014-07-04T05:58:00+01:00 - 2014-07-04T06:00:00+01:00 - 120 - - b0378srp - - House Sparrow - Michaela Strachan presents the story and sound of the house sparrow. - audio - 120 - - p01k03ym - - - Tweet of the Day - House Sparrow - - 2013-08-02T05:58:00+01:00 - - - BBC Radio 4 - - - - b01s6xyk - Tweet of the Day - - 265 - 2013-05-06T05:58:00+01:00 - - - BBC Radio 4 - - - - 2013-08-02T06:45:19+01:00 - 1 - 0 - - - Available to listen - - - - - - diff --git a/Tests/TestData/actionRunnerData - default.js b/Tests/TestData/actionRunnerData - default.js deleted file mode 100644 index a708c20..0000000 --- a/Tests/TestData/actionRunnerData - default.js +++ /dev/null @@ -1 +0,0 @@ -var jsonData = { "ActionGuid": "abcd" } \ No newline at end of file diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 5dca393..8a6470a 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -1,231 +1,26 @@ - - - + + - Debug - AnyCPU - {6D9E7904-B2AC-49E3-83A7-6B48876F46B9} - Library - Properties - Tests - Tests - v4.5.1 - 512 + net8.0 + disable + disable + false + true - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - bin\ReleaseAzure\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - bin\AzureRelease\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - bin\WebWizRelease\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - False - ..\packages\Autofac.3.5.0\lib\net40\Autofac.dll - - - ..\packages\AutoMapper.4.2.1\lib\net45\AutoMapper.dll - True - - - ..\packages\DelegateDecompiler.0.18.0\lib\net40-Client\DelegateDecompiler.dll - True - - - ..\packages\DelegateDecompiler.EntityFramework.0.18.0\lib\net45\DelegateDecompiler.EntityFramework.dll - True - - - ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll - True - - - ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll - True - - - ..\packages\GenericLibsBase.1.0.1\lib\GenericLibsBase.dll - True - - - ..\packages\GenericServices.1.0.9\lib\GenericServices.dll - True - - - False - ..\packages\log4net.2.0.3\lib\net40-full\log4net.dll - - - False - ..\packages\Microsoft.AspNet.SignalR.Core.2.0.3\lib\net45\Microsoft.AspNet.SignalR.Core.dll - - - False - ..\packages\Microsoft.Owin.2.1.0\lib\net45\Microsoft.Owin.dll - - - False - ..\packages\Microsoft.Owin.Security.2.1.0\lib\net45\Microsoft.Owin.Security.dll - - - True - ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - ..\packages\Mono.Reflection.1.0.0.0\lib\Mono.Reflection.dll - - - ..\packages\Moq.4.2.1408.0717\lib\net40\Moq.dll - - - False - ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll - - - ..\packages\NUnit.2.6.3\lib\nunit.framework.dll - - - False - ..\packages\Owin.1.0\lib\net40\Owin.dll - - - - - - - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True - - - ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True - - - ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True - - - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True - - - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True - - - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Settings.settings - - - - - - - - - - - Designer - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - {264e1878-12de-4099-b8d7-cc53a73fea49} - DataLayer - - - {cffee5e0-3b99-46e0-9a82-2e74621c17c5} - SampleWebApp - - - {d2813927-0f38-43c3-b47c-ae8f00d50cae} - ServiceLayer - - + - + + + + + + - - + + + + - - - \ No newline at end of file + + diff --git a/Tests/UnitTests/Group01DataLayer/DataLayerTests.cs b/Tests/UnitTests/Group01DataLayer/DataLayerTests.cs new file mode 100644 index 0000000..a8c3752 --- /dev/null +++ b/Tests/UnitTests/Group01DataLayer/DataLayerTests.cs @@ -0,0 +1,70 @@ +using System.Linq; +using DataLayer.DataClasses; +using DataLayer.DataClasses.Concrete; +using DataLayer.Startup; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using Tests.Helpers; + +namespace Tests.UnitTests.Group01DataLayer +{ + [TestFixture] + public class DataLayerTests + { + [Test] + public void SeedSmall_LoadsExpectedBlogsPostsAndTags() + { + using var app = new TestServices(TestDataSelection.Small); + using var scope = app.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + + Assert.That(db.Blogs.Count(), Is.EqualTo(2)); + Assert.That(db.Posts.Count(), Is.EqualTo(3)); + Assert.That(db.Tags.Count(), Is.EqualTo(3)); + } + + [Test] + public void Post_ManyToManyTags_AreLoaded() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + + var post = db.Posts.Include(p => p.Tags).Include(p => p.Blogger) + .OrderBy(p => p.PostId).First(); + + Assert.That(post.Blogger, Is.Not.Null); + Assert.That(post.Tags.Count, Is.GreaterThan(0)); + } + + [Test] + public void SaveChanges_SetsLastUpdatedOnPost() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + + var post = db.Posts.OrderBy(p => p.PostId).First(); + var before = post.LastUpdated; + post.Title = "Edited title"; + db.SaveChanges(); + + Assert.That(post.LastUpdated, Is.GreaterThanOrEqualTo(before)); + } + + [Test] + public void ResetBlogs_Medium_LoadsMoreThanSmall() + { + using var small = new TestServices(TestDataSelection.Small); + using var medium = new TestServices(TestDataSelection.Medium); + + using var smallScope = small.CreateScope(); + using var mediumScope = medium.CreateScope(); + var smallDb = smallScope.ServiceProvider.GetRequiredService(); + var mediumDb = mediumScope.ServiceProvider.GetRequiredService(); + + Assert.That(mediumDb.Posts.Count(), Is.GreaterThanOrEqualTo(smallDb.Posts.Count())); + } + } +} diff --git a/Tests/UnitTests/Group01DataLayer/Test10SetupBlogs.cs b/Tests/UnitTests/Group01DataLayer/Test10SetupBlogs.cs deleted file mode 100644 index 7a03ba0..0000000 --- a/Tests/UnitTests/Group01DataLayer/Test10SetupBlogs.cs +++ /dev/null @@ -1,126 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: Test10SetupBlogs.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.Linq; -using DataLayer.DataClasses; -using DataLayer.Startup; -using DataLayer.Startup.Internal; -using NUnit.Framework; -using Tests.Helpers; - -namespace Tests.UnitTests.Group01DataLayer -{ - class Test10SetupBlogs - { - [Test] - public void Check01XmlFileLoadOk() - { - - //SETUP - - //ATTEMPT - var bloggers = LoadDbDataFromXml.FormBlogsWithPosts("DataLayer.Startup.Internal.BlogsContentSimple.xml").ToList(); - - //VERIFY - bloggers.Count().ShouldEqual(2); - bloggers.SelectMany( x => x.Posts).Count().ShouldEqual(3); - bloggers.SelectMany( x => x.Posts.SelectMany( y => y.Tags)).Distinct().Count().ShouldEqual(3); - - } - - [Test] - public void Check02XmlFileLoadBad() - { - - //SETUP - - //ATTEMPT - var ex = Assert.Throws( () => LoadDbDataFromXml.FormBlogsWithPosts("badname.xml")); - - //VERIFY - ex.Message.ShouldStartWith("Could not find the xml file you asked for."); - - } - - [Test] - public void Check10BlogsResetSmallOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - DataLayerInitialise.InitialiseThis(false, true); - - //ATTEMPT - DataLayerInitialise.ResetBlogs(db, TestDataSelection.Small); - - //VERIFY - db.Blogs.Count().ShouldEqual(2); - db.Posts.Count().ShouldEqual(3); - db.Tags.Count().ShouldEqual(3); - } - } - - [Test] - public void Check11BlogsResetMediumOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - DataLayerInitialise.InitialiseThis(false, true); - - //ATTEMPT - DataLayerInitialise.ResetBlogs(db, TestDataSelection.Medium); - - //VERIFY - db.Blogs.Count().ShouldEqual(4); - db.Posts.Count().ShouldEqual(17); - db.Tags.Count().ShouldEqual(8); - } - } - - //--------------------------------------------------------- - - [Test] - public void Check20NullInitialiserOk() - { - Check10BlogsResetSmallOk(); //we call this to ensure the database is setup - using (var db = new SampleWebAppDb()) - { - //SETUP - DataLayerInitialise.InitialiseThis(false, false); //select null initialiser - - //ATTEMPT - DataLayerInitialise.ResetBlogs(db, TestDataSelection.Small); - - //VERIFY - db.Blogs.Count().ShouldEqual(2); - db.Posts.Count().ShouldEqual(3); - db.Tags.Count().ShouldEqual(3); - } - } - } -} diff --git a/Tests/UnitTests/Group01DataLayer/Test13Validation.cs b/Tests/UnitTests/Group01DataLayer/Test13Validation.cs deleted file mode 100644 index 5bba1c2..0000000 --- a/Tests/UnitTests/Group01DataLayer/Test13Validation.cs +++ /dev/null @@ -1,230 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: Test13Validation.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.Collections.Generic; -using System.Linq; -using DataLayer.DataClasses; -using DataLayer.DataClasses.Concrete; -using DataLayer.Startup; -using GenericServices; -using NUnit.Framework; -using Tests.Helpers; - -namespace Tests.UnitTests.Group01DataLayer -{ - class Test13Validation - { - - [TestFixtureSetUp] - public void SetUpFixture() - { - using (var db = new SampleWebAppDb()) - { - DataLayerInitialise.InitialiseThis(false, true); - DataLayerInitialise.ResetBlogs(db, TestDataSelection.Small); - } - } - - [Test] - public void Check01ValidateTagOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var snap = new DbSnapShot(db); - - //ATTEMPT - var dupTag = new Tag { Name = "non-duplicate slug", Slug = Guid.NewGuid().ToString("N") }; - db.Tags.Add(dupTag); - var status = db.SaveChangesWithChecking(); - - //VERIFY - status.IsValid.ShouldEqual(true, status.Errors); - snap.CheckSnapShot(db, 0,0,0,1); - } - } - - [Test] - public void Check02ValidateTagError() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var existingTag = db.Tags.First(); - - //ATTEMPT - var dupTag = new Tag {Name = "duplicate slug", Slug = existingTag.Slug}; - db.Tags.Add(dupTag); - var status = db.SaveChangesWithChecking();; - - //VERIFY - status.IsValid.ShouldEqual(false); - status.Errors.Count.ShouldEqual(1); - status.Errors[0].ErrorMessage.ShouldEqual("The Slug on tag 'duplicate slug' must be unique and is already being used."); - } - } - - [Test] - public void Check10ValidatePostOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var snap = new DbSnapShot(db); - var existingTag = db.Tags.First(); - var existingBlogger = db.Blogs.First(); - - //ATTEMPT - var newPost = new Post() - { - Blogger = existingBlogger, - Title = "Test post", - Content = "Nothing special", - Tags = new[] { existingTag } - }; - db.Posts.Add(newPost); - var status = db.SaveChangesWithChecking();; - - //VERIFY - status.IsValid.ShouldEqual(true, status.Errors); - snap.CheckSnapShot(db,1,1); - } - } - - - [Test] - public void Check15ValidatePostTitleError() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var existingTag = db.Tags.First(); - var existingBlogger = db.Blogs.First(); - - //ATTEMPT - var newPost = new Post() - { - Blogger = existingBlogger, - Title = "Test post!", - Content = "Nothing special", - Tags = new[] { existingTag } - }; - db.Posts.Add(newPost); - var status = db.SaveChangesWithChecking();; - - //VERIFY - status.IsValid.ShouldEqual(false); - status.Errors.Count.ShouldEqual(1); - status.Errors[0].ErrorMessage.ShouldEqual("Sorry, but you can't get too excited and include a ! in the title."); - } - } - - [Test] - public void Check16ValidatePostTitleError() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var existingTag = db.Tags.First(); - var existingBlogger = db.Blogs.First(); - - //ATTEMPT - var newPost = new Post() - { - Blogger = existingBlogger, - Title = "Test post?", - Content = "Nothing special", - Tags = new[] { existingTag } - }; - db.Posts.Add(newPost); - var status = db.SaveChangesWithChecking();; - - //VERIFY - status.IsValid.ShouldEqual(false); - status.Errors.Count.ShouldEqual(1); - status.Errors[0].ErrorMessage.ShouldEqual("Sorry, but you can't ask a question, i.e. the title can't end with '?'."); - } - } - - [Test] - public void Check20ValidatePostContentOneError() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var existingTag = db.Tags.First(); - var existingBlogger = db.Blogs.First(); - - //ATTEMPT - var newPost = new Post() - { - Blogger = existingBlogger, - Title = "Test post", - Content = "Should not end sentence with sheep.", - Tags = new[] { existingTag } - }; - db.Posts.Add(newPost); - var status = db.SaveChangesWithChecking();; - - //VERIFY - status.IsValid.ShouldEqual(false); - status.Errors.Count.ShouldEqual(1); - status.Errors[0].ErrorMessage.ShouldEqual("Sorry. Not allowed to end a sentance with 'sheep'."); - } - } - - - [Test] - public void Check21ValidatePostContentTwoErrors() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var existingTag = db.Tags.First(); - var existingBlogger = db.Blogs.First(); - - //ATTEMPT - var newPost = new Post() - { - Blogger = existingBlogger, - Title = "Test post", - Content = "Should not end sentence with sheep. Nor end sentence with lamb.", - Tags = new[] { existingTag } - }; - db.Posts.Add(newPost); - var status = db.SaveChangesWithChecking();; - - //VERIFY - status.IsValid.ShouldEqual(false); - status.Errors.Count.ShouldEqual(2); - status.Errors[0].ErrorMessage.ShouldEqual("Sorry. Not allowed to end a sentance with 'sheep'."); - status.Errors[1].ErrorMessage.ShouldEqual("Sorry. Not allowed to end a sentance with 'lamb'."); - } - } - } -} - diff --git a/Tests/UnitTests/Group01DataLayer/Test14ReadWriteBlogs.cs b/Tests/UnitTests/Group01DataLayer/Test14ReadWriteBlogs.cs deleted file mode 100644 index 9c70554..0000000 --- a/Tests/UnitTests/Group01DataLayer/Test14ReadWriteBlogs.cs +++ /dev/null @@ -1,331 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: Test14ReadWriteBlogs.cs -// Date Created: 2014/05/20 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.Data.Entity; -using System.Linq; -using System.Threading; -using DataLayer.DataClasses; -using DataLayer.DataClasses.Concrete; -using DataLayer.Startup; -using GenericServices; -using NUnit.Framework; -using Tests.Helpers; - -namespace Tests.UnitTests.Group01DataLayer -{ - class Test14ReadWriteBlogs - { - - [SetUp] - public void SetUp() - { - using (var db = new SampleWebAppDb()) - { - DataLayerInitialise.InitialiseThis(false, true); - DataLayerInitialise.ResetBlogs(db, TestDataSelection.Small); - } - } - - [Test] - public void Check01ReadBlogsNoPostsOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - - //ATTEMPT - var blogs = db.Blogs.ToList(); - - //VERIFY - blogs.Count.ShouldEqual(2); - blogs.All(x => x.Posts == null).ShouldEqual(true); - } - } - - [Test] - public void Check02ReadBlogsWithPostsOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - - //ATTEMPT - var blogs = db.Blogs.Include(x => x.Posts).ToList(); - - //VERIFY - blogs.Count.ShouldEqual(2); - blogs.All(x => x.Posts != null).ShouldEqual(true); - blogs.All(x => x.Posts.All(y => y.Tags == null)).ShouldEqual(true); - } - } - - [Test] - public void Check03ReadBlogsWithPostTagsOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - - //ATTEMPT - var blogs = db.Blogs.Include(x => x.Posts.Select(y => y.Tags)).ToList(); - - //VERIFY - blogs.Count.ShouldEqual(2); - blogs.All(x => x.Posts != null).ShouldEqual(true); - blogs.All(x => x.Posts.All(y => y.Tags != null)).ShouldEqual(true); - - } - } - - [Test] - public void Check05ReadPostsOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - - //ATTEMPT - var posts = db.Posts.ToList(); - - //VERIFY - posts.Count.ShouldEqual(3); - posts.All(x => x.Blogger != null).ShouldEqual(true); - posts.All(x => x.Tags == null).ShouldEqual(true); - } - } - - - [Test] - public void Check06ReadPostsWithTagsOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - - //ATTEMPT - var posts = db.Posts.Include(x => x.Tags).ToList(); - - //VERIFY - posts.Count.ShouldEqual(3); - posts.All(x => x.Blogger != null).ShouldEqual(true); - posts.All(x => x.Tags != null).ShouldEqual(true); - } - } - - [Test] - public void Check10ReadTAllocatedTagsWithUglySlugOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - - //ATTEMPT - var postsWithuglyTags = db.Posts.Where(x => x.Tags.Any(y => y.Slug == "ugly")).ToList(); - var uglyTagPosts = db.Tags.Include(x => x.Posts).Single(y => y.Slug == "ugly").Posts; - - //VERIFY - postsWithuglyTags.Count.ShouldEqual(2); - uglyTagPosts.Count().ShouldEqual(2); - } - } - - //----------------------------------------------------------------- - //now adding new posts, tags etc. - - [Test] - public void Check20AddPostOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var snap = new DbSnapShot(db); - - //ATTEMPT - var uglyTag = db.Tags.Single(x => x.Slug == "ugly"); - var jonBlogger = db.Blogs.First(); - var newPost = new Post - { - Blogger = jonBlogger, - Content = "a few simple words.", - Title = "A new post", - Tags = new[] { uglyTag } - }; - - db.Posts.Add(newPost); - var status = db.SaveChangesWithChecking(); - - //VERIFY - status.IsValid.ShouldEqual(true, status.Errors); - snap.CheckSnapShot(db, 1, 1); - var uglyPosts = db.Tags.Include(x => x.Posts).Single(y => y.Slug == "ugly").Posts; - uglyPosts.Count.ShouldEqual(3); - } - } - - [Test] - public void Check21CheckUpdateSimpleOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var snap = new DbSnapShot(db); - var newGuid = Guid.NewGuid().ToString(); - - //ATTEMPT - var firstPost = db.Posts.First(); - firstPost.Title = newGuid; - var status = db.SaveChangesWithChecking(); - - //VERIFY - status.IsValid.ShouldEqual(true, status.Errors); - snap.CheckSnapShot(db); - db.Posts.First().Title.ShouldEqual(newGuid); - } - } - - - [Test] - public void Check22CheckUpdateLastUpdatedOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var snap = new DbSnapShot(db); - var firstPost = db.Posts.First(); - var originalDateTime = firstPost.LastUpdated; - Thread.Sleep(400); - - //ATTEMPT - firstPost.Title = Guid.NewGuid().ToString(); - var status = db.SaveChangesWithChecking(); - - //VERIFY - status.IsValid.ShouldEqual(true, status.Errors); - snap.CheckSnapShot(db); - Assert.GreaterOrEqual(db.Posts.First().LastUpdated.Subtract(originalDateTime).Milliseconds, 400); - } - } - - [Test] - public void Check25UpdatePostToAddTagOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var snap = new DbSnapShot(db); - var badTag = db.Tags.Single(x => x.Slug == "bad"); - var firstPost = db.Posts.First(); - - //ATTEMPT - db.Entry(firstPost).Collection(x => x.Tags).Load(); - firstPost.Tags.Add(badTag); - var status = db.SaveChangesWithChecking(); - - //VERIFY - status.IsValid.ShouldEqual(true, status.Errors); - snap.CheckSnapShot(db, 0, 1); - firstPost = db.Blogs.Include(x => x.Posts.Select(y => y.Tags)).First().Posts.First(); - firstPost.Tags.Count.ShouldEqual(3); - } - } - - [Test] - public void Check26ReplaceTagsOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var snap = new DbSnapShot(db); - var firstPost = db.Posts.First(); - var tagsNotInFirstPostTracked = db.Tags.Where(x => x.Posts.All(y => y.PostId != firstPost.PostId)).ToList(); - - //ATTEMPT - - db.Entry(firstPost).Collection(x => x.Tags).Load(); - firstPost.Tags = tagsNotInFirstPostTracked; - var status = db.SaveChangesWithChecking(); - - //VERIFY - status.IsValid.ShouldEqual(true, status.Errors); - snap.CheckSnapShot(db, 0, -1); - firstPost = db.Blogs.Include(x => x.Posts.Select(y => y.Tags)).First().Posts.First(); - firstPost.Tags.Count.ShouldEqual(1); - } - } - - [Test] - public void Check30CheckCreateLastUpdatedOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var snap = new DbSnapShot(db); - var firstPostUntracked = db.Posts.AsNoTracking().First(); - var originalDateTime = firstPostUntracked.LastUpdated; - Thread.Sleep(400); - - //ATTEMPT - firstPostUntracked.Title = Guid.NewGuid().ToString(); - firstPostUntracked.Blogger = db.Blogs.First(); - firstPostUntracked.Tags = db.Tags.Take(2).ToList(); - db.Posts.Add(firstPostUntracked); - var status = db.SaveChangesWithChecking(); - - //VERIFY - status.IsValid.ShouldEqual(true, status.Errors); - snap.CheckSnapShot(db,1,2); - var loadedPost = db.Posts.Single(x => x.PostId == firstPostUntracked.PostId); - Assert.GreaterOrEqual(loadedPost.LastUpdated.Subtract(originalDateTime).Milliseconds, 400); - } - } - - [Test] - public void Check31CheckCreateDataOk() - { - using (var db = new SampleWebAppDb()) - { - //SETUP - var snap = new DbSnapShot(db); - var firstPostUntracked = db.Posts.AsNoTracking().First(); - - //ATTEMPT - firstPostUntracked.Title = Guid.NewGuid().ToString(); - firstPostUntracked.Blogger = db.Blogs.First(); - firstPostUntracked.Tags = db.Tags.Take(2).ToList(); - db.Posts.Add(firstPostUntracked); - var status = db.SaveChangesWithChecking(); - - //VERIFY - status.IsValid.ShouldEqual(true, status.Errors); - snap.CheckSnapShot(db,1,2); - var loadedPost = db.Posts.Include( x => x.Blogger).Include( x => x.Tags).Single(x => x.PostId == firstPostUntracked.PostId); - loadedPost.Blogger.BlogId.ShouldEqual(db.Blogs.First().BlogId); - CollectionAssert.AreEquivalent(db.Tags.Take(2).Select(x => x.TagId), loadedPost.Tags.Select(x => x.TagId)); - } - } - } -} \ No newline at end of file diff --git a/Tests/UnitTests/Group03ServiceLayer/ServiceLayerAsyncTests.cs b/Tests/UnitTests/Group03ServiceLayer/ServiceLayerAsyncTests.cs new file mode 100644 index 0000000..bab5ad5 --- /dev/null +++ b/Tests/UnitTests/Group03ServiceLayer/ServiceLayerAsyncTests.cs @@ -0,0 +1,59 @@ +using System.Linq; +using System.Threading.Tasks; +using DataLayer.DataClasses; +using GenericServices; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ServiceLayer.PostServices; +using Tests.Helpers; + +namespace Tests.UnitTests.Group03ServiceLayer +{ + [TestFixture] + public class ServiceLayerAsyncTests + { + [Test] + public async Task DetailAsync_ReturnsPost() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var detail = scope.ServiceProvider.GetRequiredService(); + + var firstId = db.Posts.OrderBy(p => p.PostId).First().PostId; + var response = await detail.GetDetailAsync(firstId); + + Assert.That(response.IsValid, Is.True, string.Join(";", response.Errors.Select(e => e.ErrorMessage))); + Assert.That(response.Result.PostId, Is.EqualTo(firstId)); + } + + [Test] + public async Task CreateAsync_WithSelectedTags_Succeeds() + { + using var app = new TestServices(); + int createdId; + using (var scope = app.CreateScope()) + { + var db = scope.ServiceProvider.GetRequiredService(); + var createSetup = scope.ServiceProvider.GetRequiredService(); + var createSvc = scope.ServiceProvider.GetRequiredService(); + + var dto = await createSetup.GetDtoAsync(); + dto.Title = "Async New Post"; + dto.Content = "Async content."; + dto.Bloggers.SelectedValue = db.Blogs.First().BlogId.ToString(); + dto.UserChosenTags.FinalSelection = db.Tags.Take(2).Select(t => t.TagId.ToString()).ToArray(); + + var response = await createSvc.CreateAsync(dto); + Assert.That(response.IsValid, Is.True, string.Join(";", response.Errors.Select(e => e.ErrorMessage))); + } + + using (var scope = app.CreateScope()) + { + var db = scope.ServiceProvider.GetRequiredService(); + createdId = db.Posts.Count(p => p.Title == "Async New Post"); + Assert.That(createdId, Is.EqualTo(1)); + } + } + } +} diff --git a/Tests/UnitTests/Group03ServiceLayer/ServiceLayerCrudTests.cs b/Tests/UnitTests/Group03ServiceLayer/ServiceLayerCrudTests.cs new file mode 100644 index 0000000..fa68ee3 --- /dev/null +++ b/Tests/UnitTests/Group03ServiceLayer/ServiceLayerCrudTests.cs @@ -0,0 +1,151 @@ +using System.Linq; +using DataLayer.DataClasses; +using DataLayer.DataClasses.Concrete; +using GenericServices; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ServiceLayer.BlogServices; +using ServiceLayer.PostServices; +using ServiceLayer.TagServices; +using Tests.Helpers; + +namespace Tests.UnitTests.Group03ServiceLayer +{ + [TestFixture] + public class ServiceLayerCrudTests + { + [Test] + public void BlogListDto_FlattensPostsCount() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var list = scope.ServiceProvider.GetRequiredService(); + + var blogs = list.GetAll().ToList(); + + Assert.That(blogs.Count, Is.EqualTo(2)); + Assert.That(blogs.Sum(b => b.PostsCount), Is.EqualTo(3)); + } + + [Test] + public void TagListDto_FlattensPostsCount() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var list = scope.ServiceProvider.GetRequiredService(); + + var tags = list.GetAll().ToList(); + + Assert.That(tags.Count, Is.EqualTo(3)); + Assert.That(tags.All(t => !string.IsNullOrEmpty(t.Slug))); + } + + [Test] + public void SimplePostDto_FlattensBloggerNameAndProjectsTags() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var list = scope.ServiceProvider.GetRequiredService(); + + var posts = list.GetAll().ToList(); + + Assert.That(posts.Count, Is.EqualTo(3)); + Assert.That(posts.All(p => !string.IsNullOrEmpty(p.BloggerName))); + Assert.That(posts.All(p => p.Tags != null)); + } + + [Test] + public void DetailSetup_PopulatesBloggerAndTagPickers() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var setup = scope.ServiceProvider.GetRequiredService(); + + var firstId = db.Posts.OrderBy(p => p.PostId).First().PostId; + var dto = setup.GetOriginal(firstId).Result; + + Assert.That(dto.Bloggers.KeyValueList, Is.Not.Empty); + Assert.That(dto.UserChosenTags.AllPossibleOptions, Is.Not.Empty); + Assert.That(dto.UserChosenTags.FinalSelection, Is.Not.Empty); + } + + [Test] + public void UpdatePost_ChangesTitleAndReplacesTags() + { + using var app = new TestServices(); + int postId; + using (var scope = app.CreateScope()) + { + var db = scope.ServiceProvider.GetRequiredService(); + var setupSvc = scope.ServiceProvider.GetRequiredService(); + var updateSvc = scope.ServiceProvider.GetRequiredService(); + + postId = db.Posts.OrderBy(p => p.PostId).First().PostId; + var dto = setupSvc.GetOriginal(postId).Result; + dto.Title = "UPDATED TITLE"; + dto.Bloggers.SelectedValue = dto.BlogId.ToString(); + dto.UserChosenTags.FinalSelection = + new[] { dto.UserChosenTags.AllPossibleOptions.First().Value.ToString() }; + + var response = updateSvc.Update(dto); + Assert.That(response.IsValid, Is.True, string.Join(";", response.Errors.Select(e => e.ErrorMessage))); + Assert.That(response.SuccessMessage, Does.Contain("updated")); + } + + using (var scope = app.CreateScope()) + { + var db = scope.ServiceProvider.GetRequiredService(); + var post = db.Posts.Include(p => p.Tags).First(p => p.PostId == postId); + Assert.That(post.Title, Is.EqualTo("UPDATED TITLE")); + Assert.That(post.Tags.Count, Is.EqualTo(1)); + } + } + + [Test] + public void CreatePost_WithSelectedTags_Succeeds() + { + using var app = new TestServices(); + using (var scope = app.CreateScope()) + { + var db = scope.ServiceProvider.GetRequiredService(); + var createSetup = scope.ServiceProvider.GetRequiredService(); + var createSvc = scope.ServiceProvider.GetRequiredService(); + + var dto = createSetup.GetDto(); + dto.Title = "Brand New Post"; + dto.Content = "Some content here."; + dto.Bloggers.SelectedValue = db.Blogs.First().BlogId.ToString(); + dto.UserChosenTags.FinalSelection = db.Tags.Take(2).Select(t => t.TagId.ToString()).ToArray(); + + var response = createSvc.Create(dto); + Assert.That(response.IsValid, Is.True, string.Join(";", response.Errors.Select(e => e.ErrorMessage))); + Assert.That(response.SuccessMessage, Does.Contain("created")); + } + + using (var scope = app.CreateScope()) + { + var db = scope.ServiceProvider.GetRequiredService(); + var created = db.Posts.Include(p => p.Tags).FirstOrDefault(p => p.Title == "Brand New Post"); + Assert.That(created, Is.Not.Null); + Assert.That(created.Tags.Count, Is.EqualTo(2)); + } + } + + [Test] + public void DeletePost_RemovesIt() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var deleteSvc = scope.ServiceProvider.GetRequiredService(); + + var postId = db.Posts.OrderBy(p => p.PostId).First().PostId; + var response = deleteSvc.Delete(postId); + + Assert.That(response.IsValid, Is.True, string.Join(";", response.Errors.Select(e => e.ErrorMessage))); + Assert.That(db.Posts.Any(p => p.PostId == postId), Is.False); + } + } +} diff --git a/Tests/UnitTests/Group03ServiceLayer/ServiceLayerValidationTests.cs b/Tests/UnitTests/Group03ServiceLayer/ServiceLayerValidationTests.cs new file mode 100644 index 0000000..3ffb3e3 --- /dev/null +++ b/Tests/UnitTests/Group03ServiceLayer/ServiceLayerValidationTests.cs @@ -0,0 +1,95 @@ +using System.Linq; +using DataLayer.DataClasses; +using DataLayer.DataClasses.Concrete; +using GenericServices; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ServiceLayer.PostServices; +using Tests.Helpers; + +namespace Tests.UnitTests.Group03ServiceLayer +{ + [TestFixture] + public class ServiceLayerValidationTests + { + [Test] + public void CreatePost_WithNoBlogger_IsRejected() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var createSetup = scope.ServiceProvider.GetRequiredService(); + var createSvc = scope.ServiceProvider.GetRequiredService(); + + var dto = createSetup.GetDto(); + dto.Title = "No blogger post"; + dto.Content = "content"; + dto.Bloggers.SelectedValue = null; + dto.UserChosenTags.FinalSelection = new[] { db.Tags.First().TagId.ToString() }; + + var response = createSvc.Create(dto); + + Assert.That(response.IsValid, Is.False); + Assert.That(string.Join(";", response.Errors.Select(e => e.ErrorMessage)), + Does.Contain("The blogger was not selected")); + } + + [Test] + public void CreatePost_WithNoTags_IsRejected() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var createSetup = scope.ServiceProvider.GetRequiredService(); + var createSvc = scope.ServiceProvider.GetRequiredService(); + + var dto = createSetup.GetDto(); + dto.Title = "No tags post"; + dto.Content = "content"; + dto.Bloggers.SelectedValue = db.Blogs.First().BlogId.ToString(); + dto.UserChosenTags.FinalSelection = new string[0]; + + var response = createSvc.Create(dto); + + Assert.That(response.IsValid, Is.False); + Assert.That(string.Join(";", response.Errors.Select(e => e.ErrorMessage)), + Does.Contain("at least one tag")); + } + + [Test] + public void CreatePost_WithExclamationInTitle_IsRejectedByEntityRule() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var createSetup = scope.ServiceProvider.GetRequiredService(); + var createSvc = scope.ServiceProvider.GetRequiredService(); + + var dto = createSetup.GetDto(); + dto.Title = "Bad!"; + dto.Content = "ok content"; + dto.Bloggers.SelectedValue = db.Blogs.First().BlogId.ToString(); + dto.UserChosenTags.FinalSelection = new[] { db.Tags.First().TagId.ToString() }; + + var response = createSvc.Create(dto); + + Assert.That(response.IsValid, Is.False); + } + + [Test] + public void CreateTag_WithDuplicateSlug_IsRejected() + { + using var app = new TestServices(); + using var scope = app.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var createSvc = scope.ServiceProvider.GetRequiredService(); + + var existingSlug = db.Tags.First().Slug; + var response = createSvc.Create(new Tag { Name = "Some Name", Slug = existingSlug }); + + Assert.That(response.IsValid, Is.False); + Assert.That(string.Join(";", response.Errors.Select(e => e.ErrorMessage)), + Does.Contain("must be unique")); + } + } +} diff --git a/Tests/UnitTests/Group03ServiceLayer/Test10DiSimple.cs b/Tests/UnitTests/Group03ServiceLayer/Test10DiSimple.cs deleted file mode 100644 index b502ff5..0000000 --- a/Tests/UnitTests/Group03ServiceLayer/Test10DiSimple.cs +++ /dev/null @@ -1,296 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: Test10DiSimple.cs -// Date Created: 2014/05/22 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.Linq; -using System.Reflection; -using Autofac; -using Autofac.Core; -using NUnit.Framework; -using Tests.DependencyItems; -using Tests.Helpers; - -namespace Tests.UnitTests.Group03ServiceLayer -{ - class Test10DiSimple - { - - [Test] - public void Test01AutoFacSimple() - { - //SETUP - var builder = new ContainerBuilder(); - builder.RegisterType().As(); - var container = builder.Build(); - - //ATTEMPT & VERIFY - using (var lifetimeScope = container.BeginLifetimeScope()) - { - var instance = lifetimeScope.Resolve(); - Assert.NotNull(instance); - (instance is SimpleClass).ShouldEqual(true); - } - - } - - [Test] - public void Test02AutoFacTransient() - { - //Setup - var builder = new ContainerBuilder(); - builder.RegisterType().As(); - var container = builder.Build(); - - //Attempt - ISimpleClass instance1; - using (var lifetimeScope = container.BeginLifetimeScope()) - instance1 = lifetimeScope.Resolve(); - ISimpleClass instance2; - using (var lifetimeScope = container.BeginLifetimeScope()) - instance2 = lifetimeScope.Resolve(); - - //Verify - Assert.NotNull(instance1); - Assert.NotNull(instance2); - Assert.AreNotSame(instance1, instance2); - - } - - - [Test] - public void Test03AutoFacSingle() - { - //Setup - var builder = new ContainerBuilder(); - builder.RegisterType().As().SingleInstance(); - var container = builder.Build(); - - //Attempt - ISimpleClass instance1; - using (var lifetimeScope = container.BeginLifetimeScope()) - instance1 = lifetimeScope.Resolve(); - ISimpleClass instance2; - using (var lifetimeScope = container.BeginLifetimeScope()) - instance2 = lifetimeScope.Resolve(); - - //Verify - Assert.NotNull(instance1); - Assert.NotNull(instance2); - Assert.AreSame(instance1, instance2); - - } - - [Test] - public void Test04AutoFacLifeTimeScope() - { - //Setup - var builder = new ContainerBuilder(); - builder.RegisterType().As().InstancePerLifetimeScope(); - var container = builder.Build(); - - //Attempt and VERIFY - ISimpleClass scope1Instance1; - ISimpleClass scope1Instance2; - using (var lifetimeScope = container.BeginLifetimeScope()) - { - scope1Instance1 = lifetimeScope.Resolve(); - scope1Instance2 = lifetimeScope.Resolve(); - Assert.NotNull(scope1Instance1); - Assert.NotNull(scope1Instance2); - Assert.AreSame(scope1Instance1, scope1Instance2); - } - - using (var lifetimeScope = container.BeginLifetimeScope()) - { - ISimpleClass scope2Instance1 = lifetimeScope.Resolve(); - Assert.NotNull(scope2Instance1); - Assert.NotNull(scope1Instance1); - Assert.NotNull(scope1Instance2); - Assert.AreNotSame(scope1Instance1, scope2Instance1); - Assert.AreNotSame(scope1Instance1, scope2Instance1); - } - - } - - //----------------------------------------------------------- - //item with constructor param - - [Test] - public void Test05AutoFacConstructor() - { - //SETUP - var builder = new ContainerBuilder(); - builder.RegisterType().As() - .WithParameter("myInt", 42); - var container = builder.Build(); - - //ATTEMPT & VERIFY - using (var lifetimeScope = container.BeginLifetimeScope()) - { - var instance = lifetimeScope.Resolve(); - Assert.NotNull(instance); - instance.MyInt.ShouldEqual(42); - } - - } - - - //----------------------------------------------------------- - //tests on IDisposable items - - private int _numTimeDisposeCalled; - - [Test] - public void Test15AutoFacDisposeCreate() - { - //Setup - var builder = new ContainerBuilder(); - Action checker = (() => _numTimeDisposeCalled++); - builder.RegisterType().As().WithParameter("disposeWasCalled", checker); - var container = builder.Build(); - - //Attempt - _numTimeDisposeCalled = 0; - var mydisp = container.Resolve(); - - //Verify - Assert.NotNull(mydisp); - _numTimeDisposeCalled.ShouldEqual(0); - - } - - [Test] - public void Test16AutoFacDisposeCalled() - { - //Setup - var builder = new ContainerBuilder(); - Action checker = (() => _numTimeDisposeCalled++); - builder.RegisterType().As().WithParameter("disposeWasCalled", checker); - var container = builder.Build(); - - //Attempt - _numTimeDisposeCalled = 0; - using (var lifetimeScope = container.BeginLifetimeScope()) - { - var mydisp = lifetimeScope.Resolve(); - Assert.NotNull(mydisp); - } - - //Verify - _numTimeDisposeCalled.ShouldEqual(1); - - } - - //-------------------------------------------------------------- - //register generic - - [Test] - public void Test20AutoFacRegisterGeneric() - { - //SETUP - var builder = new ContainerBuilder(); - builder.RegisterGeneric(typeof(GenericInterface<>)).As(typeof(IGenericInterface<>)); - var container = builder.Build(); - - //ATTEMPT & VERIFY - using (var lifetimeScope = container.BeginLifetimeScope()) - { - var instance = lifetimeScope.Resolve>(); - Assert.NotNull(instance); - (instance is GenericInterface).ShouldEqual(true); - instance.GetTypeName().ShouldEqual(typeof(SimpleClass).Name); - } - - } - - [Test] - public void Test21AutoFacRegisterGenericAfterRegisterAssembly() - { - //SETUP - var builder = new ContainerBuilder(); - builder.RegisterAssemblyTypes(GetType().Assembly).AsImplementedInterfaces(); - builder.RegisterGeneric(typeof(GenericInterface<>)).As(typeof(IGenericInterface<>)); - var container = builder.Build(); - - //ATTEMPT & VERIFY - using (var lifetimeScope = container.BeginLifetimeScope()) - { - var instance = lifetimeScope.Resolve>(); - Assert.NotNull(instance); - (instance is GenericInterface).ShouldEqual(true); - instance.GetTypeName().ShouldEqual(typeof(SimpleClass).Name); - } - - } - - //--------------------------------------------------------- - //tests on what happens if ctor is private - - [Test] - public void Test30AutoFacRegisterClassWithPrivateCtorBad() - { - //SETUP - var builder = new ContainerBuilder(); - builder.RegisterType().As(); - var container = builder.Build(); - - //ATTEMPT & VERIFY - using (var lifetimeScope = container.BeginLifetimeScope()) - { - var ex = Assert.Throws(() => lifetimeScope.Resolve()); - ex.Message.ShouldStartWith("No constructors on type"); - } - - } - - [Test] - public void Test31AutoFacTryCtorWithPrivateCtorAsOptionOk() - { - //SETUP - var builder = new ContainerBuilder(); - builder.RegisterType().As(); - builder.RegisterGeneric(typeof (ClassToTestClassWithPrivateCtor<>)) - .As(typeof (IClassToTestClassWithPrivateCtor<>)) - .OnActivating(e => - { - var interfaceToLookup = e.Instance.GetType().GetGenericArguments()[0]; - var resolvedInterface = - e.Context.ComponentRegistry.RegistrationsFor(new TypedService(interfaceToLookup)).SingleOrDefault(); - ((ISetType)e.Instance).SetType(resolvedInterface.Activator.LimitType); - }); - var container = builder.Build(); - - //ATTEMPT & VERIFY - using (var lifetimeScope = container.BeginLifetimeScope()) - { - var instance = lifetimeScope.Resolve>(); - Assert.NotNull(instance); - (instance is ClassToTestClassWithPrivateCtor).ShouldEqual(true); - } - - } - } -} diff --git a/Tests/UnitTests/Group03ServiceLayer/Test11AutoFacModules.cs b/Tests/UnitTests/Group03ServiceLayer/Test11AutoFacModules.cs deleted file mode 100644 index 3d4ff00..0000000 --- a/Tests/UnitTests/Group03ServiceLayer/Test11AutoFacModules.cs +++ /dev/null @@ -1,167 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: Test11AutoFacModules.cs -// Date Created: 2014/05/22 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System.Linq; -using Autofac; -using DataLayer.DataClasses; -using DataLayer.DataClasses.Concrete; -using DataLayer.Startup; -using GenericServices; -using GenericServices.Services.Concrete; -using NUnit.Framework; -using SampleWebApp.Infrastructure; -using ServiceLayer.Startup; -using Tests.Helpers; - -namespace Tests.UnitTests.Group03ServiceLayer -{ - [TestFixture] - public class Test11AutoFacModules - { - - [TestFixtureSetUp] - public void FixtureSetUp() - { - using (var db = new SampleWebAppDb()) - { - DataLayerInitialise.InitialiseThis(false, true); - DataLayerInitialise.ResetBlogs(db, TestDataSelection.Small); - } - } - - - //------------------------------------- - //DataLayer - - [Test] - public void CheckSetupDbContextLifetimeScopeItems() - { - //SETUP - var builder = new ContainerBuilder(); - builder.RegisterModule( new DataLayerModule()); - var container = builder.Build(); - - //ATTEMPT & VERIFY - using (var lifetimeScope = container.BeginLifetimeScope()) - { - var instance1 = lifetimeScope.Resolve(); - var instance2 = lifetimeScope.Resolve(); - Assert.NotNull(instance1); - (instance1 is SampleWebAppDb).ShouldEqual(true); - Assert.AreSame(instance1, instance2); //check that lifetimescope is working - } - } - - - //--------------------------------------------- - //ServiceLayer, which also resolves DataLayer - - [Test] - public void Test10ServiceSetupServiceLayer() - { - //SETUP - var builder = new ContainerBuilder(); - builder.RegisterModule(new ServiceLayerModule()); - var container = builder.Build(); - - //ATTEMPT & VERIFY - CheckExampleServicesResolve(container); - } - - - [Test] - public void Test15SetupServiceLayerDirectGenerics() - { - //SETUP - var builder = new ContainerBuilder(); - builder.RegisterModule(new ServiceLayerModule()); - var container = builder.Build(); - - //ATTEMPT & VERIFY - using (var lifetimeScope = container.BeginLifetimeScope()) - { - var instance = lifetimeScope.Resolve(); - Assert.NotNull(instance); - (instance is ListService).ShouldEqual(true); - } - } - - [Test] - public void Test16UseServiceLayerDirectGenerics() - { - //SETUP - var builder = new ContainerBuilder(); - builder.RegisterModule(new ServiceLayerModule()); - var container = builder.Build(); - - //ATTEMPT & VERIFY - using (var lifetimeScope = container.BeginLifetimeScope()) - { - var service = lifetimeScope.Resolve(); - var posts = service.GetAll().ToList(); - posts.Count.ShouldEqual(3); - } - } - - //------------------------------------------------------ - //MVC layer - - [Test] - public void Test20ViaMvcSetup() - { - //SETUP - var container = AutofacDi.SetupDependency(); - - //ATTEMPT & VERIFY - CheckExampleServicesResolve(container); - - } - - //------------------------------------------------------- - //private helper - - private static void CheckExampleServicesResolve(IContainer container) - { - using (var lifetimeScope = container.BeginLifetimeScope()) - { - //DataLayer - Data classes - - //DataLayer - repositories - var db1 = lifetimeScope.Resolve(); - var db2 = lifetimeScope.Resolve(); - Assert.NotNull(db1); - Assert.AreSame(db1, db2); //check that lifetimescope is working - - //ServiceLayer - complex - var service1 = lifetimeScope.Resolve(); - var service2 = lifetimeScope.Resolve(); - Assert.NotNull(service1); - Assert.AreNotSame(service1, service2); //check transient - (service1 is ListService).ShouldEqual(true); - } - } - } -} diff --git a/Tests/UnitTests/Group06Mvc/Test02Validation.cs b/Tests/UnitTests/Group06Mvc/Test02Validation.cs deleted file mode 100644 index 7ef1d18..0000000 --- a/Tests/UnitTests/Group06Mvc/Test02Validation.cs +++ /dev/null @@ -1,273 +0,0 @@ -#region licence -// The MIT License (MIT) -// -// Filename: Test02Validation.cs -// Date Created: 2014/06/10 -// -// Copyright (c) 2014 Jon Smith (www.selectiveanalytics.com & www.thereformedprogrammer.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion -using System; -using System.Linq; -using GenericLibsBase.Core; -using GenericServices.Core; -using NUnit.Framework; -using SampleWebApp.Infrastructure; -using Tests.Helpers; - -namespace Tests.UnitTests.Group06Mvc -{ - class Test02Validation - { - - [Test] - public void Check01TestModelValidate() - { - //SETUP - var model = new ModelStateTester.TestModel("123", 50, true); - - //ATTEMPT - var vErrors = model.Validate(null).ToList(); - - //VERIFY - vErrors.Count.ShouldEqual(2); - vErrors[0].MemberNames.Any().ShouldEqual(false); - vErrors[0].ErrorMessage.ShouldEqual("This is a top level error caused by CreateValidationError being set."); - vErrors[1].MemberNames.Any().ShouldEqual(false); - vErrors[1].ErrorMessage.ShouldEqual("This is a top level error caused by MyInt having value 50."); - } - - - [Test] - public void Check05TestModelStateValidateOnly() - { - //SETUP - var model = new ModelStateTester.TestModel("123", 50, true); - - //ATTEMPT - var modelState = model.ReturnModelState(); - - //VERIFY - modelState.IsValid.ShouldEqual(false); - modelState.Keys.Count.ShouldEqual(1); - modelState.Keys.First().ShouldEqual(""); - modelState[modelState.Keys.First()].Errors.Count.ShouldEqual(2); - modelState[modelState.Keys.First()].Errors[0].ErrorMessage.ShouldEqual("This is a top level error caused by CreateValidationError being set."); - modelState[modelState.Keys.First()].Errors[1].ErrorMessage.ShouldEqual("This is a top level error caused by MyInt having value 50."); - } - - [Test] - public void Check06TestModelStateValidateOneOnly() - { - //SETUP - var model = new ModelStateTester.TestModel("123", 2, true); - - //ATTEMPT - var modelState = model.ReturnModelState(); - - //VERIFY - modelState.IsValid.ShouldEqual(false); - modelState.Keys.Count.ShouldEqual(1); - modelState.Keys.First().ShouldEqual(""); - modelState[modelState.Keys.First()].Errors.Count.ShouldEqual(1); - modelState[modelState.Keys.First()].Errors[0].ErrorMessage.ShouldEqual("This is a top level error caused by CreateValidationError being set."); - } - - [Test] - public void Check06TestModelStateIntAttributeOnly() - { - //SETUP - var model = new ModelStateTester.TestModel("123", -1, false); - - //ATTEMPT - var modelState = model.ReturnModelState(); - - //VERIFY - modelState.IsValid.ShouldEqual(false); - modelState.Keys.Count.ShouldEqual(1); - modelState.Keys.First().ShouldEqual("MyInt"); - modelState[modelState.Keys.First()].Errors.Count.ShouldEqual(1); - modelState[modelState.Keys.First()].Errors[0].ErrorMessage.ShouldEqual("The field MyInt must be between 0 and 100."); - - } - - [Test] - public void Check07TestModelStateStringAttributeOnly() - { - //SETUP - var model = new ModelStateTester.TestModel("", 2, false); - - //ATTEMPT - var modelState = model.ReturnModelState(); - - //VERIFY - modelState.IsValid.ShouldEqual(false); - modelState.Keys.Count.ShouldEqual(1); - modelState.Keys.First().ShouldEqual("MyString"); - CollectionAssert.AreEquivalent(new[] - { - "The field MyString must be a string or array type with a minimum length of '2'.", - "The MyString field is required." - }, - modelState[modelState.Keys.First()].Errors.Select( x => x.ErrorMessage)); - - - } - - [Test] - public void Check08TestModelStateMixedErrorsOnly() - { - //SETUP - var model = new ModelStateTester.TestModel("", -1, true); - - //ATTEMPT - var modelState = model.ReturnModelState(); - - //VERIFY - modelState.IsValid.ShouldEqual(false); - CollectionAssert.AreEquivalent(new[] { "MyInt", "MyString" }, modelState.Keys); //Note: only runs Validate if no attribute errors - modelState["MyInt"].Errors.Count.ShouldEqual(1); - modelState["MyString"].Errors.Count.ShouldEqual(2); - } - - //--------------------------------------------------------------------- - //now use to check ValidationHelper ReturnModelErrorsAsJson - - [Test] - public void Check15TestModelStateValidateOnly() - { - //SETUP - var model = new ModelStateTester.TestModel("123", 50, true); - - //ATTEMPT - var jsonResult = model.ReturnModelState().ReturnModelErrorsAsJson(); - - //VERIFY - var json = jsonResult.Data.SerialiseToJson(); - json.ShouldEqual("{\"errorsDict\":{\"\":{\"errors\":[\"This is a top level error caused by CreateValidationError being set.\",\"This is a top level error caused by MyInt having value 50.\"]}}}"); - } - - [Test] - public void Check16TestModelStateValidateOneOnly() - { - //SETUP - var model = new ModelStateTester.TestModel("123", 2, true); - - //ATTEMPT - var jsonResult = model.ReturnModelState().ReturnModelErrorsAsJson(); - - //VERIFY - var json = jsonResult.Data.SerialiseToJson(); - json.ShouldEqual("{\"errorsDict\":{\"\":{\"errors\":[\"This is a top level error caused by CreateValidationError being set.\"]}}}"); - } - - - [Test] - public void Check16TestModelStateIntAttributeOnly() - { - //SETUP - var model = new ModelStateTester.TestModel("123", -1, false); - - //ATTEMPT - var jsonResult = model.ReturnModelState().ReturnModelErrorsAsJson(); - - //VERIFY - var json = jsonResult.Data.SerialiseToJson(); - json.ShouldEqual("{\"errorsDict\":{\"MyInt\":{\"errors\":[\"The field MyInt must be between 0 and 100.\"]}}}"); - } - - [Test] - public void Check17TestModelStateStringAttributeOnly() - { - //SETUP - var model = new ModelStateTester.TestModel("", 2, false); - - //ATTEMPT - var jsonResult = model.ReturnModelState().ReturnModelErrorsAsJson(); - - //VERIFY - var json = jsonResult.Data.SerialiseToJson(); - const string order1 = "{\"errorsDict\":{\"MyString\":{\"errors\":[\"The field MyString must be a string or array type with a minimum length of '2'.\",\"The MyString field is required.\"]}}}"; - const string order1Json = "{\"errorsDict\":{\"MyString\":{\"errors\":[\"The field MyString must be a string or array type with a minimum length of \\u00272\\u0027.\",\"The MyString field is required.\"]}}}"; - - const string order2 = "{\"errorsDict\":{\"MyString\":{\"errors\":[\"The MyString field is required.\",\"The field MyString must be a string or array type with a minimum length of '2'.\"]}}}"; - const string order2Json = - "{\"errorsDict\":{\"MyString\":{\"errors\":[\"The MyString field is required.\",\"The field MyString must be a string or array type with a minimum length of \\u00272\\u0027.\"]}}}"; - (json == order1Json || json == order2Json).ShouldEqual(true); - - } - - [Test] - public void Check18TestModelStateMixedErrorsOnly() - { - //SETUP - var model = new ModelStateTester.TestModel("", -1, true); - - //ATTEMPT - var jsonResult = model.ReturnModelState().ReturnModelErrorsAsJson(); - - //VERIFY - var json = jsonResult.Data.SerialiseToJson(); - const string order1 = "{\"errorsDict\":{\"MyString\":{\"errors\":[\"The field MyString must be a string or array type with a minimum length of '2'.\",\"The MyString field is required.\"]},"; - const string order1Json = "{\"errorsDict\":{\"MyString\":{\"errors\":[\"The field MyString must be a string or array type with a minimum length of \\u00272\\u0027.\",\"The MyString field is required.\"]},"; - const string order2 = "{\"errorsDict\":{\"MyString\":{\"errors\":[\"The MyString field is required.\",\"The field MyString must be a string or array type with a minimum length of '2'.\"]},"; - const string order2Json = - "{\"errorsDict\":{\"MyString\":{\"errors\":[\"The MyString field is required.\",\"The field MyString must be a string or array type with a minimum length of \\u00272\\u0027.\"]},"; - const string part2 = "\"MyInt\":{\"errors\":[\"The field MyInt must be between 0 and 100.\"]}}}"; - (json == order1Json + part2 || json == order2Json + part2).ShouldEqual(true); - } - - //------------------------------------------------------------------- - //now the ReturnErrorsAsJson - - [Test] - public void Check20StatusToJsonTopLevel() - { - //SETUP - var status = new SuccessOrErrors(); - var dto = new {MyInt = 1}; - - //ATTEMPT - status.AddSingleError("This is a top level error."); - var jsonResult = status.ReturnErrorsAsJson(dto); - - //VERIFY - var json = jsonResult.Data.SerialiseToJson(); - json.ShouldEqual("{\"errorsDict\":{\"\":{\"errors\":[\"This is a top level error.\"]}}}"); - } - - [Test] - public void Check21StatusToJsonProperty() - { - //SETUP - var status = new SuccessOrErrors(); - var dto = new { MyInt = 1 }; - - //ATTEMPT - status.AddNamedParameterError("MyInt", "This is a property level error."); - var jsonResult = status.ReturnErrorsAsJson(dto); - - //VERIFY - var json = jsonResult.Data.SerialiseToJson(); - json.ShouldEqual("{\"errorsDict\":{\"MyInt\":{\"errors\":[\"This is a property level error.\"]}}}"); - } - - } -} diff --git a/Tests/packages.config b/Tests/packages.config deleted file mode 100644 index 1638b50..0000000 --- a/Tests/packages.config +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/global.json b/global.json new file mode 100644 index 0000000..3fea262 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "8.0.0", + "rollForward": "latestFeature" + } +}