diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..710698c --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +############### +# folder # +############### +/**/DROP/ +/**/TEMP/ +/**/packages/ +/**/bin/ +/**/obj/ +_site +.idea/ diff --git a/api/.gitignore b/api/.gitignore new file mode 100644 index 0000000..f798527 --- /dev/null +++ b/api/.gitignore @@ -0,0 +1,5 @@ +############### +# temp file # +############### +*.yml +.manifest diff --git a/api/index.md b/api/index.md new file mode 100644 index 0000000..1cb6831 --- /dev/null +++ b/api/index.md @@ -0,0 +1,2 @@ +# PLACEHOLDER +TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*! diff --git a/articles/intro.md b/articles/intro.md new file mode 100644 index 0000000..901a16a --- /dev/null +++ b/articles/intro.md @@ -0,0 +1 @@ +# Add your introductions here! diff --git a/articles/toc.yml b/articles/toc.yml new file mode 100644 index 0000000..f64352c --- /dev/null +++ b/articles/toc.yml @@ -0,0 +1,2 @@ +- name: Introduction + href: intro.md diff --git a/docfx.json b/docfx.json new file mode 100644 index 0000000..fb53a19 --- /dev/null +++ b/docfx.json @@ -0,0 +1,64 @@ +{ + "metadata": [ + { + "src": [ + { + "files": [ + "src/**.csproj" + ] + } + ], + "dest": "api", + "disableGitFeatures": false, + "disableDefaultFilter": false + } + ], + "build": { + "content": [ + { + "files": [ + "api/**.yml", + "api/index.md" + ] + }, + { + "files": [ + "articles/**.md", + "articles/**/toc.yml", + "toc.yml", + "*.md" + ] + } + ], + "resource": [ + { + "files": [ + "images/**" + ] + } + ], + "overwrite": [ + { + "files": [ + "apidoc/**.md" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + } + ], + "dest": "_site", + "globalMetadataFiles": [], + "fileMetadataFiles": [], + "template": [ + "statictoc" + ], + "postProcessors": [], + "markdownEngineName": "markdig", + "noLangKeyword": false, + "keepFileLink": false, + "cleanupCacheHistory": false, + "disableGitFeatures": false + } +} \ No newline at end of file diff --git a/index.md b/index.md new file mode 100644 index 0000000..95887de --- /dev/null +++ b/index.md @@ -0,0 +1,4 @@ +# This is the **HOMEPAGE**. +Refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files. +## Quick Start Notes: +1. Add images to the *images* folder if the file is referencing an image. diff --git a/src/tand/Tand.Core.Tests/LogTarget.cs b/src/tand/Tand.Core.Tests/LogTarget.cs new file mode 100644 index 0000000..fed2ad6 --- /dev/null +++ b/src/tand/Tand.Core.Tests/LogTarget.cs @@ -0,0 +1,35 @@ +using System; +using Tand.Core.Models; + +namespace Tand.Core.Tests +{ + public class LogTarget : ITandTarget + { + private readonly Action _logHandle; + + public LogTarget(Action logHandle) + { + _logHandle = logHandle; + } + + public void OnEnterMethod(CallEnterContext enterContext) + { + _logHandle(enterContext.Instance.ToString()); + foreach (var (name, val) in enterContext.Arguments) + { + _logHandle($"name: {name}, value: {val}"); + } + } + + public void OnLeaveMethod(CallLeaveContext callLeaveContext) + { + _logHandle(callLeaveContext.Instance.ToString()); + foreach (var (name, val) in callLeaveContext.Arguments) + { + _logHandle($"name: {name}, value: {val}"); + } + + _logHandle($"result: {callLeaveContext.CallResult}"); + } + } +} \ No newline at end of file diff --git a/src/tand/Tand.Core.Tests/Tand.Core.Tests.csproj b/src/tand/Tand.Core.Tests/Tand.Core.Tests.csproj new file mode 100644 index 0000000..9930c99 --- /dev/null +++ b/src/tand/Tand.Core.Tests/Tand.Core.Tests.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + + diff --git a/src/tand/Tand.Core.Tests/TandSample.cs b/src/tand/Tand.Core.Tests/TandSample.cs new file mode 100644 index 0000000..3c7567b --- /dev/null +++ b/src/tand/Tand.Core.Tests/TandSample.cs @@ -0,0 +1,60 @@ +using System; +using Xunit; +using Xunit.Abstractions; + +namespace Tand.Core.Tests +{ + public class TandTest + { + private readonly ITestOutputHelper _outputHelper; + + public TandTest(ITestOutputHelper outputHelper) + { + _outputHelper = outputHelper; + } + + [Fact] + public void GenerateTand() + { + var tand = new Tand(new SampleResolver(_outputHelper)); + + var sample = tand.DecorateWithTand(new TandSample()); + var result = sample.LogMyParams("Hello, World", 42); + _outputHelper.WriteLine($"Got result: {result}"); + } + } + + + public class SampleResolver : IDependencyResolver + { + private readonly ITestOutputHelper _outputHelper; + + public SampleResolver(ITestOutputHelper outputHelper) + { + _outputHelper = outputHelper; + } + + public ITandTarget TargetOfType(Type type) + { + return new LogTarget(_outputHelper.WriteLine); + } + } + + public interface ITAndSample + { + [Tand(typeof(LogTarget))] + int LogMyParams(string s, int i); + } + + public class TandSample : ITAndSample + { + + private int _counter; + public string ContextSample { get; set; } + + public int LogMyParams(string s, int i) + { + return ++_counter; + } + } +} \ No newline at end of file diff --git a/src/tand/Tand.Core/CallEnterContext.cs b/src/tand/Tand.Core/CallEnterContext.cs new file mode 100644 index 0000000..7810bd2 --- /dev/null +++ b/src/tand/Tand.Core/CallEnterContext.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Linq; +using Tand.Core.Models; + +namespace Tand.Core +{ + public readonly struct CallEnterContext + { + private readonly IDictionary _methodArgs; + + public CallEnterContext(T instance, IDictionary args) + { + Instance = instance; + _methodArgs = args; + } + + public T Instance { get; } + + public object? this[string argName] => _methodArgs.ContainsKey(argName) ? _methodArgs[argName] : null; + + public IEnumerable Arguments => _methodArgs.Select(kv => new MethodArgument(kv.Key, kv.Value)); + } +} \ No newline at end of file diff --git a/src/tand/Tand.Core/IDependencyResolver.cs b/src/tand/Tand.Core/IDependencyResolver.cs new file mode 100644 index 0000000..8f7610a --- /dev/null +++ b/src/tand/Tand.Core/IDependencyResolver.cs @@ -0,0 +1,9 @@ +using System; + +namespace Tand.Core +{ + public interface IDependencyResolver + { + ITandTarget TargetOfType(Type type); + } +} \ No newline at end of file diff --git a/src/tand/Tand.Core/ITandTarget.cs b/src/tand/Tand.Core/ITandTarget.cs new file mode 100644 index 0000000..3afca63 --- /dev/null +++ b/src/tand/Tand.Core/ITandTarget.cs @@ -0,0 +1,11 @@ +using Tand.Core.Models; + +namespace Tand.Core +{ + public interface ITandTarget + { + void OnEnterMethod(CallEnterContext enterContext); + + void OnLeaveMethod(CallLeaveContext leaveContext); + } +} \ No newline at end of file diff --git a/src/tand/Tand.Core/Models/CallLeaveContext.cs b/src/tand/Tand.Core/Models/CallLeaveContext.cs new file mode 100644 index 0000000..5decb76 --- /dev/null +++ b/src/tand/Tand.Core/Models/CallLeaveContext.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Tand.Core.Models +{ + public readonly struct CallLeaveContext + { + private readonly IDictionary _methodArgs; + + public CallLeaveContext( + T instance, + IDictionary args, + object callResult + ) + { + Instance = instance; + _methodArgs = args; + CallResult = callResult; + } + + public T Instance { get; } + + public object CallResult { get; } + + public object? this[string argName] => _methodArgs.ContainsKey(argName) ? _methodArgs[argName] : null; + + public IEnumerable Arguments => _methodArgs.Select(kv => new MethodArgument(kv.Key, kv.Value)); + } +} \ No newline at end of file diff --git a/src/tand/Tand.Core/Models/MethodArgument.cs b/src/tand/Tand.Core/Models/MethodArgument.cs new file mode 100644 index 0000000..5c646a1 --- /dev/null +++ b/src/tand/Tand.Core/Models/MethodArgument.cs @@ -0,0 +1,21 @@ +namespace Tand.Core.Models +{ + public readonly struct MethodArgument + { + public MethodArgument(string name, object value) + { + Name = name; + Value = value; + } + + public string Name { get; } + + public object Value { get; } + + public void Deconstruct(out string name, out object value) + { + name = Name; + value = Value; + } + } +} \ No newline at end of file diff --git a/src/tand/Tand.Core/Tand.Core.csproj b/src/tand/Tand.Core/Tand.Core.csproj new file mode 100644 index 0000000..5505550 --- /dev/null +++ b/src/tand/Tand.Core/Tand.Core.csproj @@ -0,0 +1,9 @@ + + + + netstandard2.1 + 8 + enable + + + diff --git a/src/tand/Tand.Core/Tand.cs b/src/tand/Tand.Core/Tand.cs new file mode 100644 index 0000000..e4086d7 --- /dev/null +++ b/src/tand/Tand.Core/Tand.cs @@ -0,0 +1,38 @@ +using System.Reflection; + +namespace Tand.Core +{ + public class Tand + { + private readonly IDependencyResolver _dependencyResolver; + + public Tand(IDependencyResolver dependencyResolver) + { + _dependencyResolver = dependencyResolver; + } + + public TService DecorateWithTand(TImplementation toBeDecorated) + where TService : class + where TImplementation : class, TService + { + var proxy = DispatchProxy.Create>(); + InitProxy(proxy, toBeDecorated); + return proxy; + } + + private void InitProxy(object proxyObj, TService toBeDecorated) + { + var proxy = proxyObj switch + { + TandProxy tp => tp, + _ => null + }; + + if (proxy == null) return; + + proxy.Decorated = toBeDecorated; + proxy.ImplementationType = typeof(TImplementation); + proxy.DependencyResolver = _dependencyResolver; + } + } +} \ No newline at end of file diff --git a/src/tand/Tand.Core/TandAttribute.cs b/src/tand/Tand.Core/TandAttribute.cs new file mode 100644 index 0000000..6b04ff9 --- /dev/null +++ b/src/tand/Tand.Core/TandAttribute.cs @@ -0,0 +1,16 @@ +using System; + +namespace Tand.Core +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public class TandAttribute : Attribute + { + + public TandAttribute(Type targetType) + { + TargetType = targetType; + } + + public Type TargetType { get; } + } +} \ No newline at end of file diff --git a/src/tand/Tand.Core/TandProxy.cs b/src/tand/Tand.Core/TandProxy.cs new file mode 100644 index 0000000..7ca32d4 --- /dev/null +++ b/src/tand/Tand.Core/TandProxy.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Tand.Core.Models; + +namespace Tand.Core +{ + public class TandProxy : DispatchProxy + { + private readonly IDictionary _targetCache; + + public TandProxy() + { + _targetCache = new ConcurrentDictionary(); + } + + public Type ImplementationType { get; set; } + public T Decorated { private get; set; } + + public IDependencyResolver DependencyResolver { get; set; } + + protected override object Invoke(MethodInfo targetMethod, object[] args) + { + var mappedMethodArgs = CollectArgs(targetMethod, args); + var enterContext = new CallEnterContext(Decorated, mappedMethodArgs); + var targets = TargetTypesForMethod(targetMethod); + foreach (var target in targets) + { + target.OnEnterMethod(enterContext); + } + + var result = targetMethod.Invoke(Decorated, args); + + var leaveContext = new CallLeaveContext(Decorated, mappedMethodArgs, result); + + foreach (var target in targets) + { + target.OnLeaveMethod(leaveContext); + } + + return result; + } + + private static IDictionary CollectArgs(MethodBase methodInfo, IReadOnlyList argValues) + { + var result = new Dictionary(); + var parameters = methodInfo.GetParameters(); + for (var i = 0; i < parameters.Length && i < argValues.Count; i++) + { + result.Add(parameters[i].Name, argValues[i]); + } + + return result; + } + + private ICollection> TargetTypesForMethod(MethodInfo methodInfo) + { + var hash = methodInfo.GetHashCode(); + if (!_targetCache.ContainsKey(hash)) + { + _targetCache[hash] = methodInfo.GetCustomAttributes() + .Select(attr => attr.TargetType) + .ToArray(); + } + + return _targetCache[hash] + .Select(type => DependencyResolver.TargetOfType(type)) + .ToList(); + } + } +} \ No newline at end of file diff --git a/src/tand/Tand.Extensions.DependencyInjection.Tests/Tand.Extensions.DependencyInjection.Tests.csproj b/src/tand/Tand.Extensions.DependencyInjection.Tests/Tand.Extensions.DependencyInjection.Tests.csproj new file mode 100644 index 0000000..627671d --- /dev/null +++ b/src/tand/Tand.Extensions.DependencyInjection.Tests/Tand.Extensions.DependencyInjection.Tests.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + + diff --git a/src/tand/Tand.Extensions.DependencyInjection.Tests/TandServiceExtensionsTests.cs b/src/tand/Tand.Extensions.DependencyInjection.Tests/TandServiceExtensionsTests.cs new file mode 100644 index 0000000..b4de5d5 --- /dev/null +++ b/src/tand/Tand.Extensions.DependencyInjection.Tests/TandServiceExtensionsTests.cs @@ -0,0 +1,60 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Tand.Core; +using Tand.Core.Models; +using Xunit; + +namespace Tand.Extensions.DependencyInjection.Tests +{ + public class TandServiceExtensionsTests + { + public const string Greeting = "Hello, World!"; + + [Fact] + public void RegisterService_RegisterSampleService_SuccessfullyResolve() + { + var calledOnEnter = false; + var calledOnExit = false; + var servides = new ServiceCollection(); + servides.AddTand(); + servides.AddSingleton(new TestDecorator(_ => { calledOnEnter = true;}, _ => { calledOnExit = true;})); + servides.AddTandTransient(); + var provider = servides.BuildServiceProvider(); + + var sampleService = provider.GetService(); + Assert.NotNull(sampleService); + var result = sampleService.Greet(); + + Assert.Equal(Greeting, result); + Assert.True(calledOnEnter); + Assert.True(calledOnExit); + } + } + + public class TestDecorator : ITandTarget + { + private readonly Action> _onEnterHandle; + private readonly Action> _onLeaveHandle; + + public TestDecorator(Action> onEnterHandle, Action> onLeaveHandle) + { + _onEnterHandle = onEnterHandle; + _onLeaveHandle = onLeaveHandle; + } + + public void OnEnterMethod(CallEnterContext enterContext) => _onEnterHandle(enterContext); + + public void OnLeaveMethod(CallLeaveContext leaveContext) => _onLeaveHandle(leaveContext); + } + + public interface ISampleService + { + [Tand(typeof(TestDecorator))] + string Greet(); + } + + public class SampleServiceImpl : ISampleService + { + public string Greet() => TandServiceExtensionsTests.Greeting; + } +} \ No newline at end of file diff --git a/src/tand/Tand.Extensions.DependencyInjection/DependencyResolverProxy.cs b/src/tand/Tand.Extensions.DependencyInjection/DependencyResolverProxy.cs new file mode 100644 index 0000000..d3a0a30 --- /dev/null +++ b/src/tand/Tand.Extensions.DependencyInjection/DependencyResolverProxy.cs @@ -0,0 +1,21 @@ +using System; +using Tand.Core; + +namespace Tand.Extensions.DependencyInjection +{ + public class DependencyResolverProxy : IDependencyResolver + { + private readonly IServiceProvider _serviceProvider; + + public DependencyResolverProxy(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public ITandTarget TargetOfType(Type type) => _serviceProvider.GetService(type) switch + { + ITandTarget target => target, + _ => throw new ArgumentException() + }; + } +} \ No newline at end of file diff --git a/src/tand/Tand.Extensions.DependencyInjection/Tand.Extensions.DependencyInjection.csproj b/src/tand/Tand.Extensions.DependencyInjection/Tand.Extensions.DependencyInjection.csproj new file mode 100644 index 0000000..23d7076 --- /dev/null +++ b/src/tand/Tand.Extensions.DependencyInjection/Tand.Extensions.DependencyInjection.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.1 + + + + + + + + + + + diff --git a/src/tand/Tand.Extensions.DependencyInjection/TandServiceExtensions.cs b/src/tand/Tand.Extensions.DependencyInjection/TandServiceExtensions.cs new file mode 100644 index 0000000..cc384a0 --- /dev/null +++ b/src/tand/Tand.Extensions.DependencyInjection/TandServiceExtensions.cs @@ -0,0 +1,31 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace Tand.Extensions.DependencyInjection +{ + public static class TandServiceExtensions + { + public static void AddTand(this IServiceCollection serviceCollection) + { + serviceCollection.TryAddSingleton(sp => new Tand.Core.Tand(new DependencyResolverProxy(sp))); + } + + public static IServiceCollection AddTandTransient(this IServiceCollection services) + where TService : class + where TImplementation : class, TService + { + services.AddTransient(); + services.AddTransient(GetTandForType); + return services; + } + + private static TService GetTandForType(IServiceProvider serviceProvider) where TImplementation : class, TService where TService : class + { + var tand = serviceProvider.GetService(); + var instance = serviceProvider.GetService(); + var proxy = tand.DecorateWithTand(instance); + return proxy; + } + } +} \ No newline at end of file diff --git a/src/tand/Tand.sln b/src/tand/Tand.sln new file mode 100644 index 0000000..ee3a12c --- /dev/null +++ b/src/tand/Tand.sln @@ -0,0 +1,86 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tand.Core", "Tand.Core\Tand.Core.csproj", "{994166B2-862B-451B-B3E5-B2797EFF7022}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4A0DFFF5-7BB2-481A-BB0F-152D89823F48}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C51CA370-A0C7-4229-90FA-ADF7B51DE021}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tand.Core.Tests", "Tand.Core.Tests\Tand.Core.Tests.csproj", "{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tand.Extensions.DependencyInjection", "Tand.Extensions.DependencyInjection\Tand.Extensions.DependencyInjection.csproj", "{C535C043-7A0E-4F17-89E4-493E7805CFAC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tand.Extensions.DependencyInjection.Tests", "Tand.Extensions.DependencyInjection.Tests\Tand.Extensions.DependencyInjection.Tests.csproj", "{D1287B4D-319A-4D7A-BB5B-93C4E8320480}" +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(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|Any CPU.Build.0 = Debug|Any CPU + {994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|x64.ActiveCfg = Debug|Any CPU + {994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|x64.Build.0 = Debug|Any CPU + {994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|x86.ActiveCfg = Debug|Any CPU + {994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|x86.Build.0 = Debug|Any CPU + {994166B2-862B-451B-B3E5-B2797EFF7022}.Release|Any CPU.ActiveCfg = Release|Any CPU + {994166B2-862B-451B-B3E5-B2797EFF7022}.Release|Any CPU.Build.0 = Release|Any CPU + {994166B2-862B-451B-B3E5-B2797EFF7022}.Release|x64.ActiveCfg = Release|Any CPU + {994166B2-862B-451B-B3E5-B2797EFF7022}.Release|x64.Build.0 = Release|Any CPU + {994166B2-862B-451B-B3E5-B2797EFF7022}.Release|x86.ActiveCfg = Release|Any CPU + {994166B2-862B-451B-B3E5-B2797EFF7022}.Release|x86.Build.0 = Release|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|x64.ActiveCfg = Debug|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|x64.Build.0 = Debug|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|x86.ActiveCfg = Debug|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|x86.Build.0 = Debug|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|Any CPU.Build.0 = Release|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|x64.ActiveCfg = Release|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|x64.Build.0 = Release|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|x86.ActiveCfg = Release|Any CPU + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|x86.Build.0 = Release|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|x64.ActiveCfg = Debug|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|x64.Build.0 = Debug|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|x86.ActiveCfg = Debug|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|x86.Build.0 = Debug|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|Any CPU.Build.0 = Release|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|x64.ActiveCfg = Release|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|x64.Build.0 = Release|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|x86.ActiveCfg = Release|Any CPU + {C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|x86.Build.0 = Release|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|x64.ActiveCfg = Debug|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|x64.Build.0 = Debug|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|x86.ActiveCfg = Debug|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|x86.Build.0 = Debug|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|Any CPU.Build.0 = Release|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|x64.ActiveCfg = Release|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|x64.Build.0 = Release|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|x86.ActiveCfg = Release|Any CPU + {D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {994166B2-862B-451B-B3E5-B2797EFF7022} = {4A0DFFF5-7BB2-481A-BB0F-152D89823F48} + {7CFEE412-6D6A-407B-9FAE-1640F74D98E7} = {C51CA370-A0C7-4229-90FA-ADF7B51DE021} + {C535C043-7A0E-4F17-89E4-493E7805CFAC} = {4A0DFFF5-7BB2-481A-BB0F-152D89823F48} + {D1287B4D-319A-4D7A-BB5B-93C4E8320480} = {C51CA370-A0C7-4229-90FA-ADF7B51DE021} + EndGlobalSection +EndGlobal diff --git a/toc.yml b/toc.yml new file mode 100644 index 0000000..c06f5ab --- /dev/null +++ b/toc.yml @@ -0,0 +1,5 @@ +- name: Articles + href: articles/ +- name: Api Documentation + href: api/ + homepage: api/index.md