From 7e5e6930086fc2b1c6a6c27619bdcf818650b53c Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Sun, 6 Mar 2022 23:21:05 -0500 Subject: [PATCH] WIP on Bit Badger theme Building it in-place for now; will move it to its own assembly before going live --- .../Extensions/PageExtensions.cs | 2 +- ....cs => 20220307034307_Initial.Designer.cs} | 5 +- ...6_Initial.cs => 20220307034307_Initial.cs} | 1 + .../WebLogDbContextModelSnapshot.cs | 3 + src/MyWebLog.Data/Page.cs | 5 + .../Features/Pages/SinglePageModel.cs | 5 + src/MyWebLog/Features/Posts/PostController.cs | 4 +- .../Features/Shared/MyWebLogController.cs | 2 + .../Shared/TagHelpers/ImageTagHelper.cs | 37 + .../Shared/TagHelpers/LinkTagHelper.cs | 55 ++ src/MyWebLog/MyWebLog.csproj | 8 + src/MyWebLog/Program.cs | 2 +- .../BitBadger/Shared/_AppSidebar.cshtml | 29 + .../Themes/BitBadger/Shared/_Layout.cshtml | 56 ++ .../Themes/BitBadger/SinglePage.cshtml | 13 + src/MyWebLog/Themes/BitBadger/SolutionInfo.cs | 147 ++++ .../Themes/BitBadger/Solutions.cshtml | 43 ++ src/MyWebLog/Themes/BitBadger/solutions.json | 683 ++++++++++++++++++ .../Default/Shared/_DefaultFooter.cshtml | 2 +- .../Themes/Default/Shared/_Layout.cshtml | 3 +- src/MyWebLog/Themes/_ViewImports.cshtml | 2 + src/MyWebLog/wwwroot/css/BitBadger/style.css | 262 +++++++ .../wwwroot/img/BitBadger/bit-badger-auth.png | Bin 0 -> 23158 bytes .../wwwroot/img/BitBadger/bitbadger.png | Bin 0 -> 17821 bytes .../wwwroot/img/BitBadger/facebook.png | Bin 0 -> 6518 bytes .../wwwroot/img/BitBadger/favicon.ico | Bin 0 -> 9528 bytes .../img/BitBadger/screenshots/bay-vista.png | Bin 0 -> 55577 bytes .../img/BitBadger/screenshots/cassy-fiano.png | Bin 0 -> 58589 bytes .../screenshots/dr-melissa-clouthier.png | Bin 0 -> 70797 bytes .../emerald-mountain-christian-school.png | Bin 0 -> 71356 bytes .../BitBadger/screenshots/futility-closet.png | Bin 0 -> 92669 bytes .../BitBadger/screenshots/hard-corps-wife.png | Bin 0 -> 71627 bytes .../BitBadger/screenshots/liberty-pundits.png | Bin 0 -> 69306 bytes .../BitBadger/screenshots/mindy-mackenzie.png | Bin 0 -> 38444 bytes .../screenshots/my-prayer-journal.png | Bin 0 -> 23468 bytes .../wwwroot/img/BitBadger/screenshots/nsx.png | Bin 0 -> 47811 bytes .../BitBadger/screenshots/olivet-baptist.png | Bin 0 -> 15508 bytes .../screenshots/photography-by-michelle.png | Bin 0 -> 91626 bytes .../BitBadger/screenshots/prayer-tracker.png | Bin 0 -> 42936 bytes .../screenshots/riehl-world-news.png | Bin 0 -> 73056 bytes .../img/BitBadger/screenshots/tcms.png | Bin 0 -> 34726 bytes .../img/BitBadger/screenshots/tech-blog.png | Bin 0 -> 61486 bytes .../BitBadger/screenshots/the-shark-tank.png | Bin 0 -> 97351 bytes .../screenshots/virtual-prayer-room.png | Bin 0 -> 44572 bytes .../wwwroot/img/BitBadger/twitter.png | Bin 0 -> 10348 bytes 45 files changed, 1362 insertions(+), 7 deletions(-) rename src/MyWebLog.Data/Migrations/{20220227160816_Initial.Designer.cs => 20220307034307_Initial.Designer.cs} (99%) rename src/MyWebLog.Data/Migrations/{20220227160816_Initial.cs => 20220307034307_Initial.cs} (99%) create mode 100644 src/MyWebLog/Features/Shared/TagHelpers/ImageTagHelper.cs create mode 100644 src/MyWebLog/Features/Shared/TagHelpers/LinkTagHelper.cs create mode 100644 src/MyWebLog/Themes/BitBadger/Shared/_AppSidebar.cshtml create mode 100644 src/MyWebLog/Themes/BitBadger/Shared/_Layout.cshtml create mode 100644 src/MyWebLog/Themes/BitBadger/SinglePage.cshtml create mode 100644 src/MyWebLog/Themes/BitBadger/SolutionInfo.cs create mode 100644 src/MyWebLog/Themes/BitBadger/Solutions.cshtml create mode 100644 src/MyWebLog/Themes/BitBadger/solutions.json create mode 100644 src/MyWebLog/wwwroot/css/BitBadger/style.css create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/bit-badger-auth.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/bitbadger.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/facebook.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/favicon.ico create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/bay-vista.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/cassy-fiano.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/dr-melissa-clouthier.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/emerald-mountain-christian-school.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/futility-closet.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/hard-corps-wife.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/liberty-pundits.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/mindy-mackenzie.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/my-prayer-journal.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/nsx.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/olivet-baptist.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/photography-by-michelle.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/prayer-tracker.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/riehl-world-news.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/tcms.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/tech-blog.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/the-shark-tank.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/screenshots/virtual-prayer-room.png create mode 100644 src/MyWebLog/wwwroot/img/BitBadger/twitter.png diff --git a/src/MyWebLog.Data/Extensions/PageExtensions.cs b/src/MyWebLog.Data/Extensions/PageExtensions.cs index 4d8c26f..ea64a82 100644 --- a/src/MyWebLog.Data/Extensions/PageExtensions.cs +++ b/src/MyWebLog.Data/Extensions/PageExtensions.cs @@ -55,7 +55,7 @@ public static class PageExtensions /// The page number to retrieve /// The pages public static async Task> FindPageOfPages(this DbSet db, int pageNbr) => - await db.Skip((pageNbr - 1) * 50).Take(25).ToListAsync().ConfigureAwait(false); + await db.OrderBy(p => p.Title).Skip((pageNbr - 1) * 25).Take(25).ToListAsync().ConfigureAwait(false); /// /// Retrieve a page by its ID (tracked) diff --git a/src/MyWebLog.Data/Migrations/20220227160816_Initial.Designer.cs b/src/MyWebLog.Data/Migrations/20220307034307_Initial.Designer.cs similarity index 99% rename from src/MyWebLog.Data/Migrations/20220227160816_Initial.Designer.cs rename to src/MyWebLog.Data/Migrations/20220307034307_Initial.Designer.cs index f9df601..37c93a6 100644 --- a/src/MyWebLog.Data/Migrations/20220227160816_Initial.Designer.cs +++ b/src/MyWebLog.Data/Migrations/20220307034307_Initial.Designer.cs @@ -11,7 +11,7 @@ using MyWebLog.Data; namespace MyWebLog.Data.Migrations { [DbContext(typeof(WebLogDbContext))] - [Migration("20220227160816_Initial")] + [Migration("20220307034307_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -123,6 +123,9 @@ namespace MyWebLog.Data.Migrations b.Property("ShowInPageList") .HasColumnType("INTEGER"); + b.Property("Template") + .HasColumnType("TEXT"); + b.Property("Text") .IsRequired() .HasColumnType("TEXT"); diff --git a/src/MyWebLog.Data/Migrations/20220227160816_Initial.cs b/src/MyWebLog.Data/Migrations/20220307034307_Initial.cs similarity index 99% rename from src/MyWebLog.Data/Migrations/20220227160816_Initial.cs rename to src/MyWebLog.Data/Migrations/20220307034307_Initial.cs index cf155f5..6381fc9 100644 --- a/src/MyWebLog.Data/Migrations/20220227160816_Initial.cs +++ b/src/MyWebLog.Data/Migrations/20220307034307_Initial.cs @@ -87,6 +87,7 @@ namespace MyWebLog.Data.Migrations PublishedOn = table.Column(type: "TEXT", nullable: false), UpdatedOn = table.Column(type: "TEXT", nullable: false), ShowInPageList = table.Column(type: "INTEGER", nullable: false), + Template = table.Column(type: "TEXT", nullable: true), Text = table.Column(type: "TEXT", nullable: false) }, constraints: table => diff --git a/src/MyWebLog.Data/Migrations/WebLogDbContextModelSnapshot.cs b/src/MyWebLog.Data/Migrations/WebLogDbContextModelSnapshot.cs index 8b1df7b..bd813ee 100644 --- a/src/MyWebLog.Data/Migrations/WebLogDbContextModelSnapshot.cs +++ b/src/MyWebLog.Data/Migrations/WebLogDbContextModelSnapshot.cs @@ -121,6 +121,9 @@ namespace MyWebLog.Data.Migrations b.Property("ShowInPageList") .HasColumnType("INTEGER"); + b.Property("Template") + .HasColumnType("TEXT"); + b.Property("Text") .IsRequired() .HasColumnType("TEXT"); diff --git a/src/MyWebLog.Data/Page.cs b/src/MyWebLog.Data/Page.cs index e1b3dd7..7233fdb 100644 --- a/src/MyWebLog.Data/Page.cs +++ b/src/MyWebLog.Data/Page.cs @@ -45,6 +45,11 @@ public class Page /// public bool ShowInPageList { get; set; } = false; + /// + /// The template to use when rendering this page + /// + public string? Template { get; set; } = null; + /// /// The current text of the page /// diff --git a/src/MyWebLog/Features/Pages/SinglePageModel.cs b/src/MyWebLog/Features/Pages/SinglePageModel.cs index 6138cac..e9913c4 100644 --- a/src/MyWebLog/Features/Pages/SinglePageModel.cs +++ b/src/MyWebLog/Features/Pages/SinglePageModel.cs @@ -10,6 +10,11 @@ public class SinglePageModel : MyWebLogModel /// public Page Page { get; init; } + /// + /// Is this the home page? + /// + public bool IsHome => Page.Id == WebLog.DefaultPage; + /// /// Constructor /// diff --git a/src/MyWebLog/Features/Posts/PostController.cs b/src/MyWebLog/Features/Posts/PostController.cs index 90054f5..91b34d7 100644 --- a/src/MyWebLog/Features/Posts/PostController.cs +++ b/src/MyWebLog/Features/Posts/PostController.cs @@ -21,7 +21,7 @@ public class PostController : MyWebLogController if (WebLog.DefaultPage == "posts") return await PageOfPosts(1); var page = await Db.Pages.FindById(WebLog.DefaultPage); - return page is null ? NotFound() : ThemedView("SinglePage", new SinglePageModel(page, WebLog)); + return page is null ? NotFound() : ThemedView(page.Template ?? "SinglePage", new SinglePageModel(page, WebLog)); } [HttpGet("~/page/{pageNbr:int}")] @@ -42,7 +42,7 @@ public class PostController : MyWebLogController var page = await Db.Pages.FindByPermalink(permalink); if (page != null) { - return ThemedView("SinglePage", new SinglePageModel(page, WebLog)); + return ThemedView(page.Template ?? "SinglePage", new SinglePageModel(page, WebLog)); } // TOOD: search prior permalinks for posts and pages diff --git a/src/MyWebLog/Features/Shared/MyWebLogController.cs b/src/MyWebLog/Features/Shared/MyWebLogController.cs index f26b38b..b743564 100644 --- a/src/MyWebLog/Features/Shared/MyWebLogController.cs +++ b/src/MyWebLog/Features/Shared/MyWebLogController.cs @@ -34,6 +34,8 @@ public abstract class MyWebLogController : Controller protected ViewResult ThemedView(string template, object model) { + // TODO: get actual version + ViewBag.Version = "2"; return View(template, model); } } diff --git a/src/MyWebLog/Features/Shared/TagHelpers/ImageTagHelper.cs b/src/MyWebLog/Features/Shared/TagHelpers/ImageTagHelper.cs new file mode 100644 index 0000000..db07dae --- /dev/null +++ b/src/MyWebLog/Features/Shared/TagHelpers/ImageTagHelper.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; +using System.Text.Encodings.Web; + +namespace MyWebLog.Features.Shared.TagHelpers; + +/// +/// Image tag helper to load a theme's image +/// +[HtmlTargetElement("img", Attributes = "asp-theme")] +public class ImageTagHelper : Microsoft.AspNetCore.Mvc.TagHelpers.ImageTagHelper +{ + /// + /// The theme for which the image should be loaded + /// + [HtmlAttributeName("asp-theme")] + public string Theme { get; set; } = ""; + + /// + public ImageTagHelper(IFileVersionProvider fileVersionProvider, HtmlEncoder htmlEncoder, + IUrlHelperFactory urlHelperFactory) + : base(fileVersionProvider, htmlEncoder, urlHelperFactory) { } + + /// + public override void Process(TagHelperContext context, TagHelperOutput output) + { + if (Theme == "") + { + base.Process(context, output); + return; + } + + output.Attributes.SetAttribute("src", $"~/img/{Theme}/{context.AllAttributes["src"]?.Value}"); + ProcessUrlAttribute("src", output); + } +} diff --git a/src/MyWebLog/Features/Shared/TagHelpers/LinkTagHelper.cs b/src/MyWebLog/Features/Shared/TagHelpers/LinkTagHelper.cs new file mode 100644 index 0000000..dc25fa2 --- /dev/null +++ b/src/MyWebLog/Features/Shared/TagHelpers/LinkTagHelper.cs @@ -0,0 +1,55 @@ +using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; +using System.Text.Encodings.Web; + +namespace MyWebLog.Features.Shared.TagHelpers; + +/// +/// Tag helper to link stylesheets for a theme +/// +[HtmlTargetElement("link", Attributes = "asp-theme")] +public class LinkTagHelper : Microsoft.AspNetCore.Mvc.TagHelpers.LinkTagHelper +{ + /// + /// The theme for which a style sheet should be loaded + /// + [HtmlAttributeName("asp-theme")] + public string Theme { get; set; } = ""; + + /// + /// The style sheet to be loaded (defaults to "style") + /// + [HtmlAttributeName("asp-style")] + public string Style { get; set; } = "style"; + + /// + public LinkTagHelper(IWebHostEnvironment hostingEnvironment, TagHelperMemoryCacheProvider cacheProvider, + IFileVersionProvider fileVersionProvider, HtmlEncoder htmlEncoder, JavaScriptEncoder javaScriptEncoder, + IUrlHelperFactory urlHelperFactory) + : base(hostingEnvironment, cacheProvider, fileVersionProvider, htmlEncoder, javaScriptEncoder, urlHelperFactory) + { } + + /// + public override void Process(TagHelperContext context, TagHelperOutput output) + { + if (Theme == "") + { + base.Process(context, output); + return; + } + + switch (context.AllAttributes["rel"]?.Value.ToString()) + { + case "stylesheet": + output.Attributes.SetAttribute("href", $"~/css/{Theme}/{Style}.css"); + break; + case "icon": + output.Attributes.SetAttribute("type", "image/x-icon"); + output.Attributes.SetAttribute("href", $"~/img/{Theme}/favicon.ico"); + break; + } + ProcessUrlAttribute("href", output); + } +} diff --git a/src/MyWebLog/MyWebLog.csproj b/src/MyWebLog/MyWebLog.csproj index 325e63e..31a7042 100644 --- a/src/MyWebLog/MyWebLog.csproj +++ b/src/MyWebLog/MyWebLog.csproj @@ -6,6 +6,14 @@ enable + + + + + + + + diff --git a/src/MyWebLog/Program.cs b/src/MyWebLog/Program.cs index 2a16434..c27e550 100644 --- a/src/MyWebLog/Program.cs +++ b/src/MyWebLog/Program.cs @@ -43,7 +43,7 @@ builder.Services.AddDbContext(o => { // TODO: can get from DI? var db = WebLogCache.HostToDb(new HttpContextAccessor().HttpContext!); - // "Data Source=Db/empty.db" + // "empty"; o.UseSqlite($"Data Source=Db/{db}.db"); }); diff --git a/src/MyWebLog/Themes/BitBadger/Shared/_AppSidebar.cshtml b/src/MyWebLog/Themes/BitBadger/Shared/_AppSidebar.cshtml new file mode 100644 index 0000000..e9a27bf --- /dev/null +++ b/src/MyWebLog/Themes/BitBadger/Shared/_AppSidebar.cshtml @@ -0,0 +1,29 @@ +@{ + var data = await SolutionInfo.GetAll(); + string[] cats = new[] { "Web Sites and Applications", "WordPress", "Static Sites", "Personal" }; + IEnumerable solutionsForCat(string cat) => + data.Where(it => it.Category == cat && it.FrontPage.Display).OrderBy(it => it.FrontPage.Order ?? 99); + string aboutTitle(string title) => $"{title} | Bit Badger Solutions"; +} + diff --git a/src/MyWebLog/Themes/BitBadger/Shared/_Layout.cshtml b/src/MyWebLog/Themes/BitBadger/Shared/_Layout.cshtml new file mode 100644 index 0000000..a167b5a --- /dev/null +++ b/src/MyWebLog/Themes/BitBadger/Shared/_Layout.cshtml @@ -0,0 +1,56 @@ +@model MyWebLogModel + + + + + + + @ViewBag.Title « @Model.WebLog.Name + + + + + + +
+ @RenderBody() +
+ + + diff --git a/src/MyWebLog/Themes/BitBadger/SinglePage.cshtml b/src/MyWebLog/Themes/BitBadger/SinglePage.cshtml new file mode 100644 index 0000000..0c4c9f2 --- /dev/null +++ b/src/MyWebLog/Themes/BitBadger/SinglePage.cshtml @@ -0,0 +1,13 @@ +@using MyWebLog.Features.Pages +@model SinglePageModel +@{ + Layout = "_Layout"; + ViewBag.Title = Model.Page.Title; +} +
+
+ @if (!Model.IsHome) {

@Model.Page.Title

} + @Html.Raw(Model.Page.Text) +
+ @if (Model.IsHome) { @await Html.PartialAsync("_AppSidebar") } +
diff --git a/src/MyWebLog/Themes/BitBadger/SolutionInfo.cs b/src/MyWebLog/Themes/BitBadger/SolutionInfo.cs new file mode 100644 index 0000000..631f4ee --- /dev/null +++ b/src/MyWebLog/Themes/BitBadger/SolutionInfo.cs @@ -0,0 +1,147 @@ +using System.Reflection; +using System.Text.Json; + +namespace MyWebLog.Themes.BitBadger; + +/// +/// A technology used in a solution +/// +public class Technology +{ + /// + /// The name of the technology + /// + public string Name { get; set; } = ""; + + /// + /// Why this technology was used in this project + /// + public string Purpose { get; set; } = ""; + + /// + /// Whether this project currently uses this technology + /// + public bool? IsCurrent { get; set; } = null; +} + +/// +/// Information about the solutions displayed on the front page +/// +public class FrontPageInfo +{ + /// + /// Whether the solution should be on the front page sidebar + /// + public bool Display { get; set; } = false; + + /// + /// The order in which this solution should be displayed + /// + public byte? Order { get; set; } = null; + + /// + /// The description text for the front page sidebar + /// + public string? Text { get; set; } = null; +} + +/// +/// Information about a solution +/// +public class SolutionInfo +{ + /// + /// The name of the solution + /// + public string Name { get; set; } = ""; + + /// + /// The URL slug for the page for this solution + /// + public string Slug { get; set; } = ""; + + /// + /// The URL for the solution (not the page describing it) + /// + public string Url { get; set; } = ""; + + /// + /// The category into which this solution falls + /// + public string Category { get; set; } = ""; + + /// + /// A short summary of the solution + /// + public string? Summary { get; set; } = null; + + /// + /// Whether this solution is inactive + /// + public bool? IsInactive { get; set; } = null; + + /// + /// Whether this solution is active + /// + public bool IsActive => !(IsInactive ?? false); + + /// + /// Whether a link should not be generated to the URL for this solution + /// + public bool? DoNotLink { get; set; } = null; + + /// + /// Whether a link should be generated to this solution + /// + public bool LinkToSite => !(DoNotLink ?? false); + + /// + /// Whether an "About" link should be generated for this solution + /// + public bool? SkipAboutLink { get; set; } = null; + + /// + /// Whether an "About" link should be generated for this solution + /// + public bool LinkToAboutPage => !(SkipAboutLink ?? false); + + /// + /// Whether to generate a link to an archive site + /// + public bool? LinkToArchive { get; set; } = null; + + /// + /// The URL of the archive site for this solution + /// + public string? ArchiveUrl { get; set; } = null; + + /// + /// Home page sidebar display information + /// + public FrontPageInfo FrontPage { get; set; } = default!; + + /// + /// Technologies used for this solution + /// + public ICollection Technologies { get; set; } = new List(); + + /// + /// Cache for reading solution info + /// + private static readonly Lazy?>> _slnInfo = new(() => + { + var asm = Assembly.GetAssembly(typeof(SolutionInfo)) + ?? throw new ArgumentNullException("Could not load the containing assembly"); + using var stream = asm.GetManifestResourceStream("MyWebLog.Themes.BitBadger.solutions.json") + ?? throw new ArgumentNullException("Could not load the solution data"); + return JsonSerializer.DeserializeAsync>(stream); + }); + + /// + /// Get all known solutions + /// + /// + /// if any required object is null + public static async Task> GetAll() => + await _slnInfo.Value ?? throw new ArgumentNullException("Could not deserialize solution data"); +} diff --git a/src/MyWebLog/Themes/BitBadger/Solutions.cshtml b/src/MyWebLog/Themes/BitBadger/Solutions.cshtml new file mode 100644 index 0000000..7b9ac84 --- /dev/null +++ b/src/MyWebLog/Themes/BitBadger/Solutions.cshtml @@ -0,0 +1,43 @@ +@{ + Layout = "_Layout"; + ViewBag.Title = "All Solutions"; + + var data = await SolutionInfo.GetAll(); + var active = data.Where(it => it.IsActive && it.LinkToAboutPage).OrderBy(it => it.Slug); + var inactive = data.Where(it => !it.IsActive && it.LinkToAboutPage).OrderBy(it => it.Slug); +} +
+

