diff --git a/BotSharp.sln b/BotSharp.sln
index ad95f29e8..3b6426304 100644
--- a/BotSharp.sln
+++ b/BotSharp.sln
@@ -157,518 +157,786 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Core.A2A", "src\In
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.MultiTenancy", "src\Plugins\BotSharp.Plugin.MultiTenancy\BotSharp.Plugin.MultiTenancy.csproj", "{562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.AgentSkills", "src\Plugins\BotSharp.Plugin.AgentSkills\BotSharp.Plugin.AgentSkills.csproj", "{511BC47F-8640-4E5A-820F-662956911CFD}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{197885F1-2EB2-4709-B9AA-A777878D74B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{197885F1-2EB2-4709-B9AA-A777878D74B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{197885F1-2EB2-4709-B9AA-A777878D74B3}.Debug|x64.ActiveCfg = Debug|Any CPU
{197885F1-2EB2-4709-B9AA-A777878D74B3}.Debug|x64.Build.0 = Debug|Any CPU
+ {197885F1-2EB2-4709-B9AA-A777878D74B3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {197885F1-2EB2-4709-B9AA-A777878D74B3}.Debug|x86.Build.0 = Debug|Any CPU
{197885F1-2EB2-4709-B9AA-A777878D74B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{197885F1-2EB2-4709-B9AA-A777878D74B3}.Release|Any CPU.Build.0 = Release|Any CPU
{197885F1-2EB2-4709-B9AA-A777878D74B3}.Release|x64.ActiveCfg = Release|Any CPU
{197885F1-2EB2-4709-B9AA-A777878D74B3}.Release|x64.Build.0 = Release|Any CPU
+ {197885F1-2EB2-4709-B9AA-A777878D74B3}.Release|x86.ActiveCfg = Release|Any CPU
+ {197885F1-2EB2-4709-B9AA-A777878D74B3}.Release|x86.Build.0 = Release|Any CPU
{36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Debug|x64.ActiveCfg = Debug|x64
{36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Debug|x64.Build.0 = Debug|x64
+ {36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Debug|x86.Build.0 = Debug|Any CPU
{36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Release|Any CPU.Build.0 = Release|Any CPU
{36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Release|x64.ActiveCfg = Release|x64
{36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Release|x64.Build.0 = Release|x64
+ {36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Release|x86.ActiveCfg = Release|Any CPU
+ {36F5CEBD-31A8-4BEF-8BAA-BAC4E63E4815}.Release|x86.Build.0 = Release|Any CPU
{07AD18C5-CE7B-495A-815F-170E93CCC42A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{07AD18C5-CE7B-495A-815F-170E93CCC42A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{07AD18C5-CE7B-495A-815F-170E93CCC42A}.Debug|x64.ActiveCfg = Debug|Any CPU
{07AD18C5-CE7B-495A-815F-170E93CCC42A}.Debug|x64.Build.0 = Debug|Any CPU
+ {07AD18C5-CE7B-495A-815F-170E93CCC42A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {07AD18C5-CE7B-495A-815F-170E93CCC42A}.Debug|x86.Build.0 = Debug|Any CPU
{07AD18C5-CE7B-495A-815F-170E93CCC42A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{07AD18C5-CE7B-495A-815F-170E93CCC42A}.Release|Any CPU.Build.0 = Release|Any CPU
{07AD18C5-CE7B-495A-815F-170E93CCC42A}.Release|x64.ActiveCfg = Release|Any CPU
{07AD18C5-CE7B-495A-815F-170E93CCC42A}.Release|x64.Build.0 = Release|Any CPU
+ {07AD18C5-CE7B-495A-815F-170E93CCC42A}.Release|x86.ActiveCfg = Release|Any CPU
+ {07AD18C5-CE7B-495A-815F-170E93CCC42A}.Release|x86.Build.0 = Release|Any CPU
{3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Debug|x64.ActiveCfg = Debug|Any CPU
{3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Debug|x64.Build.0 = Debug|Any CPU
+ {3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Debug|x86.Build.0 = Debug|Any CPU
{3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Release|Any CPU.Build.0 = Release|Any CPU
{3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Release|x64.ActiveCfg = Release|Any CPU
{3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Release|x64.Build.0 = Release|Any CPU
+ {3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Release|x86.ActiveCfg = Release|Any CPU
+ {3EAB9CF3-0F47-4BFB-8BAC-8ADFF24AD899}.Release|x86.Build.0 = Release|Any CPU
{57806BAF-7736-425A-B499-13A2A2DF1E63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57806BAF-7736-425A-B499-13A2A2DF1E63}.Debug|Any CPU.Build.0 = Debug|Any CPU
{57806BAF-7736-425A-B499-13A2A2DF1E63}.Debug|x64.ActiveCfg = Debug|Any CPU
{57806BAF-7736-425A-B499-13A2A2DF1E63}.Debug|x64.Build.0 = Debug|Any CPU
+ {57806BAF-7736-425A-B499-13A2A2DF1E63}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {57806BAF-7736-425A-B499-13A2A2DF1E63}.Debug|x86.Build.0 = Debug|Any CPU
{57806BAF-7736-425A-B499-13A2A2DF1E63}.Release|Any CPU.ActiveCfg = Release|Any CPU
{57806BAF-7736-425A-B499-13A2A2DF1E63}.Release|Any CPU.Build.0 = Release|Any CPU
{57806BAF-7736-425A-B499-13A2A2DF1E63}.Release|x64.ActiveCfg = Release|Any CPU
{57806BAF-7736-425A-B499-13A2A2DF1E63}.Release|x64.Build.0 = Release|Any CPU
+ {57806BAF-7736-425A-B499-13A2A2DF1E63}.Release|x86.ActiveCfg = Release|Any CPU
+ {57806BAF-7736-425A-B499-13A2A2DF1E63}.Release|x86.Build.0 = Release|Any CPU
{68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Debug|Any CPU.Build.0 = Debug|Any CPU
{68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Debug|x64.ActiveCfg = Debug|Any CPU
{68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Debug|x64.Build.0 = Debug|Any CPU
+ {68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Debug|x86.Build.0 = Debug|Any CPU
{68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Release|Any CPU.ActiveCfg = Release|Any CPU
{68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Release|Any CPU.Build.0 = Release|Any CPU
{68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Release|x64.ActiveCfg = Release|Any CPU
{68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Release|x64.Build.0 = Release|Any CPU
+ {68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Release|x86.ActiveCfg = Release|Any CPU
+ {68C7C9E9-496B-4004-A1F8-75FFB8C06C76}.Release|x86.Build.0 = Release|Any CPU
{2323A7A3-E938-488D-A57E-638638054BC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2323A7A3-E938-488D-A57E-638638054BC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2323A7A3-E938-488D-A57E-638638054BC4}.Debug|x64.ActiveCfg = Debug|Any CPU
{2323A7A3-E938-488D-A57E-638638054BC4}.Debug|x64.Build.0 = Debug|Any CPU
+ {2323A7A3-E938-488D-A57E-638638054BC4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2323A7A3-E938-488D-A57E-638638054BC4}.Debug|x86.Build.0 = Debug|Any CPU
{2323A7A3-E938-488D-A57E-638638054BC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2323A7A3-E938-488D-A57E-638638054BC4}.Release|Any CPU.Build.0 = Release|Any CPU
{2323A7A3-E938-488D-A57E-638638054BC4}.Release|x64.ActiveCfg = Release|Any CPU
{2323A7A3-E938-488D-A57E-638638054BC4}.Release|x64.Build.0 = Release|Any CPU
+ {2323A7A3-E938-488D-A57E-638638054BC4}.Release|x86.ActiveCfg = Release|Any CPU
+ {2323A7A3-E938-488D-A57E-638638054BC4}.Release|x86.Build.0 = Release|Any CPU
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Debug|x64.ActiveCfg = Debug|Any CPU
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Debug|x64.Build.0 = Debug|Any CPU
+ {6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Debug|x86.Build.0 = Debug|Any CPU
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Release|Any CPU.Build.0 = Release|Any CPU
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Release|x64.ActiveCfg = Release|Any CPU
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Release|x64.Build.0 = Release|Any CPU
+ {6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Release|x86.ActiveCfg = Release|Any CPU
+ {6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Release|x86.Build.0 = Release|Any CPU
{FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Debug|x64.ActiveCfg = Debug|Any CPU
{FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Debug|x64.Build.0 = Debug|Any CPU
+ {FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Debug|x86.Build.0 = Debug|Any CPU
{FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Release|Any CPU.Build.0 = Release|Any CPU
{FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Release|x64.ActiveCfg = Release|Any CPU
{FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Release|x64.Build.0 = Release|Any CPU
+ {FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Release|x86.ActiveCfg = Release|Any CPU
+ {FE2E6CC1-EB80-4518-B3A3-CB373EDA6A83}.Release|x86.Build.0 = Release|Any CPU
{0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Debug|x64.ActiveCfg = Debug|Any CPU
{0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Debug|x64.Build.0 = Debug|Any CPU
+ {0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Debug|x86.Build.0 = Debug|Any CPU
{0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Release|Any CPU.Build.0 = Release|Any CPU
{0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Release|x64.ActiveCfg = Release|Any CPU
{0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Release|x64.Build.0 = Release|Any CPU
+ {0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Release|x86.ActiveCfg = Release|Any CPU
+ {0308FBFD-57EB-4709-9AE4-A80D516AD84D}.Release|x86.Build.0 = Release|Any CPU
{8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Debug|x64.ActiveCfg = Debug|Any CPU
{8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Debug|x64.Build.0 = Debug|Any CPU
+ {8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Debug|x86.Build.0 = Debug|Any CPU
{8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Release|Any CPU.Build.0 = Release|Any CPU
{8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Release|x64.ActiveCfg = Release|Any CPU
{8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Release|x64.Build.0 = Release|Any CPU
+ {8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Release|x86.ActiveCfg = Release|Any CPU
+ {8300F66D-9EB8-438A-BF0F-70DFBE07D9DE}.Release|x86.Build.0 = Release|Any CPU
{7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Debug|x64.ActiveCfg = Debug|Any CPU
{7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Debug|x64.Build.0 = Debug|Any CPU
+ {7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Debug|x86.Build.0 = Debug|Any CPU
{7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Release|Any CPU.Build.0 = Release|Any CPU
{7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Release|x64.ActiveCfg = Release|Any CPU
{7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Release|x64.Build.0 = Release|Any CPU
+ {7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Release|x86.ActiveCfg = Release|Any CPU
+ {7E63F5F8-4EA0-498B-ABFE-2BBE4D7DDBA7}.Release|x86.Build.0 = Release|Any CPU
{46B7B54F-1425-4C9D-824A-9B826855D249}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{46B7B54F-1425-4C9D-824A-9B826855D249}.Debug|Any CPU.Build.0 = Debug|Any CPU
{46B7B54F-1425-4C9D-824A-9B826855D249}.Debug|x64.ActiveCfg = Debug|Any CPU
{46B7B54F-1425-4C9D-824A-9B826855D249}.Debug|x64.Build.0 = Debug|Any CPU
+ {46B7B54F-1425-4C9D-824A-9B826855D249}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {46B7B54F-1425-4C9D-824A-9B826855D249}.Debug|x86.Build.0 = Debug|Any CPU
{46B7B54F-1425-4C9D-824A-9B826855D249}.Release|Any CPU.ActiveCfg = Release|Any CPU
{46B7B54F-1425-4C9D-824A-9B826855D249}.Release|Any CPU.Build.0 = Release|Any CPU
{46B7B54F-1425-4C9D-824A-9B826855D249}.Release|x64.ActiveCfg = Release|Any CPU
{46B7B54F-1425-4C9D-824A-9B826855D249}.Release|x64.Build.0 = Release|Any CPU
+ {46B7B54F-1425-4C9D-824A-9B826855D249}.Release|x86.ActiveCfg = Release|Any CPU
+ {46B7B54F-1425-4C9D-824A-9B826855D249}.Release|x86.Build.0 = Release|Any CPU
{A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Debug|x64.ActiveCfg = Debug|Any CPU
{A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Debug|x64.Build.0 = Debug|Any CPU
+ {A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Debug|x86.Build.0 = Debug|Any CPU
{A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Release|Any CPU.Build.0 = Release|Any CPU
{A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Release|x64.ActiveCfg = Release|Any CPU
{A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Release|x64.Build.0 = Release|Any CPU
+ {A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Release|x86.ActiveCfg = Release|Any CPU
+ {A1118A2C-C6D7-4E22-9462-964AEC7CC46E}.Release|x86.Build.0 = Release|Any CPU
{631D9C12-86C4-44F0-99C3-D32C0754BF37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{631D9C12-86C4-44F0-99C3-D32C0754BF37}.Debug|Any CPU.Build.0 = Debug|Any CPU
{631D9C12-86C4-44F0-99C3-D32C0754BF37}.Debug|x64.ActiveCfg = Debug|Any CPU
{631D9C12-86C4-44F0-99C3-D32C0754BF37}.Debug|x64.Build.0 = Debug|Any CPU
+ {631D9C12-86C4-44F0-99C3-D32C0754BF37}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {631D9C12-86C4-44F0-99C3-D32C0754BF37}.Debug|x86.Build.0 = Debug|Any CPU
{631D9C12-86C4-44F0-99C3-D32C0754BF37}.Release|Any CPU.ActiveCfg = Release|Any CPU
{631D9C12-86C4-44F0-99C3-D32C0754BF37}.Release|Any CPU.Build.0 = Release|Any CPU
{631D9C12-86C4-44F0-99C3-D32C0754BF37}.Release|x64.ActiveCfg = Release|Any CPU
{631D9C12-86C4-44F0-99C3-D32C0754BF37}.Release|x64.Build.0 = Release|Any CPU
+ {631D9C12-86C4-44F0-99C3-D32C0754BF37}.Release|x86.ActiveCfg = Release|Any CPU
+ {631D9C12-86C4-44F0-99C3-D32C0754BF37}.Release|x86.Build.0 = Release|Any CPU
{298AC787-A104-414C-B114-82BE764FBD9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{298AC787-A104-414C-B114-82BE764FBD9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{298AC787-A104-414C-B114-82BE764FBD9C}.Debug|x64.ActiveCfg = Debug|Any CPU
{298AC787-A104-414C-B114-82BE764FBD9C}.Debug|x64.Build.0 = Debug|Any CPU
+ {298AC787-A104-414C-B114-82BE764FBD9C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {298AC787-A104-414C-B114-82BE764FBD9C}.Debug|x86.Build.0 = Debug|Any CPU
{298AC787-A104-414C-B114-82BE764FBD9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{298AC787-A104-414C-B114-82BE764FBD9C}.Release|Any CPU.Build.0 = Release|Any CPU
{298AC787-A104-414C-B114-82BE764FBD9C}.Release|x64.ActiveCfg = Release|Any CPU
{298AC787-A104-414C-B114-82BE764FBD9C}.Release|x64.Build.0 = Release|Any CPU
+ {298AC787-A104-414C-B114-82BE764FBD9C}.Release|x86.ActiveCfg = Release|Any CPU
+ {298AC787-A104-414C-B114-82BE764FBD9C}.Release|x86.Build.0 = Release|Any CPU
{DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Debug|x64.ActiveCfg = Debug|Any CPU
{DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Debug|x64.Build.0 = Debug|Any CPU
+ {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Debug|x86.Build.0 = Debug|Any CPU
{DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Release|Any CPU.Build.0 = Release|Any CPU
{DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Release|x64.ActiveCfg = Release|Any CPU
{DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Release|x64.Build.0 = Release|Any CPU
+ {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Release|x86.ActiveCfg = Release|Any CPU
+ {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Release|x86.Build.0 = Release|Any CPU
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Debug|x64.ActiveCfg = Debug|Any CPU
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Debug|x64.Build.0 = Debug|Any CPU
+ {8BC29F8A-78D6-422C-B522-10687ADC38ED}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8BC29F8A-78D6-422C-B522-10687ADC38ED}.Debug|x86.Build.0 = Debug|Any CPU
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|Any CPU.Build.0 = Release|Any CPU
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|x64.ActiveCfg = Release|Any CPU
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|x64.Build.0 = Release|Any CPU
+ {8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|x86.ActiveCfg = Release|Any CPU
+ {8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|x86.Build.0 = Release|Any CPU
{73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Debug|x64.ActiveCfg = Debug|Any CPU
{73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Debug|x64.Build.0 = Debug|Any CPU
+ {73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Debug|x86.Build.0 = Debug|Any CPU
{73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Release|Any CPU.Build.0 = Release|Any CPU
{73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Release|x64.ActiveCfg = Release|Any CPU
{73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Release|x64.Build.0 = Release|Any CPU
+ {73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Release|x86.ActiveCfg = Release|Any CPU
+ {73EE2CD0-3B27-4F02-A67B-762CBDD740D0}.Release|x86.Build.0 = Release|Any CPU
{72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Debug|x64.ActiveCfg = Debug|Any CPU
{72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Debug|x64.Build.0 = Debug|Any CPU
+ {72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Debug|x86.Build.0 = Debug|Any CPU
{72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Release|Any CPU.Build.0 = Release|Any CPU
{72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Release|x64.ActiveCfg = Release|Any CPU
{72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Release|x64.Build.0 = Release|Any CPU
+ {72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Release|x86.ActiveCfg = Release|Any CPU
+ {72CA059E-6AAA-406C-A1EB-A2243E652F5F}.Release|x86.Build.0 = Release|Any CPU
{BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Debug|x64.ActiveCfg = Debug|Any CPU
{BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Debug|x64.Build.0 = Debug|Any CPU
+ {BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Debug|x86.Build.0 = Debug|Any CPU
{BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Release|Any CPU.Build.0 = Release|Any CPU
{BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Release|x64.ActiveCfg = Release|Any CPU
{BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Release|x64.Build.0 = Release|Any CPU
+ {BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Release|x86.ActiveCfg = Release|Any CPU
+ {BC57D428-A1A4-4D38-A2D0-AC6CA943F247}.Release|x86.Build.0 = Release|Any CPU
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|x64.ActiveCfg = Debug|Any CPU
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|x64.Build.0 = Debug|Any CPU
+ {E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|x86.Build.0 = Debug|Any CPU
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|Any CPU.Build.0 = Release|Any CPU
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|x64.ActiveCfg = Release|Any CPU
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|x64.Build.0 = Release|Any CPU
+ {E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|x86.ActiveCfg = Release|Any CPU
+ {E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|x86.Build.0 = Release|Any CPU
{F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Debug|x64.ActiveCfg = Debug|Any CPU
{F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Debug|x64.Build.0 = Debug|Any CPU
+ {F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Debug|x86.Build.0 = Debug|Any CPU
{F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Release|Any CPU.Build.0 = Release|Any CPU
{F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Release|x64.ActiveCfg = Release|Any CPU
{F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Release|x64.Build.0 = Release|Any CPU
+ {F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Release|x86.ActiveCfg = Release|Any CPU
+ {F06B22CB-B143-4680-8FFF-35B9E50E6C47}.Release|x86.Build.0 = Release|Any CPU
{EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Debug|x64.ActiveCfg = Debug|Any CPU
{EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Debug|x64.Build.0 = Debug|Any CPU
+ {EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Debug|x86.Build.0 = Debug|Any CPU
{EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Release|Any CPU.Build.0 = Release|Any CPU
{EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Release|x64.ActiveCfg = Release|Any CPU
{EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Release|x64.Build.0 = Release|Any CPU
+ {EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Release|x86.ActiveCfg = Release|Any CPU
+ {EDCD9C20-2D9D-4098-A16E-03F97B306CB8}.Release|x86.Build.0 = Release|Any CPU
{DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Debug|x64.ActiveCfg = Debug|Any CPU
{DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Debug|x64.Build.0 = Debug|Any CPU
+ {DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Debug|x86.Build.0 = Debug|Any CPU
{DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Release|Any CPU.Build.0 = Release|Any CPU
{DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Release|x64.ActiveCfg = Release|Any CPU
{DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Release|x64.Build.0 = Release|Any CPU
+ {DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Release|x86.ActiveCfg = Release|Any CPU
+ {DCA18996-4D3A-4E98-BCD0-1FB77C59253E}.Release|x86.Build.0 = Release|Any CPU
{5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Debug|x64.ActiveCfg = Debug|Any CPU
{5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Debug|x64.Build.0 = Debug|Any CPU
+ {5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Debug|x86.Build.0 = Debug|Any CPU
{5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Release|Any CPU.Build.0 = Release|Any CPU
{5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Release|x64.ActiveCfg = Release|Any CPU
{5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Release|x64.Build.0 = Release|Any CPU
+ {5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Release|x86.ActiveCfg = Release|Any CPU
+ {5CA3335E-E6AD-46FD-B277-29BBC3A16500}.Release|x86.Build.0 = Release|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Debug|x64.ActiveCfg = Debug|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Debug|x64.Build.0 = Debug|Any CPU
+ {32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Debug|x86.Build.0 = Debug|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Release|Any CPU.Build.0 = Release|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Release|x64.ActiveCfg = Release|Any CPU
{32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Release|x64.Build.0 = Release|Any CPU
+ {32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Release|x86.ActiveCfg = Release|Any CPU
+ {32D9E720-6FE6-4F29-94B1-B10B05BFAD75}.Release|x86.Build.0 = Release|Any CPU
{D775DB67-A4B4-44E5-9144-522689590057}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D775DB67-A4B4-44E5-9144-522689590057}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D775DB67-A4B4-44E5-9144-522689590057}.Debug|x64.ActiveCfg = Debug|Any CPU
{D775DB67-A4B4-44E5-9144-522689590057}.Debug|x64.Build.0 = Debug|Any CPU
+ {D775DB67-A4B4-44E5-9144-522689590057}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D775DB67-A4B4-44E5-9144-522689590057}.Debug|x86.Build.0 = Debug|Any CPU
{D775DB67-A4B4-44E5-9144-522689590057}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D775DB67-A4B4-44E5-9144-522689590057}.Release|Any CPU.Build.0 = Release|Any CPU
{D775DB67-A4B4-44E5-9144-522689590057}.Release|x64.ActiveCfg = Release|Any CPU
{D775DB67-A4B4-44E5-9144-522689590057}.Release|x64.Build.0 = Release|Any CPU
+ {D775DB67-A4B4-44E5-9144-522689590057}.Release|x86.ActiveCfg = Release|Any CPU
+ {D775DB67-A4B4-44E5-9144-522689590057}.Release|x86.Build.0 = Release|Any CPU
{267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Debug|x64.ActiveCfg = Debug|Any CPU
{267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Debug|x64.Build.0 = Debug|Any CPU
+ {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Debug|x86.Build.0 = Debug|Any CPU
{267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Release|Any CPU.Build.0 = Release|Any CPU
{267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Release|x64.ActiveCfg = Release|Any CPU
{267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Release|x64.Build.0 = Release|Any CPU
+ {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Release|x86.ActiveCfg = Release|Any CPU
+ {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Release|x86.Build.0 = Release|Any CPU
{289E25C8-63F1-4D52-9909-207724DB40CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{289E25C8-63F1-4D52-9909-207724DB40CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{289E25C8-63F1-4D52-9909-207724DB40CB}.Debug|x64.ActiveCfg = Debug|Any CPU
{289E25C8-63F1-4D52-9909-207724DB40CB}.Debug|x64.Build.0 = Debug|Any CPU
+ {289E25C8-63F1-4D52-9909-207724DB40CB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {289E25C8-63F1-4D52-9909-207724DB40CB}.Debug|x86.Build.0 = Debug|Any CPU
{289E25C8-63F1-4D52-9909-207724DB40CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{289E25C8-63F1-4D52-9909-207724DB40CB}.Release|Any CPU.Build.0 = Release|Any CPU
{289E25C8-63F1-4D52-9909-207724DB40CB}.Release|x64.ActiveCfg = Release|Any CPU
{289E25C8-63F1-4D52-9909-207724DB40CB}.Release|x64.Build.0 = Release|Any CPU
+ {289E25C8-63F1-4D52-9909-207724DB40CB}.Release|x86.ActiveCfg = Release|Any CPU
+ {289E25C8-63F1-4D52-9909-207724DB40CB}.Release|x86.Build.0 = Release|Any CPU
{CCF745F2-0C95-4ED0-983B-507C528B39EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CCF745F2-0C95-4ED0-983B-507C528B39EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CCF745F2-0C95-4ED0-983B-507C528B39EA}.Debug|x64.ActiveCfg = Debug|Any CPU
{CCF745F2-0C95-4ED0-983B-507C528B39EA}.Debug|x64.Build.0 = Debug|Any CPU
+ {CCF745F2-0C95-4ED0-983B-507C528B39EA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {CCF745F2-0C95-4ED0-983B-507C528B39EA}.Debug|x86.Build.0 = Debug|Any CPU
{CCF745F2-0C95-4ED0-983B-507C528B39EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CCF745F2-0C95-4ED0-983B-507C528B39EA}.Release|Any CPU.Build.0 = Release|Any CPU
{CCF745F2-0C95-4ED0-983B-507C528B39EA}.Release|x64.ActiveCfg = Release|Any CPU
{CCF745F2-0C95-4ED0-983B-507C528B39EA}.Release|x64.Build.0 = Release|Any CPU
+ {CCF745F2-0C95-4ED0-983B-507C528B39EA}.Release|x86.ActiveCfg = Release|Any CPU
+ {CCF745F2-0C95-4ED0-983B-507C528B39EA}.Release|x86.Build.0 = Release|Any CPU
{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Debug|x64.ActiveCfg = Debug|Any CPU
{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Debug|x64.Build.0 = Debug|Any CPU
+ {806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Debug|x86.Build.0 = Debug|Any CPU
{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Release|Any CPU.Build.0 = Release|Any CPU
{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Release|x64.ActiveCfg = Release|Any CPU
{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Release|x64.Build.0 = Release|Any CPU
+ {806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Release|x86.ActiveCfg = Release|Any CPU
+ {806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}.Release|x86.Build.0 = Release|Any CPU
{6406DC61-0F30-42E8-A1DB-B38CDF454273}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6406DC61-0F30-42E8-A1DB-B38CDF454273}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6406DC61-0F30-42E8-A1DB-B38CDF454273}.Debug|x64.ActiveCfg = Debug|Any CPU
{6406DC61-0F30-42E8-A1DB-B38CDF454273}.Debug|x64.Build.0 = Debug|Any CPU
+ {6406DC61-0F30-42E8-A1DB-B38CDF454273}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6406DC61-0F30-42E8-A1DB-B38CDF454273}.Debug|x86.Build.0 = Debug|Any CPU
{6406DC61-0F30-42E8-A1DB-B38CDF454273}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6406DC61-0F30-42E8-A1DB-B38CDF454273}.Release|Any CPU.Build.0 = Release|Any CPU
{6406DC61-0F30-42E8-A1DB-B38CDF454273}.Release|x64.ActiveCfg = Release|Any CPU
{6406DC61-0F30-42E8-A1DB-B38CDF454273}.Release|x64.Build.0 = Release|Any CPU
+ {6406DC61-0F30-42E8-A1DB-B38CDF454273}.Release|x86.ActiveCfg = Release|Any CPU
+ {6406DC61-0F30-42E8-A1DB-B38CDF454273}.Release|x86.Build.0 = Release|Any CPU
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Debug|x64.ActiveCfg = Debug|Any CPU
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Debug|x64.Build.0 = Debug|Any CPU
+ {E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Debug|x86.Build.0 = Debug|Any CPU
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|Any CPU.Build.0 = Release|Any CPU
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|x64.ActiveCfg = Release|Any CPU
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|x64.Build.0 = Release|Any CPU
+ {E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|x86.ActiveCfg = Release|Any CPU
+ {E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|x86.Build.0 = Release|Any CPU
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Debug|x64.ActiveCfg = Debug|Any CPU
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Debug|x64.Build.0 = Debug|Any CPU
+ {6507D336-3A4D-41D4-81C0-2B900173A5FE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6507D336-3A4D-41D4-81C0-2B900173A5FE}.Debug|x86.Build.0 = Debug|Any CPU
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Release|Any CPU.Build.0 = Release|Any CPU
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Release|x64.ActiveCfg = Release|Any CPU
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Release|x64.Build.0 = Release|Any CPU
+ {6507D336-3A4D-41D4-81C0-2B900173A5FE}.Release|x86.ActiveCfg = Release|Any CPU
+ {6507D336-3A4D-41D4-81C0-2B900173A5FE}.Release|x86.Build.0 = Release|Any CPU
{A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Debug|x64.ActiveCfg = Debug|Any CPU
{A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Debug|x64.Build.0 = Debug|Any CPU
+ {A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Debug|x86.Build.0 = Debug|Any CPU
{A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Release|Any CPU.Build.0 = Release|Any CPU
{A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Release|x64.ActiveCfg = Release|Any CPU
{A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Release|x64.Build.0 = Release|Any CPU
+ {A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Release|x86.ActiveCfg = Release|Any CPU
+ {A72B3BEB-E14B-4917-BE44-97EAE4E122D2}.Release|x86.Build.0 = Release|Any CPU
{D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Debug|x64.ActiveCfg = Debug|Any CPU
{D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Debug|x64.Build.0 = Debug|Any CPU
+ {D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Debug|x86.Build.0 = Debug|Any CPU
{D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Release|Any CPU.Build.0 = Release|Any CPU
{D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Release|x64.ActiveCfg = Release|Any CPU
{D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Release|x64.Build.0 = Release|Any CPU
+ {D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Release|x86.ActiveCfg = Release|Any CPU
+ {D6A99D4F-6248-419E-8A43-B38ADEBABA2C}.Release|x86.Build.0 = Release|Any CPU
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Debug|x64.ActiveCfg = Debug|Any CPU
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Debug|x64.Build.0 = Debug|Any CPU
+ {54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Debug|x86.Build.0 = Debug|Any CPU
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Release|Any CPU.Build.0 = Release|Any CPU
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Release|x64.ActiveCfg = Release|Any CPU
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Release|x64.Build.0 = Release|Any CPU
+ {54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Release|x86.ActiveCfg = Release|Any CPU
+ {54E83C6F-54EE-4ADC-8D72-93C009CC4FB4}.Release|x86.Build.0 = Release|Any CPU
{BF029B0A-768B-43A1-8D91-E70B95505716}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF029B0A-768B-43A1-8D91-E70B95505716}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF029B0A-768B-43A1-8D91-E70B95505716}.Debug|x64.ActiveCfg = Debug|Any CPU
{BF029B0A-768B-43A1-8D91-E70B95505716}.Debug|x64.Build.0 = Debug|Any CPU
+ {BF029B0A-768B-43A1-8D91-E70B95505716}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BF029B0A-768B-43A1-8D91-E70B95505716}.Debug|x86.Build.0 = Debug|Any CPU
{BF029B0A-768B-43A1-8D91-E70B95505716}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF029B0A-768B-43A1-8D91-E70B95505716}.Release|Any CPU.Build.0 = Release|Any CPU
{BF029B0A-768B-43A1-8D91-E70B95505716}.Release|x64.ActiveCfg = Release|Any CPU
{BF029B0A-768B-43A1-8D91-E70B95505716}.Release|x64.Build.0 = Release|Any CPU
+ {BF029B0A-768B-43A1-8D91-E70B95505716}.Release|x86.ActiveCfg = Release|Any CPU
+ {BF029B0A-768B-43A1-8D91-E70B95505716}.Release|x86.Build.0 = Release|Any CPU
{05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Debug|x64.ActiveCfg = Debug|Any CPU
{05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Debug|x64.Build.0 = Debug|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Debug|x86.Build.0 = Debug|Any CPU
{05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Release|Any CPU.Build.0 = Release|Any CPU
{05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Release|x64.ActiveCfg = Release|Any CPU
{05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Release|x64.Build.0 = Release|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Release|x86.ActiveCfg = Release|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Release|x86.Build.0 = Release|Any CPU
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Debug|x64.ActiveCfg = Debug|Any CPU
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Debug|x64.Build.0 = Debug|Any CPU
+ {EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Debug|x86.Build.0 = Debug|Any CPU
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Release|Any CPU.Build.0 = Release|Any CPU
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Release|x64.ActiveCfg = Release|Any CPU
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Release|x64.Build.0 = Release|Any CPU
+ {EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Release|x86.ActiveCfg = Release|Any CPU
+ {EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Release|x86.Build.0 = Release|Any CPU
{F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Debug|x64.ActiveCfg = Debug|Any CPU
{F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Debug|x64.Build.0 = Debug|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Debug|x86.Build.0 = Debug|Any CPU
{F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|Any CPU.Build.0 = Release|Any CPU
{F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|x64.ActiveCfg = Release|Any CPU
{F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|x64.Build.0 = Release|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|x86.ActiveCfg = Release|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|x86.Build.0 = Release|Any CPU
{6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Debug|x64.ActiveCfg = Debug|Any CPU
{6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Debug|x64.Build.0 = Debug|Any CPU
+ {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Debug|x86.Build.0 = Debug|Any CPU
{6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Release|Any CPU.Build.0 = Release|Any CPU
{6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Release|x64.ActiveCfg = Release|Any CPU
{6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Release|x64.Build.0 = Release|Any CPU
+ {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Release|x86.ActiveCfg = Release|Any CPU
+ {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Release|x86.Build.0 = Release|Any CPU
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Debug|x64.ActiveCfg = Debug|Any CPU
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Debug|x64.Build.0 = Debug|Any CPU
+ {7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Debug|x86.Build.0 = Debug|Any CPU
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Release|Any CPU.Build.0 = Release|Any CPU
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Release|x64.ActiveCfg = Release|Any CPU
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Release|x64.Build.0 = Release|Any CPU
+ {7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Release|x86.ActiveCfg = Release|Any CPU
+ {7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Release|x86.Build.0 = Release|Any CPU
{F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Debug|x64.ActiveCfg = Debug|Any CPU
{F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Debug|x64.Build.0 = Debug|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Debug|x86.Build.0 = Debug|Any CPU
{F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Release|Any CPU.Build.0 = Release|Any CPU
{F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Release|x64.ActiveCfg = Release|Any CPU
{F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Release|x64.Build.0 = Release|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Release|x86.ActiveCfg = Release|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Release|x86.Build.0 = Release|Any CPU
{AFD64412-4D6A-452E-82A2-79E5D8842E29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AFD64412-4D6A-452E-82A2-79E5D8842E29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AFD64412-4D6A-452E-82A2-79E5D8842E29}.Debug|x64.ActiveCfg = Debug|Any CPU
{AFD64412-4D6A-452E-82A2-79E5D8842E29}.Debug|x64.Build.0 = Debug|Any CPU
+ {AFD64412-4D6A-452E-82A2-79E5D8842E29}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AFD64412-4D6A-452E-82A2-79E5D8842E29}.Debug|x86.Build.0 = Debug|Any CPU
{AFD64412-4D6A-452E-82A2-79E5D8842E29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AFD64412-4D6A-452E-82A2-79E5D8842E29}.Release|Any CPU.Build.0 = Release|Any CPU
{AFD64412-4D6A-452E-82A2-79E5D8842E29}.Release|x64.ActiveCfg = Release|Any CPU
{AFD64412-4D6A-452E-82A2-79E5D8842E29}.Release|x64.Build.0 = Release|Any CPU
+ {AFD64412-4D6A-452E-82A2-79E5D8842E29}.Release|x86.ActiveCfg = Release|Any CPU
+ {AFD64412-4D6A-452E-82A2-79E5D8842E29}.Release|x86.Build.0 = Release|Any CPU
{AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Debug|x64.ActiveCfg = Debug|Any CPU
{AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Debug|x64.Build.0 = Debug|Any CPU
+ {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Debug|x86.Build.0 = Debug|Any CPU
{AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|Any CPU.Build.0 = Release|Any CPU
{AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|x64.ActiveCfg = Release|Any CPU
{AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|x64.Build.0 = Release|Any CPU
+ {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|x86.ActiveCfg = Release|Any CPU
+ {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|x86.Build.0 = Release|Any CPU
{781F1465-365C-0F22-1775-25025DAFA4C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{781F1465-365C-0F22-1775-25025DAFA4C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{781F1465-365C-0F22-1775-25025DAFA4C7}.Debug|x64.ActiveCfg = Debug|Any CPU
{781F1465-365C-0F22-1775-25025DAFA4C7}.Debug|x64.Build.0 = Debug|Any CPU
+ {781F1465-365C-0F22-1775-25025DAFA4C7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {781F1465-365C-0F22-1775-25025DAFA4C7}.Debug|x86.Build.0 = Debug|Any CPU
{781F1465-365C-0F22-1775-25025DAFA4C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{781F1465-365C-0F22-1775-25025DAFA4C7}.Release|Any CPU.Build.0 = Release|Any CPU
{781F1465-365C-0F22-1775-25025DAFA4C7}.Release|x64.ActiveCfg = Release|Any CPU
{781F1465-365C-0F22-1775-25025DAFA4C7}.Release|x64.Build.0 = Release|Any CPU
+ {781F1465-365C-0F22-1775-25025DAFA4C7}.Release|x86.ActiveCfg = Release|Any CPU
+ {781F1465-365C-0F22-1775-25025DAFA4C7}.Release|x86.Build.0 = Release|Any CPU
{8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Debug|x64.ActiveCfg = Debug|Any CPU
{8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Debug|x64.Build.0 = Debug|Any CPU
+ {8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Debug|x86.Build.0 = Debug|Any CPU
{8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Release|Any CPU.Build.0 = Release|Any CPU
{8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Release|x64.ActiveCfg = Release|Any CPU
{8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Release|x64.Build.0 = Release|Any CPU
+ {8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Release|x86.ActiveCfg = Release|Any CPU
+ {8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Release|x86.Build.0 = Release|Any CPU
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Debug|x64.ActiveCfg = Debug|Any CPU
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Debug|x64.Build.0 = Debug|Any CPU
+ {C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Debug|x86.Build.0 = Debug|Any CPU
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Release|Any CPU.Build.0 = Release|Any CPU
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Release|x64.ActiveCfg = Release|Any CPU
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Release|x64.Build.0 = Release|Any CPU
+ {C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Release|x86.ActiveCfg = Release|Any CPU
+ {C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Release|x86.Build.0 = Release|Any CPU
{B268E2F0-060F-8466-7D81-ABA4D735CA59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B268E2F0-060F-8466-7D81-ABA4D735CA59}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B268E2F0-060F-8466-7D81-ABA4D735CA59}.Debug|x64.ActiveCfg = Debug|Any CPU
{B268E2F0-060F-8466-7D81-ABA4D735CA59}.Debug|x64.Build.0 = Debug|Any CPU
+ {B268E2F0-060F-8466-7D81-ABA4D735CA59}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B268E2F0-060F-8466-7D81-ABA4D735CA59}.Debug|x86.Build.0 = Debug|Any CPU
{B268E2F0-060F-8466-7D81-ABA4D735CA59}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B268E2F0-060F-8466-7D81-ABA4D735CA59}.Release|Any CPU.Build.0 = Release|Any CPU
{B268E2F0-060F-8466-7D81-ABA4D735CA59}.Release|x64.ActiveCfg = Release|Any CPU
{B268E2F0-060F-8466-7D81-ABA4D735CA59}.Release|x64.Build.0 = Release|Any CPU
+ {B268E2F0-060F-8466-7D81-ABA4D735CA59}.Release|x86.ActiveCfg = Release|Any CPU
+ {B268E2F0-060F-8466-7D81-ABA4D735CA59}.Release|x86.Build.0 = Release|Any CPU
{970BE341-9AC8-99A5-6572-E703C1E02FCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{970BE341-9AC8-99A5-6572-E703C1E02FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{970BE341-9AC8-99A5-6572-E703C1E02FCB}.Debug|x64.ActiveCfg = Debug|Any CPU
{970BE341-9AC8-99A5-6572-E703C1E02FCB}.Debug|x64.Build.0 = Debug|Any CPU
+ {970BE341-9AC8-99A5-6572-E703C1E02FCB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {970BE341-9AC8-99A5-6572-E703C1E02FCB}.Debug|x86.Build.0 = Debug|Any CPU
{970BE341-9AC8-99A5-6572-E703C1E02FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{970BE341-9AC8-99A5-6572-E703C1E02FCB}.Release|Any CPU.Build.0 = Release|Any CPU
{970BE341-9AC8-99A5-6572-E703C1E02FCB}.Release|x64.ActiveCfg = Release|Any CPU
{970BE341-9AC8-99A5-6572-E703C1E02FCB}.Release|x64.Build.0 = Release|Any CPU
+ {970BE341-9AC8-99A5-6572-E703C1E02FCB}.Release|x86.ActiveCfg = Release|Any CPU
+ {970BE341-9AC8-99A5-6572-E703C1E02FCB}.Release|x86.Build.0 = Release|Any CPU
{7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Debug|x64.ActiveCfg = Debug|Any CPU
{7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Debug|x64.Build.0 = Debug|Any CPU
+ {7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Debug|x86.Build.0 = Debug|Any CPU
{7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Release|Any CPU.Build.0 = Release|Any CPU
{7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Release|x64.ActiveCfg = Release|Any CPU
{7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Release|x64.Build.0 = Release|Any CPU
+ {7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Release|x86.ActiveCfg = Release|Any CPU
+ {7D0DB012-9798-4BB9-B15B-A5B0B7B3B094}.Release|x86.Build.0 = Release|Any CPU
{7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Debug|x64.ActiveCfg = Debug|Any CPU
{7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Debug|x64.Build.0 = Debug|Any CPU
+ {7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Debug|x86.Build.0 = Debug|Any CPU
{7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Release|Any CPU.Build.0 = Release|Any CPU
{7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Release|x64.ActiveCfg = Release|Any CPU
{7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Release|x64.Build.0 = Release|Any CPU
+ {7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Release|x86.ActiveCfg = Release|Any CPU
+ {7C0C7D13-D161-4AB0-9C29-83A0F1FF990E}.Release|x86.Build.0 = Release|Any CPU
{B067B126-88CD-4282-BEEF-7369B64423EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B067B126-88CD-4282-BEEF-7369B64423EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B067B126-88CD-4282-BEEF-7369B64423EF}.Debug|x64.ActiveCfg = Debug|Any CPU
{B067B126-88CD-4282-BEEF-7369B64423EF}.Debug|x64.Build.0 = Debug|Any CPU
+ {B067B126-88CD-4282-BEEF-7369B64423EF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B067B126-88CD-4282-BEEF-7369B64423EF}.Debug|x86.Build.0 = Debug|Any CPU
{B067B126-88CD-4282-BEEF-7369B64423EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B067B126-88CD-4282-BEEF-7369B64423EF}.Release|Any CPU.Build.0 = Release|Any CPU
{B067B126-88CD-4282-BEEF-7369B64423EF}.Release|x64.ActiveCfg = Release|Any CPU
{B067B126-88CD-4282-BEEF-7369B64423EF}.Release|x64.Build.0 = Release|Any CPU
+ {B067B126-88CD-4282-BEEF-7369B64423EF}.Release|x86.ActiveCfg = Release|Any CPU
+ {B067B126-88CD-4282-BEEF-7369B64423EF}.Release|x86.Build.0 = Release|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Debug|x64.ActiveCfg = Debug|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Debug|x64.Build.0 = Debug|Any CPU
+ {0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Debug|x86.Build.0 = Debug|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Release|Any CPU.Build.0 = Release|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Release|x64.ActiveCfg = Release|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Release|x64.Build.0 = Release|Any CPU
+ {0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Release|x86.ActiveCfg = Release|Any CPU
+ {0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Release|x86.Build.0 = Release|Any CPU
{FC63C875-E880-D8BB-B8B5-978AB7B62983}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC63C875-E880-D8BB-B8B5-978AB7B62983}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC63C875-E880-D8BB-B8B5-978AB7B62983}.Debug|x64.ActiveCfg = Debug|Any CPU
{FC63C875-E880-D8BB-B8B5-978AB7B62983}.Debug|x64.Build.0 = Debug|Any CPU
+ {FC63C875-E880-D8BB-B8B5-978AB7B62983}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FC63C875-E880-D8BB-B8B5-978AB7B62983}.Debug|x86.Build.0 = Debug|Any CPU
{FC63C875-E880-D8BB-B8B5-978AB7B62983}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC63C875-E880-D8BB-B8B5-978AB7B62983}.Release|Any CPU.Build.0 = Release|Any CPU
{FC63C875-E880-D8BB-B8B5-978AB7B62983}.Release|x64.ActiveCfg = Release|Any CPU
{FC63C875-E880-D8BB-B8B5-978AB7B62983}.Release|x64.Build.0 = Release|Any CPU
+ {FC63C875-E880-D8BB-B8B5-978AB7B62983}.Release|x86.ActiveCfg = Release|Any CPU
+ {FC63C875-E880-D8BB-B8B5-978AB7B62983}.Release|x86.Build.0 = Release|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Debug|x64.ActiveCfg = Debug|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Debug|x64.Build.0 = Debug|Any CPU
+ {242F2D93-FCCE-4982-8075-F3052ECCA92C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {242F2D93-FCCE-4982-8075-F3052ECCA92C}.Debug|x86.Build.0 = Debug|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Release|Any CPU.Build.0 = Release|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Release|x64.ActiveCfg = Release|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Release|x64.Build.0 = Release|Any CPU
+ {242F2D93-FCCE-4982-8075-F3052ECCA92C}.Release|x86.ActiveCfg = Release|Any CPU
+ {242F2D93-FCCE-4982-8075-F3052ECCA92C}.Release|x86.Build.0 = Release|Any CPU
{E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Debug|x64.ActiveCfg = Debug|Any CPU
{E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Debug|x64.Build.0 = Debug|Any CPU
+ {E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Debug|x86.Build.0 = Debug|Any CPU
{E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Release|Any CPU.Build.0 = Release|Any CPU
{E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Release|x64.ActiveCfg = Release|Any CPU
{E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Release|x64.Build.0 = Release|Any CPU
+ {E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Release|x86.ActiveCfg = Release|Any CPU
+ {E7C243B9-E751-B3B4-8F16-95C76CA90D31}.Release|x86.Build.0 = Release|Any CPU
{394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Debug|x64.ActiveCfg = Debug|Any CPU
{394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Debug|x64.Build.0 = Debug|Any CPU
+ {394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Debug|x86.Build.0 = Debug|Any CPU
{394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Release|Any CPU.Build.0 = Release|Any CPU
{394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Release|x64.ActiveCfg = Release|Any CPU
{394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Release|x64.Build.0 = Release|Any CPU
+ {394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Release|x86.ActiveCfg = Release|Any CPU
+ {394B858B-9C26-B977-A2DA-8CC7BE5914CB}.Release|x86.Build.0 = Release|Any CPU
{13223C71-9EAC-9835-28ED-5A4833E6F915}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13223C71-9EAC-9835-28ED-5A4833E6F915}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13223C71-9EAC-9835-28ED-5A4833E6F915}.Debug|x64.ActiveCfg = Debug|Any CPU
{13223C71-9EAC-9835-28ED-5A4833E6F915}.Debug|x64.Build.0 = Debug|Any CPU
+ {13223C71-9EAC-9835-28ED-5A4833E6F915}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {13223C71-9EAC-9835-28ED-5A4833E6F915}.Debug|x86.Build.0 = Debug|Any CPU
{13223C71-9EAC-9835-28ED-5A4833E6F915}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13223C71-9EAC-9835-28ED-5A4833E6F915}.Release|Any CPU.Build.0 = Release|Any CPU
{13223C71-9EAC-9835-28ED-5A4833E6F915}.Release|x64.ActiveCfg = Release|Any CPU
{13223C71-9EAC-9835-28ED-5A4833E6F915}.Release|x64.Build.0 = Release|Any CPU
+ {13223C71-9EAC-9835-28ED-5A4833E6F915}.Release|x86.ActiveCfg = Release|Any CPU
+ {13223C71-9EAC-9835-28ED-5A4833E6F915}.Release|x86.Build.0 = Release|Any CPU
{E8D01281-D52A-BFF4-33DB-E35D91754272}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E8D01281-D52A-BFF4-33DB-E35D91754272}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8D01281-D52A-BFF4-33DB-E35D91754272}.Debug|x64.ActiveCfg = Debug|Any CPU
{E8D01281-D52A-BFF4-33DB-E35D91754272}.Debug|x64.Build.0 = Debug|Any CPU
+ {E8D01281-D52A-BFF4-33DB-E35D91754272}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E8D01281-D52A-BFF4-33DB-E35D91754272}.Debug|x86.Build.0 = Debug|Any CPU
{E8D01281-D52A-BFF4-33DB-E35D91754272}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8D01281-D52A-BFF4-33DB-E35D91754272}.Release|Any CPU.Build.0 = Release|Any CPU
{E8D01281-D52A-BFF4-33DB-E35D91754272}.Release|x64.ActiveCfg = Release|Any CPU
{E8D01281-D52A-BFF4-33DB-E35D91754272}.Release|x64.Build.0 = Release|Any CPU
+ {E8D01281-D52A-BFF4-33DB-E35D91754272}.Release|x86.ActiveCfg = Release|Any CPU
+ {E8D01281-D52A-BFF4-33DB-E35D91754272}.Release|x86.Build.0 = Release|Any CPU
{562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Debug|Any CPU.Build.0 = Debug|Any CPU
{562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Debug|x64.ActiveCfg = Debug|Any CPU
{562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Debug|x64.Build.0 = Debug|Any CPU
+ {562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Debug|x86.Build.0 = Debug|Any CPU
{562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Release|Any CPU.ActiveCfg = Release|Any CPU
{562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Release|Any CPU.Build.0 = Release|Any CPU
{562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Release|x64.ActiveCfg = Release|Any CPU
{562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Release|x64.Build.0 = Release|Any CPU
+ {562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Release|x86.ActiveCfg = Release|Any CPU
+ {562DD0C6-DAC8-02CC-C1DD-D43DF186CE76}.Release|x86.Build.0 = Release|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Debug|x64.Build.0 = Debug|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Debug|x86.Build.0 = Debug|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Release|x64.ActiveCfg = Release|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Release|x64.Build.0 = Release|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Release|x86.ActiveCfg = Release|Any CPU
+ {511BC47F-8640-4E5A-820F-662956911CFD}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -745,6 +1013,7 @@ Global
{13223C71-9EAC-9835-28ED-5A4833E6F915} = {53E7CD86-0D19-40D9-A0FA-AB4613837E89}
{E8D01281-D52A-BFF4-33DB-E35D91754272} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
{562DD0C6-DAC8-02CC-C1DD-D43DF186CE76} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
+ {511BC47F-8640-4E5A-820F-662956911CFD} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 1c198a828..fd492781b 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -62,6 +62,7 @@
+
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/AgentSkillsPlugin.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/AgentSkillsPlugin.cs
new file mode 100644
index 000000000..96d438913
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/AgentSkillsPlugin.cs
@@ -0,0 +1,40 @@
+using BotSharp.Abstraction.Agents;
+using BotSharp.Abstraction.Settings;
+using BotSharp.Plugin.AgentSkills.Functions;
+using Microsoft.Extensions.Configuration;
+
+namespace BotSharp.Plugin.AgentSkills;
+
+///
+/// Agent Skills plugin for BotSharp.
+/// Enables AI agents to leverage reusable skills following the Agent Skills specification.
+///
+public class AgentSkillsPlugin : IBotSharpPlugin
+{
+ public string Id => "a5b3e8c1-7d2f-4a9e-b6c4-8f5d1e2a3b4c";
+ public string Name => "Agent Skills";
+ public string Description => "Enables AI agents to leverage reusable skills following the Agent Skills specification (https://agentskills.io).";
+ public string IconUrl => "https://raw.githubusercontent.com/SciSharp/BotSharp/master/docs/static/logos/BotSharp.png";
+ public string[] AgentIds => [];
+
+ public void RegisterDI(IServiceCollection services, IConfiguration config)
+ {
+ // Register settings
+ services.AddScoped(provider =>
+ {
+ var settingService = provider.GetRequiredService();
+ return settingService.Bind("AgentSkills");
+ });
+
+ // Register skill loader
+ services.AddScoped();
+
+ // Register hooks
+ services.AddScoped();
+
+ // Register function callbacks
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/BotSharp.Plugin.AgentSkills.csproj b/src/Plugins/BotSharp.Plugin.AgentSkills/BotSharp.Plugin.AgentSkills.csproj
new file mode 100644
index 000000000..6cbf6656a
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/BotSharp.Plugin.AgentSkills.csproj
@@ -0,0 +1,57 @@
+
+
+
+ $(TargetFramework)
+ enable
+ $(LangVersion)
+ $(BotSharpVersion)
+ $(GeneratePackageOnBuild)
+ $(GenerateDocumentationFile)
+ $(SolutionDir)packages
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Enums/UtilityName.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Enums/UtilityName.cs
new file mode 100644
index 000000000..a400b2a95
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Enums/UtilityName.cs
@@ -0,0 +1,9 @@
+namespace BotSharp.Plugin.AgentSkills.Enums;
+
+///
+/// Utility name constants for Agent Skills plugin.
+///
+public class UtilityName
+{
+ public const string AgentSkills = "agent-skills";
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Functions/ListSkillDirectoryFn.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Functions/ListSkillDirectoryFn.cs
new file mode 100644
index 000000000..575d9b5c9
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Functions/ListSkillDirectoryFn.cs
@@ -0,0 +1,107 @@
+namespace BotSharp.Plugin.AgentSkills.Functions;
+
+///
+/// Function that lists contents of a skill's directory.
+///
+public class ListSkillDirectoryFn : IFunctionCallback
+{
+ public string Name => "skill-list_skill_directory";
+ public string Indication => "Listing skill directory...";
+
+ private readonly IServiceProvider _services;
+ private readonly ILogger _logger;
+ private readonly BotSharpOptions _options;
+
+ public ListSkillDirectoryFn(
+ IServiceProvider services,
+ ILogger logger,
+ BotSharpOptions options)
+ {
+ _services = services;
+ _logger = logger;
+ _options = options;
+ }
+
+ public async Task Execute(RoleDialogModel message)
+ {
+ var args = JsonSerializer.Deserialize(message.FunctionArgs, _options.JsonSerializerOptions);
+ var skillName = args?.SkillName;
+ var relativePath = args?.RelativePath;
+
+ if (string.IsNullOrWhiteSpace(skillName))
+ {
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = "Skill name is required."
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+
+ try
+ {
+ var settings = _services.GetRequiredService();
+ var loader = _services.GetRequiredService();
+
+ // Load skills and find the requested one
+ var state = loader.LoadSkills(settings);
+ var skill = state.GetSkill(skillName);
+
+ if (skill is null)
+ {
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = $"Skill '{skillName}' not found."
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+
+ var entries = loader.ListSkillDirectory(skill, relativePath).ToList();
+
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = true,
+ skill_name = skill.Name,
+ path = relativePath ?? "/",
+ entries = entries.Select(e => new
+ {
+ name = e.Name,
+ type = e.IsDirectory ? "directory" : "file",
+ size = e.Size
+ })
+ }, _options.JsonSerializerOptions);
+
+ return true;
+ }
+ catch (UnauthorizedAccessException ex)
+ {
+ _logger.LogWarning(ex, "Path traversal attempt for skill: {SkillName}", skillName);
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = "Access denied: path traversal detected."
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to list skill directory: {SkillName}/{Path}", skillName, relativePath);
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = $"Failed to list directory: {ex.Message}"
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+ }
+
+ private class ListSkillDirectoryArgs
+ {
+ [JsonPropertyName("skill_name")]
+ public string? SkillName { get; set; }
+
+ [JsonPropertyName("relative_path")]
+ public string? RelativePath { get; set; }
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Functions/ReadSkillFileFn.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Functions/ReadSkillFileFn.cs
new file mode 100644
index 000000000..116b3378e
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Functions/ReadSkillFileFn.cs
@@ -0,0 +1,132 @@
+namespace BotSharp.Plugin.AgentSkills.Functions;
+
+///
+/// Function that reads a file within a skill's directory.
+///
+public class ReadSkillFileFn : IFunctionCallback
+{
+ public string Name => "skill-read_skill_file";
+ public string Indication => "Reading skill file...";
+
+ private readonly IServiceProvider _services;
+ private readonly ILogger _logger;
+ private readonly BotSharpOptions _options;
+
+ public ReadSkillFileFn(
+ IServiceProvider services,
+ ILogger logger,
+ BotSharpOptions options)
+ {
+ _services = services;
+ _logger = logger;
+ _options = options;
+ }
+
+ public async Task Execute(RoleDialogModel message)
+ {
+ var args = JsonSerializer.Deserialize(message.FunctionArgs, _options.JsonSerializerOptions);
+ var skillName = args?.SkillName;
+ var filePath = args?.FilePath;
+
+ if (string.IsNullOrWhiteSpace(skillName))
+ {
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = "Skill name is required."
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+
+ if (string.IsNullOrWhiteSpace(filePath))
+ {
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = "File path is required."
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+
+ try
+ {
+ var settings = _services.GetRequiredService();
+ var loader = _services.GetRequiredService();
+
+ // Load skills and find the requested one
+ var state = loader.LoadSkills(settings);
+ var skill = state.GetSkill(skillName);
+
+ if (skill is null)
+ {
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = $"Skill '{skillName}' not found."
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+
+ var content = loader.ReadSkillFile(skill, filePath);
+
+ // Truncate if necessary
+ var maxSize = settings.MaxOutputSizeBytes;
+ var originalLength = content.Length;
+ var truncated = content.Length > maxSize;
+ if (truncated)
+ {
+ content = content.Substring(0, maxSize);
+ }
+
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = true,
+ skill_name = skill.Name,
+ file_path = filePath,
+ content,
+ truncated,
+ total_length = originalLength
+ }, _options.JsonSerializerOptions);
+
+ return true;
+ }
+ catch (UnauthorizedAccessException ex)
+ {
+ _logger.LogWarning(ex, "Path traversal attempt for skill: {SkillName}", skillName);
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = "Access denied: path traversal detected."
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+ catch (FileNotFoundException)
+ {
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = $"File not found: {filePath}"
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to read skill file: {SkillName}/{FilePath}", skillName, filePath);
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = $"Failed to read file: {ex.Message}"
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+ }
+
+ private class ReadSkillFileArgs
+ {
+ [JsonPropertyName("skill_name")]
+ public string? SkillName { get; set; }
+
+ [JsonPropertyName("file_path")]
+ public string? FilePath { get; set; }
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Functions/ReadSkillFn.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Functions/ReadSkillFn.cs
new file mode 100644
index 000000000..e6fe21c6f
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Functions/ReadSkillFn.cs
@@ -0,0 +1,88 @@
+namespace BotSharp.Plugin.AgentSkills.Functions;
+
+///
+/// Function that reads the full content of a skill's SKILL.md file.
+///
+public class ReadSkillFn : IFunctionCallback
+{
+ public string Name => "skill-read_skill";
+ public string Indication => "Reading skill instructions...";
+
+ private readonly IServiceProvider _services;
+ private readonly ILogger _logger;
+ private readonly BotSharpOptions _options;
+
+ public ReadSkillFn(
+ IServiceProvider services,
+ ILogger logger,
+ BotSharpOptions options)
+ {
+ _services = services;
+ _logger = logger;
+ _options = options;
+ }
+
+ public async Task Execute(RoleDialogModel message)
+ {
+ var args = JsonSerializer.Deserialize(message.FunctionArgs, _options.JsonSerializerOptions);
+ var skillName = args?.SkillName;
+
+ if (string.IsNullOrWhiteSpace(skillName))
+ {
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = "Skill name is required."
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+
+ try
+ {
+ var settings = _services.GetRequiredService();
+ var loader = _services.GetRequiredService();
+
+ // Load skills and find the requested one
+ var state = loader.LoadSkills(settings);
+ var skill = state.GetSkill(skillName);
+
+ if (skill is null)
+ {
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = $"Skill '{skillName}' not found. Available skills: {string.Join(", ", state.AllSkills.Select(s => s.Name))}"
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+
+ var content = loader.ReadSkillContent(skill);
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = true,
+ skill_name = skill.Name,
+ source = skill.Source.ToString().ToLowerInvariant(),
+ path = skill.Path,
+ content
+ }, _options.JsonSerializerOptions);
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to read skill: {SkillName}", skillName);
+ message.Content = JsonSerializer.Serialize(new
+ {
+ success = false,
+ error = $"Failed to read skill '{skillName}': {ex.Message}"
+ }, _options.JsonSerializerOptions);
+ return false;
+ }
+ }
+
+ private class ReadSkillArgs
+ {
+ [JsonPropertyName("skill_name")]
+ public string? SkillName { get; set; }
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Hooks/AgentSkillHook.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Hooks/AgentSkillHook.cs
new file mode 100644
index 000000000..1e970411f
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Hooks/AgentSkillHook.cs
@@ -0,0 +1,135 @@
+using BotSharp.Abstraction.Agents;
+using BotSharp.Abstraction.Agents.Enums;
+using BotSharp.Abstraction.Agents.Settings;
+
+namespace BotSharp.Plugin.AgentSkills.Hooks;
+
+public class AgentSkillHook : AgentHookBase
+{
+ public override string SelfId => "471ca181-375f-b16f-7134-5f868ecd31c6";
+
+ private readonly SkillLoader _skillLoader;
+ private readonly AgentSkillsSettings _options;
+ private SkillsState _state;
+
+ public AgentSkillHook(IServiceProvider services, AgentSettings settings)
+ : base(services, settings)
+ {
+ _skillLoader = services.GetRequiredService();
+ _options = services.GetRequiredService();
+ _state = _skillLoader.LoadSkills(_options);
+ }
+
+ public override bool OnInstructionLoaded(string template, IDictionary dict)
+ {
+ if (Agent.Type == AgentType.Routing || Agent.Type == AgentType.Planning)
+ {
+ return base.OnInstructionLoaded(template, dict);
+ }
+
+ // Refresh skills if needed or if this is the first load
+ if (_state.AllSkills.Count == 0)
+ {
+ LoadSkills(_options);
+ }
+
+ var skillsList = GenerateSkillsList(_state);
+
+ var locations = $"- **User Skills**: `{_options.UserSkillsDir}`";
+ if (_options.ProjectSkillsDir != null)
+ {
+ locations += Environment.NewLine + $"- **Project Skills**: `{_options.ProjectSkillsDir}`";
+ }
+ dict["skills_locations"] = locations;
+ dict["skills_list"] = skillsList;
+
+ return base.OnInstructionLoaded(template, dict);
+ }
+
+ ///
+ /// Loads skills from configured directories.
+ ///
+ private void LoadSkills(AgentSkillsSettings settings)
+ {
+ var skills = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ // Load user-level skills
+ var userDir = settings.GetUserSkillsDirectory();
+ if (Directory.Exists(userDir))
+ {
+ foreach (var skill in _skillLoader.LoadSkillsFromDirectory(userDir, SkillSource.User))
+ {
+ skills[skill.Name] = skill;
+ }
+ }
+
+ // Load project-level skills (overrides user-level with same name)
+ var projectDir = settings.GetProjectSkillsDirectory();
+ if (projectDir != null && Directory.Exists(projectDir))
+ {
+ foreach (var skill in _skillLoader.LoadSkillsFromDirectory(projectDir, SkillSource.Project))
+ {
+ skills[skill.Name] = skill;
+ }
+ }
+
+ _state = new SkillsState
+ {
+ UserSkills = skills.Values.Where(s => s.Source == SkillSource.User).ToList(),
+ ProjectSkills = skills.Values.Where(s => s.Source == SkillSource.Project).ToList(),
+ LastRefreshed = DateTimeOffset.UtcNow
+ };
+ }
+
+ ///
+ /// Generates a formatted list of available skills.
+ ///
+ /// The current skills state.
+ /// The formatted skills list.
+ public static string GenerateSkillsList(SkillsState state)
+ {
+ var lines = new List();
+
+ // Group by source for clarity
+ if (state.ProjectSkills.Count > 0)
+ {
+ lines.Add("*Project Skills:*");
+ foreach (var skill in state.ProjectSkills)
+ {
+ lines.Add(skill.ToDisplayString());
+ }
+ }
+
+ if (state.UserSkills.Count > 0)
+ {
+ // Filter out user skills that are overridden by project skills
+ var projectSkillNames = state.ProjectSkills
+ .Select(s => s.Name)
+ .ToHashSet(StringComparer.OrdinalIgnoreCase);
+
+ var nonOverriddenUserSkills = state.UserSkills
+ .Where(s => !projectSkillNames.Contains(s.Name))
+ .ToList();
+
+ if (nonOverriddenUserSkills.Count > 0)
+ {
+ if (lines.Count > 0)
+ {
+ lines.Add("");
+ }
+ lines.Add("*User Skills:*");
+ foreach (var skill in nonOverriddenUserSkills)
+ {
+ lines.Add(skill.ToDisplayString());
+ }
+ }
+ }
+
+ if (lines.Count == 0)
+ {
+ return "*No skills available.*";
+ }
+
+ return string.Join(Environment.NewLine, lines);
+ }
+}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Hooks/AgentSkillsUtilityHook.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Hooks/AgentSkillsUtilityHook.cs
new file mode 100644
index 000000000..2d7d7f87c
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Hooks/AgentSkillsUtilityHook.cs
@@ -0,0 +1,45 @@
+using BotSharp.Abstraction.Agents;
+
+namespace BotSharp.Plugin.AgentSkills.Hooks;
+
+///
+/// Hook that adds Agent Skills utilities to agents.
+///
+public class AgentSkillsUtilityHook : IAgentUtilityHook
+{
+ private static readonly string PREFIX = "skill-";
+ private static readonly string READ_SKILL_FN = $"{PREFIX}read_skill";
+ private static readonly string READ_SKILL_FILE_FN = $"{PREFIX}read_skill_file";
+ private static readonly string LIST_SKILL_DIRECTORY_FN = $"{PREFIX}list_skill_directory";
+
+ public void AddUtilities(List utilities)
+ {
+ var utility = new AgentUtility
+ {
+ Category = "skill",
+ Name = UtilityName.AgentSkills,
+ Items = [
+ new UtilityItem
+ {
+ FunctionName = READ_SKILL_FN,
+ TemplateName = $"{READ_SKILL_FN}.fn",
+ Description = "Reads the full content of a skill's SKILL.md file to get detailed instructions."
+ },
+ new UtilityItem
+ {
+ FunctionName = READ_SKILL_FILE_FN,
+ TemplateName = $"{READ_SKILL_FILE_FN}.fn",
+ Description = "Reads a file within a skill's directory."
+ },
+ new UtilityItem
+ {
+ FunctionName = LIST_SKILL_DIRECTORY_FN,
+ TemplateName = $"{LIST_SKILL_DIRECTORY_FN}.fn",
+ Description = "Lists the contents of a skill's directory."
+ }
+ ]
+ };
+
+ utilities.Add(utility);
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Loading/SkillLoader.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Loading/SkillLoader.cs
new file mode 100644
index 000000000..643cf1704
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Loading/SkillLoader.cs
@@ -0,0 +1,306 @@
+using Microsoft.Extensions.Logging.Abstractions;
+
+namespace BotSharp.Plugin.AgentSkills.Loading;
+
+///
+/// Discovers, validates, and loads skills from configured directories.
+///
+public sealed class SkillLoader
+{
+ private readonly SkillParser _parser;
+ private readonly ILogger _logger;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Optional logger instance.
+ public SkillLoader(ILogger? logger = null)
+ {
+ _parser = new SkillParser();
+ _logger = logger ?? NullLogger.Instance;
+ }
+
+ ///
+ /// Loads all skills from the configured directories.
+ ///
+ /// The skills settings containing directory paths.
+ /// The loaded skills state.
+ public SkillsState LoadSkills(AgentSkillsSettings settings)
+ {
+ var userSkills = new List();
+ var projectSkills = new List();
+
+ // Load user-level skills
+ if (settings.EnableUserSkills)
+ {
+ var userSkillsDir = settings.GetUserSkillsDirectory();
+ userSkills.AddRange(LoadSkillsFromDirectory(userSkillsDir, SkillSource.User));
+ }
+
+ // Load project-level skills
+ if (settings.EnableProjectSkills)
+ {
+ var projectSkillsDir = settings.GetProjectSkillsDirectory();
+ if (projectSkillsDir is not null)
+ {
+ projectSkills.AddRange(LoadSkillsFromDirectory(projectSkillsDir, SkillSource.Project));
+ }
+ }
+
+ _logger.LogInformation(
+ "Loaded {UserCount} user skills and {ProjectCount} project skills",
+ userSkills.Count,
+ projectSkills.Count);
+
+ return new SkillsState
+ {
+ UserSkills = userSkills,
+ ProjectSkills = projectSkills,
+ LastRefreshed = DateTimeOffset.UtcNow
+ };
+ }
+
+ ///
+ /// Loads a single skill by name.
+ ///
+ /// The name of the skill to load.
+ /// The skills settings containing directory paths.
+ /// The loaded skill metadata, or null if not found.
+ public SkillMetadata? LoadSkill(string skillName, AgentSkillsSettings settings)
+ {
+ // Check project-level first (takes precedence)
+ var projectSkillPath = settings.GetProjectSkillPath(skillName);
+ if (projectSkillPath is not null)
+ {
+ var skill = TryLoadSkill(projectSkillPath, SkillSource.Project);
+ if (skill is not null)
+ {
+ return skill;
+ }
+ }
+
+ // Check user-level
+ var userSkillPath = settings.GetUserSkillPath(skillName);
+ return TryLoadSkill(userSkillPath, SkillSource.User);
+ }
+
+ ///
+ /// Loads all skills from a specific directory.
+ ///
+ /// The directory containing skill subdirectories.
+ /// The source type for loaded skills.
+ /// Collection of successfully loaded skills.
+ public IEnumerable LoadSkillsFromDirectory(string skillsDirectory, SkillSource source)
+ {
+ if (!Directory.Exists(skillsDirectory))
+ {
+ _logger.LogDebug("Skills directory does not exist: {Directory}", skillsDirectory);
+ yield break;
+ }
+
+ var skillDirectories = Directory.GetDirectories(skillsDirectory);
+
+ foreach (var skillDir in skillDirectories)
+ {
+ var skill = TryLoadSkill(skillDir, source);
+ if (skill is not null)
+ {
+ yield return skill;
+ }
+ }
+ }
+
+ ///
+ /// Attempts to load a skill from a directory.
+ ///
+ /// The skill directory path.
+ /// The source type for the skill.
+ /// The loaded skill metadata, or null if loading fails.
+ private SkillMetadata? TryLoadSkill(string skillDirectory, SkillSource source)
+ {
+ var skillFilePath = Path.Combine(skillDirectory, SkillMetadata.SkillFileName);
+
+ if (!File.Exists(skillFilePath))
+ {
+ _logger.LogDebug("No SKILL.md found in: {Directory}", skillDirectory);
+ return null;
+ }
+
+ // Security check: ensure the skill file is not a symlink pointing outside
+ if (IsSymbolicLink(skillFilePath))
+ {
+ var realPath = GetRealPath(skillFilePath);
+ if (realPath is null || !IsPathSafe(realPath, skillDirectory))
+ {
+ _logger.LogWarning(
+ "Skipping skill with potentially unsafe symlink: {Directory}",
+ skillDirectory);
+ return null;
+ }
+ }
+
+ try
+ {
+ var skill = _parser.Parse(skillFilePath, source);
+ _logger.LogDebug("Loaded skill: {SkillName} from {Source}", skill.Name, source);
+ return skill;
+ }
+ catch (SkillParseException ex)
+ {
+ _logger.LogWarning("Failed to parse skill: {Error}", ex.Message);
+ return null;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Unexpected error loading skill from: {Directory}", skillDirectory);
+ return null;
+ }
+ }
+
+ ///
+ /// Reads the full content of a SKILL.md file.
+ ///
+ /// The skill metadata.
+ /// The full content of the SKILL.md file.
+ /// Thrown if the file does not exist.
+ public string ReadSkillContent(SkillMetadata skill)
+ {
+ var skillFilePath = skill.SkillFilePath;
+
+ if (!File.Exists(skillFilePath))
+ {
+ throw new FileNotFoundException($"SKILL.md not found for skill '{skill.Name}'", skillFilePath);
+ }
+
+ return File.ReadAllText(skillFilePath);
+ }
+
+ ///
+ /// Reads a file within a skill directory.
+ ///
+ /// The skill metadata.
+ /// Relative path to the file within the skill directory.
+ /// The file content.
+ /// Thrown if path traversal is detected.
+ /// Thrown if the file does not exist.
+ public string ReadSkillFile(SkillMetadata skill, string relativePath)
+ {
+ var safePath = ResolveSafePath(skill.Path, relativePath);
+ if (safePath is null)
+ {
+ throw new UnauthorizedAccessException($"Path traversal attempt detected: {relativePath}");
+ }
+
+ if (!File.Exists(safePath))
+ {
+ throw new FileNotFoundException($"File not found: {relativePath}", safePath);
+ }
+
+ return File.ReadAllText(safePath);
+ }
+
+ ///
+ /// Lists files in a skill directory.
+ ///
+ /// The skill metadata.
+ /// Optional relative path within the skill directory.
+ /// Collection of file and directory entries.
+ public IEnumerable ListSkillDirectory(SkillMetadata skill, string? relativePath = null)
+ {
+ var targetDir = skill.Path;
+
+ if (!string.IsNullOrEmpty(relativePath))
+ {
+ var safePath = ResolveSafePath(skill.Path, relativePath);
+ if (safePath is null)
+ {
+ throw new UnauthorizedAccessException($"Path traversal attempt detected: {relativePath}");
+ }
+ targetDir = safePath;
+ }
+
+ if (!Directory.Exists(targetDir))
+ {
+ yield break;
+ }
+
+ foreach (var dir in Directory.GetDirectories(targetDir))
+ {
+ var name = Path.GetFileName(dir);
+ yield return new SkillDirectoryEntry { Name = name, IsDirectory = true };
+ }
+
+ foreach (var file in Directory.GetFiles(targetDir))
+ {
+ var name = Path.GetFileName(file);
+ var size = new FileInfo(file).Length;
+ yield return new SkillDirectoryEntry { Name = name, IsDirectory = false, Size = size };
+ }
+ }
+
+ ///
+ /// Checks if a path is a symbolic link.
+ ///
+ private static bool IsSymbolicLink(string path)
+ {
+ try
+ {
+ var fileInfo = new FileInfo(path);
+ return fileInfo.LinkTarget != null;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Gets the real path of a symbolic link.
+ ///
+ private static string? GetRealPath(string path)
+ {
+ try
+ {
+ var fileInfo = new FileInfo(path);
+ return fileInfo.LinkTarget != null ? Path.GetFullPath(fileInfo.LinkTarget) : Path.GetFullPath(path);
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// Checks if a path is safe (within the base directory).
+ ///
+ private static bool IsPathSafe(string path, string baseDir)
+ {
+ var normalizedPath = Path.GetFullPath(path);
+ var normalizedBase = Path.GetFullPath(baseDir);
+ return normalizedPath.StartsWith(normalizedBase, StringComparison.OrdinalIgnoreCase);
+ }
+
+ ///
+ /// Resolves a relative path within a base directory safely.
+ ///
+ private static string? ResolveSafePath(string baseDir, string relativePath)
+ {
+ try
+ {
+ var combined = Path.Combine(baseDir, relativePath);
+ var fullPath = Path.GetFullPath(combined);
+ var normalizedBase = Path.GetFullPath(baseDir);
+
+ if (!fullPath.StartsWith(normalizedBase, StringComparison.OrdinalIgnoreCase))
+ {
+ return null;
+ }
+
+ return fullPath;
+ }
+ catch
+ {
+ return null;
+ }
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Loading/SkillParser.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Loading/SkillParser.cs
new file mode 100644
index 000000000..06fddae20
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Loading/SkillParser.cs
@@ -0,0 +1,205 @@
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
+
+namespace BotSharp.Plugin.AgentSkills.Loading;
+
+///
+/// Parses SKILL.md files to extract YAML frontmatter and create .
+///
+public sealed class SkillParser
+{
+ private const string FrontmatterDelimiter = "---";
+
+ private readonly IDeserializer _yamlDeserializer;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SkillParser()
+ {
+ _yamlDeserializer = new DeserializerBuilder()
+ .WithNamingConvention(HyphenatedNamingConvention.Instance)
+ .IgnoreUnmatchedProperties()
+ .Build();
+ }
+
+ ///
+ /// Parses a SKILL.md file and extracts the skill metadata.
+ ///
+ /// The path to the SKILL.md file.
+ /// The source location of the skill.
+ /// The parsed skill metadata.
+ /// Thrown when parsing fails.
+ public SkillMetadata Parse(string skillFilePath, SkillSource source)
+ {
+ // Validate the file exists and is within size limits
+ var fileValidation = SkillValidator.ValidateSkillFile(skillFilePath);
+ if (!fileValidation.IsValid)
+ {
+ throw new SkillParseException(skillFilePath, fileValidation.ErrorMessage!);
+ }
+
+ var content = File.ReadAllText(skillFilePath);
+ var skillDirectory = Path.GetDirectoryName(skillFilePath)!;
+ var directoryName = Path.GetFileName(skillDirectory);
+
+ return ParseContent(content, skillDirectory, directoryName, source);
+ }
+
+ ///
+ /// Parses SKILL.md content and extracts the skill metadata.
+ ///
+ /// The content of the SKILL.md file.
+ /// The directory containing the skill.
+ /// The name of the skill directory.
+ /// The source location of the skill.
+ /// The parsed skill metadata.
+ /// Thrown when parsing fails.
+ public SkillMetadata ParseContent(string content, string skillDirectory, string directoryName, SkillSource source)
+ {
+ var frontmatter = ExtractFrontmatter(content);
+ if (frontmatter is null)
+ {
+ throw new SkillParseException(skillDirectory, "SKILL.md must have YAML frontmatter delimited by '---'.");
+ }
+
+ SkillFrontmatter yamlData;
+ try
+ {
+ yamlData = _yamlDeserializer.Deserialize(frontmatter);
+ }
+ catch (Exception ex)
+ {
+ throw new SkillParseException(skillDirectory, $"Failed to parse YAML frontmatter: {ex.Message}", ex);
+ }
+
+ // Validate required fields
+ if (string.IsNullOrWhiteSpace(yamlData.Name))
+ {
+ throw new SkillParseException(skillDirectory, "Skill 'name' is required in frontmatter.");
+ }
+
+ if (string.IsNullOrWhiteSpace(yamlData.Description))
+ {
+ throw new SkillParseException(skillDirectory, "Skill 'description' is required in frontmatter.");
+ }
+
+ // Validate name format
+ var nameValidation = SkillValidator.ValidateName(yamlData.Name);
+ if (!nameValidation.IsValid)
+ {
+ throw new SkillParseException(skillDirectory, nameValidation.ErrorMessage!);
+ }
+
+ // Validate name matches directory
+ var matchValidation = SkillValidator.ValidateNameMatchesDirectory(yamlData.Name, directoryName);
+ if (!matchValidation.IsValid)
+ {
+ throw new SkillParseException(skillDirectory, matchValidation.ErrorMessage!);
+ }
+
+ // Validate description length
+ var descValidation = SkillValidator.ValidateDescription(yamlData.Description);
+ if (!descValidation.IsValid)
+ {
+ throw new SkillParseException(skillDirectory, descValidation.ErrorMessage!);
+ }
+
+ // Parse allowed tools
+ var allowedTools = AllowedTool.Parse(yamlData.AllowedTools);
+
+ // Build metadata dictionary
+ Dictionary? metadata = null;
+ if (yamlData.Metadata is not null && yamlData.Metadata.Count > 0)
+ {
+ metadata = new Dictionary(yamlData.Metadata);
+ }
+
+ return new SkillMetadata
+ {
+ Name = yamlData.Name,
+ Description = yamlData.Description,
+ Path = skillDirectory,
+ Source = source,
+ License = yamlData.License,
+ Compatibility = yamlData.Compatibility,
+ Metadata = metadata,
+ AllowedTools = allowedTools.Count > 0 ? allowedTools : null
+ };
+ }
+
+ ///
+ /// Extracts the YAML frontmatter from SKILL.md content.
+ ///
+ private static string? ExtractFrontmatter(string content)
+ {
+ if (string.IsNullOrWhiteSpace(content))
+ {
+ return null;
+ }
+
+ var lines = content.Split('\n');
+
+ // First line must be the frontmatter delimiter
+ if (lines.Length == 0 || lines[0].Trim() != FrontmatterDelimiter)
+ {
+ return null;
+ }
+
+ // Find the closing delimiter
+ var frontmatterLines = new List();
+ for (var i = 1; i < lines.Length; i++)
+ {
+ if (lines[i].Trim() == FrontmatterDelimiter)
+ {
+ return string.Join('\n', frontmatterLines);
+ }
+ frontmatterLines.Add(lines[i]);
+ }
+
+ // No closing delimiter found
+ return null;
+ }
+
+ ///
+ /// Internal class representing the YAML frontmatter structure.
+ ///
+ private sealed class SkillFrontmatter
+ {
+ public string? Name { get; set; }
+ public string? Description { get; set; }
+ public string? License { get; set; }
+ public string? Compatibility { get; set; }
+ public string? AllowedTools { get; set; }
+ public Dictionary? Metadata { get; set; }
+ }
+}
+
+///
+/// Exception thrown when skill parsing fails.
+///
+public sealed class SkillParseException : Exception
+{
+ ///
+ /// Gets the path to the skill that failed to parse.
+ ///
+ public string SkillPath { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SkillParseException(string skillPath, string message)
+ : base($"Failed to parse skill at '{skillPath}': {message}")
+ {
+ SkillPath = skillPath;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SkillParseException(string skillPath, string message, Exception innerException)
+ : base($"Failed to parse skill at '{skillPath}': {message}", innerException)
+ {
+ SkillPath = skillPath;
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Loading/SkillValidator.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Loading/SkillValidator.cs
new file mode 100644
index 000000000..e8594ca3b
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Loading/SkillValidator.cs
@@ -0,0 +1,133 @@
+namespace BotSharp.Plugin.AgentSkills.Loading;
+
+///
+/// Validates skill names and files according to the Agent Skills specification.
+///
+public static partial class SkillValidator
+{
+ ///
+ /// Pattern for valid skill names: lowercase alphanumeric with hyphens, max 64 characters.
+ ///
+ private static readonly Regex SkillNamePatternRegex = new Regex(
+ @"^[a-z0-9][a-z0-9\-]{0,62}[a-z0-9]$|^[a-z0-9]$",
+ RegexOptions.Compiled);
+
+ ///
+ /// Validates a skill name according to the Agent Skills specification.
+ ///
+ /// The skill name to validate.
+ /// A validation result indicating success or failure with error message.
+ public static SkillValidationResult ValidateName(string? name)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ return SkillValidationResult.Failure("Skill name cannot be null or empty.");
+ }
+
+ if (name.Length > 64)
+ {
+ return SkillValidationResult.Failure($"Skill name exceeds maximum length of 64 characters. Actual: {name.Length}");
+ }
+
+ if (!SkillNamePatternRegex.IsMatch(name))
+ {
+ return SkillValidationResult.Failure(
+ "Skill name must contain only lowercase letters, numbers, and hyphens. " +
+ "Must start and end with a letter or number.");
+ }
+
+ return SkillValidationResult.Success();
+ }
+
+ ///
+ /// Validates that a skill name matches its directory name.
+ ///
+ /// The skill name from YAML frontmatter.
+ /// The directory name containing the skill.
+ /// A validation result indicating success or failure with error message.
+ public static SkillValidationResult ValidateNameMatchesDirectory(string skillName, string directoryName)
+ {
+ if (!string.Equals(skillName, directoryName, StringComparison.OrdinalIgnoreCase))
+ {
+ return SkillValidationResult.Failure(
+ $"Skill name '{skillName}' does not match directory name '{directoryName}'.");
+ }
+
+ return SkillValidationResult.Success();
+ }
+
+ ///
+ /// Validates a skill description.
+ ///
+ /// The description to validate.
+ /// A validation result indicating success or failure with error message.
+ public static SkillValidationResult ValidateDescription(string? description)
+ {
+ if (string.IsNullOrWhiteSpace(description))
+ {
+ return SkillValidationResult.Failure("Skill description cannot be null or empty.");
+ }
+
+ if (description.Length > 1024)
+ {
+ return SkillValidationResult.Failure(
+ $"Skill description exceeds maximum length of 1024 characters. Actual: {description.Length}");
+ }
+
+ return SkillValidationResult.Success();
+ }
+
+ ///
+ /// Validates that a SKILL.md file exists and is within size limits.
+ ///
+ /// The path to the SKILL.md file.
+ /// A validation result indicating success or failure with error message.
+ public static SkillValidationResult ValidateSkillFile(string skillFilePath)
+ {
+ if (!File.Exists(skillFilePath))
+ {
+ return SkillValidationResult.Failure($"SKILL.md file not found at: {skillFilePath}");
+ }
+
+ var fileInfo = new FileInfo(skillFilePath);
+ if (fileInfo.Length > 10 * 1024 * 1024) // 10 MB limit
+ {
+ return SkillValidationResult.Failure(
+ $"SKILL.md file exceeds maximum size of 10 MB. Actual: {fileInfo.Length / (1024 * 1024):F2} MB");
+ }
+
+ return SkillValidationResult.Success();
+ }
+}
+
+///
+/// Represents the result of a skill validation operation.
+///
+public readonly struct SkillValidationResult
+{
+ ///
+ /// Gets whether the validation was successful.
+ ///
+ public bool IsValid { get; }
+
+ ///
+ /// Gets the error message if validation failed.
+ ///
+ public string? ErrorMessage { get; }
+
+ private SkillValidationResult(bool isValid, string? errorMessage)
+ {
+ IsValid = isValid;
+ ErrorMessage = errorMessage;
+ }
+
+ ///
+ /// Creates a successful validation result.
+ ///
+ public static SkillValidationResult Success() => new(true, null);
+
+ ///
+ /// Creates a failed validation result with an error message.
+ ///
+ public static SkillValidationResult Failure(string errorMessage) => new(false, errorMessage);
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Models/AllowedTool.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Models/AllowedTool.cs
new file mode 100644
index 000000000..09572d20b
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Models/AllowedTool.cs
@@ -0,0 +1,63 @@
+namespace BotSharp.Plugin.AgentSkills.Models;
+
+///
+/// Represents an allowed tool specification from a skill's allowed-tools field.
+/// Supports both exact matches and glob patterns.
+///
+public sealed record AllowedTool
+{
+ ///
+ /// The tool name or pattern (e.g., "read_file" or "execute_*").
+ ///
+ public string Name { get; init; } = string.Empty;
+
+ ///
+ /// Whether this represents a glob pattern.
+ ///
+ public bool IsPattern { get; init; }
+
+ private Regex? _regex;
+
+ ///
+ /// Checks if the given tool name matches this allowed tool specification.
+ ///
+ /// The tool name to check.
+ /// True if the tool name matches; otherwise, false.
+ public bool Matches(string toolName)
+ {
+ if (!IsPattern)
+ {
+ return string.Equals(Name, toolName, StringComparison.OrdinalIgnoreCase);
+ }
+
+ _regex ??= new Regex(
+ "^" + Regex.Escape(Name).Replace("\\*", ".*") + "$",
+ RegexOptions.IgnoreCase | RegexOptions.Compiled);
+
+ return _regex.IsMatch(toolName);
+ }
+
+ ///
+ /// Parses a space-delimited allowed-tools string into individual instances.
+ ///
+ /// Space-delimited string of tool names/patterns.
+ /// Collection of parsed allowed tools.
+ public static IReadOnlyList Parse(string? allowedToolsString)
+ {
+ if (string.IsNullOrWhiteSpace(allowedToolsString))
+ {
+ return [];
+ }
+
+ var tools = new List();
+ var parts = allowedToolsString.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
+
+ foreach (var part in parts)
+ {
+ var isPattern = part.Contains('*');
+ tools.Add(new AllowedTool { Name = part, IsPattern = isPattern });
+ }
+
+ return tools;
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillDirectoryEntry.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillDirectoryEntry.cs
new file mode 100644
index 000000000..9560c84b8
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillDirectoryEntry.cs
@@ -0,0 +1,22 @@
+namespace BotSharp.Plugin.AgentSkills.Models;
+
+///
+/// Represents an entry in a skill directory listing.
+///
+public sealed record SkillDirectoryEntry
+{
+ ///
+ /// The name of the file or directory.
+ ///
+ public string Name { get; init; } = string.Empty;
+
+ ///
+ /// Whether this is a directory.
+ ///
+ public bool IsDirectory { get; init; }
+
+ ///
+ /// The file size in bytes (only for files).
+ ///
+ public long? Size { get; init; }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillMetadata.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillMetadata.cs
new file mode 100644
index 000000000..3949c9ed4
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillMetadata.cs
@@ -0,0 +1,79 @@
+namespace BotSharp.Plugin.AgentSkills.Models;
+
+///
+/// Represents the metadata of a skill parsed from SKILL.md YAML frontmatter.
+/// Follows the Agent Skills specification: https://agentskills.io
+///
+public sealed record SkillMetadata
+{
+ ///
+ /// Maximum allowed length for skill name.
+ ///
+ public const int MaxNameLength = 64;
+
+ ///
+ /// Maximum allowed length for skill description.
+ ///
+ public const int MaxDescriptionLength = 1024;
+
+ ///
+ /// Maximum file size for SKILL.md in bytes (10 MB).
+ ///
+ public const long MaxSkillFileSize = 10 * 1024 * 1024;
+
+ ///
+ /// The standard skill definition filename.
+ ///
+ public const string SkillFileName = "SKILL.md";
+
+ ///
+ /// Required. Skill identifier (lowercase alphanumeric with hyphens, max 64 characters).
+ /// Must match the directory name.
+ ///
+ public string Name { get; init; } = string.Empty;
+
+ ///
+ /// Required. Brief description of the skill's purpose (max 1024 characters).
+ ///
+ public string Description { get; init; } = string.Empty;
+
+ ///
+ /// Absolute path to the skill directory containing SKILL.md.
+ ///
+ public string Path { get; init; } = string.Empty;
+
+ ///
+ /// Whether the skill is from user-level or project-level location.
+ ///
+ public SkillSource Source { get; init; }
+
+ ///
+ /// Optional. SPDX license identifier (e.g., "MIT", "Apache-2.0").
+ ///
+ public string? License { get; init; }
+
+ ///
+ /// Optional. Compatibility constraints (e.g., "vscode", "cursor", "any").
+ ///
+ public string? Compatibility { get; init; }
+
+ ///
+ /// Optional. Additional key-value metadata pairs.
+ ///
+ public IReadOnlyDictionary? Metadata { get; init; }
+
+ ///
+ /// Optional. List of tools the skill is allowed to use.
+ ///
+ public IReadOnlyList? AllowedTools { get; init; }
+
+ ///
+ /// Gets the full path to the SKILL.md file.
+ ///
+ public string SkillFilePath => System.IO.Path.Combine(Path, SkillFileName);
+
+ ///
+ /// Returns a display string for the skill suitable for system prompts.
+ ///
+ public string ToDisplayString() => $"- **{Name}**: {Description}";
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillSource.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillSource.cs
new file mode 100644
index 000000000..a93de977c
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillSource.cs
@@ -0,0 +1,17 @@
+namespace BotSharp.Plugin.AgentSkills.Models;
+
+///
+/// Represents the source location of a skill.
+///
+public enum SkillSource
+{
+ ///
+ /// User-level skill stored in ~/.botsharp/skills/
+ ///
+ User,
+
+ ///
+ /// Project-level skill stored in {project}/.botsharp/skills/
+ ///
+ Project
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillsState.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillsState.cs
new file mode 100644
index 000000000..333e74543
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Models/SkillsState.cs
@@ -0,0 +1,62 @@
+namespace BotSharp.Plugin.AgentSkills.Models;
+
+///
+/// Represents the current state of loaded skills.
+///
+public sealed class SkillsState
+{
+ ///
+ /// Gets or sets the collection of user-level skills.
+ ///
+ public IReadOnlyList UserSkills { get; init; } = [];
+
+ ///
+ /// Gets or sets the collection of project-level skills.
+ ///
+ public IReadOnlyList ProjectSkills { get; init; } = [];
+
+ ///
+ /// Gets the timestamp when skills were last loaded.
+ ///
+ public DateTimeOffset LastRefreshed { get; init; } = DateTimeOffset.UtcNow;
+
+ ///
+ /// Gets all skills combined, with project skills taking precedence over user skills
+ /// when there are name conflicts.
+ ///
+ public IReadOnlyList AllSkills
+ {
+ get
+ {
+ var projectSkillNames = ProjectSkills.Select(s => s.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
+ var userSkillsWithoutOverrides = UserSkills.Where(s => !projectSkillNames.Contains(s.Name));
+ return [.. ProjectSkills, .. userSkillsWithoutOverrides];
+ }
+ }
+
+ ///
+ /// Gets a skill by name, checking project skills first, then user skills.
+ ///
+ /// The skill name to find.
+ /// The skill metadata if found; otherwise, null.
+ public SkillMetadata? GetSkill(string name)
+ {
+ return ProjectSkills.FirstOrDefault(s => s.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
+ ?? UserSkills.FirstOrDefault(s => s.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
+ }
+
+ ///
+ /// Gets skills filtered by source.
+ ///
+ /// The source to filter by.
+ /// Skills from the specified source.
+ public IReadOnlyList GetSkillsBySource(SkillSource source)
+ {
+ return source switch
+ {
+ SkillSource.User => UserSkills,
+ SkillSource.Project => ProjectSkills,
+ _ => []
+ };
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Settings/AgentSkillsSettings.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Settings/AgentSkillsSettings.cs
new file mode 100644
index 000000000..2e3781c3b
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Settings/AgentSkillsSettings.cs
@@ -0,0 +1,112 @@
+namespace BotSharp.Plugin.AgentSkills.Settings;
+
+///
+/// Configuration settings for the Agent Skills plugin.
+///
+public class AgentSkillsSettings
+{
+ ///
+ /// Enable user-level skills from ~/.botsharp/skills/
+ ///
+ public bool EnableUserSkills { get; set; } = true;
+
+ ///
+ /// Enable project-level skills from {project}/.botsharp/skills/
+ ///
+ public bool EnableProjectSkills { get; set; } = true;
+
+ ///
+ /// Override path for user skills directory. If null, uses default ~/.botsharp/skills/
+ ///
+ public string? UserSkillsDir { get; set; }
+
+ ///
+ /// Override path for project skills directory. If null, uses default {project}/.botsharp/skills/
+ ///
+ public string? ProjectSkillsDir { get; set; }
+
+ ///
+ /// Cache loaded skills in memory.
+ ///
+ public bool CacheSkills { get; set; } = true;
+
+ ///
+ /// Validate skills on startup.
+ ///
+ public bool ValidateOnStartup { get; set; } = true;
+
+ ///
+ /// Skills cache duration in seconds.
+ ///
+ public int SkillsCacheDurationSeconds { get; set; } = 300;
+
+ ///
+ /// Enable read_skill tool to read full SKILL.md content.
+ ///
+ public bool EnableReadSkillTool { get; set; } = true;
+
+ ///
+ /// Enable read_skill_file tool to read files in skill directories.
+ ///
+ public bool EnableReadFileTool { get; set; } = true;
+
+ ///
+ /// Enable list_skill_directory tool to list skill directory contents.
+ ///
+ public bool EnableListDirectoryTool { get; set; } = true;
+
+ ///
+ /// Maximum output size in bytes for skill content.
+ ///
+ public int MaxOutputSizeBytes { get; set; } = 50 * 1024;
+
+ ///
+ /// Gets the resolved user skills directory path.
+ ///
+ public string GetUserSkillsDirectory()
+ {
+ if (!string.IsNullOrEmpty(UserSkillsDir))
+ {
+ return UserSkillsDir;
+ }
+
+ var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
+ return Path.Combine(homeDir, ".botsharp", "skills");
+ }
+
+ ///
+ /// Gets the resolved project skills directory path.
+ ///
+ /// The project root directory.
+ public string? GetProjectSkillsDirectory(string? projectRoot = null)
+ {
+ if (!string.IsNullOrEmpty(ProjectSkillsDir))
+ {
+ return ProjectSkillsDir;
+ }
+
+ if (string.IsNullOrEmpty(projectRoot))
+ {
+ projectRoot = Directory.GetCurrentDirectory();
+ }
+
+ return Path.Combine(projectRoot, ".botsharp", "skills");
+ }
+
+ ///
+ /// Gets the path to a specific skill in user skills directory.
+ ///
+ public string GetUserSkillPath(string skillName)
+ {
+ return Path.Combine(GetUserSkillsDirectory(), skillName);
+ }
+
+ ///
+ /// Gets the path to a specific skill in project skills directory.
+ ///
+ public string? GetProjectSkillPath(string skillName, string? projectRoot = null)
+ {
+ var projectSkillsDir = GetProjectSkillsDirectory(projectRoot);
+ return projectSkillsDir != null ? Path.Combine(projectSkillsDir, skillName) : null;
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/Using.cs b/src/Plugins/BotSharp.Plugin.AgentSkills/Using.cs
new file mode 100644
index 000000000..73125f6ef
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/Using.cs
@@ -0,0 +1,25 @@
+global using System;
+global using System.Collections.Generic;
+global using System.IO;
+global using System.Text;
+global using System.Linq;
+global using System.Text.Json;
+global using System.Text.Json.Serialization;
+global using System.Text.RegularExpressions;
+global using System.Threading.Tasks;
+global using BotSharp.Abstraction.Conversations;
+global using BotSharp.Abstraction.Plugins;
+global using BotSharp.Abstraction.Conversations.Models;
+global using BotSharp.Abstraction.Functions;
+global using BotSharp.Abstraction.Agents.Models;
+global using BotSharp.Abstraction.Templating;
+global using Microsoft.Extensions.DependencyInjection;
+global using Microsoft.Extensions.Logging;
+global using BotSharp.Abstraction.Utilities;
+global using BotSharp.Abstraction.Messaging;
+global using BotSharp.Abstraction.Options;
+global using BotSharp.Plugin.AgentSkills.Enums;
+global using BotSharp.Plugin.AgentSkills.Hooks;
+global using BotSharp.Plugin.AgentSkills.Loading;
+global using BotSharp.Plugin.AgentSkills.Models;
+global using BotSharp.Plugin.AgentSkills.Settings;
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/471ca181-375f-b16f-7134-5f868ecd31c6/agent.json b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/471ca181-375f-b16f-7134-5f868ecd31c6/agent.json
new file mode 100644
index 000000000..b98cf0d84
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/471ca181-375f-b16f-7134-5f868ecd31c6/agent.json
@@ -0,0 +1,35 @@
+{
+ "id": "471ca181-375f-b16f-7134-5f868ecd31c6",
+ "name": "Agent Skill",
+ "description": "You have access to a skills library that provides specialized capabilities and domain knowledge.",
+ "iconUrl": "https://cdn-icons-png.flaticon.com/512/3161/3161158.png",
+ "type": "task",
+ "createdDateTime": "2025-11-15T13:49:00Z",
+ "updatedDateTime": "2025-11-15T13:49:00Z",
+ "disabled": false,
+ "isPublic": true,
+ "profiles": [ "skill" ],
+ "utilities": [
+ {
+ "Category": "skill",
+ "Name": "agent-skills",
+ "Items": [
+ {
+ "FunctionName": "READ_SKILL_FN",
+ "TemplateName": "READ_SKILL_FN.fn",
+ "Description": "Reads the full content of a skill's SKILL.md file to get detailed instructions."
+ },
+ {
+ "FunctionName": "READ_SKILL_FILE_FN",
+ "TemplateName": "READ_SKILL_FILE_FN.fn",
+ "Description": "Reads a file within a skill's directory."
+ },
+ {
+ "FunctionName": "LIST_SKILL_DIRECTORY_FN",
+ "TemplateName": "LIST_SKILL_DIRECTORY_FN.fn",
+ "Description": "Lists the contents of a skill's directory."
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/471ca181-375f-b16f-7134-5f868ecd31c6/instructions/instruction.liquid b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/471ca181-375f-b16f-7134-5f868ecd31c6/instructions/instruction.liquid
new file mode 100644
index 000000000..d2c012351
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/471ca181-375f-b16f-7134-5f868ecd31c6/instructions/instruction.liquid
@@ -0,0 +1,54 @@
+
+ You have access to a skills library that provides specialized capabilities and domain knowledge.
+
+ {skills_locations}
+
+ **Available Skills:**
+
+ {skills_list}
+
+ ---
+
+ ### How to Use Skills (Progressive Disclosure) - CRITICAL
+
+ Skills follow a **progressive disclosure** pattern - you know they exist (name + description above),
+ but you **MUST read the full instructions before using them**.
+
+ **MANDATORY Workflow:**
+
+ 1. **Recognize when a skill applies**: Check if the user's task matches any skill's description above
+ 2. **Read the skill's full instructions FIRST**: Use `read_skill` tool to get the complete SKILL.md content
+ - This tells you exactly what scripts exist, their parameters, and how to use them
+ - **NEVER assume or guess script names, paths, or arguments**
+ 3. **Follow the skill's instructions precisely**: SKILL.md contains step-by-step workflows and examples
+ 4. **Execute scripts only after reading**: Use the exact script paths and argument formats from SKILL.md
+
+ **IMPORTANT RULES:**
+
+ ⚠️ **NEVER call `execute_skill_script` without first reading the skill with `read_skill`**
+ - You do NOT know what scripts exist in a skill until you read it
+ - You do NOT know the correct script arguments until you read the SKILL.md
+ - Guessing script names will fail - always read first
+
+ ✅ **Correct Workflow Example:**
+ ```
+ User: "Split this PDF into pages"
+ 1. Recognize: "split-pdf" skill matches this task
+ 2. Call: read_skill("split-pdf") → Get full instructions
+ 3. Learn: SKILL.md shows the actual script path and argument format
+ 4. Execute: Use the exact command format from SKILL.md
+ ```
+
+ ❌ **Wrong Workflow (DO NOT DO THIS):**
+ ```
+ User: "Split this PDF into pages"
+ 1. Recognize: "split-pdf" skill matches this task
+ 2. Guess: execute_skill_script("split-pdf", "split_pdf.py", ...) ← WRONG! Never guess!
+ ```
+
+ **Skills are Self-Documenting:**
+ - Each SKILL.md tells you exactly what the skill does and how to use it
+ - The skill may contain Python scripts, config files, or reference docs
+ - Always use the exact paths and formats specified in SKILL.md
+
+ Remember: **Read first, then execute.** This ensures you use skills correctly!
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/skill-list_skill_directory.json b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/skill-list_skill_directory.json
new file mode 100644
index 000000000..6e5d35887
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/skill-list_skill_directory.json
@@ -0,0 +1,18 @@
+{
+ "name": "skill-list_skill_directory",
+ "description": "Lists the contents of a skill's directory. Use this to discover what files and subdirectories are available within a skill.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "skill_name": {
+ "type": "string",
+ "description": "The name of the skill to list."
+ },
+ "relative_path": {
+ "type": "string",
+ "description": "Optional relative path to a subdirectory within the skill directory. If not provided, lists the root of the skill directory."
+ }
+ },
+ "required": ["skill_name"]
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/skill-read_skill.json b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/skill-read_skill.json
new file mode 100644
index 000000000..cea6f9a65
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/skill-read_skill.json
@@ -0,0 +1,14 @@
+{
+ "name": "skill-read_skill",
+ "description": "Reads the full content of a skill's SKILL.md file to get detailed instructions. Use this when you need to understand how to apply a specific skill.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "skill_name": {
+ "type": "string",
+ "description": "The name of the skill to read (e.g., 'web-research', 'code-review'). Use the skill names from the available skills list."
+ }
+ },
+ "required": ["skill_name"]
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/skill-read_skill_file.json b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/skill-read_skill_file.json
new file mode 100644
index 000000000..4be74cc35
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/skill-read_skill_file.json
@@ -0,0 +1,18 @@
+{
+ "name": "skill-read_skill_file",
+ "description": "Reads a file within a skill's directory. Use this to access supporting files like scripts, templates, or data files that a skill may include.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "skill_name": {
+ "type": "string",
+ "description": "The name of the skill containing the file."
+ },
+ "file_path": {
+ "type": "string",
+ "description": "The relative path to the file within the skill directory (e.g., 'scripts/helper.py', 'templates/prompt.txt')."
+ }
+ },
+ "required": ["skill_name", "file_path"]
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/skill-list_skill_directory.fn.liquid b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/skill-list_skill_directory.fn.liquid
new file mode 100644
index 000000000..16c38e506
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/skill-list_skill_directory.fn.liquid
@@ -0,0 +1 @@
+When you need to discover what files and subdirectories are available within a skill, use the skill-list_skill_directory function. This helps you understand the skill's structure before reading specific files.
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/skill-read_skill.fn.liquid b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/skill-read_skill.fn.liquid
new file mode 100644
index 000000000..d1d4b689d
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/skill-read_skill.fn.liquid
@@ -0,0 +1 @@
+When you need to understand how to apply a specific skill, use the skill-read_skill function to read the full SKILL.md content. This provides detailed instructions on when and how to use the skill.
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/skill-read_skill_file.fn.liquid b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/skill-read_skill_file.fn.liquid
new file mode 100644
index 000000000..4dcf3d796
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AgentSkills/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/skill-read_skill_file.fn.liquid
@@ -0,0 +1 @@
+When you need to access supporting files within a skill directory (such as scripts, templates, or data files), use the skill-read_skill_file function. Provide the skill name and the relative file path.
\ No newline at end of file
diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj
index 9374d95fd..065bc9140 100644
--- a/src/WebStarter/WebStarter.csproj
+++ b/src/WebStarter/WebStarter.csproj
@@ -35,6 +35,7 @@
+
@@ -91,6 +92,7 @@
+
\ No newline at end of file
diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json
index 39587b64e..5acc7fce3 100644
--- a/src/WebStarter/appsettings.json
+++ b/src/WebStarter/appsettings.json
@@ -1061,10 +1061,15 @@
"BotSharp.Plugin.PythonInterpreter",
"BotSharp.Plugin.FuzzySharp",
"BotSharp.Plugin.MMPEmbedding",
- "BotSharp.Plugin.MultiTenancy"
+ "BotSharp.Plugin.MultiTenancy",
+ "BotSharp.Plugin.AgentSkills"
]
},
-
+ "AgentSkills": {
+ "EnableUserSkills": false,
+ "EnableProjectSkills": true,
+ "ProjectSkillsDir": "C:\\workshop\\github\\BotSharp\\src\\WebStarter\\skills"
+ },
"TenantStore": {
"Enabled": false,
"Tenants": [
diff --git a/src/WebStarter/skills/code-review/SKILL.md b/src/WebStarter/skills/code-review/SKILL.md
new file mode 100644
index 000000000..cd64cb557
--- /dev/null
+++ b/src/WebStarter/skills/code-review/SKILL.md
@@ -0,0 +1,94 @@
+---
+name: code-review
+description: A skill for conducting thorough code reviews, identifying issues, suggesting improvements, and ensuring code quality standards are met.
+license: MIT
+compatibility: any
+allowed-tools: read_file list_directory grep_search
+metadata:
+ author: Maf.AgentSkills
+ version: 1.0.0
+ category: development
+---
+
+# Code Review Skill
+
+This skill helps you conduct thorough and constructive code reviews.
+
+## When to Use
+
+Use this skill when:
+- Reviewing pull requests or code changes
+- Auditing code quality in a project
+- Helping developers improve their code
+- Checking for security vulnerabilities or bugs
+
+## Review Checklist
+
+Use the checklist in `templates/review-checklist.md` to ensure comprehensive coverage.
+
+### Categories
+
+1. **Correctness**: Does the code do what it's supposed to do?
+2. **Security**: Are there any security vulnerabilities?
+3. **Performance**: Are there performance concerns?
+4. **Maintainability**: Is the code easy to understand and modify?
+5. **Testing**: Is the code adequately tested?
+6. **Documentation**: Is the code well-documented?
+
+## Instructions
+
+### 1. Understand Context
+
+Before reviewing:
+- Understand the purpose of the change
+- Read any related issue or ticket
+- Know the project's coding standards
+
+### 2. Review Systematically
+
+Go through the code in this order:
+1. **Architecture**: Does the overall approach make sense?
+2. **Logic**: Is the logic correct and complete?
+3. **Edge Cases**: Are edge cases handled?
+4. **Error Handling**: Are errors handled appropriately?
+5. **Style**: Does the code follow conventions?
+
+### 3. Provide Constructive Feedback
+
+For each issue found:
+- Explain **what** the issue is
+- Explain **why** it's a problem
+- Suggest **how** to fix it
+- Categorize severity (blocker, major, minor, suggestion)
+
+### 4. Output Format
+
+```markdown
+# Code Review: [File/PR Name]
+
+## Summary
+[Overall assessment: approve, request changes, or comment]
+
+## Critical Issues 🔴
+[Issues that must be fixed before merge]
+
+## Major Issues 🟠
+[Important issues that should be addressed]
+
+## Minor Issues 🟡
+[Nice-to-have improvements]
+
+## Suggestions 💡
+[Optional improvements for consideration]
+
+## Positive Highlights ✨
+[Things done well - always include some!]
+```
+
+## Best Practices
+
+- Be respectful and constructive
+- Focus on the code, not the person
+- Ask questions when unclear
+- Acknowledge good patterns
+- Suggest alternatives, don't just criticize
diff --git a/src/WebStarter/skills/code-review/templates/review-checklist.md b/src/WebStarter/skills/code-review/templates/review-checklist.md
new file mode 100644
index 000000000..724f43437
--- /dev/null
+++ b/src/WebStarter/skills/code-review/templates/review-checklist.md
@@ -0,0 +1,54 @@
+# Code Review Checklist
+
+Use this checklist during code reviews to ensure comprehensive coverage.
+
+## ✅ Correctness
+- [ ] Code implements the intended functionality
+- [ ] Logic is correct and handles all scenarios
+- [ ] Edge cases are handled properly
+- [ ] No off-by-one errors
+- [ ] Null/undefined values are handled
+
+## 🔒 Security
+- [ ] No SQL injection vulnerabilities
+- [ ] No XSS vulnerabilities
+- [ ] Input validation is performed
+- [ ] Sensitive data is not logged
+- [ ] Authentication/authorization is correct
+- [ ] No hardcoded secrets or credentials
+
+## ⚡ Performance
+- [ ] No unnecessary database queries (N+1 problem)
+- [ ] Appropriate data structures used
+- [ ] No memory leaks
+- [ ] Caching used where appropriate
+- [ ] Large operations are async/background
+
+## 🔧 Maintainability
+- [ ] Code is readable and self-documenting
+- [ ] Functions/methods are focused (single responsibility)
+- [ ] No code duplication (DRY)
+- [ ] Naming is clear and consistent
+- [ ] Complex logic has comments
+- [ ] Magic numbers are constants
+
+## 🧪 Testing
+- [ ] Unit tests cover main functionality
+- [ ] Edge cases have tests
+- [ ] Tests are readable and maintainable
+- [ ] Mocking is used appropriately
+- [ ] Integration tests for critical paths
+
+## 📚 Documentation
+- [ ] Public APIs are documented
+- [ ] Complex algorithms have explanations
+- [ ] README updated if needed
+- [ ] Breaking changes documented
+- [ ] Migration guide if applicable
+
+## 🎨 Style
+- [ ] Follows project coding standards
+- [ ] Consistent formatting
+- [ ] No commented-out code
+- [ ] No debug statements left
+- [ ] Imports organized
diff --git a/src/WebStarter/skills/skill-creator/SKILL.md b/src/WebStarter/skills/skill-creator/SKILL.md
new file mode 100644
index 000000000..9d234b316
--- /dev/null
+++ b/src/WebStarter/skills/skill-creator/SKILL.md
@@ -0,0 +1,106 @@
+---
+name: skill-creator
+description: A meta-skill that helps create new Agent Skills by providing templates, best practices, and validation guidance.
+license: MIT
+compatibility: any
+metadata:
+ author: Maf.AgentSkills
+ version: 1.0.0
+ category: meta
+---
+
+# Skill Creator
+
+This meta-skill helps you create new Agent Skills following the [Agent Skills specification](https://agentskills.io).
+
+## When to Use
+
+Use this skill when:
+- Creating a new skill from scratch
+- Converting existing documentation into a skill
+- Validating an existing skill's structure
+- Learning how to write effective skills
+
+## Skill Structure
+
+Every skill must have:
+
+```
+skill-name/
+├── SKILL.md # Required: skill definition with YAML frontmatter
+├── templates/ # Optional: reusable templates
+├── scripts/ # Optional: automation scripts
+├── examples/ # Optional: usage examples
+└── resources/ # Optional: additional resources
+```
+
+## SKILL.md Template
+
+```markdown
+---
+name: my-skill-name
+description: A brief description of what this skill does (max 1024 chars)
+license: MIT
+compatibility: any
+allowed-tools: tool1 tool2 pattern_*
+metadata:
+ author: Your Name
+ version: 1.0.0
+ category: category-name
+---
+
+# Skill Title
+
+Brief introduction to the skill.
+
+## When to Use
+
+Describe scenarios when this skill should be applied.
+
+## Instructions
+
+Step-by-step instructions for applying the skill.
+
+### Step 1: [Name]
+Details...
+
+### Step 2: [Name]
+Details...
+
+## Output Format
+
+Describe expected output format if applicable.
+
+## Tips & Best Practices
+
+Additional guidance for effective use.
+```
+
+## Naming Rules
+
+Skill names must:
+- Use only lowercase letters, numbers, and hyphens
+- Start and end with a letter or number
+- Be 1-64 characters long
+- Match the directory name exactly
+
+**Valid**: `web-research`, `code-review`, `api-client-v2`
+**Invalid**: `Web_Research`, `-invalid`, `skill.name`
+
+## Writing Effective Instructions
+
+1. **Be Specific**: Provide clear, actionable steps
+2. **Use Examples**: Show input/output examples
+3. **Structure Consistently**: Use headings and lists
+4. **Include Templates**: Provide reusable templates
+5. **Explain Why**: Help users understand the reasoning
+6. **Handle Edge Cases**: Document exceptions and limitations
+
+## Best Practices
+
+- Keep skills focused on a single domain/task
+- Make skills reusable across different contexts
+- Include all necessary context in the skill
+- Test skills with various scenarios
+- Update skills based on user feedback
+- Version skills when making breaking changes
diff --git a/src/WebStarter/skills/split-pdf/SKILL.md b/src/WebStarter/skills/split-pdf/SKILL.md
new file mode 100644
index 000000000..4c4b99aee
--- /dev/null
+++ b/src/WebStarter/skills/split-pdf/SKILL.md
@@ -0,0 +1,67 @@
+---
+name: split-pdf
+description: Split PDF files into separate single-page documents or extract specific page ranges. Use when you need to divide a PDF into multiple files, extract particular pages, or process PDF pages individually. Works with multi-page PDF documents.
+license: MIT
+---
+
+# Split PDF
+
+将 PDF 文件拆分为多个单页文件或提取指定页面范围。
+
+## 使用场景
+
+- 将多页 PDF 拆分为独立的单页文件
+- 提取 PDF 的特定页面范围
+- 需要单独处理 PDF 各个页面时
+
+## 使用方法
+
+使用 `scripts/split-pdf.cs` 脚本进行 PDF 拆分:
+
+### 拆分所有页面
+```bash
+dotnet scripts/split-pdf.cs input.pdf output-dir/
+```
+
+### 拆分指定页面范围
+```bash
+# 拆分第 1-5 页
+dotnet scripts/split-pdf.cs input.pdf output-dir/ 1-5
+
+# 拆分第 10-20 页
+dotnet scripts/split-pdf.cs input.pdf output-dir/ 10-20
+```
+
+### 示例
+
+```bash
+# 将 document.pdf 的所有页面拆分到 pages/ 目录
+dotnet scripts/split-pdf.cs document.pdf pages/
+
+# 只提取前 3 页
+dotnet scripts/split-pdf.cs document.pdf output/ 1-3
+```
+
+## 输出格式
+
+拆分后的文件命名格式:`{原文件名}_page_{页码}.pdf`
+
+例如,拆分 `report.pdf` 后会生成:
+- `report_page_001.pdf`
+- `report_page_002.pdf`
+- `report_page_003.pdf`
+- ...
+
+## 依赖项
+
+脚本使用以下 NuGet 包(已在脚本中声明):
+- **PdfSharpCore 1.3.65** - PDF 操作核心库
+- **Spectre.Console 0.49.1** - 美化的控制台输出
+
+
+## 注意事项
+
+- 页码从 1 开始计数
+- 如果指定的页面范围超出实际页数,会自动调整到有效范围
+- 输出目录不存在时会自动创建
+- 支持中文文件名和路径
diff --git a/src/WebStarter/skills/split-pdf/scripts/split-pdf.cs b/src/WebStarter/skills/split-pdf/scripts/split-pdf.cs
new file mode 100644
index 000000000..451d67c54
--- /dev/null
+++ b/src/WebStarter/skills/split-pdf/scripts/split-pdf.cs
@@ -0,0 +1,112 @@
+#!/usr/bin/env dotnet
+#:package PdfSharpCore@1.3.65
+#:package Spectre.Console@0.49.1
+#:property PublishAot=true
+
+using PdfSharpCore.Pdf;
+using PdfSharpCore.Pdf.IO;
+using Spectre.Console;
+using System;
+using System.IO;
+
+// ==================== 参数校验 ====================
+if (args.Length < 2)
+{
+ AnsiConsole.MarkupLine("[red]错误: 参数不足[/]");
+ AnsiConsole.MarkupLine("[yellow]用法: dotnet split-pdf.cs <输出目录> [页面范围][/]");
+ AnsiConsole.MarkupLine("[gray]示例: dotnet split-pdf.cs input.pdf ./output/[/]");
+ AnsiConsole.MarkupLine("[gray] dotnet split-pdf.cs input.pdf ./output/ 1-5[/]");
+ return 1;
+}
+
+var pdfPath = args[0];
+var outputDir = args[1];
+var pageRange = args.Length >= 3 ? args[2] : null;
+
+// 验证 PDF 文件
+if (!File.Exists(pdfPath))
+{
+ AnsiConsole.MarkupLine($"[red]错误: 文件不存在: {pdfPath}[/]");
+ return 1;
+}
+
+// 创建输出目录
+if (!Directory.Exists(outputDir))
+{
+ Directory.CreateDirectory(outputDir);
+ AnsiConsole.MarkupLine($"[green]✓[/] 创建目录: {outputDir}");
+}
+
+// ==================== 拆分 PDF ====================
+try
+{
+ AnsiConsole.MarkupLine($"[cyan]📄 处理文件:[/] {Path.GetFileName(pdfPath)}");
+ AnsiConsole.MarkupLine($"[cyan]📂 输出目录:[/] {outputDir}");
+
+ using var inputDocument = PdfReader.Open(pdfPath, PdfDocumentOpenMode.Import);
+ var totalPages = inputDocument.PageCount;
+
+ // 解析页面范围
+ int startPage = 1, endPage = totalPages;
+ if (!string.IsNullOrEmpty(pageRange))
+ {
+ var parts = pageRange.Split('-');
+ if (parts.Length == 2 &&
+ int.TryParse(parts[0], out startPage) &&
+ int.TryParse(parts[1], out endPage))
+ {
+ startPage = Math.Max(1, Math.Min(startPage, totalPages));
+ endPage = Math.Max(startPage, Math.Min(endPage, totalPages));
+ }
+ else
+ {
+ AnsiConsole.MarkupLine($"[yellow]警告: 无效的页面范围 '{pageRange}',将拆分所有页面[/]");
+ startPage = 1;
+ endPage = totalPages;
+ }
+ }
+
+ AnsiConsole.MarkupLine($"[blue]ℹ️ 总页数:[/] {totalPages}");
+ AnsiConsole.MarkupLine($"[blue]ℹ️ 拆分范围:[/] 第 {startPage} - {endPage} 页");
+ Console.WriteLine();
+
+ var baseName = Path.GetFileNameWithoutExtension(pdfPath);
+ var savedCount = 0;
+
+ await AnsiConsole.Progress()
+ .StartAsync(async ctx =>
+ {
+ var task = ctx.AddTask("[green]拆分 PDF 页面[/]", maxValue: endPage - startPage + 1);
+
+ for (int i = startPage; i <= endPage; i++)
+ {
+ task.Description = $"[green]拆分第 {i}/{endPage} 页[/]";
+
+ // 创建单页 PDF
+ using var outputDocument = new PdfDocument();
+ outputDocument.AddPage(inputDocument.Pages[i - 1]);
+
+ var outputPath = Path.Combine(outputDir, $"{baseName}_page_{i:D3}.pdf");
+ outputDocument.Save(outputPath);
+
+ savedCount++;
+ AnsiConsole.MarkupLine($" [gray]✓ 已保存: {Path.GetFileName(outputPath)}[/]");
+
+ task.Increment(1);
+ await Task.CompletedTask;
+ }
+ });
+
+ Console.WriteLine();
+ AnsiConsole.MarkupLine($"[green]✅ 拆分完成![/]");
+ AnsiConsole.MarkupLine($"[gray]已生成 {savedCount} 个 PDF 文件[/]");
+ AnsiConsole.MarkupLine($"[gray]保存位置: {Path.GetFullPath(outputDir)}[/]");
+
+ return 0;
+}
+catch (Exception ex)
+{
+ AnsiConsole.MarkupLine($"[red]❌ 错误: {ex.Message}[/]");
+ AnsiConsole.WriteException(ex);
+ return 1;
+}
diff --git a/src/WebStarter/skills/web-research/SKILL.md b/src/WebStarter/skills/web-research/SKILL.md
new file mode 100644
index 000000000..c47edbdca
--- /dev/null
+++ b/src/WebStarter/skills/web-research/SKILL.md
@@ -0,0 +1,87 @@
+---
+name: web-research
+description: A skill for conducting comprehensive web research on any topic, synthesizing information from multiple sources into well-organized summaries.
+license: MIT
+compatibility: any
+allowed-tools: read_file web_search fetch_url
+metadata:
+ author: Maf.AgentSkills
+ version: 1.0.0
+ category: research
+---
+
+# Web Research Skill
+
+This skill helps you conduct comprehensive web research on any topic.
+
+## When to Use
+
+Use this skill when the user asks you to:
+- Research a topic thoroughly
+- Find and summarize information from multiple sources
+- Create a research report or literature review
+- Compare different perspectives on a subject
+
+## Instructions
+
+### 1. Clarify the Research Scope
+
+Before starting, ensure you understand:
+- The specific topic or question
+- The depth of research required (quick overview vs. deep dive)
+- Any specific sources or domains to focus on
+- The desired output format
+
+### 2. Search Strategy
+
+1. **Start broad**: Use general search queries to understand the landscape
+2. **Narrow down**: Use specific keywords based on initial findings
+3. **Diversify sources**: Look for academic, industry, and news perspectives
+4. **Verify facts**: Cross-reference important claims across sources
+
+### 3. Information Synthesis
+
+When synthesizing information:
+- Organize by themes, not by source
+- Highlight areas of consensus and disagreement
+- Note the credibility and recency of sources
+- Identify gaps in available information
+
+### 4. Output Format
+
+Structure your research report as:
+
+```markdown
+# Research Report: [Topic]
+
+## Executive Summary
+[2-3 sentence overview]
+
+## Key Findings
+1. [Finding 1]
+2. [Finding 2]
+...
+
+## Detailed Analysis
+
+### [Theme 1]
+[Analysis with citations]
+
+### [Theme 2]
+[Analysis with citations]
+
+## Sources
+- [Source 1]: [URL]
+- [Source 2]: [URL]
+...
+
+## Limitations & Further Research
+[What wasn't covered, what needs more investigation]
+```
+
+## Tips
+
+- Always cite your sources
+- Be transparent about the limitations of your research
+- Distinguish between facts, expert opinions, and speculation
+- Update findings if you discover contradictory information