34 Commits

Author SHA1 Message Date
omegaleo 4885d99fd4 chore: update changelog and version to v1.2.1.1 2026-01-28 14:44:09 +00:00
omegaleo a01521da41 Merge remote-tracking branch 'origin/main' 2026-01-28 14:40:33 +00:00
omegaleo 624c808635 Updated nuget publishing workflow 2026-01-28 14:40:27 +00:00
omegaleo 072754e354 Update README.md 2026-01-28 14:35:19 +00:00
omegaleo be7867fe37 Delete .github/workflows/webpage.yml 2026-01-28 14:34:41 +00:00
omegaleo d9289d8eb2 Merge remote-tracking branch 'origin/main' 2026-01-28 14:25:03 +00:00
omegaleo b39763c104 fixed issue building for IIS 2026-01-28 14:24:58 +00:00
omegaleo 1a4eb80696 Add GitHub Actions workflow for GitHub Pages deployment
This workflow automates the deployment of static content to GitHub Pages upon pushes to the main branch or manual triggers.
2026-01-28 14:14:56 +00:00
omegaleo 0e4819a5a2 Merge remote-tracking branch 'origin/main' 2026-01-28 14:09:58 +00:00
omegaleo 7d3729db01 Added version to Changelog project 2026-01-28 14:09:53 +00:00
omegaleo a53e669bc1 chore: update changelog and version to v1.2.1 2026-01-28 14:07:57 +00:00
omegaleo 73a3c3cbe5 Merge remote-tracking branch 'origin/main' 2026-01-28 14:07:03 +00:00
omegaleo 56f4c88f4b Added shared library to published packages and fixed workflows 2026-01-28 14:06:57 +00:00
omegaleo 5d45842274 chore: update changelog and version to v1.2.0 2026-01-28 13:45:43 +00:00
omegaleo 192ab04f89 Fixed tagging workflow 2026-01-28 13:44:54 +00:00
omegaleo d791145f95 Fixed documentation project 2026-01-28 13:44:06 +00:00
omegaleo 65dc996a22 Merge remote-tracking branch 'origin/main' 2026-01-28 13:41:11 +00:00
omegaleo 43acc83207 Updated README 2026-01-28 13:41:06 +00:00
omegaleo a6cd274cc4 chore: update changelog and version to v1.2.0 2026-01-28 13:32:58 +00:00
omegaleo e3ca453144 Updated changelog workflow to update the project versions 2026-01-28 13:31:46 +00:00
omegaleo 3c4d726f40 Merge remote-tracking branch 'origin/main' 2026-01-28 13:30:08 +00:00
omegaleo c8c61573d8 Updated changelog workflow 2026-01-28 13:30:03 +00:00
omegaleo 17d0a1d57c chore: update changelog and version to v1.2.0 2026-01-28 13:28:16 +00:00
omegaleo 73a7983b7e Updated changelog workflow 2026-01-28 13:27:25 +00:00
omegaleo 4e131d158c Updated CHANGELOG 2026-01-28 13:24:58 +00:00
omegaleo dc18f79a7e Updated workflow 2026-01-28 13:18:07 +00:00
omegaleo 27a3408828 Merge remote-tracking branch 'origin/main' 2026-01-28 13:15:50 +00:00
omegaleo d20a80c44c Migrated Documentation library from NetFlow.DocumentationHelper.Library 2026-01-28 13:15:44 +00:00
omegaleo ac91759807 Create FUNDING.yml 2025-12-23 16:55:47 +00:00
omegaleo f0d9c49f6d Update issue templates 2025-12-23 16:55:25 +00:00
omegaleo ab700413fb updated helper lib package 2025-12-23 16:52:58 +00:00
omegaleo 9d27ec0ac9 updated packages 2025-12-23 16:50:43 +00:00
omegaleo 6681523a85 Dev (#7)
* Fixed dependency

* Updates to NeoDictionary

* Changes to NeoDictionary

* Started working on a Git implementation to integrate into Game Engines in the future

* Added commit functionality to the git library

* New changes

* Added select for NeoDictionary.cs

* Fixed issue with previous new method

* Added a Benchmarking Tool to be used mostly in game engines

* Added IndexOf to NeoDictionary.cs

* Added new method for BenchmarkUtility.cs

* added an instacedobject class

* Added a new shuffle method for lists

* fixed return type

* Added new Changelog generator

* Added new Game logic library to assist with game projects

* Added Web Project

* Added Nuget package configs

* Add workflow for publishing game library NuGet package

* Add README for OmegaLeo's Helper Library

* Updated Website to reflect all libraries

* Fixed missing library in Changelog

* Added Contributing and Code of Conduct

* Fixed web project

* new documentation changes

* fix packages

* Fixed DocumentationHelper package dependencies

* Added Serilog

* Added logging

* Fixed documentation

* Added logging for cache

* fixed documentation

* Updated README.md

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update OmegaLeo.HelperLib.Web/Controllers/HomeController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update OmegaLeo.HelperLib.Web/Controllers/HomeController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix error

* changes for Github Packages

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-23 16:46:44 +00:00
omegaleo 53650e4bfe Dev changes (#5)
* Fixed dependency

* Updates to NeoDictionary

* Changes to NeoDictionary

* Started working on a Git implementation to integrate into Game Engines in the future

* Added commit functionality to the git library

* New changes

* Added select for NeoDictionary.cs

* Fixed issue with previous new method

* Added a Benchmarking Tool to be used mostly in game engines

* Added IndexOf to NeoDictionary.cs

* Added new method for BenchmarkUtility.cs

* added an instacedobject class

* Added a new shuffle method for lists

* fixed return type

* Added new Changelog generator

* Added new Game logic library to assist with game projects

* Added Web Project

* Added Nuget package configs

* Add workflow for publishing game library NuGet package

* Add README for OmegaLeo's Helper Library

* Updated Website to reflect all libraries

* Fixed missing library in Changelog

* Added Contributing and Code of Conduct

* Fixed web project

* new documentation changes

* fix packages

* Fixed DocumentationHelper package dependencies

* Added Serilog

* Added logging

* Fixed documentation

* Added logging for cache

* fixed documentation

* Updated README.md

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update OmegaLeo.HelperLib.Web/Controllers/HomeController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update OmegaLeo.HelperLib.Web/Controllers/HomeController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix error

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-23 16:37:30 +00:00
162 changed files with 1556 additions and 160 deletions
+15
View File
@@ -0,0 +1,15 @@
# These are supported funding model platforms
github: omegaleo # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: omegaleo # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
+38
View File
@@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: omegaleo
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: omegaleo
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
Regular → Executable
+32 -12
View File
@@ -6,35 +6,55 @@ on:
description: 'Tag name:'
type: string
required: true
run-name: "Generating changelog for Release v${{github.event.inputs.tagName}}"
run-name: "Generating changelog and Creating Tag for Release v${{github.event.inputs.tagName}}"
jobs:
generate_changelog:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
ref: ${{ github.ref }}
token: ${{ secrets.TOKEN }}
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Update Project Versions
dotnet-version: '9.0.x'
- name: Update OmegaLeo.HelperLib Version
run: sed -i "s/\(<Version>\)[0-9]\+\.[0-9]\+\.[0-9]\+/\1${{github.event.inputs.tagName}}/" "./OmegaLeo.HelperLib/OmegaLeo.HelperLib.csproj"
- name: Update Project Versions
- name: Update OmegaLeo.HelperLib.Changelog Version
run: sed -i "s/\(<Version>\)[0-9]\+\.[0-9]\+\.[0-9]\+/\1${{github.event.inputs.tagName}}/" "./OmegaLeo.HelperLib.Changelog/OmegaLeo.HelperLib.Changelog.csproj"
- name: Build and Run Changelog Generator
run: dotnet run --project "./OmegaLeo.HelperLib.ChangelogHandler/OmegaLeo.HelperLib.ChangelogHandler.csproj"
- name: Update OmegaLeo.HelperLib.Documentation Version
run: sed -i "s/\(<Version>\)[0-9]\+\.[0-9]\+\.[0-9]\+/\1${{github.event.inputs.tagName}}/" "./OmegaLeo.HelperLib.Documentation/OmegaLeo.HelperLib.Documentation.csproj"
- name: Update OmegaLeo.HelperLib.Game Version
run: sed -i "s/\(<Version>\)[0-9]\+\.[0-9]\+\.[0-9]\+/\1${{github.event.inputs.tagName}}/" "./OmegaLeo.HelperLib.Game/OmegaLeo.HelperLib.Game.csproj"
- name: Update OmegaLeo.HelperLib.Shared Version
run: sed -i "s/\(<Version>\)[0-9]\+\.[0-9]\+\.[0-9]\+/\1${{github.event.inputs.tagName}}/" "./OmegaLeo.HelperLib.Shared/OmegaLeo.HelperLib.Shared.csproj"
- name: Build Solution
run: dotnet build --configuration Release
- name: Run Changelog Generator
run: dotnet run --project "./OmegaLeo.HelperLib.ChangelogHandler/OmegaLeo.HelperLib.ChangelogHandler.csproj" --configuration Release
env:
UNITYFLOW_SECRET: ${{ secrets.TOKEN }}
- name: Create Tag
TAG_VERSION: ${{ github.event.inputs.tagName }}
- name: Commit and Push Changes
run: |
git config --local user.email "nunodiogo@omegaleo.pt"
git config --local user.name "Nuno Diogo"
git add .
git commit -m "Automatically generated changelog for v${{github.event.inputs.tagName}}"
git diff --staged --quiet || git commit -m "chore: update changelog and version to v${{github.event.inputs.tagName}}"
git push origin ${{ github.ref }}
- name: Create and Push Tag
run: |
git tag -a "${{ github.event.inputs.tagName }}" -m "Release ${{ github.event.inputs.tagName }}"
git push origin "${{ github.event.inputs.tagName }}"
Regular → Executable
View File
+58
View File
@@ -32,6 +32,8 @@ jobs:
run: dotnet pack "./OmegaLeo.HelperLib/OmegaLeo.HelperLib.csproj" -c Release /p:Version=${{ github.event.release.tag_name }} /p:PackageReleaseNotes="See https://github.com/omegaleo/OmegaLeo.HelperLib/releases/tag/${{ github.event.release.tag_name }}"
- name: Publish Nuget Package
run: dotnet nuget push ./OmegaLeo.HelperLib/bin/Release/OmegaLeo.HelperLib.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.nuget_api_key }} --source https://api.nuget.org/v3/index.json --skip-duplicate
- name: Publish to GitHub Packages
run: dotnet nuget push ./OmegaLeo.HelperLib/bin/Release/OmegaLeo.HelperLib.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
- name: Upload assets to release
uses: actions/upload-release-asset@v1
env:
@@ -56,6 +58,8 @@ jobs:
run: dotnet pack "./OmegaLeo.HelperLib.Changelog/OmegaLeo.HelperLib.Changelog.csproj" -c Release /p:Version=${{ github.event.release.tag_name }} /p:PackageReleaseNotes="See https://github.com/omegaleo/OmegaLeo.HelperLib/releases/tag/${{ github.event.release.tag_name }}"
- name: Publish Nuget Package
run: dotnet nuget push ./OmegaLeo.HelperLib.Changelog/bin/Release/OmegaLeo.HelperLib.Changelog.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.nuget_api_key }} --source https://api.nuget.org/v3/index.json --skip-duplicate
- name: Publish to GitHub Packages
run: dotnet nuget push ./OmegaLeo.HelperLib.Changelog/bin/Release/OmegaLeo.HelperLib.Changelog.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
- name: Upload assets to release
uses: actions/upload-release-asset@v1
env:
@@ -80,6 +84,8 @@ jobs:
run: dotnet pack "./OmegaLeo.HelperLib.Game/OmegaLeo.HelperLib.Game.csproj" -c Release /p:Version=${{ github.event.release.tag_name }} /p:PackageReleaseNotes="See https://github.com/omegaleo/OmegaLeo.HelperLib/releases/tag/${{ github.event.release.tag_name }}"
- name: Publish Nuget Package
run: dotnet nuget push ./OmegaLeo.HelperLib.Game/bin/Release/OmegaLeo.HelperLib.Game.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.nuget_api_key }} --source https://api.nuget.org/v3/index.json --skip-duplicate
- name: Publish to GitHub Packages
run: dotnet nuget push ./OmegaLeo.HelperLib.Game/bin/Release/OmegaLeo.HelperLib.Game.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
- name: Upload assets to release
uses: actions/upload-release-asset@v1
env:
@@ -89,3 +95,55 @@ jobs:
asset_path: ./OmegaLeo.HelperLib.Game/bin/Release/OmegaLeo.HelperLib.Game.${{ github.event.release.tag_name }}.nupkg
asset_name: OmegaLeo.HelperLib.Game.${{ github.event.release.tag_name }}.nupkg
asset_content_type: application/zip
publish-doc-lib:
runs-on: ubuntu-latest
needs: [ get-release ]
steps:
- uses: actions/checkout@v2
- name: Setup .Net Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '8.0.x'
- name: Update Project Version
run: sed -i "s/\(<Version>\([0-9]\+\.\)\{2\}\)\([0-9]\+\)/\1${{ github.event.release.tag_name }}/" "./OmegaLeo.HelperLib.Documentation/OmegaLeo.HelperLib.Documentation.csproj"
- name: Create Nuget Package
run: dotnet pack "./OmegaLeo.HelperLib.Documentation/OmegaLeo.HelperLib.Documentation.csproj" -c Release /p:Version=${{ github.event.release.tag_name }} /p:PackageReleaseNotes="See https://github.com/omegaleo/OmegaLeo.HelperLib/releases/tag/${{ github.event.release.tag_name }}"
- name: Publish Nuget Package
run: dotnet nuget push ./OmegaLeo.HelperLib.Documentation/bin/Release/OmegaLeo.HelperLib.Documentation.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.nuget_api_key }} --source https://api.nuget.org/v3/index.json --skip-duplicate
- name: Publish to GitHub Packages
run: dotnet nuget push ./OmegaLeo.HelperLib.Documentation/bin/Release/OmegaLeo.HelperLib.Documentation.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
- name: Upload assets to release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.TOKEN }}
with:
upload_url: ${{ needs.get-release.outputs.upload_url }}
asset_path: ./OmegaLeo.HelperLib.Documentation/bin/Release/OmegaLeo.HelperLib.Documentation.${{ github.event.release.tag_name }}.nupkg
asset_name: OmegaLeo.HelperLib.Documentation.${{ github.event.release.tag_name }}.nupkg
asset_content_type: application/zip
publish-shared-lib:
runs-on: ubuntu-latest
needs: [ get-release ]
steps:
- uses: actions/checkout@v2
- name: Setup .Net Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '8.0.x'
- name: Update Project Version
run: sed -i "s/\(<Version>\([0-9]\+\.\)\{2\}\)\([0-9]\+\)/\1${{ github.event.release.tag_name }}/" "./OmegaLeo.HelperLib.Shared/OmegaLeo.HelperLib.Shared.csproj"
- name: Create Nuget Package
run: dotnet pack "./OmegaLeo.HelperLib.Shared/OmegaLeo.HelperLib.Shared.csproj" -c Release /p:Version=${{ github.event.release.tag_name }} /p:PackageReleaseNotes="See https://github.com/omegaleo/OmegaLeo.HelperLib/releases/tag/${{ github.event.release.tag_name }}"
- name: Publish Nuget Package
run: dotnet nuget push ./OmegaLeo.HelperLib.Shared/bin/Release/OmegaLeo.HelperLib.Shared.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.nuget_api_key }} --source https://api.nuget.org/v3/index.json --skip-duplicate
- name: Publish to GitHub Packages
run: dotnet nuget push ./OmegaLeo.HelperLib.Shared/bin/Release/OmegaLeo.HelperLib.Shared.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
- name: Upload assets to release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.TOKEN }}
with:
upload_url: ${{ needs.get-release.outputs.upload_url }}
asset_path: ./OmegaLeo.HelperLib.Shared/bin/Release/OmegaLeo.HelperLib.Shared.${{ github.event.release.tag_name }}.nupkg
asset_name: OmegaLeo.HelperLib.Shared.${{ github.event.release.tag_name }}.nupkg
asset_content_type: application/zip
Regular → Executable
+9
View File
@@ -3,3 +3,12 @@ obj/
/packages/
riderModule.iml
/_ReSharper.Caches/
/.vs
<<<<<<< Updated upstream
/OmegaLeo.HelperLib.Web
=======
/OmegaLeo.HelperLib.Web/.config
/OmegaLeo.HelperLib.Web/Properties/PublishProfiles
/OmegaLeo.HelperLib.Web/publish
>>>>>>> Stashed changes
/OmegaLeo.HelperLib.Web/OmegaLeo.HelperLib.Web.csproj.user
Generated Regular → Executable
View File
Generated Regular → Executable
View File
Generated Regular → Executable
View File
View File
View File
View File
View File
View File
View File
Generated Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
@@ -1,20 +0,0 @@
using System;
using NetFlow.DocumentationHelper.Library.Attributes;
namespace OmegaLeo.HelperLib.Changelog.Attributes
{
[Changelog("v1.0.0", "Created ChangelogAttribute to be used to register changes in the code.")]
[Documentation(nameof(ChangelogAttribute), "Attribute to annotate classes, methods, or properties with changelog information.")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)]
public class ChangelogAttribute : Attribute
{
public string Version { get; }
public string Description { get; }
public ChangelogAttribute(string version, string description)
{
Version = version;
Description = description;
}
}
}
+9 -3
View File
@@ -1,7 +1,13 @@
# Changelog
## Version 1.2.0
## Version v1.0.0
**OmegaLeo.HelperLib.Changelog.Helpers**
- **ChangelogHelper**:
- Created ChangelogHelper to generate markdown from changelog attributes.
- **Class: ChangelogTool**: Created the class ChangelogTool to extract changelogs via attributes
- **Class: ChangelogAttribute**: Created ChangelogAttribute to be used to register changes in the code.
## Version 1.0.0
**OmegaLeo.HelperLib.Changelog.Tools**
- **ChangelogTool**:
- Created the class ChangelogTool to extract changelogs via attributes
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using OmegaLeo.HelperLib.Shared.Attributes;
namespace OmegaLeo.HelperLib.Changelog.Helpers
{
[Documentation(nameof(ChangelogHelper),
"Helper class to generate changelog markdown from ChangelogAttributes in the provided Assemblies.")]
[Changelog("1.2.0", "Created ChangelogHelper to generate markdown from changelog attributes.")]
public static class ChangelogHelper
{
[Documentation(nameof(GetChangelogMarkdown),
"Generates a markdown formatted changelog from the changelog attributes in the provided assemblies.")]
public static string GetChangelogMarkdown(IEnumerable<Assembly> assemblies)
{
var changelog = new StringBuilder();
var entriesByVersionDate =
new Dictionary<(string Version, string Date),
Dictionary<string, List<(string ClassName, string Description)>>>();
foreach (var assembly in assemblies)
{
try
{
foreach (var type in assembly.GetTypes())
{
// Get type-level changelog attributes
var typeAttrs = type.GetCustomAttributes<ChangelogAttribute>().ToList();
// Get member-level changelog attributes (methods, properties, fields, etc.)
var memberAttrs = type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance)
.SelectMany(m => m.GetCustomAttributes<ChangelogAttribute>()
.Select(attr => (Member: m, Attribute: attr)))
.ToList();
if (typeAttrs.Any() || memberAttrs.Any())
{
var namespaceName = type.Namespace ?? "Global";
var className = type.Name.Split('`')[0];
// Process type-level attributes
foreach (var attr in typeAttrs)
{
AddEntry(entriesByVersionDate, namespaceName, className, attr.Version, attr.Date,
attr.Description);
}
// Process member-level attributes
foreach (var (member, attr) in memberAttrs)
{
var memberName = $"{className}.{member.Name}";
AddEntry(entriesByVersionDate, namespaceName, memberName, attr.Version, attr.Date,
attr.Description);
}
}
}
}
catch (ReflectionTypeLoadException)
{
// Skip assemblies that can't be fully loaded
}
}
foreach (var versionGroup in entriesByVersionDate.OrderByDescending(x => x.Key.Version))
{
changelog.AppendLine($"## Version {versionGroup.Key.Version}");
if (!string.IsNullOrEmpty(versionGroup.Key.Date))
{
changelog.AppendLine($"### {versionGroup.Key.Date}");
}
changelog.AppendLine();
foreach (var namespaceGroup in versionGroup.Value.OrderBy(x => x.Key))
{
changelog.AppendLine($"**{namespaceGroup.Key}**");
foreach (var entry in namespaceGroup.Value.OrderBy(x => x.ClassName))
{
changelog.AppendLine($@"- **{entry.ClassName}**:
- {entry.Description}");
}
changelog.AppendLine();
}
}
return changelog.ToString();
}
private static void AddEntry(
Dictionary<(string Version, string Date), Dictionary<string, List<(string ClassName, string Description)>>>
entriesByVersionDate,
string namespaceName,
string className,
string version,
string date,
string description)
{
var key = (version, date ?? string.Empty);
if (!entriesByVersionDate.ContainsKey(key))
entriesByVersionDate[key] = new Dictionary<string, List<(string, string)>>();
if (!entriesByVersionDate[key].ContainsKey(namespaceName))
entriesByVersionDate[key][namespaceName] = new List<(string, string)>();
entriesByVersionDate[key][namespaceName].Add((className, description));
}
}
}
View File
View File
+16 -6
View File
@@ -4,28 +4,38 @@
<TargetFramework>netstandard2.1</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>1.2.1.1</Version>
<Title>Omega Leo's Helper Library - Changelog</Title>
<Authors>Nuno "Omega Leo" Diogo</Authors>
<Description>Package to help with Changelog generation</Description>
<PackageProjectUrl>https://github.com/omegaleo/HelperLib</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/omegaleo/HelperLib</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<PackageLicenseExpression>AGPL-3.0-only</PackageLicenseExpression>
<PackageTags>csharp;dotnet;utility;helper;benchmark</PackageTags>
<RepositoryType>git</RepositoryType>
</PropertyGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\"/>
<None Include="CHANGELOG.md" Pack="true" PackagePath="\"/>
<None Include="LICENSE.md" Pack="true" PackagePath="\"/>
<None Include="README.md" Pack="true" PackagePath="\">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Include="CHANGELOG.md" Pack="true" PackagePath="\">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Include="LICENSE.md" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<Reference Include="NetFlow.DocumentationHelper.Library">
<HintPath>..\..\..\..\..\..\home\omegaleo\.nuget\packages\netflow.documentationhelper.library\1.1.2\lib\netstandard2.1\NetFlow.DocumentationHelper.Library.dll</HintPath>
<Reference Include="OmegaLeo.HelperLib.Documentation">
<HintPath>..\..\..\..\..\..\home\omegaleo\.nuget\packages\OmegaLeo.HelperLib.Documentation\1.1.2\lib\netstandard2.1\OmegaLeo.HelperLib.Documentation.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.2" />
<ProjectReference Include="..\OmegaLeo.HelperLib.Documentation\OmegaLeo.HelperLib.Documentation.csproj" />
<ProjectReference Include="..\OmegaLeo.HelperLib.Shared\OmegaLeo.HelperLib.Shared.csproj" />
</ItemGroup>
</Project>
+1 -1
View File
@@ -3,7 +3,7 @@ Package to help with Changelog generation by providing a new Changelog attribute
Example attribute usage:
```cs
[Changelog("v1.0.0", "This is a test")]
[Changelog("1.0.0", "This is a test")]
[Changelog("v1.0.1", "This is another test")]
public class Test
{
+2 -3
View File
@@ -2,12 +2,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using NetFlow.DocumentationHelper.Library.Attributes;
using OmegaLeo.HelperLib.Changelog.Attributes;
using OmegaLeo.HelperLib.Shared.Attributes;
namespace OmegaLeo.HelperLib.Changelog.Tools
{
[Changelog("v1.0.0", "Created the class ChangelogTool to extract changelogs via attributes")]
[Changelog("1.0.0", "Created the class ChangelogTool to extract changelogs via attributes")]
[Documentation("ChangelogTool", "Provides methods to extract changelog information from assembly attributes.")]
public class ChangelogTool
{
+2 -1
View File
@@ -2,13 +2,14 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\OmegaLeo.HelperLib.Changelog\OmegaLeo.HelperLib.Changelog.csproj" />
<ProjectReference Include="..\OmegaLeo.HelperLib.Game\OmegaLeo.HelperLib.Game.csproj" />
<ProjectReference Include="..\OmegaLeo.HelperLib\OmegaLeo.HelperLib.csproj" />
</ItemGroup>
+7 -2
View File
@@ -4,7 +4,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using GameDevLibrary.Helpers;
using OmegaLeo.HelperLib.Changelog.Helpers;
using OmegaLeo.HelperLib.Helpers;
using OmegaLeo.HelperLib.Changelog.Models;
using OmegaLeo.HelperLib.Changelog.Tools;
@@ -14,6 +15,9 @@ var changelogs = new Dictionary<string, Assembly>()
{
{Path.Join(root, "OmegaLeo.HelperLib.Changelog", "CHANGELOG.md"), typeof(Changelog).Assembly},
{Path.Join(root, "OmegaLeo.HelperLib", "CHANGELOG.md"), typeof(BenchmarkUtility).Assembly},
{Path.Join(root, "OmegaLeo.HelperLib.Game", "CHANGELOG.md"), typeof(OmegaLeo.HelperLib.Game.Models.ConsoleCommand).Assembly},
{Path.Join(root, "OmegaLeo.HelperLib.Documentation", "CHANGELOG.md"), typeof(OmegaLeo.HelperLib.Documentation.Helpers.DocumentationHelperTool).Assembly},
{Path.Join(root, "OmegaLeo.HelperLib.Shared", "CHANGELOG.md"), typeof(OmegaLeo.HelperLib.Shared.Attributes.ChangelogAttribute).Assembly},
};
foreach (var changelog in changelogs)
@@ -24,7 +28,8 @@ foreach (var changelog in changelogs)
void GenerateChangelog(string path, Assembly libraryAssembly)
{
var changelogMarkdown = ChangelogTool.GetMarkdown(libraryAssembly);
var changelogMarkdown = $@"# Changelog
{ChangelogHelper.GetChangelogMarkdown(new []{libraryAssembly})}";
File.WriteAllText(path,changelogMarkdown);
}
View File
+2 -2
View File
@@ -3,8 +3,8 @@
// /media/omegaleo/Development/Library Dev/HelperLib
using System.Reflection;
using GameDevLibrary.Extensions;
using GameDevLibrary.Helpers;
using OmegaLeo.HelperLib.Extensions;
using OmegaLeo.HelperLib.Helpers;
using LibGit2Sharp;
using OmegaLeo.HelperLib.Changelog.Tools;
using OmegaLeo.HelperLib.Git;
@@ -1,10 +0,0 @@
using OmegaLeo.HelperLib.Changelog.Attributes;
namespace OmegaLeo.HelperLib.ConsoleApp;
[Changelog("v1.0.0", "Test")]
[Changelog("v1.0.1", "Test 1")]
public class TestClass
{
}
@@ -0,0 +1,8 @@
# Changelog
## Version 1.2.0
### January 26, 2026
**OmegaLeo.HelperLib.Documentation.Helpers**
- **DocumentationHelperTool**:
- Migrated DocumentationHelper library from NetFlow.DocumentationHelper.Library to it's own package in OmegaLeo.HelperLib
@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using Microsoft.Extensions.DependencyModel;
using OmegaLeo.HelperLib.Shared.Attributes;
using OmegaLeo.HelperLib.Documentation.Models;
namespace OmegaLeo.HelperLib.Documentation.Helpers
{
[Changelog("1.2.0", "Migrated DocumentationHelper library from NetFlow.DocumentationHelper.Library to it's own package in OmegaLeo.HelperLib", "January 26, 2026")]
public static class DocumentationHelperTool
{
[Documentation("GenerateDocumentation (bool generateForPackageAssembly)",
@"Generates a List of objects of type DocumentationStructure that contain the following fields:
**AssemblyName**: Name of the main Assembly, used to identify the root namespace
**ClassName**: Name of the class, used to identify the upper level object
**Title**: Title what we're generating documentation for
**Description**: Description of what we're generating documentation for, this can contain usage examples and can use the args array to pass names(e.g.: This method uses this methodology)
**Args**: Array of strings that describe the parameters of the method or class
**CodeExample**: A code example of how to use the method or class
*Note: If generateForPackageAssembly is set to true, this will generate documentation for the library as well.*",
new []
{
"generateForPackageAssembly - Generate documentation for the DocumentationHelper library as well?"
},
@"```csharp
DocumentationHelperTool.GenerateDocumentation(true); // Generates documentation for all assemblies including the DocumentationHelper.Library package assembly
DocumentationHelperTool.GenerateDocumentation(false); // Generates documentation for all assemblies excluding the DocumentationHelper.Library package assembly
```")]
public static IEnumerable<DocumentationStructure> GenerateDocumentation(bool generateForPackageAssembly = false)
{
EnsureReferencedAssembliesLoaded();
var assemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !a.IsDynamic)
.Select(a =>
new DocumentationAssembly()
{
AssemblyName = a.GetName(false)?.Name ?? nameof(a),
Types = GetTypesWithDocumentationAttribute(a)
}).Where(x => x.Types.Any()).ToList();
if (!generateForPackageAssembly)
{
assemblies =
assemblies.Where(x => x.AssemblyName != typeof(DocumentationHelperTool).Assembly.GetName().Name)
.ToList();
}
foreach (var assembly in assemblies)
{
foreach (var type in assembly.Types)
{
var doc = GetDocumentation(type, assembly.AssemblyName);
yield return doc;
}
}
}
static void EnsureReferencedAssembliesLoaded()
{
try
{
var loadedNames = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.GetName(false) != null)
.Select(a => a.GetName(false).Name)
.ToHashSet(StringComparer.OrdinalIgnoreCase);
var deps = DependencyContext.Default?.RuntimeLibraries;
if (deps == null) return;
foreach (var lib in deps)
{
if (!loadedNames.Contains(lib.Name))
{
try
{
Assembly.Load(new AssemblyName(lib.Name));
}
catch (Exception ex)
{
Console.Error.WriteLine($"warning OMEGA001: Failed to load assembly '{lib.Name}': {ex.Message}");
}
}
}
}
catch (Exception ex)
{
// best-effort only
Console.Error.WriteLine($"warning OMEGA001: EnsureReferencedAssembliesLoaded failed: {ex.Message}");
}
}
static IEnumerable<Type> GetTypesWithDocumentationAttribute(Assembly assembly)
{
Type[] types;
try
{
types = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
types = ex.Types.Where(t => t != null).ToArray();
}
foreach (Type type in types)
{
if (type == null) continue;
var classHasDoc = type.GetCustomAttributes(typeof(DocumentationAttribute), true).Any();
var fieldsHaveDoc = type.GetFields()
.Any(f => f.GetCustomAttributes(typeof(DocumentationAttribute), true).Any());
var typesHaveDoc = type.GetProperties()
.Any(p => p.GetCustomAttributes(typeof(DocumentationAttribute), true).Any());
var methodsHaveDoc = type.GetMethods()
.Any(m => m.GetCustomAttributes(typeof(DocumentationAttribute), true).Any());
if (classHasDoc || fieldsHaveDoc || typesHaveDoc || methodsHaveDoc)
{
yield return type;
}
}
}
[Documentation(nameof(GetDocumentation), "Generates a DocumentationStructure object for the given Type and Assembly Name",
new []
{
"type - The Type to generate documentation for",
"assemblyName - The name of the assembly the Type belongs to"
},
@"```csharp
var doc = GetDocumentation(typeof(MyClass), ""MyAssembly"");
```")]
static DocumentationStructure GetDocumentation(Type type, string assemblyName)
{
var classDocs = type.GetCustomAttributes(typeof(DocumentationAttribute), true)
.Select(x => (DocumentationAttribute)x);
var fieldDocs = type.GetFields().SelectMany(f =>
f.GetCustomAttributes(typeof(DocumentationAttribute), true).Select(x => (DocumentationAttribute)x));
var propertyDocs = type.GetProperties().SelectMany(p =>
p.GetCustomAttributes(typeof(DocumentationAttribute), true).Select(x => (DocumentationAttribute)x));
var methodDocs = type.GetMethods().SelectMany(m =>
m.GetCustomAttributes(typeof(DocumentationAttribute), true).Select(x => (DocumentationAttribute)x));
var docStructure = new DocumentationStructure(assemblyName, type.Name);
foreach (var doc in classDocs)
{
docStructure.AddDescription(new DocumentationDescription(doc.Title, doc.Description, doc.Args, doc.CodeExample));
}
foreach (var doc in fieldDocs)
{
docStructure.AddDescription(new DocumentationDescription(doc.Title, doc.Description, doc.Args, doc.CodeExample));
}
foreach (var doc in propertyDocs)
{
docStructure.AddDescription(new DocumentationDescription(doc.Title, doc.Description, doc.Args, doc.CodeExample));
}
foreach (var doc in methodDocs)
{
docStructure.AddDescription(new DocumentationDescription(doc.Title, doc.Description, doc.Args, doc.CodeExample));
}
return docStructure;
}
static Dictionary<string, string> loadedXmlDocumentation =
new Dictionary<string, string>();
public static void LoadXmlDocumentation(string xmlDocumentation)
{
using (XmlReader xmlReader = XmlReader.Create(new StringReader(xmlDocumentation)))
{
while (xmlReader.Read())
{
if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == "member")
{
string raw_name = xmlReader["name"];
loadedXmlDocumentation[raw_name] = xmlReader.ReadInnerXml();
}
}
}
}
}
}
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
namespace OmegaLeo.HelperLib.Documentation.Models
{
public class DocumentationAssembly
{
public string AssemblyName;
public IEnumerable<Type> Types;
}
}
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using OmegaLeo.HelperLib.Shared.Attributes;
namespace OmegaLeo.HelperLib.Documentation.Models
{
public class DocumentationStructure
{
public string AssemblyName;
public string ClassName;
public List<DocumentationDescription> Descriptions;
public DocumentationStructure(string assemblyName, string className)
{
AssemblyName = assemblyName;
ClassName = className;
Descriptions = new List<DocumentationDescription>();
}
public void AddDescription(DocumentationDescription description)
{
Descriptions.Add(description);
}
}
public class DocumentationDescription
{
public string Title;
public string Description;
public string[] Parameters;
public string CodeExample = string.Empty;
[Documentation(nameof(DocumentationDescription), "Description of the current Documented object", new []
{
"title - Name of the object",
"description - Description of what the object does",
"parameters - The parameters for the object (in case of a method with parameters)",
"codeExample - Code example of how to use the object"
})]
public DocumentationDescription(string title, string description, string[] parameters = default, string codeExample = "")
{
Title = title;
Description = description;
Parameters = parameters ?? Array.Empty<string>();
CodeExample = codeExample;
}
}
}
@@ -0,0 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>OmegaLeo.HelperLib.Documentation</RootNamespace>
<Version>1.2.1.1</Version>
<Title>Omega Leo's Helper Library</Title>
<Authors>Nuno "Omega Leo" Diogo</Authors>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageProjectUrl>https://github.com/omegaleo/HelperLib</PackageProjectUrl>
<RepositoryUrl>https://github.com/omegaleo/HelperLib</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<PackageLicenseExpression>AGPL-3.0-only</PackageLicenseExpression>
<PackageTags>csharp;dotnet;utility;helper;documentation;</PackageTags>
<RepositoryType>git</RepositoryType>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="10.0.2" />
</ItemGroup>
<ItemGroup>
<Folder Include="Attributes\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OmegaLeo.HelperLib.Shared\OmegaLeo.HelperLib.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\" />
<None Include="CHANGELOG.md" Pack="true" PackagePath="\" />
<None Update="README.md">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Update="CHANGELOG.md">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,30 @@
# Omega Leo's Helper Library - Documentation
Package to help with generating and managing documentation for your C# projects.
## Features
- Attribute-based documentation: Use custom attributes to annotate your classes, methods, and properties with documentation comments.
- Documentation extraction tool: A tool to extract and format documentation into various formats (Markdown, HTML, etc.).
- Integration with build processes: Easily integrate documentation generation into your CI/CD pipelines.
## Example attribute usage:
```cs
[Documentation("GenerateDocumentation (bool generateForPackageAssembly)",
@"Generates a List of objects of type DocumentationStructure that contain the following fields:
**AssemblyName**: Name of the main Assembly, used to identify the root namespace
**ClassName**: Name of the class, used to identify the upper level object
**Title**: Title what we're generating documentation for
**Description**: Description of what we're generating documentation for, this can contain usage examples and can use the args array to pass names(e.g.: This method uses this methodology)
**Args**: Array of strings that describe the parameters of the method or class
**CodeExample**: A code example of how to use the method or class
*Note: If generateForPackageAssembly is set to true, this will generate documentation for the library as well.*",
new []
{
"generateForPackageAssembly - Generate documentation for the DocumentationHelper library as well?"
},
@"```csharp
DocumentationHelperTool.GenerateDocumentation(true); // Generates documentation for all assemblies including the DocumentationHelper.Library package assembly
DocumentationHelperTool.GenerateDocumentation(false); // Generates documentation for all assemblies excluding the DocumentationHelper.Library package assembly
```")]
public static IEnumerable<DocumentationStructure> GenerateDocumentation(bool generateForPackageAssembly = false)
```
+1
View File
@@ -0,0 +1 @@
# Changelog
+11
View File
@@ -1,10 +1,21 @@
using System.Collections.Generic;
using OmegaLeo.HelperLib.Shared.Attributes;
using OmegaLeo.HelperLib.Game.Models;
namespace OmegaLeo.HelperLib.Game.Extensions
{
public static class ListExtensions
{
[Documentation(nameof(Shuffle),
"Shuffles the elements of the list in place using the provided RandomNumberGenerator.",
null,
@"```csharp
var list = new List<int> { 1, 2, 3, 4};
var rng = new RandomNumberGenerator();
// List before: [1, 2, 3, 4]
list.Shuffle(rng);
// List after: [3, 1, 4, 2] (example output)
```")]
public static void Shuffle<T>(this IList<T> list, RandomNumberGenerator rng)
{
for (int i = list.Count - 1; i > 0; i--)
+8
View File
@@ -1,7 +1,12 @@
using OmegaLeo.HelperLib.Shared.Attributes;
using OmegaLeo.HelperLib.Game.Models;
namespace OmegaLeo.HelperLib.Game.Handlers
{
[Documentation(nameof(DelayedActionHandler), "Handler for managing delayed actions, allowing cancellation and status checking.", null, @"```csharp
var action = new DelayedAction(...);
var handler = new DelayedActionHandler(action);
```")]
public class DelayedActionHandler
{
private readonly DelayedAction _action;
@@ -11,6 +16,9 @@ namespace OmegaLeo.HelperLib.Game.Handlers
_action = action;
}
[Documentation(nameof(Cancel), "Cancels the delayed action if it has not yet executed.", null, @"```csharp
handler.Cancel();
```")]
public void Cancel()
{
if (_action != null)
View File
View File
View File
View File
View File
View File
View File
+14 -2
View File
@@ -4,11 +4,14 @@
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
<Title>Omega Leo's Helper Library - Game Logic</Title>
<Version>0.0.2</Version>
<Version>1.2.1.1</Version>
<Authors>Nuno "Omega Leo" Diogo</Authors>
<PackageProjectUrl>https://github.com/omegaleo/HelperLib</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/omegaleo/HelperLib/blob/main/LICENSE</PackageLicenseUrl>
<RepositoryUrl>https://github.com/omegaleo/HelperLib</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<PackageLicenseExpression>AGPL-3.0-only</PackageLicenseExpression>
<PackageTags>csharp;dotnet;utility;helper;benchmark</PackageTags>
<RepositoryType>git</RepositoryType>
</PropertyGroup>
<ItemGroup>
@@ -19,4 +22,13 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
</ItemGroup>
<ItemGroup>
<None Update="README.md">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Update="CHANGELOG.md">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
View File
View File
View File
View File
-1
View File
@@ -1 +0,0 @@
# OmegaLeo's Helper Library - Game Logic
+8
View File
@@ -0,0 +1,8 @@
# OmegaLeo's Helper Library - Game Logic
Lightweight utility library for C# projects and game development helpers.
## Features
- Game development specific helpers and utilities
- Helpers for common game development tasks
- Easy to integrate into existing projects
- Open source under the AGPL v3 License
+1 -1
View File
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NetFlow.DocumentationHelper.Library.Attributes;
using OmegaLeo.HelperLib.Shared.Attributes;
using OmegaLeo.HelperLib.Game.Models;
namespace OmegaLeo.HelperLib.Game.Services
+1 -1
View File
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using NetFlow.DocumentationHelper.Library.Attributes;
using OmegaLeo.HelperLib.Shared.Attributes;
using OmegaLeo.HelperLib.Game.Handlers;
using OmegaLeo.HelperLib.Game.Models;
+1 -1
View File
@@ -1,6 +1,6 @@
using System;
using System.IO;
using NetFlow.DocumentationHelper.Library.Attributes;
using OmegaLeo.HelperLib.Shared.Attributes;
using Newtonsoft.Json;
using OmegaLeo.HelperLib.Game.Interfaces;
View File
View File
+1 -1
View File
@@ -1,6 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using NetFlow.DocumentationHelper.Library.Attributes;
using OmegaLeo.HelperLib.Shared.Attributes;
using OmegaLeo.HelperLib.Game.Models;
namespace OmegaLeo.HelperLib.Game.Utilities
+1 -1
View File
@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using GameDevLibrary.Extensions;
using OmegaLeo.HelperLib.Extensions;
using LibGit2Sharp;
using OmegaLeo.HelperLib.Git.Models;
View File
+1 -2
View File
@@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>GameDevLibrary.Git</RootNamespace>
<RootNamespace>OmegaLeo.HelperLib.Git</RootNamespace>
<Version>0.0.2</Version>
<Title>Omega Leo's Helper Library - LibGit2Sharp Implementation</Title>
<Authors>Nuno "Omega Leo" Diogo</Authors>
@@ -13,7 +13,6 @@
<ItemGroup>
<PackageReference Include="LibGit2Sharp" Version="0.30.0"/>
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.2"/>
</ItemGroup>
<ItemGroup>
+32
View File
@@ -0,0 +1,32 @@
using System;
namespace OmegaLeo.HelperLib.Shared.Attributes
{
[Documentation(nameof(ChangelogAttribute), "Attribute to annotate classes, methods, or properties with changelog information.",
new []
{
"Version - Changelog version",
"Description - Description of what was changed",
"Date - Date of the changes (Optional)"
},
@"```cs
[Changelog(""1.0.0"", ""Created ChangelogAttribute to be used to register changes in the code."")]
public class ChangelogAttribute : Attribute" )]
[Changelog("1.0.0", "Created ChangelogAttribute to be used to register changes in the code.")]
[Changelog("1.2.1", "Created documentation for ChangelogAttribute.", "January 28, 2026")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)]
public class ChangelogAttribute : Attribute
{
public string Version { get; }
public string Description { get; }
public string Date { get; set; }
public ChangelogAttribute(string version, string description, string date = "")
{
Version = version;
Description = description;
Date = date;
}
}
}
@@ -0,0 +1,45 @@
using System;
namespace OmegaLeo.HelperLib.Shared.Attributes
{
[System.AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
[Changelog("1.2.1", "Created documentation for DocumentationAttribute.", "January 28, 2026")]
[Documentation("DocumentationAttribute",
"Attribute to annotate classes, methods, or properties with documentation information.",
new string[]
{
"title: The title of the documentation.",
"description: A brief description.",
"args: An array of argument descriptions.",
"codeExample: An optional code example."
},
@"```csharp
[Documentation(
""MyMethod"",
""This method does something important."",
new string[] { ""param1: The first parameter."", ""param2: The second parameter."" },
""MyMethod(param1, param2);""
)]
public void MyMethod(string param1, int param2)
{
// Method implementation
}
```
"
)]
public class DocumentationAttribute : Attribute
{
public string Title;
public string Description;
public string[] Args;
public string CodeExample = string.Empty;
public DocumentationAttribute(string title, string description, string[] args = null, string codeExample = "")
{
Title = title;
Description = description;
Args = args ?? Array.Empty<string>();
CodeExample = codeExample;
}
}
}
+16
View File
@@ -0,0 +1,16 @@
# Changelog
## Version 1.2.1
### January 28, 2026
**OmegaLeo.HelperLib.Shared.Attributes**
- **ChangelogAttribute**:
- Created documentation for ChangelogAttribute.
- **DocumentationAttribute**:
- Created documentation for DocumentationAttribute.
## Version 1.0.0
**OmegaLeo.HelperLib.Shared.Attributes**
- **ChangelogAttribute**:
- Created ChangelogAttribute to be used to register changes in the code.
@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>OmegaLeo.HelperLib.Shared</RootNamespace>
<Version>1.2.1.1</Version>
<Title>Omega Leo's Helper Library - Shared Components</Title>
<Authors>Nuno "Omega Leo" Diogo</Authors>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageProjectUrl>https://github.com/omegaleo/HelperLib</PackageProjectUrl>
<RepositoryUrl>https://github.com/omegaleo/HelperLib</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<PackageLicenseExpression>AGPL-3.0-only</PackageLicenseExpression>
<PackageTags>csharp;dotnet;</PackageTags>
<RepositoryType>git</RepositoryType>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Include="CHANGELOG.md" Pack="true" PackagePath="\">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
+4
View File
@@ -0,0 +1,4 @@
# Omega Leo's Helper Library - Shared Components
Lightweight utility library for C# projects.
This library contains shared components and utilities that are used by other packages in the Omega Leo's Helper Library suite.
+274 -38
View File
@@ -1,9 +1,13 @@
// File: `OmegaLeo.HelperLib.Web/Controllers/HomeController.cs`
using System.Diagnostics;
using System.Reflection;
using GameDevLibrary.Helpers;
using System.Runtime.ExceptionServices;
using OmegaLeo.HelperLib.Helpers;
using Microsoft.AspNetCore.Mvc;
using NetFlow.DocumentationHelper.Library.Helpers;
using OmegaLeo.HelperLib.Changelog.Helpers;
using OmegaLeo.HelperLib.Documentation.Helpers;
using OmegaLeo.HelperLib.Documentation.Models;
using OmegaLeo.HelperLib.Changelog.Tools;
using OmegaLeo.HelperLib.Web.Models;
@@ -25,31 +29,49 @@ public class HomeController : Controller
if (_libraryCache != null) return;
var root = GetSolutionRoot();
_logger.LogInformation("Initializing libraries from base directory: {Root}", root);
_libraryCache = new Dictionary<string, LibraryDocumentationViewModel>
{
["core"] = GenerateLibraryDocs(
typeof(BenchmarkUtility).Assembly,
Path.Join(root, "OmegaLeo.HelperLib", "CHANGELOG.md"),
Path.Combine(root, "changelogs", "OmegaLeo.HelperLib.CHANGELOG.md"),
"Core Library",
"Core utilities and helper functions for general C# development",
"OmegaLeo.HelperLib"
),
["changelog"] = GenerateLibraryDocs(
typeof(Changelog.Models.Changelog).Assembly,
Path.Join(root, "OmegaLeo.HelperLib.Changelog", "CHANGELOG.md"),
Path.Combine(root, "changelogs", "OmegaLeo.HelperLib.Changelog.CHANGELOG.md"),
"Changelog Library",
"Tools for managing and generating changelogs",
"OmegaLeo.HelperLib.Changelog"
),
["game"] = GenerateLibraryDocs(
typeof(OmegaLeo.HelperLib.Game.Models.ConsoleCommand).Assembly,
Path.Join(root, "OmegaLeo.HelperLib.Game", "CHANGELOG.md"),
Path.Combine(root, "changelogs", "OmegaLeo.HelperLib.Game.CHANGELOG.md"),
"Game Development Library",
"Game development utilities for Unity and Godot",
"OmegaLeo.HelperLib.Game"
)
),
["documentation"] = GenerateLibraryDocs(
typeof(OmegaLeo.HelperLib.Documentation.Helpers.DocumentationHelperTool).Assembly,
Path.Combine(root, "changelogs", "OmegaLeo.HelperLib.Documentation.CHANGELOG.md"),
"Documentation Library",
"Tools for generating documentation from code attributes",
"OmegaLeo.HelperLib.Documentation",
true
),
["shared"] = GenerateLibraryDocs(
typeof(OmegaLeo.HelperLib.Shared.Attributes.ChangelogAttribute).Assembly,
Path.Combine(root, "shared", "OmegaLeo.HelperLib.Shared.CHANGELOG.md"),
"Shared Library",
"Library of shared attributes and utilities used across other OmegaLeo.HelperLib packages",
"OmegaLeo.HelperLib.Shared"
),
};
_logger.LogInformation("Initialized {Count} libraries", _libraryCache.Count);
}
public IActionResult Index()
@@ -62,7 +84,18 @@ public class HomeController : Controller
if (string.IsNullOrEmpty(id) || !_libraryCache.ContainsKey(id))
return NotFound();
return View(_libraryCache[id]);
var cache = _libraryCache[id];
if (cache.Documentation.Any())
{
_logger.LogInformation($"Found cache for {id}: {cache.Documentation.Count} entries");
}
else
{
_logger.LogError($"Cache for {id} is empty!");
}
return View(cache);
}
public IActionResult Privacy()
@@ -76,55 +109,258 @@ public class HomeController : Controller
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
private LibraryDocumentationViewModel GenerateLibraryDocs(Assembly assembly, string changelogPath, string displayName, string description, string nugetPackageId)
private void LogDocumentationHelperInfo()
{
var allDocumentation = DocumentationHelperTool.GenerateDocumentation();
var assemblyName = assembly.GetName().Name;
try
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var target = assemblies.FirstOrDefault(a =>
a.GetName().Name.Equals("OmegaLeo.HelperLib.Documentation", StringComparison.OrdinalIgnoreCase));
var filteredDocumentation = allDocumentation
.Where(d => d.AssemblyName.Equals(assemblyName, StringComparison.OrdinalIgnoreCase))
.OrderBy(d => d.ClassName)
if (target == null)
{
_logger.LogWarning("OmegaLeo.HelperLib.Documentation not loaded. Loaded assemblies ({Count}):",
assemblies.Length);
foreach (var a in assemblies.OrderBy(a => a.GetName().Name))
{
_logger.LogInformation(" {Name} {Version} => {Location}", a.GetName().Name, a.GetName().Version,
SafeLocation(a));
}
return;
}
_logger.LogInformation("Found {Name} {Version} at {Location}", target.GetName().Name,
target.GetName().Version, SafeLocation(target));
Type attrType = null;
try
{
attrType = target.GetType("OmegaLeo.HelperLib.Documentation.Attributes.DocumentationAttribute",
false, true);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to GetType for DocumentationAttribute in {Assembly}",
target.GetName().Name);
}
if (attrType == null)
{
_logger.LogWarning("Type 'DocumentationAttribute' not found in {Assembly}.", target.GetName().Name);
}
else
{
var ctors = attrType.GetConstructors(BindingFlags.Public | BindingFlags.Instance |
BindingFlags.NonPublic);
if (!ctors.Any())
_logger.LogWarning("No constructors found on DocumentationAttribute in {Assembly}.",
target.GetName().Name);
foreach (var ctor in ctors)
{
var sig = string.Join(", ", ctor.GetParameters().Select(p => p.ParameterType.Name + " " + p.Name));
_logger.LogInformation("DocumentationAttribute ctor: ({Signature})", sig);
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to log DocumentationHelper assembly info.");
}
static string SafeLocation(Assembly a)
{
try
{
return string.IsNullOrEmpty(a.Location) ? "<in-memory>" : a.Location;
}
catch
{
return "<unknown>";
}
}
}
private void InspectDocumentationHelperMethod()
{
try
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
Type helperType = null;
foreach (var asm in assemblies)
{
try
{
var t = asm.GetTypes().FirstOrDefault(tt =>
tt.Name.Equals("DocumentationHelperTool", StringComparison.OrdinalIgnoreCase)
|| tt.FullName?.EndsWith(".DocumentationHelperTool") == true);
if (t != null)
{
helperType = t;
break;
}
}
catch (ReflectionTypeLoadException rtlex)
{
_logger.LogDebug(rtlex, "Could not enumerate types in {Assembly}", asm.GetName().Name);
foreach (var loaderEx in rtlex.LoaderExceptions ?? Array.Empty<Exception>())
_logger.LogDebug(loaderEx, "Loader exception for {Assembly}", asm.GetName().Name);
}
catch (Exception ex)
{
_logger.LogDebug(ex, "Failed enumerating types in {Assembly}", asm.GetName().Name);
}
}
if (helperType == null)
{
_logger.LogWarning("DocumentationHelperTool type not found in loaded assemblies.");
return;
}
_logger.LogInformation("DocumentationHelperTool found: {Type} in {Assembly} ({Location})",
helperType.FullName, helperType.Assembly.GetName().Name, SafeLocation(helperType.Assembly));
var method = helperType.GetMethod("GenerateDocumentation",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
if (method == null)
{
_logger.LogWarning("GenerateDocumentation method not found on {Type}.", helperType.FullName);
}
else
{
var parameters = string.Join(", ",
method.GetParameters().Select(p => p.ParameterType.Name + " " + p.Name));
_logger.LogInformation("Method: {Name} ({Parameters}) -> {ReturnType}", method.Name, parameters,
method.ReturnType.FullName);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to inspect DocumentationHelperTool type/method.");
}
static string SafeLocation(Assembly a)
{
try
{
return string.IsNullOrEmpty(a.Location) ? "<in-memory>" : a.Location;
}
catch
{
return "<unknown>";
}
}
}
private LibraryDocumentationViewModel GenerateLibraryDocs(Assembly assembly, string changelogPath,
string displayName, string description, string nugetPackageId, bool generateForDocumentationAssembly = false)
{
_logger.LogInformation("=== Starting GenerateLibraryDocs for {Assembly} ===", assembly.GetName().Name);
_logger.LogInformation("Assembly location: {Location}", assembly.Location ?? "<in-memory>");
_logger.LogInformation("Changelog path: {Path}", changelogPath);
_logger.LogInformation("Changelog exists: {Exists}", System.IO.File.Exists(changelogPath));
// Log types in assembly and their attributes
try
{
var types = assembly.GetTypes();
_logger.LogInformation("Assembly {Name} contains {Count} types", assembly.GetName().Name, types.Length);
var typesWithDocAttr = types.Where(t =>
t.GetCustomAttributes().Any(a =>
a.GetType().Name.Contains("Documentation", StringComparison.OrdinalIgnoreCase)))
.ToList();
string changelogMarkdown = "";
_logger.LogInformation("Found {Count} types with DocumentationAttribute-like attributes",
typesWithDocAttr.Count);
if (typesWithDocAttr.Any())
{
foreach (var type in typesWithDocAttr.Take(5))
{
_logger.LogInformation(" Type with doc attr: {TypeName}", type.FullName);
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to inspect assembly types");
}
LogDocumentationHelperInfo();
IEnumerable<DocumentationStructure> allDocumentation = Enumerable.Empty<DocumentationStructure>();
try
{
// Pass the specific assembly to only scan that assembly
var result = DocumentationHelperTool.GenerateDocumentation(generateForDocumentationAssembly);
allDocumentation = result?
.Where(d => d.AssemblyName?.Equals(assembly.GetName().Name ,StringComparison.OrdinalIgnoreCase) == true)
.ToList() ?? Enumerable.Empty<DocumentationStructure>();
_logger.LogInformation("GenerateDocumentation returned {Count} items for {Assembly}",
allDocumentation.Count(), assembly.GetName().Name);
if (!allDocumentation.Any())
{
_logger.LogWarning(
"No documentation items generated for {Assembly}. Check if types have [Documentation] attribute applied.",
assembly.GetName().Name);
}
}
catch (MissingMethodException mmex)
{
_logger.LogError(mmex,
"Missing method when calling DocumentationHelperTool.GenerateDocumentation(). Possible assembly mismatch.");
InspectDocumentationHelperMethod();
ExceptionDispatchInfo.Capture(mmex).Throw();
}
catch (Exception ex)
{
_logger.LogError(ex, "DocumentationHelperTool.GenerateDocumentation threw an exception.");
InspectDocumentationHelperMethod();
throw;
}
/*var changelogMarkdown = string.Empty;
if (System.IO.File.Exists(changelogPath))
{
changelogMarkdown = ChangelogTool.GetMarkdown(assembly);
}
string version = assembly.GetCustomAttribute<System.Reflection.AssemblyInformationalVersionAttribute>()?.InformationalVersion
?? assembly.GetName().Version?.ToString()
?? "1.0.0";
if (version.Contains('+'))
try
{
version = version.Substring(0, version.IndexOf('+'));
ChangelogTool.ExtractChangelog(assembly);
changelogMarkdown = ChangelogTool.GetMarkdown(assembly);
_logger.LogInformation("Parsed changelog for {Assembly}", assembly.GetName().Name);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to parse changelog at {Path}", changelogPath);
}
}
else
{
_logger.LogWarning("Changelog file not found at {Path}", changelogPath);
}*/
return new LibraryDocumentationViewModel
var viewModel = new LibraryDocumentationViewModel
{
LibraryName = displayName,
Description = description,
Version = version,
NuGetPackageId = nugetPackageId,
Documentation = filteredDocumentation,
ChangelogMarkdown = changelogMarkdown
ChangelogMarkdown = ChangelogHelper.GetChangelogMarkdown(new []{assembly}),
Documentation = allDocumentation.ToList()
};
_logger.LogInformation(
"=== Completed GenerateLibraryDocs for {Assembly}. Total documentation items: {Count} ===",
assembly.GetName().Name, viewModel.Documentation.Count);
return viewModel;
}
static string GetSolutionRoot()
{
string dir = AppContext.BaseDirectory;
while (!string.IsNullOrEmpty(dir))
{
if (Directory.GetFiles(dir, "*.sln").Length > 0)
return dir;
dir = Directory.GetParent(dir)?.FullName;
}
throw new Exception("Solution root not found.");
return AppContext.BaseDirectory;
}
}
View File
+1 -1
View File
@@ -1,5 +1,5 @@
// File: `OmegaLeo.HelperLib.Web/Models/LibraryDocumentationViewModel.cs`
using NetFlow.DocumentationHelper.Library.Models;
using OmegaLeo.HelperLib.Documentation.Models;
namespace OmegaLeo.HelperLib.Web.Models
{
+4 -1
View File
@@ -15,7 +15,10 @@
<ItemGroup>
<PackageReference Include="Markdig" Version="0.40.0" />
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.2" />
<PackageReference Include="MarkdigExtensions.SyntaxHighlighting" Version="1.0.3" />
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
</ItemGroup>
</Project>
+15
View File
@@ -1,8 +1,23 @@
using Serilog;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
// Configure logging
// Configure Serilog
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console()
.WriteTo.File(
path: Path.Combine(AppContext.BaseDirectory, "logs", "documentation-.txt"),
rollingInterval: RollingInterval.Day,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.CreateLogger();
builder.Host.UseSerilog();
var app = builder.Build();
// Configure the HTTP request pipeline.
View File
View File
+16 -1
View File
@@ -1,8 +1,16 @@
@* File: `OmegaLeo.HelperLib.Web/Views/Home/Library.cshtml` *@
@using ColorCode.Styling
@using OmegaLeo.HelperLib.Extensions
@using Markdig
@model OmegaLeo.HelperLib.Web.Models.LibraryDocumentationViewModel
@{
ViewData["Title"] = Model.LibraryName;
var groupedByNamespace = Model.Documentation.GroupBy(d => d.AssemblyName).OrderBy(g => g.Key);
var pipeline = new MarkdownPipelineBuilder()
.UseAdvancedExtensions()
.UseSyntaxHighlighting(StyleDictionary.DefaultDark)
.Build();
}
<div class="container-fluid mt-4">
@@ -75,7 +83,14 @@
{
<tr>
<td><code>@desc.Title</code></td>
<td>@Html.Raw(desc.Description)</td>
<td>@Html.Raw(Markdig.Markdown.ToHtml(desc.Description))<br/>
@if (desc.CodeExample.IsNotNullOrEmpty())
{
<strong>Example:</strong><br/>
<div class="example-code mb-2">
@Html.Raw(Markdig.Markdown.ToHtml(desc.CodeExample, pipeline))
</div>
}</td>
</tr>
}
</tbody>
View File
View File
+14 -6
View File
@@ -33,6 +33,20 @@
<li class="nav-item">
<a class="nav-link" asp-area="" asp-controller="Home" asp-action="Library" asp-route-id="game">Game Dev</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-area="" asp-controller="Home" asp-action="Library" asp-route-id="documentation">Documentation</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-area="" asp-controller="Home" asp-action="Library" asp-route-id="shared">Shared Components</a>
</li>
</ul>
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="https://github.com/omegaleo/HelperLib" target="_blank" rel="noopener noreferrer" aria-label="GitHub repository">
<i class="bi bi-github" style="font-size:1.25rem;"></i> View on Github
</a>
</li>
</ul>
</div>
</div>
@@ -42,12 +56,6 @@
@RenderBody()
</main>
<footer class="border-top footer text-muted">
<div class="container">
&copy; @DateTime.Now.Year - OmegaLeo Helper Libraries
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
View File
View File
View File
View File
View File
+2 -1
View File
@@ -5,5 +5,6 @@
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"https_port": 443
}
+18
View File
@@ -20,3 +20,21 @@ html {
body {
margin-bottom: 60px;
}
pre {
overflow: auto;
padding: 1rem;
background-color: #495057;
position: relative;
color: #f2f2f2;
}
code {
background-color: transparent !important;
}
.example-code > div {
border-radius: 0.5rem !important;
background-color: #495057 !important;
}
View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File
View File
View File
View File
View File
View File
View File
View File
View File
View File

Some files were not shown because too many files have changed in this diff Show More