All Solutions

+

Active Solutions

+ @foreach (var sln in active) + { +

+ @sln.Name ~ About + @if (sln.IsActive) + { + ~ Visit + } + else if (sln.LinkToArchive ?? false) + { + ~ Visit (archive) + } +
@Html.Raw(sln.Summary) +

+ } +

Past Solutions

+ @foreach (var sln in inactive) + { +

+ @sln.Name ~ About + @if (sln.IsActive) + { + ~ Visit + } + else if (sln.LinkToArchive ?? false) + { + ~ Visit (archive) + } +
@Html.Raw(sln.Summary) +

+ } +
diff --git a/src/MyWebLog/Themes/BitBadger/solutions.json b/src/MyWebLog/Themes/BitBadger/solutions.json new file mode 100644 index 0000000..36a63a0 --- /dev/null +++ b/src/MyWebLog/Themes/BitBadger/solutions.json @@ -0,0 +1,683 @@ +[ + { + "Name": "A Word from the Word", + "Slug": "a-word-from-the-word", + "Url": "https://devotions.summershome.org", + "Category": "Personal", + "SkipAboutLink": true, + "FrontPage": { + "Display": true, + "Order": 2, + "Text": "Devotions by Daniel" + } + }, + { + "Name": "Bay Vista Baptist Church", + "Slug": "bay-vista", + "Url": "https://bayvista.org", + "Category": "Static Sites", + "Summary": "Southern Baptist church in Biloxi, Mississippi", + "FrontPage": { + "Display": true, + "Order": 1, + "Text": "Biloxi, Mississippi" + }, + "Technologies": [ + { + "Name": "Hugo", + "Purpose": "static site generation", + "IsCurrent": true + }, + { + "Name": "Azure", + "Purpose": "podcast file storage, automated builds, and static site hosting", + "IsCurrent": true + }, + { + "Name": "GitHub", + "Purpose": "source code control", + "IsCurrent": true + }, + { + "Name": "Hexo", + "Purpose": "static site generation" + }, + { + "Name": "Jekyll", + "Purpose": "static site generation" + }, + { + "Name": "WordPress", + "Purpose": "content management" + }, + { + "Name": "MySQL", + "Purpose": "data storage" + } + ] + }, + { + "Name": "Cassy Fiano", + "Slug": "cassy-fiano", + "Url": "http://www.cassyfiano.com", + "Category": "WordPress", + "Summary": "A “rising star” conservative blogger", + "IsInactive": true, + "DoNotLink": true, + "FrontPage": { + "Display": false + }, + "Technologies": [ + { + "Name": "WordPress", + "Purpose": "blogging (with a custom theme)" + }, + { + "Name": "MySQL", + "Purpose": "data storage" + }, + { + "Name": "Rackspace Cloud", + "Purpose": "backup and recovery" + }, + { + "Name": "Azure", + "Purpose": "backup and recovery" + } + ] + }, + { + "Name": "Daniel J. Summers", + "Slug": "daniel-j-summers", + "Url": "https://daniel.summershome.org", + "Category": "Personal", + "SkipAboutLink": true, + "FrontPage": { + "Display": true, + "Order": 1, + "Text": "Daniel’s personal blog" + } + }, + { + "Name": "Dr. Melissa Clouthier", + "Slug": "dr-melissa-clouthier", + "Url": "http://melissablogs.com", + "Category": "WordPress", + "Summary": "Politics, health, podcasts and more", + "IsInactive": true, + "DoNotLink": true, + "FrontPage": { + "Display": false + }, + "Technologies": [ + { + "Name": "WordPress", + "Purpose": "blogging (with a custom theme)" + }, + { + "Name": "MySQL", + "Purpose": "data storage" + }, + { + "Name": "Rackspace Cloud", + "Purpose": "backup and recovery" + }, + { + "Name": "Azure", + "Purpose": "backup and recovery" + } + ] + }, + { + "Name": "Emerald Mountain Christian School", + "Slug": "emerald-mountain-christian-school", + "Url": "http://www.emeraldmountainchristianschool.org", + "Category": "Web Sites and Applications", + "Summary": "Classical, Christ-centered education near Wetumpka, Alabama", + "IsInactive": true, + "FrontPage": { + "Display": false + }, + "Technologies": [ + { + "Name": "PHP", + "Purpose": "page generation and interactivity" + }, + { + "Name": "ASP.NET MVC", + "Purpose": "page generation and interactivity" + }, + { + "Name": "PostgreSQL", + "Purpose": "data storage" + }, + { + "Name": "Rackspace Cloud", + "Purpose": "hosting" + }, + { + "Name": "Azure", + "Purpose": "hosting" + } + ] + }, + { + "Name": "Futility Closet", + "Slug": "futility-closet", + "Url": "https://www.futilitycloset.com", + "Category": "WordPress", + "Summary": "An idler’s miscellany of compendious amusements", + "FrontPage": { + "Display": true, + "Order": 1 + }, + "Technologies": [ + { + "Name": "WordPress", + "Purpose": "blogging", + "IsCurrent": true + }, + { + "Name": "nginx", + "Purpose": "the web server", + "IsCurrent": true + }, + { + "Name": "MySQL", + "Purpose": "data storage", + "IsCurrent": true + }, + { + "Name": "Digital Ocean", + "Purpose": "web site hosting", + "IsCurrent": true + }, + { + "Name": "Azure", + "Purpose": "backup and recovery", + "IsCurrent": true + }, + { + "Name": "Rackspace Cloud", + "Purpose": "web site hosting" + } + ] + }, + { + "Name": "Hard Corps Wife", + "Slug": "hard-corps-wife", + "Url": "http://www.hardcorpswife.com", + "Category": "WordPress", + "Summary": "Cassy’s life as a Marine wife", + "IsInactive": true, + "DoNotLink": true, + "FrontPage": { + "Display": false + }, + "Technologies": [ + { + "Name": "WordPress", + "Purpose": "blogging" + }, + { + "Name": "MySQL", + "Purpose": "data storage" + }, + { + "Name": "Rackspace Cloud", + "Purpose": "backup and recovery" + } + ] + }, + { + "Name": "Liberty Pundits", + "Slug": "liberty-pundits", + "Url": "http://libertypundits.net", + "Category": "WordPress", + "Summary": "The home for conservatives", + "IsInactive": true, + "DoNotLink": true, + "FrontPage": { + "Display": false + }, + "Technologies": [ + { + "Name": "WordPress", + "Purpose": "blogging" + }, + { + "Name": "PHP", + "Purpose": "custom data migration software" + }, + { + "Name": "MySQL", + "Purpose": "data storage" + } + ] + }, + { + "Name": "Linux Resources", + "Slug": "linux-resources", + "Url": "https://blog.bitbadger.solutions/linux/", + "Category": "Web Sites and Applications", + "SkipAboutLink": true, + "FrontPage": { + "Display": true, + "Order": 99, + "Text": "Handy information for Linux folks" + } + }, + { + "Name": "Mindy Mackenzie", + "Slug": "mindy-mackenzie", + "Url": "https://mindymackenzie.com", + "Category": "WordPress", + "Summary": "Wall Street Journal best-selling author and C-suite advisor", + "FrontPage": { + "Display": true, + "Order": 2, + "Text": "WSJ-best-selling author of The Courage Solution" + }, + "Technologies": [ + { + "Name": "WordPress", + "Purpose": "blogging and content management", + "IsCurrent": true + }, + { + "Name": "nginx", + "Purpose": "the web server", + "IsCurrent": true + }, + { + "Name": "MySQL", + "Purpose": "data storage", + "IsCurrent": true + }, + { + "Name": "Digital Ocean", + "Purpose": "web site hosting", + "IsCurrent": true + }, + { + "Name": "Azure", + "Purpose": "backup and recovery", + "IsCurrent": true + } + ] + }, + { + "Name": "myPrayerJournal", + "Slug": "my-prayer-journal", + "Url": "https://prayerjournal.me", + "Category": "Web Sites and Applications", + "Summary": "Minimalist personal prayer journal", + "FrontPage": { + "Display": true, + "Order": 2 + }, + "Technologies": [ + { + "Name": "htmx", + "Purpose": "front end interactivity", + "IsCurrent": true + }, + { + "Name": "Giraffe", + "Purpose": "the back end", + "IsCurrent": true + }, + { + "Name": "LiteDB", + "Purpose": "data storage", + "IsCurrent": true + }, + { + "Name": "GitHub", + "Purpose": "source code control", + "IsCurrent": true + }, + { + "Name": "GitHub Pages", + "Purpose": "documentation", + "IsCurrent": true + }, + { + "Name": "Vue.js", + "Purpose": "the front end" + }, + { + "Name": "RavenDB", + "Purpose": "data storage" + }, + { + "Name": "PostgreSQL", + "Purpose": "data storage" + } + ] + }, + { + "Name": "Not So Extreme Makeover: Community Edition", + "Slug": "nsx", + "Url": "http://notsoextreme.org", + "Category": "Web Sites and Applications", + "Summary": "Public site for the makeover; provides event-driven management of volunteers, donations, and families needing help", + "IsInactive": true, + "DoNotLink": true, + "LinkToArchive": true, + "ArchiveUrl": "https://nsx.archive.bitbadger.solutions", + "FrontPage": { + "Display": false + }, + "Technologies": [ + { + "Name": "WordPress", + "Purpose": "content management" + }, + { + "Name": "PHP", + "Purpose": "for NSXapp" + }, + { + "Name": "MySQL", + "Purpose": "WordPress data storage" + }, + { + "Name": "PostgreSQL", + "Purpose": "NSXapp data storage" + } + ] + }, + { + "Name": "Olivet Baptist Church", + "Slug": "olivet-baptist", + "Url": "https://olivet-baptist.org", + "Category": "Static Sites", + "Summary": "Southern Baptist church in Gulfport, Mississippi", + "IsInactive": true, + "DoNotLink": true, + "LinkToArchive": true, + "ArchiveUrl": "https://olivet.archive.bitbadger.solutions", + "FrontPage": { + "Display": false + }, + "Technologies": [ + { + "Name": "Azure", + "Purpose": "podcast file storage and archive site hosting", + "IsCurrent": true + }, + { + "Name": "Vue.js", + "Purpose": "the user interface for the PWA" + }, + { + "Name": "Hexo", + "Purpose": "for generating the site pages" + }, + { + "Name": "WordPress", + "Purpose": "content management" + }, + { + "Name": "MySQL", + "Purpose": "data storage" + } + ] + }, + { + "Name": "Photography by Michelle", + "Slug": "photography-by-michelle", + "Url": "https://www.summershome.org", + "Category": "Web Sites and Applications", + "Summary": "Photography services in Albuquerque, New Mexico", + "IsInactive": true, + "DoNotLink": true, + "FrontPage": { + "Display": false + }, + "Technologies": [ + { + "Name": "ASP.NET MVC", + "Purpose": "content management / gallery creation API" + }, + { + "Name": "PostgreSQL", + "Purpose": "data storage" + }, + { + "Name": "C# / Windows Forms", + "Purpose": "desktop gallery application" + }, + { + "Name": "WordPress", + "Purpose": "content management" + }, + { + "Name": "MySQL", + "Purpose": "data storage" + } + ] + }, + { + "Name": "PrayerTracker", + "Slug": "prayer-tracker", + "Url": "https://prayer.bitbadger.solutions", + "Category": "Web Sites and Applications", + "Summary": "Provides an ongoing, centralized prayer list for Sunday School classes and other groups", + "FrontPage": { + "Display": true, + "Order": 1, + "Text": "A prayer request tracking website (Free for any church or Sunday School class!)" + }, + "Technologies": [ + { + "Name": "Giraffe", + "Purpose": "server-side logic and dynamic page generation", + "IsCurrent": true + }, + { + "Name": "PostgreSQL", + "Purpose": "data storage", + "IsCurrent": true + }, + { + "Name": "GitHub", + "Purpose": "source code control", + "IsCurrent": true + }, + { + "Name": "GitHub Pages", + "Purpose": "documentation hosting", + "IsCurrent": true + }, + { + "Name": "MongoDB", + "Purpose": "data storage" + }, + { + "Name": "ASP.NET MVC", + "Purpose": "dynamic content generation" + }, + { + "Name": "Database Abstraction", + "Purpose": "data access" + }, + { + "Name": "MySQL", + "Purpose": "data storage" + }, + { + "Name": "PHP", + "Purpose": "dynamic content generation" + } + ] + }, + { + "Name": "Riehl World News", + "Slug": "riehl-world-news", + "Url": "http://riehlworldview.com", + "Category": "WordPress", + "Summary": "Riehl news for real people", + "FrontPage": { + "Display": true, + "Order": 3 + }, + "Technologies": [ + { + "Name": "WordPress", + "Purpose": "blogging", + "IsCurrent": true + }, + { + "Name": "MySQL", + "Purpose": "data storage", + "IsCurrent": true + }, + { + "Name": "Azure", + "Purpose": "backup and recovery", + "IsCurrent": true + }, + { + "Name": "F#", + "Purpose": "custom archive static page generation" + } + ] + }, + { + "Name": "The Clearinghouse Management System", + "Slug": "tcms", + "Url": "http://tcms.us", + "Category": "Web Sites and Applications", + "Summary": "Assists a needs clearinghouse in connecting people with needs to people that can help meet those needs", + "IsInactive": true, + "DoNotLink": true, + "FrontPage": { + "Display": false + }, + "Technologies": [ + { + "Name": "PHP", + "Purpose": "the TCMS application logic" + }, + { + "Name": "WordPress", + "Purpose": "publicly-facing pages and authentication" + }, + { + "Name": "PostgreSQL", + "Purpose": "application data storage" + }, + { + "Name": "MySQL", + "Purpose": "WordPress data storage" + } + ] + }, + { + "Name": "The Bit Badger Blog", + "Slug": "tech-blog", + "Url": "https://blog.bitbadger.solutions", + "Category": "Static Sites", + "Summary": "Geek stuff from Bit Badger Solutions", + "FrontPage": { + "Display": true, + "Order": 3, + "Text": "Technical information (“geek stuff”) from Bit Badger Solutions" + }, + "Technologies": [ + { + "Name": "Hexo", + "Purpose": "static site generation", + "IsCurrent": true + }, + { + "Name": "Azure", + "Purpose": "static site hosting", + "IsCurrent": true + }, + { + "Name": "GitHub", + "Purpose": "source code control", + "IsCurrent": true + }, + { + "Name": "Custom Software", + "Purpose": "content management" + }, + { + "Name": "WordPress", + "Purpose": "content management" + }, + { + "Name": "BlogEngine.NET", + "Purpose": "content management" + }, + { + "Name": "Orchard", + "Purpose": "content management" + }, + { + "Name": "myWebLog", + "Purpose": "content management" + }, + { + "Name": "Jekyll", + "Purpose": "static site generation" + }, + { + "Name": "MySQL", + "Purpose": "data storage" + }, + { + "Name": "SQL Sever", + "Purpose": "data storage" + }, + { + "Name": "RethinkDB", + "Purpose": "data storage" + } + ] + }, + { + "Name": "The Shark Tank", + "Slug": "the-shark-tank", + "Url": "http://shark-tank.net", + "Category": "WordPress", + "Summary": "Florida’s political feeding frenzy", + "IsInactive": true, + "DoNotLink": true, + "FrontPage": { + "Display": false + }, + "Technologies": [ + { + "Name": "WordPress", + "Purpose": "blogging" + } + ] + }, + { + "Name": "Virtual Prayer Room", + "Slug": "virtual-prayer-room", + "Url": "https://virtualprayerroom.us", + "Category": "Web Sites and Applications", + "Summary": "Gives prayer warriors access to requests from wherever they may be, and sends them daily updates", + "IsInactive": true, + "DoNotLink": true, + "FrontPage": { + "Display": false + }, + "Technologies": [ + { + "Name": "PHP", + "Purpose": "the application logic" + }, + { + "Name": "PostgreSQL", + "Purpose": "data storage" + } + ] + } +] diff --git a/src/MyWebLog/Themes/Default/Shared/_DefaultFooter.cshtml b/src/MyWebLog/Themes/Default/Shared/_DefaultFooter.cshtml index b9f86bb..d32c8fa 100644 --- a/src/MyWebLog/Themes/Default/Shared/_DefaultFooter.cshtml +++ b/src/MyWebLog/Themes/Default/Shared/_DefaultFooter.cshtml @@ -1,6 +1,6 @@ 

