diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..660f3ad
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,26 @@
+# To learn more about .editorconfig see https://aka.ms/editorconfigdocs
+
+# C# or VB files
+[*.{cs,vb}]
+guidelines = 120
+
+#### Core EditorConfig Options ####
+
+#Formatting - header template
+file_header_template = ---------------------------------------------------------------\nCopyright (c) 2023 Planet Dotnet. All rights reserved.\nLicensed under the MIT License.\nSee License.txt in the project root for license information.\n---------------------------------------------------------------
+
+# Indentation and spacing
+indent_size = 4
+indent_style = space
+tab_width = 4
+
+# New line preferences
+end_of_line = crlf
+insert_final_newline = false
+
+#### .NET Coding Conventions ####
+
+# Organize usings
+dotnet_sort_system_directives_first = true
+dotnet_separate_import_directive_groups = false
+
diff --git a/Authors/mabroukmahdhi.json b/Authors/mabroukmahdhi.json
new file mode 100644
index 0000000..78d0165
--- /dev/null
+++ b/Authors/mabroukmahdhi.json
@@ -0,0 +1,19 @@
+{
+  "firstName": "Mabrouk",
+  "lastName": "Mahdhi",
+  "stateOrRegion": "Darmstadt, Germany",
+  "emailAddress": "contact@mahdhi.com",
+  "tagOrBio": "is a Senior Technical Consultant who blogs, talks and develops all around mobile and web development.",
+  "webSite": "https://mahdhi.com",
+  "twitterHandle": "mabrouk_mahdhi",
+  "githubHandle": "mabroukmahdhi",
+  "gravatarHash": "1f5b179abb9b9f8a34a4a9799e205c96",
+  "feedUris": [
+    "https://medium.com/feed/@mabroukmahdhi"
+  ],
+  "position": {  
+    "lat": 49.873207,
+    "lon": 8.650779
+  },
+  "languageCode": "en"
+}
\ No newline at end of file
diff --git a/PlanetDotnetAuthors/Models/Author.cs b/PlanetDotnet.Authors/Models/Authors/Author.cs
similarity index 80%
rename from PlanetDotnetAuthors/Models/Author.cs
rename to PlanetDotnet.Authors/Models/Authors/Author.cs
index 0d1e683..da6a3af 100644
--- a/PlanetDotnetAuthors/Models/Author.cs
+++ b/PlanetDotnet.Authors/Models/Authors/Author.cs
@@ -1,9 +1,16 @@
-using Newtonsoft.Json;
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
 using System;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
+using Newtonsoft.Json;
+using PlanetDotnet.Authors.Models.GeoPositions;
 