- myWebLog + myWebLog
diff --git a/src/MyWebLog/Themes/Default/Shared/_Layout.cshtml b/src/MyWebLog/Themes/Default/Shared/_Layout.cshtml index e70c2cc..37a8fbd 100644 --- a/src/MyWebLog/Themes/Default/Shared/_Layout.cshtml +++ b/src/MyWebLog/Themes/Default/Shared/_Layout.cshtml @@ -2,11 +2,12 @@ + - + @await RenderSectionAsync("Style", false) @ViewBag.Title « @Model.WebLog.Name diff --git a/src/MyWebLog/Themes/_ViewImports.cshtml b/src/MyWebLog/Themes/_ViewImports.cshtml index eaf3b3e..16800cf 100644 --- a/src/MyWebLog/Themes/_ViewImports.cshtml +++ b/src/MyWebLog/Themes/_ViewImports.cshtml @@ -1 +1,3 @@ @namespace MyWebLog.Themes + +@addTagHelper *, MyWebLog diff --git a/src/MyWebLog/wwwroot/css/BitBadger/style.css b/src/MyWebLog/wwwroot/css/BitBadger/style.css new file mode 100644 index 0000000..b52743a --- /dev/null +++ b/src/MyWebLog/wwwroot/css/BitBadger/style.css @@ -0,0 +1,262 @@ +html { + background-color: lightgray; +} + +body { + margin: 0px; + font-family: "Raleway", "Segoe UI", Ubuntu, Tahoma, "DejaVu Sans", "Liberation Sans", Arial, sans-serif; + background-color: #FFFAFA; +} + +a { + color: navy; + text-decoration: none; +} + +a:hover { + border-bottom: dotted 1px navy; +} + +a img { + border: 0; +} + +acronym { + border-bottom: dotted 1px black; +} + +header, h1, h2, h3, footer a { + font-family: "Oswald", "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif; +} + +h1 { + text-align: center; + margin: 1.4rem 0; + font-size: 2rem; +} + +h2 { + margin: 1.2rem 0; +} + +h3 { + margin: 1rem 0; +} + +h2, h3 { + border-bottom: solid 2px navy; +} + +@media all and (min-width:40rem) { + h2, h3 { + width: 80%; + } +} + +p { + margin: 1rem 0; +} + +#content { + margin: 0 1rem; +} + +.content { + font-size: 1.1rem; +} + +.auto { + margin: 0 auto; +} + +@media all and (min-width: 68rem) { + .content { + width: 66rem; + } +} + +.hdr { + font-size: 14pt; + font-weight: bold; +} + +.strike { + text-decoration: line-through; +} + +.alignleft { + float: left; + padding-right: 5px; +} + +ul { + padding-left: 40px; +} + +li { + list-style-type: disc; +} + +.app-info { + display: flex; + flex-flow: row-reverse wrap; + justify-content: center; +} + +abbr[title] { + text-decoration: none; + border-bottom: dotted 1px rgba(0, 0, 0, .5) +} +/* Header Style */ +.site-header { + height: 100px; + display: flex; + flex-direction: row; + justify-content: space-between; + background-image: linear-gradient(to bottom, lightgray, #FFFAFA); +} + +.site-header a, .site-header a:visited { + color: black; +} + +.site-header a:hover { + border-bottom: none; +} + +.site-header .header-title { + font-size: 3rem; + font-weight: bold; + line-height: 100px; + text-align: center; +} + +.site-header .header-spacer { + flex-grow: 3; +} + +.site-header .header-social { + padding: 25px .8rem 0 0; +} + +.site-header .header-social img { + width: 50px; + height: 50px; +} + +@media all and (max-width:40rem) { + .site-header { + height: auto; + flex-direction: column; + align-items: center; + } + + .site-header .header-title { + line-height: 3rem; + } + + .site-header .header-spacer { + display: none; + } +} +/* Home Page Styles */ +@media all and (min-width: 80rem) { + .home { + display: flex; + flex-flow: row; + align-items: flex-start; + justify-content: space-around; + } +} + +.home-lead { + font-size: 1.3rem; + text-align: center; +} + +/* Home Page Sidebar Styles */ +.app-sidebar { + text-align: center; + border-top: dotted 1px lightgray; + padding-top: 1rem; + font-size: .9rem; + display: flex; + flex-flow: row wrap; + justify-content: space-around; +} + +.app-sidebar > div { + width: 20rem; + padding-bottom: 1rem; +} + +@media all and (min-width: 68rem) { + .app-sidebar { + width: 66rem; + margin: auto; + } +} + +@media all and (min-width: 80rem) { + .app-sidebar { + width: 12rem; + border-top: none; + border-left: dotted 1px lightgray; + padding-top: 0; + padding-left: 2rem; + flex-direction: column; + } + + .app-sidebar > div { + width: auto; + } +} + +.app-sidebar a { + font-size: 10pt; + font-family: sans-serif; +} + +.app-sidebar-head { + font-family: "Oswald", "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif; + font-weight: bold; + color: maroon; + margin-bottom: .8rem; + padding: 3px 12px; + border-bottom: solid 2px lightgray; + font-size: 1rem; +} + +.app-sidebar-name, .app-sidebar-description { + margin: 0; + padding: 0; +} + +.app-sidebar-description { + font-style: italic; + color: #555555; + padding-bottom: .6rem; +} +/* Solutions Page Styles */ +.app-name { + font-family: "Oswald", "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif; + font-size: 1.3rem; + font-weight: bold; + color: maroon; +} + +/* Footer Styles */ +footer.site-footer { + display: flex; + flex-flow: row wrap; + justify-content: space-between; + padding: 20px 15px 10px 15px; + font-size: 1rem; + color: black; + clear: both; + background-image: linear-gradient(to bottom, #FFFAFA, lightgray); +} + +footer.site-footer a:link, footer.site-footer a:visited { + color: black; +} diff --git a/src/MyWebLog/wwwroot/img/BitBadger/bit-badger-auth.png b/src/MyWebLog/wwwroot/img/BitBadger/bit-badger-auth.png new file mode 100644 index 0000000000000000000000000000000000000000..42c407cbbd1072aa37412613c41d38521916c77a GIT binary patch literal 23158 zcmV*iKuy1iP)2sT;E7_K8OSUntL@_P|+c<&*Qw{6z26`El)X=xdsUJUu0P`$ z&76MLS>?OFYc0C{w%dgu0SEvD?LGRZ{zo7HfPe@;sY{Wv5kcX`MEFjSp9zR|2_m^K zlG`H)2tm=t`G>Cr#gpgYW$?XyVK>{R_<0A+_`8SYU4+15p zN8$Desfz{W_>^OgkB{Q>R*y5gw*G^FJkIF42_jHxrSMAUZz);_+1s19Y;?_{Eek>6 zS2=45AagLvp9zXCd~)&B_x#mTH!`yn=}V{wOevv>7pG*c%;s|TM3i$JIm@fdk+KG< zYv%tu@AQZYepv7Lh@gsN;kAu~mLj2wo^k?m>-u!zc*EB7H#_WkK>-i$&+h>W>B-Y0k~2f(xB@aY1R}3~y+-Pf80GCHFrTm~b1( z!x0IE@^BG_S{cc*ln9=bAxbm>MTZh;T7=t3A7{9~aK9u%k&2F$5Fbyn9O7fqAL`^4 zACr0m1c6BC=S(CY0_DLo)h8*d=Aw_GvQ6vojQT{r(v4L+Vl$erS_f=J#1FEjf)fj) zu1r}$93)&KPq=hx)`SbG?UTL`rIZg;MM;!ozAe#zrqp3) zEd^=XTwk_O(}s7AQQl(8Lh(f`KEfhnkok%>unh7oa^BrKsY3vYmm}KfdNgmVfgpyg`)yPFJnU{Y(jI_MlXyod_P3?=&$;79>a?)Ku>f36VI+8Mi$$ zqN?Yecnw4ZAyki_rGfyVnq#TfmCxx-Qt0rCc>9X>47Fu+V zA^>?l1m*dh>HD1029)xTgH&)rP7D=hr zoU)3Ca?fACm?FI#)iqu&wj>=QN-*Cf?0z_cMKuo?f#=r~)Mg+zfOw$Bo42HpAS{7{6glUGn8W^7~wj^ z7>sZq6mM4^x51L*Fqi>mFnJM@|0S12WW76~{-kN+5E6-1oY1tE7VZmxLnsi2v}NlV@$qpD=snqB0a@cz@IC3_uE>jmMC^DHL=MC)6hAu> zexbQMBJu|n?Wj7*=BYqRB7K1rv+?8bXD|bXZNlDAbV%#tWE+Zfv;VRz8z1?=n=m;w ziEZ1qNex~Ax(vYZHIQ2<@JM#W^mZv1!pS(dVbCE!3iOiNp`aX`oAigBROJ09_HU!Y zo;WOL`q>~N)N4)5&&_EWfI%2jA+(VfofXM^fl{M&9x%$ocWB+GE_X*i!GiT;AlgEp z))>P4+6+dUW0bPb;d<(Uu#}rk081Y%%i=%8D1#TJ zaVlcjoWquxY-`L!>u6#E^6J(zXYqYZECG@O{zbn;WVIRco0 z%!5WLpT=YwRE6_)S-9qB2-Rv+q1DL4Ycz&&*e9-NE#>;j%R z!2uWXRSAORM1p|Fha$h1e*qVWv|+t*wO-VG4GkV!~0@bcqc0hGO4IXCW{oytUlzQhwT3(_VBk zS0VdnzV8Fi$nGGfs{pFQ-Ym#-l_7#sZtpp{noEk7>rJig%^fH~Svfp8iY@wcw_%d!t!_ zFyurYnH#+BGAzks6&zF1LvUIT21}MBwq1hP?*rw^VEPdi zqgzzumTTm|=*kp%_^AL#qy$i80b7yIc<8{r+@nH0r%;QT{XQQ^_@Y#3o3IDfWkswG z)$eqzA#%1S!tYt?yS#0y%LE16POqo#Ph=fY%3nq|Y@aL?cpS5fvFFjhm>}0_gh@ zsfRCOq?n!;C@je5Ii=Gkl*JTtY6Y@{paL3q(WW&XTb8++-esgQO|LJxSBxc2 zc;vK2-^q6!FUnm;VHu`xkh<-Y@!cZkLLz)Y%vuncbwrL3Q_6*%ehPhTVM z0AMb9y|vI(C7M+|2FEGG>-REA;D~l2uwJfNSto_6C-9MKiqh9KsuYSyg9-H}R+yB8 zY3enP3nn!9LQPyN>&51jVD`Nr-`}8gH4D#b0M%r$)H6WEe%e5XJkQ@Na{6;3PZbZdsq+RlSnTzmPly}pln zqlD!J2CtuJvUG`<xQlZ zOGR=dP^&kvxVQjDlE^DmJSpb$D*#~3+*IoLwB&EX*H@kJ7>SQDNYzzWLIQ=68av!N zg+6AI##>ko+-K~9cNr0BRJc8(J; zPh?7yVn-YjYl@!JxZsz`@0j8QM>m><&vkk|sLPN@ZWR%#RR@59$T!ch0thIT%2-^S zh#3x9YjO%Et6TBbMsZ^RWugE(E9bDp?1DW5O$&AZ%NWvEsIEs zY*mL|q{tIGe?}-f32RKDb_L3EwA3wzQDNSboMszj5nkO?QZCDIV;TSj5u;kQE3(Uk zj#65aB)`Dd1Cq zD&jt4B1!Q?+oPlxnA!J=qcn|Wn4`gpnE;|7X`TN-WVV9=T8@zxP*CcD(1d~r2t+PQ zt-CN{9W#u4tw;inV@gxlV~Cm*r5$wJcF=0I!39szO_W{~spnraSCj?iBY_Y^TIrS` zr5RhC=qBx+#tq?w(z`3Jg~-#Ml+loymW>%d;dewZ`yRrKyyBn4W<*t|DW{#0!kUa! zB`@SyrTb9nH_faE9YM;^OaX!OBF_|)LU3Jkr`BhT0MkUb6aL#^ zT8}{j!L}V(wvE}@In-*kkd&82{|CABl=nMjQ#RRxUn+(jG;Jt!D$M{CBwbG+;x0Bq z0Z2Wb>q}%KzwFbRzg{u(pjg}GtuJ!(ZtL%hv>TuMn<}8lI}bkKJoL;2=LEyF(CH>O zGE=;1S#TT|Gcz-2G#UuP)&odL#4*#8Qr1ZIqvJ+4Lf2-A_E8-3xW|GTBScKp1i6pn z2&h1Kh)apY^l6kXk+j&1G-lKrA}V1s`<{{}SQn{=21%?>loP3RNpbR&QvCr`zfDj1 zq&wjWtN3Bc-q1~D`mP0UPBSkqILnD};o|gU}p!p;kqy?qhGbw11NSd{&W+~xWrGhL4 zBNIqxGL%v=p+~+#Yx*XXj)A#So)l(~-e5$F3iAG!XEob%FQ1f?r8Z_VdE-ypt=^Kq4oFQsA`Hpdt+v(is|WT znJ>)n*HisGQx(agfR7FUZmEP5Qxlk&oPh5Kxa5*cV45ZbPd&(KtwPye{LwP5;~=l6 zhlrZ!ah^$5r-5YC_w-PbX(&1k_LCIud5oT`&brE72gU6NB+QhzOw^)4Wcc-kQC#ex zlTN3}p}eTe=BB42?2hzEnWg;~MWY3Q#La}T;QM}p>}LdP1j|cH2zYRE3Ecvc0TH3s z?cyIk@lhN;@+hAA)Sm+v0)PJc*WtCV`7_k(8*ivb#1Qx%Jl{jN+r?)-^C>i%Ll6N^ zh>46)E|qZc#g|}wd>c$db}zI{Gxi&k5Q0k|YmjNmr@W-1qded;#cWKY`Nd`^k9(h| z)sUM@%&*MZNYXsd92RNUM00W>q+r29-}5pIhUom8%@KIMk4~op(=e1d0ZJETC7P9e zQ%z8q(h{7*4}w@{20?(oeEVDQoS%OVoQjKYf9rMxT;O^C<9Ybn*KWa!Ui1?5dwtDh zs+!Loj>?KjvajrbF*_eK5-0NH*bPz$bPQT`Ew!n`R{k!3eF`f)^$s$ z)teX@8O7Mx7@Ex?Se6wgp*_7awkTp+Kiwe;mJtK6uDlMxVgo)H4M?-B=iG~RifA_y zWaxxQnRqtgdBt6uYxM?%06LuxYPDK!FVUo35#h1N9>YEN-hk9`~!+k|PFfDpL%-up0f;si|7M8DrpMRFn(N*}k~_HVf5 zmM_CCxp@BbpO3?b4q$#^4m-D>li`#l9fxdG%jLKukU;@vPaMPjd+r4fIIerrb=b6d zON3(;`#U-)DY6wXS_!zwXcS6?-0EP4EGR1m_)v!Om;o{fG%v(<+ z#git~M!`YAQF0vY+I|++IvqT4|NS^;$1)yw@#A57z8Jv8N+aZAK*Tl(C(293hDFZ12|oyPlq?yJ6g>$dY{J%Vx5BwI38TPq zT>Smte*`mg(|G6G{~GmX4Sm0lfcx;h0CRKmAP}}~+XmaVarQaqpjNAe9jj$?-Gzk( zOrJP`rKLqIE-vBdvBNM;6SYPSXYV*0JGO6!?KrS33k1S9zVUUu=GCu;%^0dB2Nl*th=yeE-hx;f~wBg+2H0L9g3^ZCMgl z5CVSS!?bOjb=Fzfao%~@cGfm*JL_zeOC_9p-uZZZxvWKU-A)GwA9(~b)6>|$Zy$bm z_uVi6H0yN`0lps$^6d42Qbh8>A<3X+MBv2Z83Duy24gV${yJJpWjRDmF~oX4$p&iu z*kID#V8-bNBSzKKYV(muj{;Rqlq1v$>mwKL07fKOe$xJja?ss+V+fs28w8+K zF5~?lcn<*JZ{Phs3=fZBa%vK9c;la8|K0}?^gS3vXp~AosiY<3BdyV1UdFzA?!kli z-ixR+SReq$v6B%iVSo|%J{Y8S9ja79Qx;^p1nS*tD3hBdMnE9DD#~M#gC>X(7!x2K z4xQ-t*GrdB&J#?z^ocy@zu3f{gb)tGnp6lu5!gX|FHN%rMf;_~vZ&-#!dzfFC#|J<3UVP{SA3)W0VVjm@ zn!IE6}u=CmGZ?AXlG{s(xB^JgRz!(Q72CDA(mdI~@HmDQJfDs&d{S?*{ z21Z(&=t7gFnln+bUI8U!;Qr&|&^h#Z=aLAz4S(qm@V_n|1{VTc2pm|L$AQ%~{OmJc zfGu0khiO`HOBJ-%ma#B*9D5(Q6HmJCYP|eqzmFgY@Yc7z5ug3%f5uRw0n>G1SQc8# z%Ww@dzP%#DbEo`&haY?WKAv#()p*`7{vuxgn%BaP<_Dz&N$Xd;VIVbC6A(2lj>gF- zKA2>XhF6WL5}GPGD!h4wVq8kK&4gT`&DU0WPIu^RvutZh)e#peQm)*9{D6dVC_5?c zJ@VF*X53NHjs*1&6{2)tE1;fkI3jTb*3n>TO4 zqmMpG^su(X=JcZzU;|AxP`7IaAoy zMtrD~;H9t6ZlDbi3$Y;vtZv!^*v`-5k%fQ3CDvBhmI(o1bFGTYuDAlVu`x7iLok>b z=h!;k4*v4(Z^oxS`ALj6n<%?3gk_<}ISw8;fLFijj{rXab1Zl~04IHbdekb3r4Cqa zA;dr^5d-h_bBkj$6+i3!i5$TuWpbF}@rxkzw}?Qr<=;iRh2Tl;QBjSB#h)0U?J%f) z(gvJwY@pwkdYnZ*mCDd4>O7NLvFa>i8@&|gIpe4}Hb$#u>|I&Lbia?0;StoE4G0c! z!LhWsh~vkO!Zs~bOQqPk=LUm-%=@)lZ4e3k^flMw#;4qbiy!xRl*?ssF0i_~g6R_{ zFh4(!Lyta!Baa=%p+_FU()>x8Hgj?)cUnc;vuA zSf(lGNuFj8{F4zb{oX|H<3fI*f_q$1pWDiMg2>_`V0zvM@R_ zhArE+;mRwYfTut085kKE-SCwaLSVJCB5%R z1Q#$31Eyif;h;3Q$Ufq9iKy3p7@SBtID^kQ1PPdAz%``{5O9uO;G<+(FbxKx@jC_1 zm~{X6Y$r4JEXRLSDL?B)w&}Ez=L^JrFCYN)FkC&3=Ux9zST^BpfBAM05nQJX+jPJ= zN59{P=X>%75y3R&AkMs=4(t8({T@2~7JSc#=lSsZefWMjIFxhvzK?#thiM zrt#pO@8E^M@&a6c!wnd2jA`ZWr}HO-fX_X2`yB*<58w0A4~5DPr{9Wj(nsXS8HN$R z;*K}!v4qQV&f)d@==Zv4x7M(-yny-HIV>&CVtH{<<~ad8u>TMaK6(@*Lk*mB);JcI zRxmMf0%g;V3uH|YI|DbB&V+jTPuFyrah~x67b;$;a8Clgz6s6)T)F#aaM9zg!2S2% ziI05f!+7b-Uxw#A_vc~23sxck0` z;B|W_nN}Qi3J93k=!u?DXYj|&^q!G(BM2`f=J5dKN)1oE_8HiH)l=}f&wK=5`qwYx z(#tQw!rTHZ(}oZNjF*ddtwrztLz)aa+t5U9j87vkOIeIvN z7X%0b4k5UvrB3ejlkzQ9L(3uYMm#W{2&mVpa9szF9iPS{hmWFcTCj3V`5Dq!gI4&p^*VgxP%FvG&H{QCdF;=(K*JG>u1`q8bJICca>)oSPPhtJ)afG6cggC5^h=nS@bW1Q!^@Ah>|n z>7u>1hUK|=9N7ObzWk*xpq(FX!!YOV?%QPEkwPn+g zDAE&g%M1bpq0tx$iGBZogO41*#PJDqyIr)~YnY#(M-T)kl}eIR?l>SK%+Af?;fMBN z--CNmEtL?o+IZL7-+^kQj>lhi8LoZOb-3p0YhV}*eXqYEp%Ox!g`Jqu=xf6;U|BXC zw*=qw!Fd1(VDsiN3=cOEczpyxfOfZswN@L;D=i$Gm_lo{C8^2zQ-gkze4qcs^CAQ7 zZb5lfnB*QF9>L_qBuvx9c{|R>dFP%V&$5Y<;A&Ss)el-+T*QYy{65@&?|rD2N+8e2 zgFm_lKf3b=_@L|H1uuLdp7G3QChd~e5h@{79Jt^RJkeBs1PrVj0<8-d&^qzf$$+OnM%y7ex%CYbYi-#%A?Cdc zT{wnEMzMeI!MMIqy@Vo3_+@q}1TZ`_gg3q6Z8-SI0etmqx8U2i-wG3ivTcL=0Y33} z|35zexzFLLPk%aYy6Gm2ZQ2Ci_w!TG0!f6)IYju*0}jpuDQJ)myk$FZgCG_@5ej0L z2e@|kB@m&hWQ?KL_prFKwh@g*XXeSKGqfH2CvGQcW4OWHSke@d!h5HzU`4mFW z-_JP93w>m~00*Jn?O@xsv+>)%`BJ>_1;30pzvYdXJa!ai%R#MN2KpYp{>3lhmM?t? zzy0!;4D63{hFSe6Cfw&D98JkNva z`{)M&f^eNfM~-99zJss~Bjsb!f0n5^!@%bmJ8nA3cq+9WW?-!oHfGCtpoj<~BV(AH zoRr~vIxQdyiTC=^hCHA~qlx#u_k;NS=WoUr|Mm0euCBs1Ef^&2(BHh{9k}E6+whEM zJ_|c{?!?gWu#6-z{lB{`y^ig$M4t2aQTq?yKIwqx<&by$?MMt5m|yT|068 z4L9Jbt9}|h@Zo!XblV;Dy7JZU_u%_}XbQ8JjB^e@6iNbxlV%whGaw9s)wLGx+xswj zeGf$E9v0%XZ@4%O0iX>;qW?`mS8o+pTzCj?`lA}EwN05#Mg zQAp7F!1rM=hW~r}cQH0Hg!8tag?iPE(@W;Y9a}ns=7;|KX`_vt7c;QhGUCpHl;aCB z#xOiQij|d>P{`74iYRWkogM_LHapWMdMN|Txe(aAc{Bd@J@3csU;n3=cCqEAe?_({CKBI{u_a?qKAsHAD{kP6ZN5O zss3W}bEQ(nufE{vcl(DQs4j)iUG zn@}#5@W6uy;5s(WKksa;wmO)ZnaA)@12c0A@H`*QMh!zlHFVlN%*`#JWLmO@QSkqY zB=k=*2y3C!H)29uuI!P(rcIl%vb=m|1xeR^aqFR%zU+4}H$R6%4?hIkFrbaCK*H!C z5M0Yb&+~Ec(W4*%a0oC6JpAxsbbSwH+s5+zl63F|N2k?BzuiUG_ax*1plaDLz#<&$ zR83#DcipLJA2E0xu~7jK8-x^a^4p?~Y{vvZ==21JQgVOt%E&oLJE zYLK77NP98HRDkqk0K_xkmk|4}(=2Bi7*&o%kd02)1BhjZVun7@rp;S%{P2U>DPDQI zQt(o}yRy)r29^4(3Y!XhF(SO-FW!tl`IA?pv$BM!zjM?MQuVpYrXd-rL^{|cL@uO8 zDI|&M+9&;#uJeQrNV(b0ZsyjDS2R~X~HlJn5F?EY!exMmgssoGLK12 z3u#Tvlom(qw0*3f;E0j(5Xqb_`oag`%XiKp1Vg(g!X8pAH=Y?D8O7@Anu2VnCO@c} zN~A~@nE{#cERn={k5WUKv10POv(7pj?|RpJ@rqaeE*#sA0|cQ&iZP`oVnT!^V5AP) z6zLS8G6?hJh2qB%E;yM;Pb3kM`dMqo62t;S%!6TgFvy3=d@$z2Bo7Aj<;#%nN68VW zR|OhXV5DipO)~OM*)$CVAuWZ9qUpQ_{RP>E{EjpQ5jx47U$fc7D_`*{{LQ=Gfw7@x z99W2uMaqRN;y}QYK~6j|g;22Ep69_}1k1FNcH9{s73Vc5)EMzA0JsnE zAp9ICzlB01I9NGAtrDPG4p1uvsFZzFO95P$qgDz~Eeq5t93=-ZO##akaBPN>Yr=62 zlw1QP+kopja2y85F<>$S%rK=BY&vnr;XMDzUn1L z9TqCDaKJzaFMxn6pYT(7@k@RSpZtf9V{D`m!w{S^Fv$10#d!=j>hZ2t*IFo-OR*3V z0j6nUb!`omGGJMzj2h336MZVQUMQMEX;LOcXj%e5cp&mX@ImmvNdB9_55Et<3|ahH zDRETFK%>erR1;`~uV$U2S%v&u6R1_WoNX#(K94a2hGD`mU6_UmW|%Nc3x;9BG-Nko z!?ZLb+x6>hr$Xo>5O~_t zo`tE&DSYocx1m|DNpr^~cU^#^R;yrcaS20>hBSu&`koIX#1;PpqK)J+GaRo{) zhhqykwt#CBDkTG@5<{iLP!2zrU51iNFboR@Gru2A|e- zC)Gkx2xWQ)GLgq#`6lnm?&Kae`nD+-1M<)oq&+?474weoOi&+Fp_ zFZ>nk*?T{Fy%t=@2?G^L>#4XU**te?1=VU9CC5Rl-A1`wj;~p-Cy9imav5u_7Alo; zItd;3qmhClJo$nT5*~o$-w+;1`0>#?jzFy@(5P`VYXZ$$5WaIX!p}o>fqFGSVkIby zM$B;1feka%7M5kfG%c8>2{UY+sA`J!TtnJG)FcE~22Q5iAr%iz+Gwt>Sg@qV654T! zcxH1#H>9}xP5f^KY1fojJjEW!>ng2kG{8&V2+j_g6sHjEg!b!!?k_54u@+C zxQ;-{;V8QTB^Ric36&BBh5DkZI7}W9K1iu2Xh$_%Hd#u&6_vtUH5c~XjqpBeKHtPLSq&J z>PSqH0>9#+<01kkl%bnKHHkiU@4gD3|NOteFbJFzm{8mal6k>Oxr((`D-KRP&y&^M zLcn!hv|24WJ>v;iUJ0G&EmD4l&IQ`A`PrZ*DeR4K22Brbz;@C}U~_68)S{D3x4w)3 zQmFwLhDXLQH8q9t@o{hwB%^y{q&+l&LY>8oIO04htm3jXIW zJ|7==|GTkk=XR{MR$-cke14*tKSZchD(H5*ux%UNZWjRJ89L>18NFT)CKo}TN0Rb0 zvehQ1bE7lR%6d2bWQ1Zv$5y-rqLYYv)&8qY_B&_Hh;wL+7z~5K_kB!F9>>JQaZF7f z#pLm0xaWs=;`%4;#_rv_K~cjF$}@eblu6#b%0=S!r?xn#NCE{eIBvZ0Cfxm_yYT42 zeVCbB1m_%EHjjn9B6zG_vnEjb%R~g%bwT&;n-p0LjZR-+{;M>}I$NM3kTFV4M5&li z;G^N;{azQ{ZV$a~7rkB=-EIfHUKhP?2i=J$E~P=DOW@=}TW4n`csdw%FRK%%EV^{ z*9x_y4%Q1WFueSCeiKtCPT-l(cs9QB)i0yuIuJsd%t&}tpS9g?!*$*Ge9S?9$GSqa zPG`8&(6d;5Z++XF@zke24PXDiUqh?a z(fMVePZj-@l`$&-U>0IBCku(5h9;p6qWx-%M|G}pG}p!VWv!fSNG1y~J>Ns%2bi6i zmVz=lftl$kOioVX#PlRiOio~SW*S^@n5KnlwSh)+1jEB)7#bPH@bEb}Z`V&@XlNAm z#!#G)t<_xADkapaB~&UdY84mNY6;bfi*m^YkBUQ;R0)vuM@WP!ZL&7lk5-*bU%Wsj z{iyw>Y(onG2zdI_p9#(bIF1`T>Z*qFeIMO!R}(Hxum(m-A}p?-0U>wW~VVTeL|X>nQ6?=&0t|+9<8-i^m<(YhAb@LvhYBF!F9_hSL!I0 zDzI$_LnGU9-p6=f#>Ut&Gfp=7*hJ>W1>dYem(@&B4NwY+33pt8RPUE+!_9V&eEQ96xphC#H^L za&iKb$BtrR;wYAvmt>yJv@kR@issN5nnNQP8X7}$XcQM-d;uEG5x8y{fPm}RXx1yJ z)=Q{W%Ba;`)T<@b8x_>6<)j;o+7v%0U6Xgi22RT=xZ(N9AxTdVz5+IQYMA7L@0;Tt;L3ybquU0y-2--GA*==J*O_dR%h4;(GK&C%tC}-I%(9L z90qIX<)`Xt&#N!g+|Xk45@m8|`Fbeko&^pPR+R@gq2X>%6L!$Kg~7I&}DKbv*$Yed6!;<$Jp(5WryYUXaz!`*XzZtEX_N=dk0olmaww2 zjHRUo%+JnXX=w>-YpZCr+E`m#!|K`^TB~aS5nQ)|(a}wCOJ$TRRWygr!PadThnl8> z=I~hD#V%?t5x2g{>5)mPrWt7`z13R9?w`5>KIhuVIIY!oPMI(jRUT0qnI141HiIo; zKt(e0Z{9{+h?GBF$PQJ;6`yj`9WlU<5h9~0AA9UDeBay9<|Dt0h+zKBU;h=VwFb(S z25PkiYV{$Ejc>&!B2+77G#XVj8&%Y6RWzGbRLTxs^y|NhCqL!62z;4@_Pjp&OLJfZ zc>Q`RS*%BY5`k7T@s!DNMK}^OOdLD%FkbTO&kOgZL^|Q)9V0aq4d{$aQZzX%Ozw(A ztHl%KRct3lx`ooFJ3)Vh)?P?Ai*ZCH)NQ2N6J=Tph!{g60S$4d!oCK$yJ&B}3fl;S(X<7g1 zW|11!s*Hdrq)zL(Y)(?sf0PfZX24#NN>pc5g`UlzBE&s6#@hg~JvVU3)1fqQtCneE z|NedW-uJ$XQ~5Kmf6^sL_d*py!1DtjC8ZD6&C+9}2=nT6x(*3vOi?0rx_l zm0X^4j#BCC!w z#yRo7494)bx4j8>-TeccPQ8Qa`@Y^qx8Q_r!^X!x`f+U8axM&JXg9G`uAp40f%70E zFnJDoc2*5#e-i=+5A4H@PkAePyMm&N1aD8h#$M4k(cEv1^m^`}WBBj|+I>PUeoqI;P96l+Q-#3)j-+!2!$ z4B!FB{M;Pg^yb%NW_A{*TSQ~Zv1B4X_&7a5iCF}IM-D!MAO7$j{OXIZOTy2vlxTeX z?64Hu$aTUsfl2vP`na}45EmC_F*-7Yv$mauwbiwlpF|>ZyhRK~vM|Z4xFE6LkMjPFhS(vQJnG#7NWTd73MZ-qeybO8I6R=)Wi+CwP$|hY$pT zkAQPoK5rPY%fk!?x8&ls+rEiAzyCe_`**%AmBwk*iN+Qu7Obd_3`%$1@M4>WfscLs zquBk#Cx;z@S*-qT+d-{fk7un6j`py=nGD|-7v^x)RlCt@wcxFTqYS**V!ig0`QQ#I zut7%Hs3?L=fTjcl7KP`Z_x(TEiFYP1H3=4Wu{UEjyQeEw!U>ALIigS&nZ3XjrmC>&&Yx)SAk9=2`U zhClc}e~4W>FMyd$BT&bSNq-0H16pe>Jqn8aAsJIha~Af=OqvZ#Ey0D5K9vyR_<4~-JBjKHlg9m8 zPXdaf#^lv*w*U~z_Ohg9=zELgsA3v5EoOp9-tgMHKOcjyoyXn`~#@j%V|A+HJJjEp$2^2m!R)U9{RAtgW@<_qA3F zrsabB9=48;V(0niVC&YcIRE_fP_5Px1YUgo)a#-`EXnZl$faNj*c&(5kj}R%WE66k z7!fSX#KPhdZomCD>_2b_BV$|f;@^H1K78$Un4dk4>8T@_ojHMj{-=-Q(BZ>4mDbpi zf5=0hFG3DP*ynU?bPPLp?!rwsJr$caZARbg$LDHB!*@86sRao!jl;EEeC3v}m{S^ zFb+&XS`-EkM3QMi21&Iq1Qr(NF*7rZ>6vNFoH&8W$w|!4%_0yCwc3y*@ij-#s1Kvw z7)H4|4gy2HWMX98LbFjvqgh9@UPZMkX*Yi0W6y&JF)=ZPJ^K#glmGN-G#eE>=Q+>8 z#TQ=!&+E&M!$cYF6s4fjnvkNv0176TUMA$0-+J4v_~bwRGyd$2{~w5xJo8vpjZ3ELZ#&6Ov}Js-@gO9c3ps0s|6nL_{k4~K;|X;a+*Tl z>!aWAgL8pSw~N)47S>v8Xtml{US7e{(h33&)Eh$>8Xm*w*cOa$e*!MQ>RA{a-4xDa zCK!z1x)#c1nbInkBpb9+c2RPjIC_l7wuMpU1-s6{($XppADzLopZh;?@W8|P+Bd(7 zPyW+qarxz!;KE%yF*-Jep`oFiq_d9UC2fw9!iAv>;R|2D!9&OKxi5YT?RE!( z2dI=y1c3+N2TaStfrt0u5C7=TP^(q(xzBzI)6-Lc;IM2vZYxkKmC$T9v17-17#`US z!!%*pHH?jI!n^+Zo!B%|!Ap;ok=6hJ8S6NKX(1FijJ`_q)G~3ogD2qnozGLwXQWV*$h&JLY!odRz=mkVx0&7P{3T z2oUnR!oEv!r#K?~!OLHWpS|e@n5K#O`FSiZEMRS|1=Ds>snk)b)KRV0Q7$)7sWo7l zHke_;wrp6IjYhMM;o%_+H6-7>T5(Y>mryF%FwLlIodMGd`#>2?tLYMAogg43AdCpU zAE4dsV{xg4LysQA;UkY>er5`fJbXWn9X)`nuf7`BUw;EE%ZBguV;n28;VkMc1yy^o z#J>`NTXOMSnkUl&L70I+q-kk((qFpOAXFd}ri9eDjd9M_TU2tsWhwI_lQ z2m+2H$7kihC1QB+!Ta&)fBXRc@~v+{rCQOVWT9j^RKbsix6}8(|9v63;(k2t!uL6X zz{A|!JYMmNSK<|a{8mg)O~fk_1je^*$Jp3rHSv`cOokUmZp)J#9nXi)eFUD5fCpGv zUc|z}EEX2#u`oZ2`MDV^FD`%#6I-^Ng<5?G!y}t8IyR0?o5#^?4ok*ERGDiTs8vd+ zR9#dnWz=hB)T(7vE2Ws^7YT;!>y*>G<)jB{s6Aki@7IOXNmp0fI65(l)wLda{XTBL z^%mUz&97j`jCpq{LGV|jP2WZ!1Fx#K@j_10KqUNV}lt6KL0N_s8dM zB{+_y2nXeupurCg$em z;Prj@0f!%U8wxn!c^t${Sf&NHTtzv2)#^UJB3~E>GB@)$sYMM+gwBb|PKlE~ zndb*sYjx4?dg%26EG#bJf%|`m1N$Gq>dG8Ctrc8!(S^9|vddwba&+5QZn*`m4sgwN zPr-#3U5bEn_`auIS5+9ao?WpZ%5Hrc=&C-*LTD``qaXVHKHmA3Kg7*9e*{RWQ`7qEWA+Rx6`Yc2o8>XC!F;s49&w zv~IOXY7o{y<3y=Uec`4H2yR7l0aILdWOz;KMJdm!rnaA5zuWULHN6Bs;D8Y5c02g$ zS8m4VKle#obm1;M;~CGu$jAsfoeplfZBDIx!7K&O{V? z;U(5BTq+Qb95Y2)-!ohe5Fj*0Q{&DgnfCk`Jzj6L`7f#KB9Xl}-ib1%eMXYY`v zPGzlZKycJRAi7_S$!2vy5MXhB79ab&cjDt8`#TH`4`nhG5#+!k^SF24A(0KUq35aw z-8`YBW>7RVZg3YGDo|y#j-ON1)U|k)C#7VopvvWBzN379Of$?m)iHVJW-^AOQ;P@! z8ScmVLjnw9=zAV|y$<&8djOyL)JJjbv4eQ-&;LBGyz&W{o1e$+x88;y-Ma_7ueu&r zU2_v0#|bB<@{Hi<0wpxg8WF?sV~277ec#7phxWs<8FubEA1{8Wo2p7Fxaj%Hf%576lqYN= zYq|;rh}Mtjh_ZzPx%CBnwg`}Q0Z$Z;?W zbqNjjO$M5Yf{JU};QEwqR?jGAZ)%)&Qp>ee|1F&X&!P8%isxdJuB^j(+**D$@<9V3 zllVOJQDcCTQ8;HOhsBVh(`Z5!vqMM`UP=aThTC*p7q(^L>tFpcKKy~d0l~+w|Jtu& z$GPXi3a3xV9-}Pg(20Lb0 zR1#xWqeP=Wp!L|&1%xz*eM3T|Z7T#IQ`$l{Bk7^v@5AeR@O%%OH*dk;efYhwse>n8 zbv2m5Vr-0sgP9^QHg2DgI?i;iGWWc5oOm;j`=(AF$UL`snyrwpLWQPLh@>b=f^`A< zz7Nj};QN8Z)cimSQAnpE^+}1TCJHzQZ6gWV=G3qh1 zI2#cigXj71ygoe7lkcI{34A}KwIuo6e3~=Uo?XTmEZfGRgAd_ZPrnhSWyQU{k|uO& z&-?TPLK?2Ak{;9VDiJZJ_8dMsjY?%1=WN{s+c9&@UhV*~3}Q_w-^=#{tgLph*6G3P z`>~LzHyZ#zIf*O~M8WQPKK3-zjTuGTN|+Ry;uP^0pZSf$R?0>7dhT zqZ_uK-00s%IzLNxgY1=m=-|T`9UTiPLM&tUGFp|f%)83sK(0w-85hBn6F4~z9-cy@ zUdC{?!-Q?ya9tOU-E_qEsqnXgKToQP6$WLPx#8|1z1uu(G;@c6$vYqhqL6>i`H- zGfSwHT{LPXIRCG`YwNA!s>0u%bD24}q`oAv+kD@XJxb5tc;%a_O?;2?qg_Z1j8ev z2t&f&egoOMk7JbriUm*0{C0P1Xm`TI)j67bq9{ZV_;Cgm_;E(%`|<|F6G@SDJ2p%&lgSKhangP$M>uf30*b{V%H;}5YgcgN##LOqavAG)?_hXn2$Pd%F*S7#=gytO#Ml_Jxu@W|&%kqCxUQ$- zCFa722%W^;nb3jRE0wYe3P%hMC8Xhr=(bSSN$8Zgl#5gE?QWr7KfsBT<0zHN5F&&9 zs*jf6LAm51m&>6YbU;YrCkSf{70+)vhI_LF%!61n-mc5=rIgSuW=)O>?%VAEf$yW; z4&eJfg20dYG>t&Dr?u%jt;{<`Q+eAgGTFE_+Vxy?SccbXwNR@b;G@;sSYKbm+MN}w z-~9;tk9II|dIB>uGdO?#8NB$zpJQxnEa~=);;9#7T__(e zaGbdJryT?_cWDqH2;xnX@=i#y+$fUM+`wQ01=cw`88amV9@#8BuYgjygi^7LVyP?% z^jBAICKqg1J&QYpi8z2u`g zAVf0pc4S=Wz{x0GYt_##H0VMLBZO*gPEkTx*VFEclN7cUuIBW6=(yl{kB$?QqA43w zOA9&IMh12fMIjzOxQ|-x0OR8ma9vOC|ZXm!2Vr6jL+!Vc=SDz1L`0all9VP*LyR+ev~ zR(*uo3$s{QSir@L7xB{{e;*?wBS}p#lom(3VUEgFO>&j)DQt6X9V_zBp@DQQGn_{w zIi6z)PX=q%?pgo0V&npV_}9PRp{=b4h{BGdCgK-kw0)GzWsHoTMCI7=WZd0`);bdW z0|Ywl0PRj2oghHai2=Z{(@Ca+;=nmd0%tN86XM9kC;Av${C%9B7f>h^Q7jdcetQp{ zPKcG|oA`L`4({Ap!RqoYv|0@uE0<8Ilrc1P9LFjZIabUbB~v1GhLZX}1p2Anl9X~0Z3a##N)feCDK!WAXsN0QNo zGH1aNxPApUm##sG z5DOO z{5QXYN00WfyS)Y9Z^=R>v^YuioV%WvjCe(Iu{mbavu)*wRwo`1a1%<(Li|Di!ia6 zA%z-slj&OHkjOErT-_vX+$r!`KW)=6cdq}wH+hJ)8P59iCwWSt%>_V0*}%}yQ<$Ef#`*Izn4X@-nKKg*a1bWb z+hG{ScvKp>B(Vd)GbYG50wNBgN#hW8gPZNCyNdAvg_jP_5#vx8B05ufB#CzWW2b^vhqN-EQOV z-8Iyz2ilWsZlZkNMIo^`#bPO$`i+6T+qaf*?doM*zjis!v{r6mV&XLB=jJeT;R2q0 zb`fXK#6%SNTn@Q>E|Cw;Xv7v>y15YQDk#e>vCqoK0rcbsxkZHOr@i>fk zNAy;96);T`rLPMk;~-L-5dFy94BF_lYnHP^cXhTX5=waw1VKD}_>g+lsfY;qd>)xh z25-FaPrUy6>sWmDt9b7DZ)0|L0bv*-2wLz8MYwqvEx(CoBc=n|KiEe-(bn17dVuZi z2iV@)MD<`F(^Kbg;leCt=VmcCH;2iylZYaU+e4Bm>^MzVH(E8csm-5S6h*Yl$LC3c zsZ2B`u^?=Lc^c2fY?!4}u7H>}4O?1bWc(s!L{8&k#ik==R#MJTA+&2$g=Q{#Ns2C# zonJ9EE9SxOEX@etNf^dUC*$tpdJG{1eXSL~B`*|WZ+Fk2G*JGO@9vaDY;*HI-hJLU8u<*TW7Mx@^LBGt9H>XNvioS-MKAphui5%^}@$Zud{dToQK-6kA;xqnYfV?u} zWKbv;@#dRv!uNe#x^xMXlam0T@jnnJzvrhW1;$E(e831~KM(8LLtcQppj7FLy8I3_ zoiB?Dnb4Wx8TLfF_hQ2ub{7W=(=wOtWfna>rvNiB<~fy>Cat=mW)elcQI9W21H$x~ zLZoJx>kJD*Hj@ESDl`zWerCo_tbITg%L%UFmBu&V6w;iojky<%=|k_KR_=ktQ0Q;^ z)$^i08^M&N6a(3#eyqqAuViWY9>o6ruk7N{&MO-AhNkb@^XMUbJeU^EgE3!urs zS_Je-9If|0#eJAmi;g>!a!~-ojbv0U8E<3|EyGTsOVP+RAdC2xfFU=p0(%KO@!?kP zaD*XLNxD{{Vfpl{O9iWRORH%yvJ_gWrgh)%u3rlamT!^S69kAxqe&^~#g#Y(NK@yO zzMfcG$w#62O=QXknlhIbm9yN1FY+N(b79;p4cN1uhAnch%6yj#v(Y9EY9^l)KJ@uA z(~cU2B9@sYfi<9&a=J)md7l(ii-%VJ>1tgO_9^5+71Q`It5I(6K8?`T(tB`N@!ocZ zr(4f!H{bkcXF$hf{4cuCAuPvL9SNf6aRtAA^peVh(nOK1#rUY7UB%#j!w2@DBd@ajBwokmGSzQ$$f zSXo7Lbp)%`<@;ktES3?%baJMAnqi4->t#BxBYBkmtM>mq;qj0f(Q38mNu0qJnD;+~ z;!)sL3wvp!`}kHddKvtuLfzCe+c5>j<Zx#)Bi^LpN1DK<6ty%bpg2sz zl8UaVnmx#ZKgjG_8CuRO0lJEV4OrpU+Cc2NG;(T%O&^qhsm>98zilA4(y@?63PMzFkrxd4Ne$;82cLAU~KHq*T%l^ z8FMkV9|yqTNHQ1%D8dy;B%!d1E3G!p?&Rs7=~U^Q^ZjwEs;hf?W_QJ|fW32`r=ISv zK2=>^_5R-cz6V$tD`RD>jFqu6R>sO$87pIDtc;bhGFHaQSQ#s0Wvq;qag>7`>BQfD z??<=P>(y=l_RoK*7v?J(KnNfPpaAIPRRNI67Ui}OK#f?HI&v`X{}?WrBqTyaTG>M#$gmkK@^5T97my4aU937 zf>y~jXr;82(1;R1<^dY!Kp6J`X`K5$=sG3_5EBAjDi>wBT#%(wfBe*wJL>@IE97;8 zfSr@M~nIzBrreV;#i=?hDKuw%;|mp_FD zv^L;XP*Q0FP^pzxS}6&olvYwfD+vQcWnQHLt5ixW6&r-fWWJKnN@=Mil$82KFW#tk zKK0O()ymAvR!Hmw1OtF+fMj|VAtVzS=~U;>Nzh@>M=shf+FwP3Pnhp=A2KIY299=L7($jIFGsA#s)dhBCm*&M#H_ zv++rp>rv)hDw!{3vOjOs>$WY?;TOm;fw8d~cJJDUGtO3^i~yPf0E)#j0Wb_;=L(sf zXlfEk)g*y1@E7UVoKvh`=iv=+JQslr&Dqq?Htwf+)JOQ^ZK)6bHI?Xv7Q;TpcFtT z1xdhAD)p^Mh7;C+)>=_Y=eQ7_QIlu~kub&(#UXrOA_!y`XC-aNPyRg?bKgaCQjWc7 zPR>J=&FPW`v{UMUBC}PMpp+YD@Q=lpu3+GMgbizg{FQXimjx zO9I_-Zb~SSU1zGo>D;+>!UPPsQX`!*0i{B7d~#2iV$>^?Mw^Y=3YDFRU;t1d2?wT( zfGV0ZpapD)Vs^HLQpsw2E^}ObNtGnC9r9eg+r}U{8==b%!D5wbk=~E){rPhmy97{6 z&&kfKvd^(($rl1rMaG*1b59f_q^~?MyaI+36ATK#9Ec%QMi~^9nX8Eq0@tOOtF$02 z4yANY39wii6H_t}Qb|>fyqaW)iox|5<|;n=`U?pdI*F>6CuwGLVjOR`;5EKd= z^Ya0MKtoE^WiRMVg5-_qMQ%=_K|qn6IwRor@n%l?J_V9q5@>DrEZWB)1x@bS=wd^^ z69jFW0R#pNnt(EaI5v|RW6)ZIF^XcTPhhE>l$G(*3kG7;qza)Flrbo!at5>^mSRz$ zG8drbD<~;D3}z635);{_T{?Z+7*1^kxyYT_K2P4TMdBS=N^MF5aNQoQF4c$-P-tk< zb#3T8&g3iU>^B)Rl7TXgFd_+vY36S(mC78z5P+5R)e}xl(x@=T!5Bjvhp=rYt2iKp zpit!4w?Bj*D9BiKaPCe6Sm%st-9hYx=uWjKPv}%HHl#D|PTJ?rh?jIqoDKs#0cd)B zx9c}&E6_#KApr}eh$XVauha@rkDOHH2kql8p7O9SVaYCs{L@9vHF~-5DkqnH{%-2o`fn^CqafFti zvl%)FKCj2qOx?-mb=VQQOV`iaA9-6tciIeH5~m#>=rXkP_QN8BJwHcx0;?;4r!)bf z96^+*PLw8YWrCss!_W$uonT=2&Y}*Vg;{>xApfzedl?+h`Mp;L?p5PpWL}>XYRl1}0rpxO? zpaI&Y=cAJ&w{`s+(I^r9p{%hDi(BZ?@XJJqCO zvHVl5Cf#`BwIm1wvT@@{*m%+=XKH$C`~H3V&TIMpYQfnVLEx8%heytd!eAh)iBB0L zV~FDTS%6fUe((q-c{ON}iljS$(3$?NyFh|msz%rK zC-aojAe2KY4yBW1y_7i!@w~xs>#a9CYuB%}DsvSaIB=kT|F^%Vj^O!_OI~ylU#Qi! zWeMWBE?#uWCF-Le{abk?zj?uh=kk`{5-;Ai%_$a(8!FZ6O+gTBE0szYhjFy7R4xIK zST)=SN-2~s0a}B*7Cg^Rp^$$zr!vDFE^Yb2FF&{Y889ZE=<6&0<&{@$`wzbr2jBnx zgYu^o3`%k#s+7`!I5IYa)+$SI6M}mb*V1mz-{DR*m3TA<)HYDsYFVr_KpCWBS(RHm_Ci_Tz|i1)W%j5Z$~%7j zS2hGe@J_AurG0&U)c5`0-@g6gZ++)G4=&=S*IxZnR%o@t6{N!syFC+T}S`P%{O0n`|Y>iIrCF08Q46bbU;Z7N*E|@ zGc3*pgatHP3Y6+DzrW4_0_e;{)r+M?!qq!7QFRY)-zfp|_QvA(c_X7rH0lVvERCe{d-Dg6lRz35c-~XLze}DgJmt1|Y`ncB0*e`^@5h6*fq$N(t_FAI>Ml?93C>9Gi?X=V2 zIyNemIZTWn!V`}_hC>Gr;n2hcq9}rG*(er^kXjjukQk3q92<`zkb%G55J6`ycSFTd%-U;gq}cmI@tfkzJ0{U(=+ZX0y1ht?JX$FLv$#Vipa|^| zY)kYjk|+k8o9eb$321F9<W>vpb*0 zLbVD@2!wH_tK^a%sktUf!5Bq22;H2Qb9zKxmoSRWb5cN~*-E;KnDSZM5-1gg6@<~RFVq?r+EDj;~DogNp z-E{M{XMXE}@Bd7#GT-{iwHdUYPq__}he=Z9M+3zYM-(WuM81qNuiw)iTsfaIO_we7 z&x5FK%;r)tfUW=>S>z7QN1hkEcNYU=QEGW+CdKHdkK;vyyHK($?0VvM+&BLuhDO$5 zWOO}tJ-Y+z)|R*azwiIld!>~2AN}F`Fm_;nymtM%R?Ba>L8Hm@J)bg~CK}KLHWvt+ zO>yYZ!Q#NkNNav_($i?S!_iPZ@?muc_e!&Sl>#VHAe4YgqcUY+Am(?K){rU*n5sl= z)Qisgqap)RDFcZ76>FnH#ZqEupr5ZE;WxeH@)!NUwhOQS+~@x5v7bE2KuD~$u5uv& zXh|i&dZQ7BKm9bW4#gg3f@~p@uE4 zd+w!vbpwMYz-=)b^DQ5vu8UQ!#x1Y95gSh33O|Uj{w=S7Wm)d$zwkMH;vfGWt!5Km zxg4Inb?aPxzBbyd)p)EFpp67%)adH@tZxe72jBhPprAA(%wAl#ml)6Yc_IXmgn(!Q zO^g(1m#`A(6c8{H0VyVPr|SW?qsIbFY(_#MByq+7v{tY!fjE}fH+Bdc*RRFMP~TZI zbMycGn%BMhmp=QSpTGMj&9y2G7%XTVLBIbdmMu#BzfuG^8eQ^~&2 zT~Cm-eb&eka5rHtHWslcReO;qsYhxyS(JpgTp4Lz6{85%T8vYL0_G8NijREcBPfpy z!?qpxzK=b-b^%(!;sUPYAPPh8j<4LlabR!|uYJ>-aK#l@!L}V#Di!R0?m6t*^(-EL z{83DePb9aMz#_D>qq#mpszbhyxuJHQ1}1f9+^4&Zc@Io=?E6tbp%dw#qjuxAMxzDJ zDF*ucFlY(v-G2}pH>|ZMztu@8i(HgP0nhz(9XLbYh5V0<7O~5^jFQt+?@qo52|Cxb_!szbyH$ z3S;B@@z4(+#-k5EjK_BDz(S=86-SV*W0TmhZWKcU zrBzZ^{`%HiZ*>3d-@fpfLcxuW2N;gJjr+Ub_t&op{l;fn%{iQP&IK4AUY+$t1tB;z zUcm=GqEKmU0-^F4{VX}kDdZ^5+}XIe!-mM)2R(oxB@oF(-)l|cH8