-namespace PlanetDotnetAuthors.Models
+namespace PlanetDotnet.Authors.Models.Authors
 {
     public class Author
     {
diff --git a/PlanetDotnetAuthors/Models/GeoPosition.cs b/PlanetDotnet.Authors/Models/GeoPositions/GeoPosition.cs
similarity index 53%
rename from PlanetDotnetAuthors/Models/GeoPosition.cs
rename to PlanetDotnet.Authors/Models/GeoPositions/GeoPosition.cs
index ccc81c2..e5f6204 100644
--- a/PlanetDotnetAuthors/Models/GeoPosition.cs
+++ b/PlanetDotnet.Authors/Models/GeoPositions/GeoPosition.cs
@@ -1,6 +1,12 @@
-using Newtonsoft.Json;
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
 
-namespace PlanetDotnetAuthors.Models
+using Newtonsoft.Json;
+
+namespace PlanetDotnet.Authors.Models.GeoPositions
 {
     public class GeoPosition
     {
diff --git a/PlanetDotnet.Authors/PlanetDotnet.Authors.csproj b/PlanetDotnet.Authors/PlanetDotnet.Authors.csproj
new file mode 100644
index 0000000..6b825fc
--- /dev/null
+++ b/PlanetDotnet.Authors/PlanetDotnet.Authors.csproj
@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.1</TargetFramework>
+    <Nullable>disable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
+    <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
+  </ItemGroup>
+
+	<ItemGroup>
+		<EmbeddedResource Include="..\Authors\*.json" />
+	</ItemGroup>
+
+</Project>
diff --git a/PlanetDotnetAuthors/AuthorsLoader.cs b/PlanetDotnet.Authors/Services/AuthorService.cs
similarity index 68%
rename from PlanetDotnetAuthors/AuthorsLoader.cs
rename to PlanetDotnet.Authors/Services/AuthorService.cs
index 3648351..095b5fc 100644
--- a/PlanetDotnetAuthors/AuthorsLoader.cs
+++ b/PlanetDotnet.Authors/Services/AuthorService.cs
@@ -1,22 +1,28 @@
-using Newtonsoft.Json;
-using PlanetDotnetAuthors.Models;
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Threading.Tasks;
+using Newtonsoft.Json;
+using PlanetDotnet.Authors.Models.Authors;
 
-namespace PlanetDotnetAuthors
+namespace PlanetDotnet.Authors.Services
 {
-    public static class AuthorsLoader
+    public static class AuthorService
     {
         public static async Task<IEnumerable<Author>> GetAllAuthors()
         {
             var assembly = Assembly.GetExecutingAssembly();
             var resourceNames = assembly.GetManifestResourceNames();
             var authorsResourceNames = resourceNames.Where(res =>
-                res.StartsWith("PlanetDotnetAuthors", StringComparison.OrdinalIgnoreCase) &&
+                res.StartsWith("PlanetDotnet.Authors", StringComparison.OrdinalIgnoreCase) &&
                 res.EndsWith(".json", StringComparison.OrdinalIgnoreCase));
 
             var authorsTasks = authorsResourceNames.Select(name => ReadAuthor(assembly, name));
diff --git a/PlanetDotnet.Tests.Unit/DeleteMe.cs b/PlanetDotnet.Tests.Unit/DeleteMe.cs
new file mode 100644
index 0000000..bdf1bb0
--- /dev/null
+++ b/PlanetDotnet.Tests.Unit/DeleteMe.cs
@@ -0,0 +1,16 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using Xunit;
+
+namespace PlanetDotnet.Tests.Unit
+{
+    public class DeleteMe
+    {
+        [Fact]
+        public void ShouldBeTrue() => Assert.True(true);
+    }
+}
\ No newline at end of file
diff --git a/PlanetDotnet.Tests.Unit/PlanetDotnet.Tests.Unit.csproj b/PlanetDotnet.Tests.Unit/PlanetDotnet.Tests.Unit.csproj
new file mode 100644
index 0000000..8180b84
--- /dev/null
+++ b/PlanetDotnet.Tests.Unit/PlanetDotnet.Tests.Unit.csproj
@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <ImplicitUsings>disable</ImplicitUsings>
+    <Nullable>disable</Nullable>
+
+    <IsPackable>false</IsPackable>
+    <IsTestProject>true</IsTestProject>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.1" />
+    <PackageReference Include="xunit" Version="2.4.2" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+      <PrivateAssets>all</PrivateAssets>
+    </PackageReference>
+    <PackageReference Include="coverlet.collector" Version="3.2.0">
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+      <PrivateAssets>all</PrivateAssets>
+    </PackageReference>
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\PlanetDotnet\PlanetDotnet.csproj" />
+  </ItemGroup>
+
+</Project>
diff --git a/PlanetDotnet.sln b/PlanetDotnet.sln
index 0ecf4f3..aaba29e 100644
--- a/PlanetDotnet.sln
+++ b/PlanetDotnet.sln
@@ -3,14 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio Version 17
 VisualStudioVersion = 17.4.32804.182
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlanetDotnet", "PlanetDotnet\PlanetDotnet.csproj", "{591E633A-5665-4D84-B4B6-02B627699AC4}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlanetDotnet", "PlanetDotnet\PlanetDotnet.csproj", "{AA1CF7A0-FF81-40FA-ABB2-519AF44C2460}"
 EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8FA44784-F2C3-4749-9272-38F4D8EA9398}"
-	ProjectSection(SolutionItems) = preProject
-		author-schema.json = author-schema.json
-	EndProjectSection
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlanetDotnet.Tests.Unit", "PlanetDotnet.Tests.Unit\PlanetDotnet.Tests.Unit.csproj", "{ED070F5D-3C55-4E8F-B23A-381E09931D1C}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlanetDotnetAuthors", "PlanetDotnetAuthors\PlanetDotnetAuthors.csproj", "{57C40CD9-62CF-48D2-9A5E-C4CDD1CE6082}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlanetDotnet.Authors", "PlanetDotnet.Authors\PlanetDotnet.Authors.csproj", "{0518A91D-95CA-4C21-BACF-E1E7E56D8754}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -18,14 +15,18 @@ Global
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{591E633A-5665-4D84-B4B6-02B627699AC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{591E633A-5665-4D84-B4B6-02B627699AC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{591E633A-5665-4D84-B4B6-02B627699AC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{591E633A-5665-4D84-B4B6-02B627699AC4}.Release|Any CPU.Build.0 = Release|Any CPU
-		{57C40CD9-62CF-48D2-9A5E-C4CDD1CE6082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{57C40CD9-62CF-48D2-9A5E-C4CDD1CE6082}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{57C40CD9-62CF-48D2-9A5E-C4CDD1CE6082}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{57C40CD9-62CF-48D2-9A5E-C4CDD1CE6082}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AA1CF7A0-FF81-40FA-ABB2-519AF44C2460}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AA1CF7A0-FF81-40FA-ABB2-519AF44C2460}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AA1CF7A0-FF81-40FA-ABB2-519AF44C2460}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AA1CF7A0-FF81-40FA-ABB2-519AF44C2460}.Release|Any CPU.Build.0 = Release|Any CPU
+		{ED070F5D-3C55-4E8F-B23A-381E09931D1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{ED070F5D-3C55-4E8F-B23A-381E09931D1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{ED070F5D-3C55-4E8F-B23A-381E09931D1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{ED070F5D-3C55-4E8F-B23A-381E09931D1C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0518A91D-95CA-4C21-BACF-E1E7E56D8754}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0518A91D-95CA-4C21-BACF-E1E7E56D8754}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0518A91D-95CA-4C21-BACF-E1E7E56D8754}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0518A91D-95CA-4C21-BACF-E1E7E56D8754}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/PlanetDotnet/.gitignore b/PlanetDotnet/.gitignore
new file mode 100644
index 0000000..ff5b00c
--- /dev/null
+++ b/PlanetDotnet/.gitignore
@@ -0,0 +1,264 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# Azure Functions localsettings file
+local.settings.json
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+#*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
\ No newline at end of file
diff --git a/PlanetDotnet/Brokers/Authors/AuthorBroker.cs b/PlanetDotnet/Brokers/Authors/AuthorBroker.cs
new file mode 100644
index 0000000..ad3d674
--- /dev/null
+++ b/PlanetDotnet/Brokers/Authors/AuthorBroker.cs
@@ -0,0 +1,19 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using PlanetDotnet.Authors.Models.Authors;
+using PlanetDotnet.Authors.Services;
+
+namespace PlanetDotnet.Brokers.Authors
+{
+    public class AuthorBroker : IAuthorBroker
+    {
+        public async ValueTask<IEnumerable<Author>> GetAllAuthorsAsync() =>
+           await AuthorService.GetAllAuthors();
+    }
+}
diff --git a/PlanetDotnet/Brokers/Authors/IAuthorBroker.cs b/PlanetDotnet/Brokers/Authors/IAuthorBroker.cs
new file mode 100644
index 0000000..f7dfafb
--- /dev/null
+++ b/PlanetDotnet/Brokers/Authors/IAuthorBroker.cs
@@ -0,0 +1,17 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using PlanetDotnet.Authors.Models.Authors;
+
+namespace PlanetDotnet.Brokers.Authors
+{
+    public interface IAuthorBroker
+    {
+        ValueTask<IEnumerable<Author>> GetAllAuthorsAsync();
+    }
+}
diff --git a/PlanetDotnet/Brokers/DateTimes/DateTimeBroker.cs b/PlanetDotnet/Brokers/DateTimes/DateTimeBroker.cs
new file mode 100644
index 0000000..2109e7d
--- /dev/null
+++ b/PlanetDotnet/Brokers/DateTimes/DateTimeBroker.cs
@@ -0,0 +1,16 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System;
+
+namespace PlanetDotnet.Brokers.DateTimes
+{
+    public class DateTimeBroker : IDateTimeBroker
+    {
+        public DateTimeOffset GetCurrentDateTimeOffset() =>
+            DateTimeOffset.UtcNow;
+    }
+}
\ No newline at end of file
diff --git a/PlanetDotnet/Brokers/DateTimes/IDateTimeBroker.cs b/PlanetDotnet/Brokers/DateTimes/IDateTimeBroker.cs
new file mode 100644
index 0000000..d4505c8
--- /dev/null
+++ b/PlanetDotnet/Brokers/DateTimes/IDateTimeBroker.cs
@@ -0,0 +1,15 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System;
+
+namespace PlanetDotnet.Brokers.DateTimes
+{
+    public interface IDateTimeBroker
+    {
+        DateTimeOffset GetCurrentDateTimeOffset();
+    }
+}
\ No newline at end of file
diff --git a/PlanetDotnet/Brokers/Feeds/FeedBroker.cs b/PlanetDotnet/Brokers/Feeds/FeedBroker.cs
new file mode 100644
index 0000000..94ad3c9
--- /dev/null
+++ b/PlanetDotnet/Brokers/Feeds/FeedBroker.cs
@@ -0,0 +1,37 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System.Net.Http;
+using System.ServiceModel.Syndication;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace PlanetDotnet.Brokers.Feeds
+{
+    internal class FeedBroker : IFeedBroker
+    {
+        private readonly HttpClient httpClient;
+
+        public FeedBroker(HttpClient httpClient) =>
+            this.httpClient = httpClient;
+
+        public async Task<SyndicationFeed> ReadFeedAsync(string feedUri)
+        {
+            var response = await httpClient.GetAsync(feedUri).ConfigureAwait(false);
+            using var feedStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+
+            var settings = new XmlReaderSettings
+            {
+                DtdProcessing = DtdProcessing.Parse
+            };
+
+            using var reader = XmlReader.Create(feedStream, settings);
+            var feed = SyndicationFeed.Load(reader);
+
+            return feed;
+        }
+    }
+}
diff --git a/PlanetDotnet/Brokers/Feeds/IFeedBroker.cs b/PlanetDotnet/Brokers/Feeds/IFeedBroker.cs
new file mode 100644
index 0000000..8da0272
--- /dev/null
+++ b/PlanetDotnet/Brokers/Feeds/IFeedBroker.cs
@@ -0,0 +1,16 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System.ServiceModel.Syndication;
+using System.Threading.Tasks;
+
+namespace PlanetDotnet.Brokers.Feeds
+{
+    public interface IFeedBroker
+    {
+        Task<SyndicationFeed> ReadFeedAsync(string feedUri);
+    }
+}
diff --git a/PlanetDotnet/Brokers/Loggings/ILoggingBroker.cs b/PlanetDotnet/Brokers/Loggings/ILoggingBroker.cs
new file mode 100644
index 0000000..485f6a2
--- /dev/null
+++ b/PlanetDotnet/Brokers/Loggings/ILoggingBroker.cs
@@ -0,0 +1,21 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System;
+
+namespace PlanetDotnet.Brokers.Loggings
+{
+    public interface ILoggingBroker
+    {
+        void LogInformation(string message);
+        void LogTrace(string message);
+        void LogDebug(string message);
+        void LogWarning(string message);
+        void LogError(Exception exception);
+        void LogError(Exception exception, string message);
+        void LogCritical(Exception exception);
+    }
+}
diff --git a/PlanetDotnet/Brokers/Loggings/LoggingBroker.cs b/PlanetDotnet/Brokers/Loggings/LoggingBroker.cs
new file mode 100644
index 0000000..5dd375e
--- /dev/null
+++ b/PlanetDotnet/Brokers/Loggings/LoggingBroker.cs
@@ -0,0 +1,40 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System;
+using Microsoft.Extensions.Logging;
+
+namespace PlanetDotnet.Brokers.Loggings
+{
+    public class LoggingBroker : ILoggingBroker
+    {
+        private readonly ILogger<LoggingBroker> logger;
+
+        public LoggingBroker(ILogger<LoggingBroker> logger) =>
+            this.logger = logger;
+
+        public void LogInformation(string message) =>
+            this.logger.LogInformation(message);
+
+        public void LogTrace(string message) =>
+            this.logger.LogTrace(message);
+
+        public void LogDebug(string message) =>
+            this.logger.LogDebug(message);
+
+        public void LogWarning(string message) =>
+            this.logger.LogWarning(message);
+
+        public void LogError(Exception exception) =>
+            this.logger.LogError(exception.Message, exception);
+
+        public void LogError(Exception exception, string message) =>
+            this.logger.LogError(exception, message);
+
+        public void LogCritical(Exception exception) =>
+            this.logger.LogCritical(exception, exception.Message);
+    }
+}
diff --git a/PlanetDotnet/Brokers/Serializations/ISerializationBroker.cs b/PlanetDotnet/Brokers/Serializations/ISerializationBroker.cs
new file mode 100644
index 0000000..65a601d
--- /dev/null
+++ b/PlanetDotnet/Brokers/Serializations/ISerializationBroker.cs
@@ -0,0 +1,18 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System.IO;
+using System.ServiceModel.Syndication;
+using System.Threading.Tasks;
+
+namespace PlanetDotnet.Brokers.Serializations
+{
+    public interface ISerializationBroker
+    {
+        ValueTask<Stream> SerializeFeedAsync(SyndicationFeed feed);
+        SyndicationFeed DeserializeFeed(Stream feedStream);
+    }
+}
diff --git a/PlanetDotnet/Brokers/Serializations/SerializationBroker.cs b/PlanetDotnet/Brokers/Serializations/SerializationBroker.cs
new file mode 100644
index 0000000..5657951
--- /dev/null
+++ b/PlanetDotnet/Brokers/Serializations/SerializationBroker.cs
@@ -0,0 +1,81 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System;
+using System.IO;
+using System.Linq;
+using System.ServiceModel.Syndication;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace PlanetDotnet.Brokers.Serializations
+{
+    internal class SerializationBroker : ISerializationBroker
+    {
+        public SyndicationFeed DeserializeFeed(Stream feedStream)
+        {
+            feedStream.Position = 0;
+            using var xmlReader = XmlReader.Create(feedStream, new XmlReaderSettings
+            {
+                Async = true
+            });
+
+            var feed = SyndicationFeed.Load(xmlReader);
+
+            return feed;
+        }
+
+        public async ValueTask<Stream> SerializeFeedAsync(SyndicationFeed feed)
+        {
+            var memoryStream = new MemoryStream();
+            using var xmlWriter = XmlWriter.Create(memoryStream, new XmlWriterSettings
+            {
+                Async = true,
+                Indent = true
+            });
+
+            xmlWriter.WriteStartDocument();
+            xmlWriter.WriteStartElement("rss");
+            xmlWriter.WriteAttributeString("version", "2.0");
+            xmlWriter.WriteStartElement("channel");
+            xmlWriter.WriteElementString("title", feed.Title?.Text ?? string.Empty);
+            xmlWriter.WriteElementString("link", feed.Links.FirstOrDefault()?.Uri.AbsoluteUri ?? string.Empty);
+            xmlWriter.WriteElementString("description", feed.Description?.Text ?? string.Empty);
+
+            if (feed.Language != null)
+                xmlWriter.WriteElementString("language", feed.Language);
+
+            if (feed.LastUpdatedTime != DateTimeOffset.MinValue)
+                xmlWriter.WriteElementString("lastBuildDate", feed.LastUpdatedTime.ToString("R"));
+
+            // Write items
+            foreach (var item in feed.Items)
+            {
+                xmlWriter.WriteStartElement("item");
+
+                xmlWriter.WriteElementString("title", item.Title?.Text ?? string.Empty);
+                xmlWriter.WriteElementString("link", item.Links.FirstOrDefault()?.Uri.AbsoluteUri ?? string.Empty);
+                xmlWriter.WriteElementString("description", item.Summary?.Text ?? string.Empty);
+
+                if (item.Id != null)
+                    xmlWriter.WriteElementString("guid", item.Id);
+
+                if (item.PublishDate != DateTimeOffset.MinValue)
+                    xmlWriter.WriteElementString("pubDate", item.PublishDate.ToString("R"));
+
+                xmlWriter.WriteEndElement(); // item
+            }
+
+            xmlWriter.WriteEndElement(); // channel
+            xmlWriter.WriteEndElement(); // rss
+
+            await xmlWriter.FlushAsync();
+            memoryStream.Seek(0, SeekOrigin.Begin);
+
+            return memoryStream;
+        }
+    }
+}
diff --git a/PlanetDotnet/Brokers/Storages/IStorageBroker.cs b/PlanetDotnet/Brokers/Storages/IStorageBroker.cs
new file mode 100644
index 0000000..d52d8d4
--- /dev/null
+++ b/PlanetDotnet/Brokers/Storages/IStorageBroker.cs
@@ -0,0 +1,18 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace PlanetDotnet.Brokers.Storages
+{
+    public interface IStorageBroker
+    {
+        ValueTask InitializeAsync();
+        ValueTask UploadBlobAsync(string language, Stream content);
+        ValueTask<Stream> ReadBlobAsync(string language);
+    }
+}
diff --git a/PlanetDotnet/Brokers/Storages/StorageBroker.cs b/PlanetDotnet/Brokers/Storages/StorageBroker.cs
new file mode 100644
index 0000000..19424d9
--- /dev/null
+++ b/PlanetDotnet/Brokers/Storages/StorageBroker.cs
@@ -0,0 +1,57 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Azure.Storage.Blobs;
+using Azure.Storage.Blobs.Models;
+
+namespace PlanetDotnet.Brokers.Storages
+{
+    public class StorageBroker : IStorageBroker
+    {
+        private readonly BlobContainerClient blobContainerClient;
+        private const string BlobContainerName = "feeds";
+        private const string FeedBlobStorageKey = "FeedBlobStorage";
+        private const string BlobName = "feed.{0}.rss";
+
+        public StorageBroker()
+        {
+            var blobConnectString = Environment.GetEnvironmentVariable(
+                variable: FeedBlobStorageKey,
+                target: EnvironmentVariableTarget.Process);
+
+            this.blobContainerClient = new BlobContainerClient(
+                connectionString: blobConnectString,
+                blobContainerName: BlobContainerName);
+        }
+
+        public async ValueTask InitializeAsync()
+        {
+            await this.blobContainerClient.CreateIfNotExistsAsync();
+            await this.blobContainerClient.SetAccessPolicyAsync(PublicAccessType.Blob);
+        }
+
+        public async ValueTask UploadBlobAsync(string language, Stream content)
+        {
+            var blobName = string.Format(BlobName, language);
+
+            var blobClient = this.blobContainerClient.GetBlobClient(blobName);
+
+            await blobClient.UploadAsync(content, overwrite: true);
+        }
+
+        public async ValueTask<Stream> ReadBlobAsync(string language)
+        {
+            var blobName = string.Format(BlobName, language);
+            var blobClient = this.blobContainerClient.GetBlobClient(blobName);
+
+            var response = await blobClient.DownloadAsync();
+            return response.Value.Content;
+        }
+    }
+}
diff --git a/PlanetDotnet/Extensions/ExceptionExtensions.cs b/PlanetDotnet/Extensions/ExceptionExtensions.cs
new file mode 100644
index 0000000..a563f30
--- /dev/null
+++ b/PlanetDotnet/Extensions/ExceptionExtensions.cs
@@ -0,0 +1,23 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System;
+
+namespace PlanetDotnet.Extensions
+{
+    internal static class ExceptionExtensions
+    {
+        public static TException WithData<TException>(
+            this TException exception,
+            string key,
+            object value)
+            where TException : Exception
+        {
+            exception.Data[key] = value;
+            return exception;
+        }
+    }
+}
diff --git a/PlanetDotnet/Extensions/SyndicationItemExtensions.cs b/PlanetDotnet/Extensions/SyndicationItemExtensions.cs
index 5cb476d..716ba08 100644
--- a/PlanetDotnet/Extensions/SyndicationItemExtensions.cs
+++ b/PlanetDotnet/Extensions/SyndicationItemExtensions.cs
@@ -1,3 +1,9 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
 using System.Linq;
 using System.ServiceModel.Syndication;
 
@@ -45,4 +51,5 @@ public static string ToHtml(this SyndicationContent content)
             return content.ToString();
         }
     }
-}
\ No newline at end of file
+
+}
diff --git a/PlanetDotnet/Infrastructure/CombinedFeedSource.cs b/PlanetDotnet/Infrastructure/CombinedFeedSource.cs
deleted file mode 100644
index 7e77cb3..0000000
--- a/PlanetDotnet/Infrastructure/CombinedFeedSource.cs
+++ /dev/null
@@ -1,213 +0,0 @@
-using Microsoft.Extensions.Logging;
-using PlanetDotnet.Extensions;
-using PlanetDotnetAuthors.Models;
-using Polly;
-using Polly.Retry;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Net.Http.Headers;
-using System.ServiceModel.Syndication;
-using System.Threading.Tasks;
-using System.Xml;
-
-namespace PlanetDotnet.Infrastructure
-{
-    public class CombinedFeedSource
-    {
-        private static HttpClient _httpClient;
-        private static AsyncRetryPolicy _retryPolicy;
-        private readonly IEnumerable<Author> _authors;
-        private readonly ILogger _logger;
-        private readonly string _rssFeedTitle;
-        private readonly string _rssFeedDescription;
-        private readonly string _rssFeedUrl;
-        private readonly string _rssFeedImageUrl;
-
-        public CombinedFeedSource(
-            IEnumerable<Author> authors,
-            ILogger logger,
-            string rssFeedTitle,
-            string rssFeedDescription,
-            string rssFeedUrl,
-            string rssFeedImageUrl)
-        {
-            EnsureHttpClient();
-
-            if (_retryPolicy == null)
-            {
-                // retry policy with max 2 retries, delay by x*x^1.2 where x is retry attempt
-                // this will ensure we don't retry too quickly
-                _retryPolicy = Policy.Handle<FeedReadFailedException>()
-                    .WaitAndRetryAsync(2, retry => TimeSpan.FromSeconds(retry * Math.Pow(1.2, retry)));
-            }
-
-            _authors = authors;
-            _logger = logger;
-            _rssFeedTitle = rssFeedTitle;
-            _rssFeedDescription = rssFeedDescription;
-            _rssFeedUrl = rssFeedUrl;
-            _rssFeedImageUrl = rssFeedImageUrl;
-        }
-
-        private void EnsureHttpClient()
-        {
-            if (_httpClient == null)
-            {
-                _httpClient = new HttpClient();
-                _httpClient.DefaultRequestHeaders.UserAgent.Add(
-                    new ProductInfoHeaderValue("PlanetDotnet", $"{GetType().Assembly.GetName().Version}"));
-                _httpClient.Timeout = TimeSpan.FromSeconds(15);
-
-                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13;
-            }
-        }
-
-        public async Task<SyndicationFeed> LoadFeed(int? numberOfItems, string languageCode = "mixed")
-        {
-            IEnumerable<Author> tamarins;
-            if (languageCode == null || languageCode == "mixed") // use all tamarins
-            {
-                tamarins = _authors;
-            }
-            else
-            {
-                tamarins = _authors.Where(t => t.FeedLanguageCode == languageCode);
-            }
-
-            var feedTasks = tamarins.SelectMany(t => TryReadFeeds(t)).ToArray();
-
-            _logger?.LogInformation($"Loading feed for language: {languageCode} for {feedTasks.Length} authors");
-
-            var syndicationItems = await Task.WhenAll(feedTasks).ConfigureAwait(false);
-            var combinedFeed = GetCombinedFeed(syndicationItems.SelectMany(f => f), languageCode, tamarins, numberOfItems);
-            return combinedFeed;
-        }
-
-        private IEnumerable<Task<IEnumerable<SyndicationItem>>> TryReadFeeds(Author tamarin)
-        {
-            return tamarin.FeedUris.Select(uri => TryReadFeed(tamarin, uri.AbsoluteUri));
-        }
-
-        private async Task<IEnumerable<SyndicationItem>> TryReadFeed(Author tamarin, string feedUri)
-        {
-            try
-            {
-                return await _retryPolicy.ExecuteAsync(context => ReadFeed(feedUri), new Context(feedUri)).ConfigureAwait(false);
-            }
-            catch (FeedReadFailedException ex)
-            {
-                _logger.LogError(ex, $"{tamarin.FirstName} {tamarin.LastName}'s feed of {ex.Data["FeedUri"]} failed to load.");
-            }
-
-            return new SyndicationItem[0];
-        }
-
-        private async Task<IEnumerable<SyndicationItem>> ReadFeed(string feedUri)
-        {
-            HttpResponseMessage response;
-            try
-            {
-                _logger?.LogInformation($"Loading feed {feedUri}");
-                response = await _httpClient.GetAsync(feedUri).ConfigureAwait(false);
-                if (response.IsSuccessStatusCode)
-                {
-                    using var feedStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
-                    using var reader = XmlReader.Create(feedStream);
-                    var feed = SyndicationFeed.Load(reader);
-                    var filteredItems = feed.Items
-                        .Where(item => item.ApplyDefaultFilter());
-
-                    return filteredItems;
-                }
-            }
-            catch (HttpRequestException hex)
-            {
-                throw new FeedReadFailedException("Loading remote syndication feed failed", hex)
-                    .WithData("FeedUri", feedUri);
-            }
-            catch (WebException ex)
-            {
-                throw new FeedReadFailedException("Loading remote syndication feed timed out", ex)
-                    .WithData("FeedUri", feedUri);
-            }
-            catch (XmlException ex)
-            {
-                throw new FeedReadFailedException("Failed parsing remote syndication feed", ex)
-                    .WithData("FeedUri", feedUri);
-            }
-            catch (TaskCanceledException ex)
-            {
-                throw new FeedReadFailedException("Reading feed timed out", ex)
-                    .WithData("FeedUri", feedUri);
-            }
-            catch (OperationCanceledException opcex)
-            {
-                throw new FeedReadFailedException("Reading feed timed out", opcex)
-                    .WithData("FeedUri", feedUri);
-            }
-
-            throw new FeedReadFailedException("Loading remote syndication feed failed.")
-                .WithData("FeedUri", feedUri)
-                .WithData("HttpStatusCode", (int)response.StatusCode);
-        }
-
-        private SyndicationFeed GetCombinedFeed(IEnumerable<SyndicationItem> items, string languageCode,
-            IEnumerable<Author> tamarins, int? numberOfItems)
-        {
-            DateTimeOffset GetMaxTime(SyndicationItem item)
-            {
-                return new[] { item.PublishDate.UtcDateTime, item.LastUpdatedTime.UtcDateTime }.Max();
-            }
-
-            var orderedItems = items
-                .Where(item =>
-                    GetMaxTime(item) <= DateTimeOffset.UtcNow)
-                .OrderByDescending(item => GetMaxTime(item));
-
-            var feed = new SyndicationFeed(
-                _rssFeedTitle,
-                _rssFeedDescription,
-                new Uri(_rssFeedUrl),
-                numberOfItems.HasValue ? orderedItems.Take(numberOfItems.Value) : orderedItems)
-            {
-                ImageUrl = new Uri(_rssFeedImageUrl),
-                Copyright = new TextSyndicationContent("The copyright for each post is retained by its author."),
-                Language = languageCode,
-                LastUpdatedTime = DateTimeOffset.UtcNow
-            };
-
-            foreach (var tamarin in tamarins)
-            {
-                feed.Contributors.Add(new SyndicationPerson(
-                    tamarin.EmailAddress, $"{tamarin.FirstName} {tamarin.LastName}", tamarin.WebSite.ToString()));
-            }
-
-            return feed;
-        }
-    }
-
-    public class FeedReadFailedException : Exception
-    {
-        public FeedReadFailedException(string message)
-            : base(message)
-        {
-        }
-
-        public FeedReadFailedException(string message, Exception inner)
-            : base(message, inner)
-        {
-        }
-    }
-
-    internal static class ExceptionExtensions
-    {
-        public static TException WithData<TException>(this TException exception, string key, object value) where TException : Exception
-        {
-            exception.Data[key] = value;
-            return exception;
-        }
-    }
-}
\ No newline at end of file
diff --git a/PlanetDotnet/LoadFeedsFunction.cs b/PlanetDotnet/LoadFeedsFunction.cs
index 3b8b51e..7d96325 100644
--- a/PlanetDotnet/LoadFeedsFunction.cs
+++ b/PlanetDotnet/LoadFeedsFunction.cs
@@ -1,87 +1,41 @@
-using Azure.Storage.Blobs;
-using Azure.Storage.Blobs.Models;
-using Microsoft.Azure.WebJobs;
-using Microsoft.Extensions.Logging;
-using PlanetDotnet.Infrastructure;
-using PlanetDotnetAuthors;
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
 using System;
-using System.IO;
-using System.Linq;
-using System.ServiceModel.Syndication;
 using System.Threading.Tasks;
-using System.Xml;
+using Microsoft.Azure.WebJobs;
+using Microsoft.Extensions.Logging;
+using PlanetDotnet.Services.Processings.Feeds;
 
 namespace PlanetDotnet
 {
-    public static class LoadFeedsFunction
+    public class LoadFeedsFunction
     {
+        private readonly IFeedProcessingService feedProcessingService;
+
+        public LoadFeedsFunction(IFeedProcessingService feedProcessingService) =>
+            this.feedProcessingService = feedProcessingService;
+
         [FunctionName("LoadFeedsFunction")]
-        public static async Task Run(
+        public async Task Run(
             [TimerTrigger("0 0 */1 * * *", RunOnStartup = true)] TimerInfo myTimer,
             ILogger log)
         {
-            log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
-
-            var rssFeedTitle = GetEnvironmentVariable("RssFeedTitle");
-            var rssFeedDescription = GetEnvironmentVariable("RssFeedDescription");
-            var rssFeedUrl = GetEnvironmentVariable("RssFeedUrl");
-            var rssFeedImageUrl = GetEnvironmentVariable("RssFeedImageUrl");
-
-            var authors = await AuthorsLoader.GetAllAuthors();
-            var languages = authors.Select(author => author.FeedLanguageCode).Distinct().ToList();
-            languages.Add("mixed");
-            var feedSource =
-                new CombinedFeedSource(
-                    authors,
-                    log,
-                    rssFeedTitle,
-                    rssFeedDescription,
-                    rssFeedUrl,
-                    rssFeedImageUrl);
-
-            var blobConnectString = GetEnvironmentVariable("FeedBlobStorage");
-            var container = new BlobContainerClient(blobConnectString, "feeds");
-            await container.CreateIfNotExistsAsync();
-            await container.SetAccessPolicyAsync(PublicAccessType.Blob);
-
-            foreach (var language in languages)
+            try
             {
-                log.LogInformation($"Loading {language} combined author feed");
-                var feed = await feedSource.LoadFeed(null, language);
-                using var stream = await SerializeFeed(feed);
-                await UploadBlob(container, stream, language, log);
-            }
-        }
+                log.LogInformation($"Load feeds Timer trigger function executed at: {DateTime.Now}");
 
-        private static async Task UploadBlob(BlobContainerClient container, Stream feedStream, string language, ILogger log)
-        {
-            var feedName = $"feed.{language}.rss";
-            var blob = container.GetBlobClient(feedName);
-            await blob.UploadAsync(feedStream, overwrite: true);
-
-            log.LogInformation($"Uploaded {feedName} to {blob.Uri}");
-        }
+                await this.feedProcessingService.ProcessFeedLoadingAsync();
 
-        private static async Task<Stream> SerializeFeed(SyndicationFeed feed)
-        {
-            var memoryStream = new MemoryStream();
-            using var xmlWriter = XmlWriter.Create(memoryStream, new XmlWriterSettings
+                log.LogInformation($"Load feeds Finished at: {DateTime.Now}");
+            }
+            catch (Exception ex)
             {
-                Async = true
-            });
-
-            var rssFormatter = new Rss20FeedFormatter(feed);
-            rssFormatter.WriteTo(xmlWriter);
-            await xmlWriter.FlushAsync();
-
-            memoryStream.Seek(0, SeekOrigin.Begin);
-
-            return memoryStream;
-        }
-
-        private static string GetEnvironmentVariable(string name)
-        {
-            return Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
+                log.LogError(ex, "Loading feeds could'nt be processed.");
+            }
         }
     }
 }
diff --git a/PlanetDotnet/Models/Feeds/Exceptions/FailedFeedException.cs b/PlanetDotnet/Models/Feeds/Exceptions/FailedFeedException.cs
new file mode 100644
index 0000000..0bf9409
--- /dev/null
+++ b/PlanetDotnet/Models/Feeds/Exceptions/FailedFeedException.cs
@@ -0,0 +1,21 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System;
+
+namespace PlanetDotnet.Models.Feeds.Exceptions
+{
+    public class FailedFeedException : Exception
+    {
+        public FailedFeedException(string message)
+            : base(message)
+        { }
+
+        public FailedFeedException(string message, Exception inner)
+            : base(message, inner)
+        { }
+    }
+}
diff --git a/PlanetDotnet/PlanetDotnet.csproj b/PlanetDotnet/PlanetDotnet.csproj
index 1f7ca27..69d5a8c 100644
--- a/PlanetDotnet/PlanetDotnet.csproj
+++ b/PlanetDotnet/PlanetDotnet.csproj
@@ -1,16 +1,20 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.1</TargetFramework>
-    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
+    <TargetFramework>net6.0</TargetFramework>
+    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="Azure.Storage.Blobs" Version="12.6.0" />
-    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.9" />
-    <PackageReference Include="Polly" Version="7.2.1" />
-    <PackageReference Include="System.ServiceModel.Syndication" Version="4.7.0" />
+    <None Remove=".gitignore" />
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\PlanetDotnetAuthors\PlanetDotnetAuthors.csproj" />
+    <PackageReference Include="Azure.Storage.Blobs" Version="12.19.1" />
+    <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
+    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.2.0" />
+    <PackageReference Include="Polly" Version="8.2.0" />
+    <PackageReference Include="System.ServiceModel.Syndication" Version="8.0.0" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\PlanetDotnet.Authors\PlanetDotnet.Authors.csproj" />
   </ItemGroup>
   <ItemGroup>
     <None Update="host.json">
@@ -21,4 +25,4 @@
       <CopyToPublishDirectory>Never</CopyToPublishDirectory>
     </None>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/PlanetDotnet/Properties/launchSettings.json b/PlanetDotnet/Properties/launchSettings.json
new file mode 100644
index 0000000..7076a81
--- /dev/null
+++ b/PlanetDotnet/Properties/launchSettings.json
@@ -0,0 +1,9 @@
+{
+  "profiles": {
+    "PlanetDotnet": {
+      "commandName": "Project",
+      "commandLineArgs": "--port 7287",
+      "launchBrowser": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/PlanetDotnet/Properties/serviceDependencies.json b/PlanetDotnet/Properties/serviceDependencies.json
index fcc92d1..df4dcc9 100644
--- a/PlanetDotnet/Properties/serviceDependencies.json
+++ b/PlanetDotnet/Properties/serviceDependencies.json
@@ -1,5 +1,8 @@
 {
   "dependencies": {
+    "appInsights1": {
+      "type": "appInsights"
+    },
     "storage1": {
       "type": "storage",
       "connectionId": "AzureWebJobsStorage"
diff --git a/PlanetDotnet/Properties/serviceDependencies.local.json b/PlanetDotnet/Properties/serviceDependencies.local.json
index 155d87e..b804a28 100644
--- a/PlanetDotnet/Properties/serviceDependencies.local.json
+++ b/PlanetDotnet/Properties/serviceDependencies.local.json
@@ -1,5 +1,8 @@
 {
   "dependencies": {
+    "appInsights1": {
+      "type": "appInsights.sdk"
+    },
     "storage1": {
       "type": "storage.emulator",
       "connectionId": "AzureWebJobsStorage"
diff --git a/PlanetDotnet/Services/Foundations/Feeds/FeedService.cs b/PlanetDotnet/Services/Foundations/Feeds/FeedService.cs
new file mode 100644
index 0000000..2929c59
--- /dev/null
+++ b/PlanetDotnet/Services/Foundations/Feeds/FeedService.cs
@@ -0,0 +1,215 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.ServiceModel.Syndication;
+using System.Threading.Tasks;
+using System.Xml;
+using PlanetDotnet.Authors.Models.Authors;
+using PlanetDotnet.Brokers.Authors;
+using PlanetDotnet.Brokers.Feeds;
+using PlanetDotnet.Brokers.Loggings;
+using PlanetDotnet.Extensions;
+using PlanetDotnet.Models.Feeds.Exceptions;
+using Polly;
+using Polly.Retry;
+
+namespace PlanetDotnet.Services.Foundations.Feeds
+{
+    public class FeedService : IFeedService
+    {
+        private readonly HttpClient httpClient;
+        private readonly AsyncRetryPolicy retryPolicy;
+        private readonly IAuthorBroker authorBroker;
+        private readonly ILoggingBroker loggingBroker;
+        private readonly IFeedBroker feedBroker;
+
+        private const string RssFeedTitleKey = "RssFeedTitle";
+        private const string RssFeedDescriptionKey = "RssFeedDescription";
+        private const string RssFeedUrlKey = "RssFeedUrl";
+        private const string RssFeedImageUrlKey = "RssFeedImageUrl";
+
+        public FeedService(
+            HttpClient httpClient,
+            IFeedBroker feedBroker,
+            IAuthorBroker authorBroker,
+            ILoggingBroker loggingBroker)
+        {
+            this.httpClient = httpClient;
+            this.feedBroker = feedBroker;
+            this.authorBroker = authorBroker;
+            this.loggingBroker = loggingBroker;
+
+            EnsureHttpClient();
+
+            this.retryPolicy ??= Policy.Handle<FailedFeedException>()
+                .WaitAndRetryAsync(2, retry => TimeSpan.FromSeconds(retry * Math.Pow(1.2, retry)));
+        }
+
+        public async Task<SyndicationFeed> LoadFeedAsync(int? numberOfItems, string languageCode = "mixed")
+        {
+            var authors = await this.authorBroker.GetAllAuthorsAsync();
+
+            IEnumerable<Author> languageAuthors;
+
+            if (languageCode == null || languageCode == "mixed") // use all tamarins
+            {
+                languageAuthors = authors;
+            }
+            else
+            {
+                languageAuthors = authors.Where(t => t.FeedLanguageCode == languageCode);
+            }
+
+            var feedTasks = languageAuthors.SelectMany(t => TryReadFeeds(t)).ToArray();
+
+            this.loggingBroker.LogInformation($"Loading feed for language: {languageCode} for {feedTasks.Length} authors");
+
+            var syndicationItems = await Task.WhenAll(feedTasks).ConfigureAwait(false);
+
+            var combinedFeed = GetCombinedFeed(syndicationItems.SelectMany(f => f), languageCode, languageAuthors, numberOfItems);
+
+            return combinedFeed;
+        }
+
+        private IEnumerable<Task<IEnumerable<SyndicationItem>>> TryReadFeeds(Author tamarin)
+        {
+            return tamarin.FeedUris.Select(uri => TryReadFeed(tamarin, uri.AbsoluteUri));
+        }
+
+        private async Task<IEnumerable<SyndicationItem>> TryReadFeed(Author tamarin, string feedUri)
+        {
+            try
+            {
+                return await retryPolicy.ExecuteAsync(context => ReadFeed(feedUri), new Context(feedUri)).ConfigureAwait(false);
+            }
+            catch (FailedFeedException ex)
+            {
+                loggingBroker.LogError(ex, $"{tamarin.FirstName} {tamarin.LastName}'s feed of {ex.Data["FeedUri"]} failed to load.");
+            }
+
+            return Array.Empty<SyndicationItem>();
+        }
+
+        private async Task<IEnumerable<SyndicationItem>> ReadFeed(string feedUri)
+        {
+            try
+            {
+                loggingBroker.LogInformation($"Loading feed {feedUri}");
+
+                var feed = await feedBroker.ReadFeedAsync(feedUri);
+
+                return feed.Items;
+            }
+            catch (HttpRequestException hex)
+            {
+                throw new FailedFeedException("Loading remote syndication feed failed", hex)
+                    .WithData("FeedUri", feedUri);
+            }
+            catch (WebException ex)
+            {
+                throw new FailedFeedException("Loading remote syndication feed timed out", ex)
+                    .WithData("FeedUri", feedUri);
+            }
+            catch (XmlException ex)
+            {
+                throw new FailedFeedException("Failed parsing remote syndication feed", ex)
+                    .WithData("FeedUri", feedUri);
+            }
+            catch (TaskCanceledException ex)
+            {
+                throw new FailedFeedException("Reading feed timed out", ex)
+                    .WithData("FeedUri", feedUri);
+            }
+            catch (OperationCanceledException opcex)
+            {
+                throw new FailedFeedException("Reading feed timed out", opcex)
+                    .WithData("FeedUri", feedUri);
+            }
+
+            throw new FailedFeedException("Loading remote syndication feed failed.")
+                .WithData("FeedUri", feedUri);
+        }
+
+        private SyndicationFeed GetCombinedFeed(IEnumerable<SyndicationItem> items, string languageCode,
+            IEnumerable<Author> authors, int? numberOfItems)
+        {
+
+            var rssFeedTitle = Environment.GetEnvironmentVariable(
+                    variable: RssFeedTitleKey,
+                    target: EnvironmentVariableTarget.Process);
+
+            var rssFeedDescription = Environment.GetEnvironmentVariable(
+                 variable: RssFeedDescriptionKey,
+                 target: EnvironmentVariableTarget.Process);
+
+            var rssFeedUrl = Environment.GetEnvironmentVariable(
+                variable: RssFeedUrlKey,
+                target: EnvironmentVariableTarget.Process);
+
+            var rssFeedImageUrl = Environment.GetEnvironmentVariable(
+                variable: RssFeedImageUrlKey,
+                target: EnvironmentVariableTarget.Process);
+
+            var orderedItems = items
+                .Where(item =>
+                    GetMaxTime(item) <= DateTimeOffset.UtcNow)
+                .OrderByDescending(item => GetMaxTime(item));
+
+            var feed = new SyndicationFeed(
+               rssFeedTitle,
+               rssFeedDescription,
+                new Uri(rssFeedUrl),
+                numberOfItems.HasValue ? orderedItems.Take(numberOfItems.Value) : orderedItems)
+            {
+                ImageUrl = new Uri(rssFeedImageUrl),
+                Copyright = new TextSyndicationContent("The copyright for each post is retained by its author."),
+                Language = languageCode,
+                LastUpdatedTime = DateTimeOffset.UtcNow
+            };
+
+            foreach (var author in authors)
+            {
+                feed.Contributors.Add(new SyndicationPerson(
+                    author.EmailAddress, $"{author.FirstName} {author.LastName}", author.WebSite.ToString()));
+            }
+
+            return feed;
+        }
+
+        private static DateTimeOffset GetMaxTime(SyndicationItem item)
+        {
+            try
+            {
+                return new[] { item.PublishDate.UtcDateTime, item.LastUpdatedTime.UtcDateTime }.Max();
+            }
+            catch
+            {
+                return item.PublishDate.UtcDateTime;
+            }
+        }
+
+        private void EnsureHttpClient()
+        {
+            this.httpClient.DefaultRequestHeaders.UserAgent.Add(
+                new ProductInfoHeaderValue(
+                    productName: "PlanetDotnet",
+                    productVersion: $"{GetType().Assembly.GetName().Version}"));
+
+            this.httpClient.Timeout = TimeSpan.FromSeconds(15);
+
+            ServicePointManager.SecurityProtocol =
+                SecurityProtocolType.Tls13
+                | SecurityProtocolType.Tls12
+                | SecurityProtocolType.Tls11;
+        }
+    }
+}
\ No newline at end of file
diff --git a/PlanetDotnet/Services/Foundations/Feeds/IFeedService.cs b/PlanetDotnet/Services/Foundations/Feeds/IFeedService.cs
new file mode 100644
index 0000000..8218eb8
--- /dev/null
+++ b/PlanetDotnet/Services/Foundations/Feeds/IFeedService.cs
@@ -0,0 +1,16 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System.ServiceModel.Syndication;
+using System.Threading.Tasks;
+
+namespace PlanetDotnet.Services.Foundations.Feeds
+{
+    public interface IFeedService
+    {
+        Task<SyndicationFeed> LoadFeedAsync(int? numberOfItems, string languageCode = "mixed");
+    }
+}
diff --git a/PlanetDotnet/Services/Processings/Feeds/FeedProcessingService.cs b/PlanetDotnet/Services/Processings/Feeds/FeedProcessingService.cs
new file mode 100644
index 0000000..6a7e06d
--- /dev/null
+++ b/PlanetDotnet/Services/Processings/Feeds/FeedProcessingService.cs
@@ -0,0 +1,70 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Threading.Tasks;
+using PlanetDotnet.Brokers.Authors;
+using PlanetDotnet.Brokers.Loggings;
+using PlanetDotnet.Brokers.Serializations;
+using PlanetDotnet.Brokers.Storages;
+using PlanetDotnet.Services.Foundations.Feeds;
+
+namespace PlanetDotnet.Services.Processings.Feeds
+{
+    public class FeedProcessingService : IFeedProcessingService
+    {
+        private readonly IFeedService feedService;
+        private readonly IStorageBroker storageBroker;
+        private readonly IAuthorBroker authorBroker;
+        private readonly ISerializationBroker serializationBroker;
+        private readonly ILoggingBroker loggingBroker;
+
+        public FeedProcessingService(
+            IFeedService feedService,
+            IStorageBroker storageBroker,
+            IAuthorBroker authorBroker,
+            ISerializationBroker serializationBroker,
+            ILoggingBroker loggingBroker)
+        {
+            this.feedService = feedService;
+            this.storageBroker = storageBroker;
+            this.authorBroker = authorBroker;
+            this.serializationBroker = serializationBroker;
+            this.loggingBroker = loggingBroker;
+        }
+
+        public async ValueTask ProcessFeedLoadingAsync()
+        {
+            await this.storageBroker.InitializeAsync();
+
+            var authors = await this.authorBroker.GetAllAuthorsAsync();
+
+            var languages = authors.Select(author => author.FeedLanguageCode).Distinct().ToList();
+
+            var mainCulture = CultureInfo.CurrentCulture;
+
+            foreach (var language in languages)
+            {
+                try
+                {
+                    CultureInfo.CurrentCulture = new CultureInfo(language);
+                    this.loggingBroker.LogInformation($"Loading {language} combined author feed");
+                    var feed = await feedService.LoadFeedAsync(null, language);
+                    using var stream = await this.serializationBroker.SerializeFeedAsync(feed);
+                    await this.storageBroker.UploadBlobAsync(language, stream);
+                }
+                catch (Exception ex)
+                {
+                    this.loggingBroker.LogError(ex, "error");
+                }
+            }
+
+            CultureInfo.CurrentCulture = mainCulture;
+        }
+    }
+}
diff --git a/PlanetDotnet/Services/Processings/Feeds/IFeedProcessingService.cs b/PlanetDotnet/Services/Processings/Feeds/IFeedProcessingService.cs
new file mode 100644
index 0000000..2d08eda
--- /dev/null
+++ b/PlanetDotnet/Services/Processings/Feeds/IFeedProcessingService.cs
@@ -0,0 +1,15 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using System.Threading.Tasks;
+
+namespace PlanetDotnet.Services.Processings.Feeds
+{
+    public interface IFeedProcessingService
+    {
+        ValueTask ProcessFeedLoadingAsync();
+    }
+}
diff --git a/PlanetDotnet/Startup.cs b/PlanetDotnet/Startup.cs
new file mode 100644
index 0000000..2b8b95a
--- /dev/null
+++ b/PlanetDotnet/Startup.cs
@@ -0,0 +1,38 @@
+// ---------------------------------------------------------------
+// Copyright (c) 2023 Planet Dotnet. All rights reserved.
+// Licensed under the MIT License.
+// See License.txt in the project root for license information.
+// ---------------------------------------------------------------
+
+using Microsoft.Azure.Functions.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using PlanetDotnet.Brokers.Authors;
+using PlanetDotnet.Brokers.DateTimes;
+using PlanetDotnet.Brokers.Feeds;
+using PlanetDotnet.Brokers.Loggings;
+using PlanetDotnet.Brokers.Serializations;
+using PlanetDotnet.Brokers.Storages;
+using PlanetDotnet.Services.Foundations.Feeds;
+using PlanetDotnet.Services.Processings.Feeds;
+
+[assembly: FunctionsStartup(typeof(PlanetDotnet.Startup))]
+namespace PlanetDotnet
+{
+    public class Startup : FunctionsStartup
+    {
+        public override void Configure(IFunctionsHostBuilder builder)
+        {
+            builder.Services.AddLogging();
+            builder.Services.AddSingleton<ILogger<LoggingBroker>, Logger<LoggingBroker>>();
+            builder.Services.AddSingleton<ILoggingBroker, LoggingBroker>();
+            builder.Services.AddSingleton<IDateTimeBroker, DateTimeBroker>();
+            builder.Services.AddSingleton<ISerializationBroker, SerializationBroker>();
+            builder.Services.AddSingleton<IStorageBroker, StorageBroker>();
+            builder.Services.AddSingleton<IAuthorBroker, AuthorBroker>();
+            builder.Services.AddSingleton<IFeedBroker, FeedBroker>();
+            builder.Services.AddSingleton<IFeedService, FeedService>();
+            builder.Services.AddSingleton<IFeedProcessingService, FeedProcessingService>();
+        }
+    }
+}
diff --git a/PlanetDotnet/host.json b/PlanetDotnet/host.json
index bb3b8da..fbe7613 100644
--- a/PlanetDotnet/host.json
+++ b/PlanetDotnet/host.json
@@ -1,11 +1,15 @@
 {
-    "version": "2.0",
-    "logging": {
-        "applicationInsights": {
-            "samplingExcludedTypes": "Request",
-            "samplingSettings": {
-                "isEnabled": true
-            }
-        }
+  "version": "2.0",
+  "logging": {
+    "applicationInsights": {
+      "samplingSettings": {
+        "isEnabled": true,
+        "excludedTypes": "Request"
+      },
+      "enableLiveMetricsFilters": true
+    },
+    "logLevel": {
+      "PlanetDotnet.Brokers.Loggings.LoggingBroker": "Information"
     }
+  }
 }
\ No newline at end of file
diff --git a/PlanetDotnet/local.settings.json b/PlanetDotnet/local.settings.json
deleted file mode 100644
index 6f0b5a7..0000000
--- a/PlanetDotnet/local.settings.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "IsEncrypted": false,
-  "Values": {
-    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
-    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
-    "RssFeedTitle": "Planet Xamarin",
-    "RssFeedDescription": "An aggregated feed from the Xamarin community",
-    "RssFeedUrl": "https://www.planetxamarin.com/feed",
-    "RssFeedImageUrl": "https://www.planetxamarin.com/Content/Logo.png",
-    "FeedBlobStorage": ""
-  }
-}
\ No newline at end of file
diff --git a/PlanetDotnetAuthors/PlanetDotnetAuthors.csproj b/PlanetDotnetAuthors/PlanetDotnetAuthors.csproj
deleted file mode 100644
index cb36460..0000000
--- a/PlanetDotnetAuthors/PlanetDotnetAuthors.csproj
+++ /dev/null
@@ -1,16 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
-  <PropertyGroup>
-    <TargetFramework>netstandard2.0</TargetFramework>
-    <LangVersion>latest</LangVersion>
-  </PropertyGroup>
-
-  <ItemGroup>
-    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
-    <PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <EmbeddedResource Include="..\Authors\*.json" />
-  </ItemGroup>
-</Project>
diff --git a/author-schema.json b/author-schema.json
deleted file mode 100644
index 4388d1e..0000000
--- a/author-schema.json
+++ /dev/null
@@ -1,88 +0,0 @@
-{
-  {
-    "definitions": {
-      "GeoPosition": {
-        "type": "object",
-        "properties": {
-          "lat": {
-            "type": "number"
-          },
-          "lon": {
-            "type": "number"
-          }
-        },
-        "required": [
-          "lat",
-          "lon"
-        ]
-      }
-    },
-    "type": "object",
-    "properties": {
-      "firstName": {
-        "description": "Author First Name",
-        "type": "string"
-      },
-      "lastName": {
-        "description": "Author Last Name",
-        "type": "string"
-      },
-      "stateOrRegion": {
-        "description": "Author State or Region",
-        "type": "string"
-      },
-      "emailAddress": {
-        "description": "E-mail address",
-        "type": "string",
-        "format": "email"
-      },
-      "tagOrBio": {
-        "description": "Tagline or bio",
-        "type": "string"
-      },
-      "webSite": {
-        "description": "Author Web Site",
-        "type": "string",
-        "format": "uri"
-      },
-      "feedUris": {
-        "description": "Feed URIs",
-        "type": "array",
-        "items": {
-          "type": [
-            "string",
-            "null"
-          ],
-          "format": "uri"
-        }
-      },
-      "twitterHandle": {
-        "description": "Author Twitter Handle",
-        "type": "string"
-      },
-      "gravatarHash": {
-        "description": "Author Gravatar Hash",
-        "type": "string"
-      },
-      "githubHandle": {
-        "description": "Author GitHub Handle",
-        "type": "string"
-      },
-      "position": {
-        "description": "Author GeoPosition",
-        "$ref": "#/definitions/GeoPosition"
-      },
-      "languageCode": {
-        "description": "Feed Language Code. ISO 639-1 format.",
-        "type": "string"
-      }
-    },
-    "required": [
-      "emailAddress",
-      "webSite",
-      "feedUris",
-      "githubHandle",
-      "languageCode"
-    ]
-  }
-}
\ No newline at end of file