diff --git a/.docfx/docfx.json b/.docfx/docfx.json
index 1a56bb210..79276251a 100644
--- a/.docfx/docfx.json
+++ b/.docfx/docfx.json
@@ -126,7 +126,7 @@
],
"globalMetadata": {
"_appTitle": "Cuemon for .NET",
- "_appFooter": "Generated by DocFX. Copyright 2008-2025 Geekle. All rights reserved. Code with passion; love your work; deploy with confidence 👨💻️🔥❤️🚀😎",
+ "_appFooter": "Generated by DocFX. Copyright 2008-2026 Geekle. All rights reserved. Code with passion; love your work; deploy with confidence 👨💻️🔥❤️🚀😎",
"_appLogoPath": "images/50x50.png",
"_appFaviconPath": "images/favicon.ico",
"_googleAnalyticsTagId": "UA-126254455-1",
diff --git a/.github/prompts/nuget.prompt.md b/.github/prompts/nuget.prompt.md
index b87302c13..19a08c146 100644
--- a/.github/prompts/nuget.prompt.md
+++ b/.github/prompts/nuget.prompt.md
@@ -19,7 +19,7 @@ Behavior (exact):
Exact template to prepend (preserve whitespace and trailing NBSP U+00A0 on the blank lines):
```
-Version {{version}}
+Version: {{version}}
Availability: {{previous-tfm}}
# ALM
diff --git a/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt
index 1c6b7ae5f..f51a821fa 100644
--- a/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt
index b9645f238..ce201931a 100644
--- a/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt
index 2868c236d..3e6bdf67a 100644
--- a/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt
index 1c6b7ae5f..f51a821fa 100644
--- a/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt
index 4474d088a..90816b1fe 100644
--- a/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt b/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt
index 71e1a8e8c..b68b28ab3 100644
--- a/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Core/PackageReleaseNotes.txt b/.nuget/Cuemon.Core/PackageReleaseNotes.txt
index d7e5e43f8..9a6dbdd68 100644
--- a/.nuget/Cuemon.Core/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Core/PackageReleaseNotes.txt
@@ -1,3 +1,19 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
+# New Features
+- ADDED StatisticalRegionInfo class in the Cuemon.Globalization namespace that provides information about a specific statistical region
+- ADDED StatisticalRegionKind enum in the Cuemon.Globalization namespace that defines the kind of statistical region
+
+# Improvements
+- EXTENDED World class in the Cuemon.Globalization namespace with a new method: GetStatisticalRegions, which retrieves a list of statistical regions for a given UN M.49 country code
+- EXTENDED World class in the Cuemon.Globalization namespace with a new method: GetCountry, which retrieves the country information for a given UN M.49 country code
+- EXTENDED World class in the Cuemon.Globalization namespace with a new method: GetCountry, which retrieves the country information for a given RegionInfo object
+- EXTENDED World class in the Cuemon.Globalization namespace with a new property: StatisticalRegions, which retrieves a list of all statistical regions
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
@@ -176,4 +192,4 @@ Availability: .NET 9, .NET 8 and .NET Standard 2.0
- EXTENDED Validator class in the Cuemon namespace with five new methods: ThrowIfContainsReservedKeyword, ThrowIfNotDifferent, ThrowIfDifferent, ThrowIfContainsAny and ThrowIfNotContainsAny
- CHANGED Validator class in the Cuemon namespace to comply with RSPEC-3343
- EXTENDED Decorator class in the Cuemon namespace with an additional method: RawEnclose
-
+
\ No newline at end of file
diff --git a/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt b/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt b/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt
index 0e2f14faa..7ab29b5c1 100644
--- a/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Data/PackageReleaseNotes.txt b/.nuget/Cuemon.Data/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Data/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Data/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt b/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt
index 1c6b7ae5f..f51a821fa 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt
index 7473937a7..fcfe6c936 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt
index 25ee99e93..0ffcff9b8 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt
index 1c6b7ae5f..f51a821fa 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt
index 2e3aa7803..61894afa5 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt
index f24e0b8a8..69b021a55 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt
index 2bd17ec9a..94702133e 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt
index 150fb8e0b..c585a6399 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt
index e7f0af0c3..8ad2e3567 100644
--- a/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt
@@ -1,3 +1,12 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
+# New Features
+- ADDED StatisticalRegionExtensions class in the Cuemon.Extensions.Globalization that consist of extension methods for the StatisticalRegionInfo class: IsWorld, IsRegion, IsSubregion, IsIntermediateRegion, IsCountryOrTerritory, IsArea, HasIsoCodes and HasRegionInfo
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
@@ -111,4 +120,4 @@ Availability: .NET 9, .NET 8 and .NET Standard 2.0
- ADDED HierarchyOptions class in the Cuemon.Extensions.Runtime namespace that represents a set of options to configure the behavior of the Hierarchy and HierarchySerializer class
- ADDED IHierarchy interface in the Cuemon.Extensions.Runtime namespace that defines a way to expose a node of a hierarchical structure
- ADDED HierarchySerializer class in the Cuemon.Extensions.Runtime.Serialization namespace that provides a way to serialize objects to nodes of IHierarchy
-
+
\ No newline at end of file
diff --git a/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt
index ec911b020..9fa1f66d6 100644
--- a/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt
index 0178f16a4..418efc05a 100644
--- a/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt
index b8c3448df..0b442770a 100644
--- a/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9, .NET Standard 2.1 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9, .NET Standard 2.1 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt
index e533bc877..6f726f4c9 100644
--- a/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt
index e43413641..6a13da61f 100644
--- a/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt
index 5f7bee570..62d0e6973 100644
--- a/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.IO/PackageReleaseNotes.txt b/.nuget/Cuemon.IO/PackageReleaseNotes.txt
index 1c4338aba..cf32854f0 100644
--- a/.nuget/Cuemon.IO/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.IO/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Net/PackageReleaseNotes.txt b/.nuget/Cuemon.Net/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Net/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Net/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt b/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt b/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt
index 8ca44e4f0..6ca36d8ed 100644
--- a/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt b/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt
index ed5002378..cab0250b3 100644
--- a/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Threading/PackageReleaseNotes.txt b/.nuget/Cuemon.Threading/PackageReleaseNotes.txt
index a1eca3734..495b11908 100644
--- a/.nuget/Cuemon.Threading/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Threading/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Xml/PackageReleaseNotes.txt
index 83c0d1d12..905bff1d3 100644
--- a/.nuget/Cuemon.Xml/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Xml/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.2.0
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version 10.1.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 000000000..2c1c48a56
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,123 @@
+# AGENTS.md
+
+Purpose
+- This file guides agentic coding tools working in this repo.
+- Follow the repo rules first; do not invent commands or conventions.
+
+Repository Basics
+- Workspace root: this file lives in repo root.
+- Solution lives at repo root (see `.docfx/index.md`).
+- Projects:
+ - `src/` = packages shipped to NuGet.
+ - `test/` = unit and functional tests.
+ - `tuning/` = BenchmarkDotNet benchmarks.
+ - `tooling/` = internal tools.
+
+Toolchain
+- .NET targets: net10.0, net9.0, netstandard2.0 (source); tests also net48 on Windows.
+- Use `dotnet` CLI; CI runs on Linux and Windows.
+
+Build Commands
+- Build solution (all): `dotnet build -c Release`
+- Build a project: `dotnet build src/Cuemon.Core/Cuemon.Core.csproj -c Release`
+- Pack (if needed): `dotnet pack -c Release`
+
+Lint / Analyzers
+- No separate lint command is defined.
+- Code style is enforced during build (`EnforceCodeStyleInBuild=true`).
+- For tests and benchmarks, analyzers are disabled (see `Directory.Build.props`).
+- Prefer build to surface style issues: `dotnet build -c Release`.
+
+Test Commands
+- Run all tests in a project:
+ - `dotnet test test/Cuemon.Core.Tests/Cuemon.Core.Tests.csproj -c Release`
+- Run a single test (recommended):
+ - `dotnet test test/Cuemon.Core.Tests/Cuemon.Core.Tests.csproj -c Release --filter "FullyQualifiedName~DateSpanTest.Parse_ShouldGetOneMonthOfDifference_UsingIso8601String"`
+- Run all tests under `test/`:
+ - `dotnet test -c Release test/`
+
+Integration Tests (SQL Server)
+- CI runs `test/Cuemon.Data.SqlClient.Tests.csproj` with a SQL Server container.
+- Expect a connection string env var:
+ - `CONNECTIONSTRINGS__ADVENTUREWORKS` (see CI workflow).
+- Use docker compose if you need local parity.
+
+Benchmarks (BenchmarkDotNet)
+- Benchmarks live under `tuning/` and are not unit tests.
+- Use `tooling/bdn-runner` to run benchmarks when needed.
+
+Cursor Rules
+- None found in `.cursor/rules/` or `.cursorrules`.
+
+Copilot Rules (must follow)
+- Source: `.github/copilot-instructions.md`.
+- Tests must inherit `Codebelt.Extensions.Xunit.Test` and use `using Xunit;`.
+- Do NOT use `Xunit.Abstractions` or `using Xunit.Abstractions`.
+- Test namespaces MUST match the SUT namespace (no `.Tests` suffix).
+- Test class names end with `Test`.
+- Do not use `InternalsVisibleTo`; test through public APIs.
+- Benchmarks follow the benchmark prompt and naming rules.
+- XML doc comments should match existing style for public/protected APIs.
+
+Code Style and Conventions
+
+General Principles (from `.docfx/index.md`)
+- Follow Framework Design Guidelines and Microsoft Engineering Guidelines.
+- Prefer SOLID, DRY, and separation of concerns.
+- Do not duplicate code; apply the boy scout rule.
+
+Formatting
+- Indentation: 4 spaces for `.cs` and `.vb` (`.editorconfig`).
+- XML files: 2 spaces.
+- Many modern style analyzers are disabled; keep existing style in files.
+
+Imports
+- Keep `using` directives explicit and minimal.
+- Follow existing ordering in the file; do not auto-reorder unless needed.
+
+Types and Language Features
+- Avoid style rules that are explicitly disabled in `.editorconfig`:
+ - No forced switch expressions, using declarations, or primary constructors.
+ - Avoid forced collection expressions for arrays/empty/initializers.
+ - Avoid forced expression-bodied members.
+- Use explicit types when it improves clarity; do not blindly enforce `var`.
+
+Naming
+- Public API naming follows .NET Framework Design Guidelines.
+- Test class names end with `Test`; benchmark class names end with `Benchmark`.
+- Namespaces for tests/benchmarks match the production namespace exactly.
+
+Error Handling
+- Use guard clauses and `Validator.ThrowIfNull` style patterns where present.
+- Prefer deterministic, testable error paths; avoid swallowing exceptions.
+
+Extension Methods
+- Extension methods belong only in `Cuemon.Extensions.*` projects.
+- Non-extension assemblies must hide extension-like APIs via `IDecorator`.
+
+Tests (Unit / Functional)
+- Base class: `Test` from `Codebelt.Extensions.Xunit`.
+- Use `[Fact]` for unit tests, `[Theory]` for parameterized tests.
+- Keep tests deterministic and isolated; prefer fakes/stubs/spies.
+- Avoid mocking unless necessary; Moq allowed in special cases.
+- Never mock `IMarshaller`; use `new JsonMarshaller()` instead.
+
+Benchmarks
+- Namespace matches production namespace; no `.Benchmarks` suffix.
+- Place under `tuning/` in matching benchmark project.
+- Use `[MemoryDiagnoser]` and `[GroupBenchmarksBy]` where relevant.
+- Use deterministic data and `GlobalSetup` for expensive prep.
+
+Docs / XML Comments
+- Public and protected members should have XML doc comments.
+- Follow existing wording and style; see `.github/copilot-instructions.md`.
+
+Release Notes
+- Package release notes live under `.nuget//PackageReleaseNotes.txt`.
+- Keep notes updated for public API changes.
+
+Suggested Workflow for Agents
+- Identify correct project location (src/test/tuning/tooling).
+- Follow namespace and naming rules before writing code.
+- Build or run targeted tests when changing logic.
+- Keep changes minimal and consistent with local style.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 19ad092db..08da81d72 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
For more details, please refer to `PackageReleaseNotes.txt` on a per assembly basis in the `.nuget` folder.
+## [10.2.0] - 2026-02-09
+
+This is a minor release that introduces support for UN M.49 statistical regions and countries.
+
+### Added
+
+- `StatisticalRegionInfo` class in the Cuemon.Globalization namespace that provides information about a specific statistical region,
+- `StatisticalRegionKind` enum in the Cuemon.Globalization namespace that defines the kind of statistical region,
+- `StatisticalRegionExtensions` class in the Cuemon.Extensions.Globalization namespace that consist of extension methods for the `StatisticalRegionInfo` class: `IsWorld`, `IsRegion`, `IsSubregion`, `IsIntermediateRegion`, `IsCountryOrTerritory`, `IsArea`, `HasIsoCodes` and `HasRegionInfo`.
+
+### Changed
+
+- `World` class in the Cuemon.Globalization namespace with a new method: `GetStatisticalRegions`, which retrieves a list of statistical regions for a given UN M.49 country code,
+- `World` class in the Cuemon.Globalization namespace with a new method: `GetCountry`, which retrieves the country information for a given UN M.49 country code,
+- `World` class in the Cuemon.Globalization namespace with a new method: `GetCountry`, which retrieves the country information for a given `RegionInfo` object,
+- `World` class in the Cuemon.Globalization namespace with a new property: `StatisticalRegions`, which retrieves a list of all statistical regions.
+
## [10.1.2] - 2026-01-21
This is a service update that focuses on package dependencies.
diff --git a/LICENSE.md b/LICENSE.md
index 0d0f96b79..1baff2c6b 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,5 +1,5 @@
MIT
-Copyright (c) 2009-2025 Geekle
+Copyright (c) 2009-2026 Geekle
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
diff --git a/src/Cuemon.Core/Cuemon.Core.csproj b/src/Cuemon.Core/Cuemon.Core.csproj
index 6a27f18e6..5d2ea3a9c 100644
--- a/src/Cuemon.Core/Cuemon.Core.csproj
+++ b/src/Cuemon.Core/Cuemon.Core.csproj
@@ -10,7 +10,11 @@
Cuemon
Cuemon
The Cuemon namespace contains fundamental types such as value and reference types, factories and utility classes, interfaces, attributes and feature rich delegates that support functional programming on a whole new level. The namespace is an addition to the System namespace.
- action-factory calculator configure configure-revert configure-exchange configurable condition options-pattern decorator delimited-string disposable finalize-disposable safe-invoke safe-invoke-async func-factory patterns reference-project clean-architecture clean-code task-action-factory task-func-factory template template-factory time-range time-unit validator guard text-encoding parser-factory security aes-cryptor cyclic-redundancy-check fowler-noll-vo-hash hash-factory hash-result keyed-crypto-hash keyed-crypto-algorithm message-digest non-crypto-algorithm unkeyed-crypto-hash
+ action-factory calculator configure configure-revert configure-exchange configurable condition options-pattern decorator delimited-string disposable finalize-disposable safe-invoke safe-invoke-async func-factory patterns reference-project clean-architecture clean-code task-action-factory task-func-factory template template-factory time-range time-unit validator guard text-encoding parser-factory security aes-cryptor cyclic-redundancy-check fowler-noll-vo-hash hash-factory hash-result keyed-crypto-hash keyed-crypto-algorithm message-digest non-crypto-algorithm unkeyed-crypto-hash globalization unm49 region country m49
+
+
+
+
diff --git a/src/Cuemon.Core/Globalization/StatisticalRegionInfo.cs b/src/Cuemon.Core/Globalization/StatisticalRegionInfo.cs
new file mode 100644
index 000000000..814cede52
--- /dev/null
+++ b/src/Cuemon.Core/Globalization/StatisticalRegionInfo.cs
@@ -0,0 +1,217 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace Cuemon.Globalization
+{
+ ///
+ /// Represents a geographic region or country as defined by the UN M.49 standard.
+ ///
+ ///
+ /// UN M.49 is a standard for representing country and area codes for statistical use.
+ /// This class provides a unified view of the hierarchy, treating countries as leaf nodes
+ /// in the region tree. Each instance has a that identifies its level
+ /// in the hierarchy (World, Region, Subregion, IntermediateRegion, or CountryOrTerritory).
+ /// Source: https://unstats.un.org/unsd/methodology/m49/
+ ///
+ public sealed class StatisticalRegionInfo
+ {
+ private readonly List _children = new();
+
+ ///
+ /// Initializes a new instance of the class for a region.
+ ///
+ /// The UN M.49 numeric code.
+ /// The region name.
+ /// The kind of region.
+ /// The parent region, or null for World.
+ /// or is null.
+ /// or is empty.
+ internal StatisticalRegionInfo(string code, string name, StatisticalRegionKind kind, StatisticalRegionInfo parent)
+ {
+ Validator.ThrowIfNullOrEmpty(code);
+ Validator.ThrowIfNullOrEmpty(name);
+
+ Code = code;
+ Name = name;
+ Kind = kind;
+ Parent = parent;
+ }
+
+ ///
+ /// Initializes a new instance of the class for a country.
+ ///
+ /// The UN M.49 numeric code.
+ /// The country name.
+ /// The ISO 3166-1 alpha-2 code.
+ /// The ISO 3166-1 alpha-3 code.
+ /// The parent region.
+ /// Whether this is a Least Developed Country.
+ /// Whether this is a Land Locked Developing Country.
+ /// Whether this is a Small Island Developing State.
+ /// The .NET RegionInfo, or null if not available.
+ /// or is null.
+ /// or is empty.
+ internal StatisticalRegionInfo(
+ string code,
+ string name,
+ string isoAlpha2,
+ string isoAlpha3,
+ StatisticalRegionInfo parent,
+ bool isLeastDevelopedCountry,
+ bool isLandLockedDevelopingCountry,
+ bool isSmallIslandDevelopingState,
+ RegionInfo region)
+ {
+ Validator.ThrowIfNullOrEmpty(code);
+ Validator.ThrowIfNullOrEmpty(name);
+
+ Code = code;
+ Name = name;
+ Kind = StatisticalRegionKind.CountryOrTerritory;
+ Parent = parent;
+ IsoAlpha2 = isoAlpha2;
+ IsoAlpha3 = isoAlpha3;
+ IsLeastDevelopedCountry = isLeastDevelopedCountry;
+ IsLandLockedDevelopingCountry = isLandLockedDevelopingCountry;
+ IsSmallIslandDevelopingState = isSmallIslandDevelopingState;
+ Region = region;
+ }
+
+ ///
+ /// Gets the UN M.49 numeric code for this region or country.
+ ///
+ /// The three-digit UN M.49 code (e.g., "001" for World, "840" for United States).
+ public string Code { get; }
+
+ ///
+ /// Gets the official UN name of this region or country.
+ ///
+ /// The name (e.g., "World", "Europe", "United States of America").
+ public string Name { get; }
+
+ ///
+ /// Gets the kind of this statistical region.
+ ///
+ /// A value indicating the hierarchy level.
+ public StatisticalRegionKind Kind { get; }
+
+ ///
+ /// Gets the parent region in the UN M.49 hierarchy.
+ ///
+ /// The parent region, or null if this is the World region (code "001").
+ public StatisticalRegionInfo Parent { get; internal set; }
+
+ ///
+ /// Gets the direct child regions or countries of this region.
+ ///
+ /// An enumerable list of children. Empty list if this is a leaf node (country).
+ public IEnumerable Children => _children;
+
+ ///
+ /// Gets all countries in this geographic region.
+ ///
+ /// An enumerable list of child regions where is .
+ ///
+ /// This is a convenience property that filters to return only countries.
+ /// It recursively includes all descendant countries, not just immediate children.
+ ///
+ public IEnumerable Countries => GetAllDescendants()
+ .Where(r => r.Kind == StatisticalRegionKind.CountryOrTerritory)
+ .ToList();
+
+ ///
+ /// Gets the ISO 3166-1 alpha-2 code for this country.
+ ///
+ /// The two-letter ISO code (e.g., "US", "DE"), or null if this is not a country.
+ public string IsoAlpha2 { get; }
+
+ ///
+ /// Gets the ISO 3166-1 alpha-3 code for this country.
+ ///
+ /// The three-letter ISO code (e.g., "USA", "DEU"), or null if this is not a country.
+ public string IsoAlpha3 { get; }
+
+ ///
+ /// Gets the .NET for this country if available.
+ ///
+ /// The RegionInfo instance, or null if not a country or not supported by the OS.
+ ///
+ /// Some territories (e.g., "British Indian Ocean Territory") may not have OS-level support.
+ ///
+ public RegionInfo Region { get; }
+
+ ///
+ /// Gets a value indicating whether this country is classified as a Least Developed Country (LDC).
+ ///
+ /// true if this is an LDC; otherwise, false. Always false for non-countries.
+ public bool IsLeastDevelopedCountry { get; }
+
+ ///
+ /// Gets a value indicating whether this country is classified as a Land Locked Developing Country (LLDC).
+ ///
+ /// true if this is an LLDC; otherwise, false. Always false for non-countries.
+ public bool IsLandLockedDevelopingCountry { get; }
+
+ ///
+ /// Gets a value indicating whether this country is classified as a Small Island Developing State (SIDS).
+ ///
+ /// true if this is a SIDS; otherwise, false. Always false for non-countries.
+ public bool IsSmallIslandDevelopingState { get; }
+
+ ///
+ /// Gets all ancestor regions in the hierarchy up to and including World.
+ ///
+ /// An enumerable of ancestor regions, ordered from immediate parent to World.
+ public IEnumerable GetAncestors()
+ {
+ var current = Parent;
+ while (current != null)
+ {
+ yield return current;
+ current = current.Parent;
+ }
+ }
+
+ ///
+ /// Gets all descendant regions and countries recursively.
+ ///
+ /// An enumerable of all descendants in the hierarchy.
+ public IEnumerable GetAllDescendants()
+ {
+ foreach (var child in Children)
+ {
+ yield return child;
+ foreach (var descendant in child.GetAllDescendants())
+ {
+ yield return descendant;
+ }
+ }
+ }
+
+ ///
+ /// Adds a child region to this region.
+ ///
+ /// The child region to add.
+ /// This region is a country and cannot have children.
+ internal void AddChild(StatisticalRegionInfo child)
+ {
+ if (Kind == StatisticalRegionKind.CountryOrTerritory)
+ {
+ throw new InvalidOperationException("Countries cannot have child regions.");
+ }
+
+ _children.Add(child);
+ }
+
+ ///
+ /// Returns a string that represents the current object.
+ ///
+ /// A string that represents the current object.
+ public override string ToString()
+ {
+ return $"{Name} ({Code})";
+ }
+ }
+}
diff --git a/src/Cuemon.Core/Globalization/StatisticalRegionKind.cs b/src/Cuemon.Core/Globalization/StatisticalRegionKind.cs
new file mode 100644
index 000000000..60c8a4f3a
--- /dev/null
+++ b/src/Cuemon.Core/Globalization/StatisticalRegionKind.cs
@@ -0,0 +1,37 @@
+namespace Cuemon.Globalization
+{
+ ///
+ /// Specifies the kind of a statistical region as defined by the UN M.49 standard.
+ ///
+ ///
+ /// UN M.49 defines a hierarchical structure of geographic regions for statistical use.
+ /// This enum represents the different levels in that hierarchy, from World down to individual countries.
+ ///
+ public enum StatisticalRegionKind
+ {
+ ///
+ /// The root node representing the entire World (code "001").
+ ///
+ World,
+
+ ///
+ /// A major geographic region or continent (e.g., Africa, Europe, Asia).
+ ///
+ Region,
+
+ ///
+ /// A subdivision of a region (e.g., Western Europe, Northern Africa).
+ ///
+ Subregion,
+
+ ///
+ /// An intermediate region that groups subregions (e.g., Latin America and the Caribbean).
+ ///
+ IntermediateRegion,
+
+ ///
+ /// A country or territory - a leaf node in the hierarchy with no children.
+ ///
+ CountryOrTerritory
+ }
+}
diff --git a/src/Cuemon.Core/Globalization/UnM49DataContainer.cs b/src/Cuemon.Core/Globalization/UnM49DataContainer.cs
new file mode 100644
index 000000000..302843638
--- /dev/null
+++ b/src/Cuemon.Core/Globalization/UnM49DataContainer.cs
@@ -0,0 +1,310 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using Cuemon.Reflection;
+
+namespace Cuemon.Globalization;
+
+internal sealed class UnM49DataContainer
+{
+ internal UnM49DataContainer()
+ {
+ var (regions, countries) = LoadUnM49Data();
+ BuildHierarchy(regions, countries);
+ }
+
+ internal List Regions { get; } = new();
+
+ internal Dictionary RegionsByCode { get; } = new();
+
+ internal Dictionary CountriesByCode { get; } = new();
+
+ internal Dictionary CountriesByIsoAlpha2 { get; } = new(StringComparer.OrdinalIgnoreCase);
+
+ private (List Regions, List Countries) LoadUnM49Data()
+ {
+ var resourceName = $"{nameof(Cuemon)}.{nameof(Globalization)}.unm49-data.csv";
+ var regions = new List();
+ var countries = new List();
+
+ using (var stream = Decorator.Enclose(typeof(StatisticalRegionInfo).Assembly).GetManifestResources(resourceName)
+ .Single().Value)
+ {
+ if (stream == null)
+ {
+ throw new InvalidOperationException($"Embedded resource '{resourceName}' not found.");
+ }
+
+ using (var reader = new StreamReader(stream))
+ {
+ // Skip header line
+ reader.ReadLine();
+
+ string line;
+ while ((line = reader.ReadLine()) != null)
+ {
+ var parts = ParseCsvLine(line);
+ if (parts.Length < 5) continue;
+
+ var type = parts[0];
+ var code = parts[1];
+ var name = parts[2];
+ var parentCode = parts[3];
+ var kind = parts[4];
+
+ if (type == "Region")
+ {
+ regions.Add(new Unm49RegionData
+ {
+ Code = code,
+ Name = name,
+ ParentCode = string.IsNullOrEmpty(parentCode) ? null : parentCode,
+ Kind = kind
+ });
+ }
+ else if (type == "Country" && parts.Length >= 10)
+ {
+ countries.Add(new Unm49CountryData
+ {
+ Code = code,
+ Name = name,
+ ParentCode = parentCode,
+ Kind = kind,
+ IsoAlpha2 = string.IsNullOrEmpty(parts[5]) ? null : parts[5],
+ IsoAlpha3 = string.IsNullOrEmpty(parts[6]) ? null : parts[6],
+ Ldc = parts[7] == "true",
+ Lldc = parts[8] == "true",
+ Sids = parts[9] == "true"
+ });
+ }
+ }
+ }
+ }
+
+ return (regions, countries);
+ }
+
+ private static string[] ParseCsvLine(string line)
+ {
+ var parts = new List();
+ var current = new System.Text.StringBuilder();
+ bool inQuotes = false;
+
+ for (int i = 0; i < line.Length; i++)
+ {
+ char c = line[i];
+
+ if (c == '"')
+ {
+ if (inQuotes && i + 1 < line.Length && line[i + 1] == '"')
+ {
+ // Escaped quote
+ current.Append('"');
+ i++;
+ }
+ else
+ {
+ inQuotes = !inQuotes;
+ }
+ }
+ else if (c == ',' && !inQuotes)
+ {
+ parts.Add(current.ToString());
+ current.Clear();
+ }
+ else
+ {
+ current.Append(c);
+ }
+ }
+
+ parts.Add(current.ToString());
+ return parts.ToArray();
+ }
+
+ private void BuildHierarchy(List regions, List countries)
+ {
+ // First pass: Create all region objects
+ foreach (var regionData in regions)
+ {
+ var kind = ParseKind(regionData.Kind, regionData.Code, regionData.Name);
+ var region = new StatisticalRegionInfo(regionData.Code, regionData.Name, kind, null);
+ Regions.Add(region);
+ RegionsByCode[regionData.Code] = region;
+ }
+
+ // Second pass: Set up parent-child relationships for regions
+ foreach (var regionData in regions)
+ {
+ if (!string.IsNullOrEmpty(regionData.ParentCode) &&
+ RegionsByCode.TryGetValue(regionData.ParentCode, out var parent))
+ {
+ var region = RegionsByCode[regionData.Code];
+ region.Parent = parent;
+ parent.AddChild(region);
+ }
+ }
+
+ // Third pass: Create country objects as children of their parent regions
+ foreach (var countryData in countries)
+ {
+ if (RegionsByCode.TryGetValue(countryData.ParentCode, out var parent))
+ {
+ // Validate kind is CountryOrTerritory
+ var kind = ParseKind(countryData.Kind, countryData.Code, countryData.Name);
+ if (kind != StatisticalRegionKind.CountryOrTerritory)
+ {
+ throw new InvalidOperationException(
+ $"Country {countryData.Name} ({countryData.Code}) must have kind 'CountryOrTerritory', but was '{countryData.Kind}'.");
+ }
+
+ // Try to find matching RegionInfo
+ RegionInfo regionInfo = null;
+ try
+ {
+ regionInfo = World.Regions.FirstOrDefault(r => string.Equals(r.TwoLetterISORegionName, countryData.IsoAlpha2, StringComparison.OrdinalIgnoreCase));
+ }
+ catch
+ {
+ // Some territories may not be supported by the OS
+ }
+
+ var country = new StatisticalRegionInfo(
+ countryData.Code,
+ countryData.Name,
+ countryData.IsoAlpha2,
+ countryData.IsoAlpha3,
+ parent,
+ countryData.Ldc,
+ countryData.Lldc,
+ countryData.Sids,
+ regionInfo);
+
+ CountriesByCode[countryData.Code] = country;
+ if (!string.IsNullOrEmpty(countryData.IsoAlpha2))
+ {
+ CountriesByIsoAlpha2[countryData.IsoAlpha2] = country;
+ }
+
+ // Add country as child of its immediate parent region
+ parent.AddChild(country);
+ }
+ }
+
+ // Validate hierarchy integrity
+ ValidateHierarchy();
+ }
+
+ private static StatisticalRegionKind ParseKind(string kindString, string code, string name)
+ {
+ if (string.IsNullOrEmpty(kindString))
+ {
+ throw new InvalidOperationException($"Kind is missing for entry {name} ({code}).");
+ }
+
+ if (!Enum.TryParse(kindString, out var kind))
+ {
+ throw new InvalidOperationException(
+ $"Unknown kind '{kindString}' for entry {name} ({code}).");
+ }
+
+ return kind;
+ }
+
+ private void ValidateHierarchy()
+ {
+ // Validate World has no parent
+ if (!RegionsByCode.TryGetValue("001", out var world) || world == null)
+ {
+ throw new InvalidOperationException("World region (code '001') is missing.");
+ }
+
+ if (world.Parent != null)
+ {
+ throw new InvalidOperationException("World region must not have a parent.");
+ }
+
+ if (world.Kind != StatisticalRegionKind.World)
+ {
+ throw new InvalidOperationException("World region must have kind 'World'.");
+ }
+
+ // Validate all non-World regions have a parent
+ foreach (var region in Regions)
+ {
+ if (region.Code != "001" && region.Parent == null)
+ {
+ throw new InvalidOperationException(
+ $"Region {region.Name} ({region.Code}) must have a parent.");
+ }
+ }
+
+ // Validate countries have no children
+ foreach (var country in CountriesByCode.Values)
+ {
+ if (country.Children.Any())
+ {
+ throw new InvalidOperationException(
+ $"Country {country.Name} ({country.Code}) cannot have children.");
+ }
+
+ if (country.Kind != StatisticalRegionKind.CountryOrTerritory)
+ {
+ throw new InvalidOperationException(
+ $"Country {country.Name} ({country.Code}) must have kind 'CountryOrTerritory'.");
+ }
+ }
+
+ // Validate hierarchy depth does not exceed reasonable limits
+ foreach (var region in Regions)
+ {
+ var depth = GetDepth(region);
+ if (depth > 4)
+ {
+ throw new InvalidOperationException(
+ $"Region {region.Name} ({region.Code}) exceeds maximum hierarchy depth of 4 (actual: {depth}).");
+ }
+ }
+ }
+
+ private static int GetDepth(StatisticalRegionInfo region)
+ {
+ int depth = 0;
+ var current = region;
+ while (current.Parent != null)
+ {
+ depth++;
+ current = current.Parent;
+ }
+ return depth;
+ }
+
+ ///
+ /// Internal class for CSV deserialization of UN M.49 region data.
+ ///
+ private sealed class Unm49RegionData
+ {
+ public string Code { get; set; }
+ public string Name { get; set; }
+ public string ParentCode { get; set; }
+ public string Kind { get; set; }
+ }
+
+ ///
+ /// Internal class for CSV deserialization of UN M.49 country data.
+ ///
+ private sealed class Unm49CountryData
+ {
+ public string Code { get; set; }
+ public string Name { get; set; }
+ public string ParentCode { get; set; }
+ public string IsoAlpha2 { get; set; }
+ public string IsoAlpha3 { get; set; }
+ public bool Ldc { get; set; }
+ public bool Lldc { get; set; }
+ public bool Sids { get; set; }
+ public string Kind { get; set; }
+ }
+}
diff --git a/src/Cuemon.Core/Globalization/World.cs b/src/Cuemon.Core/Globalization/World.cs
index 55ba4f55f..c6ed1eb75 100644
--- a/src/Cuemon.Core/Globalization/World.cs
+++ b/src/Cuemon.Core/Globalization/World.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -32,12 +32,61 @@ public static class World
return regions.Values;
});
+ private static readonly Lazy UnM49Data = new(() => new UnM49DataContainer());
+
///
/// Gets the by .NET specific regions of the world.
///
/// The .NET specific regions of the world.
public static IEnumerable Regions { get; } = SpecificRegions.Value;
+ ///
+ /// Gets all UN M.49 geographic regions.
+ ///
+ /// A read-only list of all instances.
+ ///
+ /// The list includes the World region (code "001") and all geographic regions.
+ /// The collection is immutable and cached for the lifetime of the application.
+ ///
+ public static IReadOnlyList StatisticalRegions { get; } = UnM49Data.Value.Regions;
+
+ ///
+ /// Gets a region or country by its UN M.49 code.
+ ///
+ /// The three-digit UN M.49 code (e.g., "001" for World, "840" for United States).
+ /// A instance, or null if the code is not found.
+ public static StatisticalRegionInfo GetStatisticalRegion(string code)
+ {
+ if (string.IsNullOrEmpty(code)) return null;
+ UnM49Data.Value.RegionsByCode.TryGetValue(code, out var region);
+ return region;
+ }
+
+ ///
+ /// Gets a country by its UN M.49 code.
+ ///
+ /// The three-digit UN M.49 country code (e.g., "840" for United States).
+ /// A instance with , or null if the code is not found.
+ public static StatisticalRegionInfo GetCountry(string m49Code)
+ {
+ if (string.IsNullOrEmpty(m49Code)) return null;
+ UnM49Data.Value.CountriesByCode.TryGetValue(m49Code, out var country);
+ return country;
+ }
+
+ ///
+ /// Gets the UN M.49 country information for the specified .
+ ///
+ /// The .NET region information.
+ /// A instance, or null if no mapping exists.
+ /// is null.
+ public static StatisticalRegionInfo GetCountry(RegionInfo region)
+ {
+ Validator.ThrowIfNull(region);
+ UnM49Data.Value.CountriesByIsoAlpha2.TryGetValue(region.TwoLetterISORegionName, out var country);
+ return country;
+ }
+
///
/// Resolves a sequence of related objects for the specified .
///
diff --git a/src/Cuemon.Core/Globalization/unm49-data.csv b/src/Cuemon.Core/Globalization/unm49-data.csv
new file mode 100644
index 000000000..f47978e33
--- /dev/null
+++ b/src/Cuemon.Core/Globalization/unm49-data.csv
@@ -0,0 +1,279 @@
+Type,Code,Name,ParentCode,Kind,IsoAlpha2,IsoAlpha3,Ldc,Lldc,Sids
+Region,001,World,,World,,,,,
+Region,002,Africa,001,Region,,,,,
+Region,009,Oceania,001,Region,,,,,
+Region,010,Antarctica,001,Region,,,,,
+Region,019,Americas,001,Region,,,,,
+Region,142,Asia,001,Region,,,,,
+Region,150,Europe,001,Region,,,,,
+Region,005,South America,419,Subregion,,,,,
+Region,011,Western Africa,202,Subregion,,,,,
+Region,013,Central America,419,Subregion,,,,,
+Region,014,Eastern Africa,202,Subregion,,,,,
+Region,015,Northern Africa,002,Subregion,,,,,
+Region,017,Middle Africa,202,Subregion,,,,,
+Region,018,Southern Africa,202,Subregion,,,,,
+Region,021,Northern America,019,Subregion,,,,,
+Region,029,Caribbean,419,Subregion,,,,,
+Region,030,Eastern Asia,142,Subregion,,,,,
+Region,034,Southern Asia,142,Subregion,,,,,
+Region,035,South-eastern Asia,142,Subregion,,,,,
+Region,039,Southern Europe,150,Subregion,,,,,
+Region,053,Australia and New Zealand,009,Subregion,,,,,
+Region,054,Melanesia,009,Subregion,,,,,
+Region,057,Micronesia,009,Subregion,,,,,
+Region,061,Polynesia,009,Subregion,,,,,
+Region,143,Central Asia,142,Subregion,,,,,
+Region,145,Western Asia,142,Subregion,,,,,
+Region,151,Eastern Europe,150,Subregion,,,,,
+Region,154,Northern Europe,150,Subregion,,,,,
+Region,155,Western Europe,150,Subregion,,,,,
+Region,202,Sub-Saharan Africa,002,IntermediateRegion,,,,,
+Region,419,Latin America and the Caribbean,019,IntermediateRegion,,,,,
+Country,012,Algeria,015,CountryOrTerritory,DZ,DZA,false,false,false
+Country,818,Egypt,015,CountryOrTerritory,EG,EGY,false,false,false
+Country,434,Libya,015,CountryOrTerritory,LY,LBY,false,false,false
+Country,504,Morocco,015,CountryOrTerritory,MA,MAR,false,false,false
+Country,729,Sudan,015,CountryOrTerritory,SD,SDN,true,false,false
+Country,788,Tunisia,015,CountryOrTerritory,TN,TUN,false,false,false
+Country,732,Western Sahara,015,CountryOrTerritory,EH,ESH,false,false,false
+Country,086,British Indian Ocean Territory,014,CountryOrTerritory,IO,IOT,false,false,false
+Country,108,Burundi,014,CountryOrTerritory,BI,BDI,true,true,false
+Country,174,Comoros,014,CountryOrTerritory,KM,COM,true,false,true
+Country,262,Djibouti,014,CountryOrTerritory,DJ,DJI,true,false,false
+Country,232,Eritrea,014,CountryOrTerritory,ER,ERI,true,false,false
+Country,231,Ethiopia,014,CountryOrTerritory,ET,ETH,true,true,false
+Country,260,French Southern Territories,014,CountryOrTerritory,TF,ATF,false,false,false
+Country,404,Kenya,014,CountryOrTerritory,KE,KEN,false,false,false
+Country,450,Madagascar,014,CountryOrTerritory,MG,MDG,true,false,false
+Country,454,Malawi,014,CountryOrTerritory,MW,MWI,true,true,false
+Country,480,Mauritius,014,CountryOrTerritory,MU,MUS,false,false,true
+Country,175,Mayotte,014,CountryOrTerritory,YT,MYT,false,false,false
+Country,508,Mozambique,014,CountryOrTerritory,MZ,MOZ,true,false,false
+Country,638,Réunion,014,CountryOrTerritory,RE,REU,false,false,false
+Country,646,Rwanda,014,CountryOrTerritory,RW,RWA,true,true,false
+Country,690,Seychelles,014,CountryOrTerritory,SC,SYC,false,false,true
+Country,706,Somalia,014,CountryOrTerritory,SO,SOM,true,false,false
+Country,728,South Sudan,014,CountryOrTerritory,SS,SSD,true,true,false
+Country,800,Uganda,014,CountryOrTerritory,UG,UGA,true,true,false
+Country,834,United Republic of Tanzania,014,CountryOrTerritory,TZ,TZA,true,false,false
+Country,894,Zambia,014,CountryOrTerritory,ZM,ZMB,true,true,false
+Country,716,Zimbabwe,014,CountryOrTerritory,ZW,ZWE,false,true,false
+Country,024,Angola,017,CountryOrTerritory,AO,AGO,true,false,false
+Country,120,Cameroon,017,CountryOrTerritory,CM,CMR,false,false,false
+Country,140,Central African Republic,017,CountryOrTerritory,CF,CAF,true,true,false
+Country,148,Chad,017,CountryOrTerritory,TD,TCD,true,true,false
+Country,178,Congo,017,CountryOrTerritory,CG,COG,false,false,false
+Country,180,Democratic Republic of the Congo,017,CountryOrTerritory,CD,COD,true,false,false
+Country,226,Equatorial Guinea,017,CountryOrTerritory,GQ,GNQ,false,false,false
+Country,266,Gabon,017,CountryOrTerritory,GA,GAB,false,false,false
+Country,678,Sao Tome and Principe,017,CountryOrTerritory,ST,STP,false,false,true
+Country,072,Botswana,018,CountryOrTerritory,BW,BWA,false,true,false
+Country,748,Eswatini,018,CountryOrTerritory,SZ,SWZ,false,true,false
+Country,426,Lesotho,018,CountryOrTerritory,LS,LSO,true,true,false
+Country,516,Namibia,018,CountryOrTerritory,NA,NAM,false,false,false
+Country,710,South Africa,018,CountryOrTerritory,ZA,ZAF,false,false,false
+Country,204,Benin,011,CountryOrTerritory,BJ,BEN,true,false,false
+Country,854,Burkina Faso,011,CountryOrTerritory,BF,BFA,true,true,false
+Country,132,Cabo Verde,011,CountryOrTerritory,CV,CPV,false,false,true
+Country,384,Côte d'Ivoire,011,CountryOrTerritory,CI,CIV,false,false,false
+Country,270,Gambia,011,CountryOrTerritory,GM,GMB,true,false,false
+Country,288,Ghana,011,CountryOrTerritory,GH,GHA,false,false,false
+Country,324,Guinea,011,CountryOrTerritory,GN,GIN,true,false,false
+Country,624,Guinea-Bissau,011,CountryOrTerritory,GW,GNB,true,false,true
+Country,430,Liberia,011,CountryOrTerritory,LR,LBR,true,false,false
+Country,466,Mali,011,CountryOrTerritory,ML,MLI,true,true,false
+Country,478,Mauritania,011,CountryOrTerritory,MR,MRT,true,false,false
+Country,562,Niger,011,CountryOrTerritory,NE,NER,true,true,false
+Country,566,Nigeria,011,CountryOrTerritory,NG,NGA,false,false,false
+Country,654,Saint Helena,011,CountryOrTerritory,SH,SHN,false,false,false
+Country,686,Senegal,011,CountryOrTerritory,SN,SEN,true,false,false
+Country,694,Sierra Leone,011,CountryOrTerritory,SL,SLE,true,false,false
+Country,768,Togo,011,CountryOrTerritory,TG,TGO,true,false,false
+Country,660,Anguilla,029,CountryOrTerritory,AI,AIA,false,false,true
+Country,028,Antigua and Barbuda,029,CountryOrTerritory,AG,ATG,false,false,true
+Country,533,Aruba,029,CountryOrTerritory,AW,ABW,false,false,true
+Country,044,Bahamas,029,CountryOrTerritory,BS,BHS,false,false,true
+Country,052,Barbados,029,CountryOrTerritory,BB,BRB,false,false,true
+Country,535,"Bonaire, Sint Eustatius and Saba",029,CountryOrTerritory,BQ,BES,false,false,true
+Country,092,British Virgin Islands,029,CountryOrTerritory,VG,VGB,false,false,true
+Country,136,Cayman Islands,029,CountryOrTerritory,KY,CYM,false,false,false
+Country,192,Cuba,029,CountryOrTerritory,CU,CUB,false,false,true
+Country,531,Curaçao,029,CountryOrTerritory,CW,CUW,false,false,true
+Country,212,Dominica,029,CountryOrTerritory,DM,DMA,false,false,true
+Country,214,Dominican Republic,029,CountryOrTerritory,DO,DOM,false,false,true
+Country,308,Grenada,029,CountryOrTerritory,GD,GRD,false,false,true
+Country,312,Guadeloupe,029,CountryOrTerritory,GP,GLP,false,false,false
+Country,332,Haiti,029,CountryOrTerritory,HT,HTI,true,false,true
+Country,388,Jamaica,029,CountryOrTerritory,JM,JAM,false,false,true
+Country,474,Martinique,029,CountryOrTerritory,MQ,MTQ,false,false,false
+Country,500,Montserrat,029,CountryOrTerritory,MS,MSR,false,false,true
+Country,630,Puerto Rico,029,CountryOrTerritory,PR,PRI,false,false,true
+Country,652,Saint Barthélemy,029,CountryOrTerritory,BL,BLM,false,false,false
+Country,659,Saint Kitts and Nevis,029,CountryOrTerritory,KN,KNA,false,false,true
+Country,662,Saint Lucia,029,CountryOrTerritory,LC,LCA,false,false,true
+Country,663,Saint Martin (French Part),029,CountryOrTerritory,MF,MAF,false,false,false
+Country,670,Saint Vincent and the Grenadines,029,CountryOrTerritory,VC,VCT,false,false,true
+Country,534,Sint Maarten (Dutch part),029,CountryOrTerritory,SX,SXM,false,false,true
+Country,780,Trinidad and Tobago,029,CountryOrTerritory,TT,TTO,false,false,true
+Country,796,Turks and Caicos Islands,029,CountryOrTerritory,TC,TCA,false,false,false
+Country,850,United States Virgin Islands,029,CountryOrTerritory,VI,VIR,false,false,true
+Country,084,Belize,013,CountryOrTerritory,BZ,BLZ,false,false,true
+Country,188,Costa Rica,013,CountryOrTerritory,CR,CRI,false,false,false
+Country,222,El Salvador,013,CountryOrTerritory,SV,SLV,false,false,false
+Country,320,Guatemala,013,CountryOrTerritory,GT,GTM,false,false,false
+Country,340,Honduras,013,CountryOrTerritory,HN,HND,false,false,false
+Country,484,Mexico,013,CountryOrTerritory,MX,MEX,false,false,false
+Country,558,Nicaragua,013,CountryOrTerritory,NI,NIC,false,false,false
+Country,591,Panama,013,CountryOrTerritory,PA,PAN,false,false,false
+Country,032,Argentina,005,CountryOrTerritory,AR,ARG,false,false,false
+Country,068,Bolivia (Plurinational State of),005,CountryOrTerritory,BO,BOL,false,true,false
+Country,074,Bouvet Island,005,CountryOrTerritory,BV,BVT,false,false,false
+Country,076,Brazil,005,CountryOrTerritory,BR,BRA,false,false,false
+Country,152,Chile,005,CountryOrTerritory,CL,CHL,false,false,false
+Country,170,Colombia,005,CountryOrTerritory,CO,COL,false,false,false
+Country,218,Ecuador,005,CountryOrTerritory,EC,ECU,false,false,false
+Country,238,Falkland Islands (Malvinas),005,CountryOrTerritory,FK,FLK,false,false,false
+Country,254,French Guiana,005,CountryOrTerritory,GF,GUF,false,false,false
+Country,328,Guyana,005,CountryOrTerritory,GY,GUY,false,false,true
+Country,600,Paraguay,005,CountryOrTerritory,PY,PRY,false,true,false
+Country,604,Peru,005,CountryOrTerritory,PE,PER,false,false,false
+Country,239,South Georgia and the South Sandwich Islands,005,CountryOrTerritory,GS,SGS,false,false,false
+Country,740,Suriname,005,CountryOrTerritory,SR,SUR,false,false,true
+Country,858,Uruguay,005,CountryOrTerritory,UY,URY,false,false,false
+Country,862,Venezuela (Bolivarian Republic of),005,CountryOrTerritory,VE,VEN,false,false,false
+Country,060,Bermuda,021,CountryOrTerritory,BM,BMU,false,false,false
+Country,124,Canada,021,CountryOrTerritory,CA,CAN,false,false,false
+Country,304,Greenland,021,CountryOrTerritory,GL,GRL,false,false,false
+Country,666,Saint Pierre and Miquelon,021,CountryOrTerritory,PM,SPM,false,false,false
+Country,840,United States of America,021,CountryOrTerritory,US,USA,false,false,false
+Country,398,Kazakhstan,143,CountryOrTerritory,KZ,KAZ,false,true,false
+Country,417,Kyrgyzstan,143,CountryOrTerritory,KG,KGZ,false,true,false
+Country,762,Tajikistan,143,CountryOrTerritory,TJ,TJK,false,true,false
+Country,795,Turkmenistan,143,CountryOrTerritory,TM,TKM,false,true,false
+Country,860,Uzbekistan,143,CountryOrTerritory,UZ,UZB,false,true,false
+Country,156,China,030,CountryOrTerritory,CN,CHN,false,false,false
+Country,344,"China, Hong Kong Special Administrative Region",030,CountryOrTerritory,HK,HKG,false,false,false
+Country,446,"China, Macao Special Administrative Region",030,CountryOrTerritory,MO,MAC,false,false,false
+Country,408,Democratic People's Republic of Korea,030,CountryOrTerritory,KP,PRK,false,false,false
+Country,392,Japan,030,CountryOrTerritory,JP,JPN,false,false,false
+Country,496,Mongolia,030,CountryOrTerritory,MN,MNG,false,true,false
+Country,410,Republic of Korea,030,CountryOrTerritory,KR,KOR,false,false,false
+Country,096,Brunei Darussalam,035,CountryOrTerritory,BN,BRN,false,false,false
+Country,116,Cambodia,035,CountryOrTerritory,KH,KHM,true,false,false
+Country,360,Indonesia,035,CountryOrTerritory,ID,IDN,false,false,false
+Country,418,Lao People's Democratic Republic,035,CountryOrTerritory,LA,LAO,true,true,false
+Country,458,Malaysia,035,CountryOrTerritory,MY,MYS,false,false,false
+Country,104,Myanmar,035,CountryOrTerritory,MM,MMR,true,false,false
+Country,608,Philippines,035,CountryOrTerritory,PH,PHL,false,false,false
+Country,702,Singapore,035,CountryOrTerritory,SG,SGP,false,false,true
+Country,764,Thailand,035,CountryOrTerritory,TH,THA,false,false,false
+Country,626,Timor-Leste,035,CountryOrTerritory,TL,TLS,true,false,true
+Country,704,Viet Nam,035,CountryOrTerritory,VN,VNM,false,false,false
+Country,004,Afghanistan,034,CountryOrTerritory,AF,AFG,true,true,false
+Country,050,Bangladesh,034,CountryOrTerritory,BD,BGD,true,false,false
+Country,064,Bhutan,034,CountryOrTerritory,BT,BTN,false,true,false
+Country,356,India,034,CountryOrTerritory,IN,IND,false,false,false
+Country,364,Iran (Islamic Republic of),034,CountryOrTerritory,IR,IRN,false,false,false
+Country,462,Maldives,034,CountryOrTerritory,MV,MDV,false,false,true
+Country,524,Nepal,034,CountryOrTerritory,NP,NPL,true,true,false
+Country,586,Pakistan,034,CountryOrTerritory,PK,PAK,false,false,false
+Country,144,Sri Lanka,034,CountryOrTerritory,LK,LKA,false,false,false
+Country,051,Armenia,145,CountryOrTerritory,AM,ARM,false,true,false
+Country,031,Azerbaijan,145,CountryOrTerritory,AZ,AZE,false,true,false
+Country,048,Bahrain,145,CountryOrTerritory,BH,BHR,false,false,false
+Country,196,Cyprus,145,CountryOrTerritory,CY,CYP,false,false,false
+Country,268,Georgia,145,CountryOrTerritory,GE,GEO,false,true,false
+Country,368,Iraq,145,CountryOrTerritory,IQ,IRQ,false,false,false
+Country,376,Israel,145,CountryOrTerritory,IL,ISR,false,false,false
+Country,400,Jordan,145,CountryOrTerritory,JO,JOR,false,false,false
+Country,414,Kuwait,145,CountryOrTerritory,KW,KWT,false,false,false
+Country,422,Lebanon,145,CountryOrTerritory,LB,LBN,false,false,false
+Country,512,Oman,145,CountryOrTerritory,OM,OMN,false,false,false
+Country,634,Qatar,145,CountryOrTerritory,QA,QAT,false,false,false
+Country,682,Saudi Arabia,145,CountryOrTerritory,SA,SAU,false,false,false
+Country,275,State of Palestine,145,CountryOrTerritory,PS,PSE,false,false,false
+Country,760,Syrian Arab Republic,145,CountryOrTerritory,SY,SYR,false,false,false
+Country,792,Türkiye,145,CountryOrTerritory,TR,TUR,false,false,false
+Country,784,United Arab Emirates,145,CountryOrTerritory,AE,ARE,false,false,false
+Country,887,Yemen,145,CountryOrTerritory,YE,YEM,true,false,false
+Country,112,Belarus,151,CountryOrTerritory,BY,BLR,false,false,false
+Country,100,Bulgaria,151,CountryOrTerritory,BG,BGR,false,false,false
+Country,203,Czechia,151,CountryOrTerritory,CZ,CZE,false,false,false
+Country,348,Hungary,151,CountryOrTerritory,HU,HUN,false,false,false
+Country,616,Poland,151,CountryOrTerritory,PL,POL,false,false,false
+Country,498,Republic of Moldova,151,CountryOrTerritory,MD,MDA,false,true,false
+Country,642,Romania,151,CountryOrTerritory,RO,ROU,false,false,false
+Country,643,Russian Federation,151,CountryOrTerritory,RU,RUS,false,false,false
+Country,703,Slovakia,151,CountryOrTerritory,SK,SVK,false,false,false
+Country,804,Ukraine,151,CountryOrTerritory,UA,UKR,false,false,false
+Country,248,Åland Islands,154,CountryOrTerritory,AX,ALA,false,false,false
+Country,208,Denmark,154,CountryOrTerritory,DK,DNK,false,false,false
+Country,233,Estonia,154,CountryOrTerritory,EE,EST,false,false,false
+Country,234,Faroe Islands,154,CountryOrTerritory,FO,FRO,false,false,false
+Country,246,Finland,154,CountryOrTerritory,FI,FIN,false,false,false
+Country,831,Guernsey,154,CountryOrTerritory,GG,GGY,false,false,false
+Country,352,Iceland,154,CountryOrTerritory,IS,ISL,false,false,false
+Country,372,Ireland,154,CountryOrTerritory,IE,IRL,false,false,false
+Country,833,Isle of Man,154,CountryOrTerritory,IM,IMN,false,false,false
+Country,832,Jersey,154,CountryOrTerritory,JE,JEY,false,false,false
+Country,428,Latvia,154,CountryOrTerritory,LV,LVA,false,false,false
+Country,440,Lithuania,154,CountryOrTerritory,LT,LTU,false,false,false
+Country,578,Norway,154,CountryOrTerritory,NO,NOR,false,false,false
+Country,744,Svalbard and Jan Mayen Islands,154,CountryOrTerritory,SJ,SJM,false,false,false
+Country,752,Sweden,154,CountryOrTerritory,SE,SWE,false,false,false
+Country,826,United Kingdom of Great Britain and Northern Ireland,154,CountryOrTerritory,GB,GBR,false,false,false
+Country,008,Albania,039,CountryOrTerritory,AL,ALB,false,false,false
+Country,020,Andorra,039,CountryOrTerritory,AD,AND,false,true,false
+Country,070,Bosnia and Herzegovina,039,CountryOrTerritory,BA,BIH,false,false,false
+Country,191,Croatia,039,CountryOrTerritory,HR,HRV,false,false,false
+Country,292,Gibraltar,039,CountryOrTerritory,GI,GIB,false,false,false
+Country,300,Greece,039,CountryOrTerritory,GR,GRC,false,false,false
+Country,336,Holy See,039,CountryOrTerritory,VA,VAT,false,true,false
+Country,380,Italy,039,CountryOrTerritory,IT,ITA,false,false,false
+Country,470,Malta,039,CountryOrTerritory,MT,MLT,false,false,false
+Country,499,Montenegro,039,CountryOrTerritory,ME,MNE,false,false,false
+Country,807,North Macedonia,039,CountryOrTerritory,MK,MKD,false,true,false
+Country,620,Portugal,039,CountryOrTerritory,PT,PRT,false,false,false
+Country,674,San Marino,039,CountryOrTerritory,SM,SMR,false,true,false
+Country,688,Serbia,039,CountryOrTerritory,RS,SRB,false,false,false
+Country,705,Slovenia,039,CountryOrTerritory,SI,SVN,false,false,false
+Country,724,Spain,039,CountryOrTerritory,ES,ESP,false,false,false
+Country,040,Austria,155,CountryOrTerritory,AT,AUT,false,true,false
+Country,056,Belgium,155,CountryOrTerritory,BE,BEL,false,false,false
+Country,250,France,155,CountryOrTerritory,FR,FRA,false,false,false
+Country,276,Germany,155,CountryOrTerritory,DE,DEU,false,false,false
+Country,438,Liechtenstein,155,CountryOrTerritory,LI,LIE,false,true,false
+Country,442,Luxembourg,155,CountryOrTerritory,LU,LUX,false,true,false
+Country,492,Monaco,155,CountryOrTerritory,MC,MCO,false,false,false
+Country,528,Netherlands (Kingdom of the),155,CountryOrTerritory,NL,NLD,false,false,false
+Country,756,Switzerland,155,CountryOrTerritory,CH,CHE,false,true,false
+Country,036,Australia,053,CountryOrTerritory,AU,AUS,false,false,false
+Country,162,Christmas Island,053,CountryOrTerritory,CX,CXR,false,false,false
+Country,166,Cocos (Keeling) Islands,053,CountryOrTerritory,CC,CCK,false,false,false
+Country,334,Heard Island and McDonald Islands,053,CountryOrTerritory,HM,HMD,false,false,false
+Country,554,New Zealand,053,CountryOrTerritory,NZ,NZL,false,false,false
+Country,574,Norfolk Island,053,CountryOrTerritory,NF,NFK,false,false,false
+Country,242,Fiji,054,CountryOrTerritory,FJ,FJI,false,false,true
+Country,540,New Caledonia,054,CountryOrTerritory,NC,NCL,false,false,true
+Country,598,Papua New Guinea,054,CountryOrTerritory,PG,PNG,false,false,true
+Country,090,Solomon Islands,054,CountryOrTerritory,SB,SLB,true,false,true
+Country,548,Vanuatu,054,CountryOrTerritory,VU,VUT,false,false,true
+Country,316,Guam,057,CountryOrTerritory,GU,GUM,false,false,true
+Country,296,Kiribati,057,CountryOrTerritory,KI,KIR,true,false,true
+Country,584,Marshall Islands,057,CountryOrTerritory,MH,MHL,false,false,true
+Country,583,Micronesia (Federated States of),057,CountryOrTerritory,FM,FSM,false,false,true
+Country,520,Nauru,057,CountryOrTerritory,NR,NRU,false,false,true
+Country,580,Northern Mariana Islands,057,CountryOrTerritory,MP,MNP,false,false,true
+Country,585,Palau,057,CountryOrTerritory,PW,PLW,false,false,true
+Country,581,United States Minor Outlying Islands,057,CountryOrTerritory,UM,UMI,false,false,false
+Country,016,American Samoa,061,CountryOrTerritory,AS,ASM,false,false,true
+Country,184,Cook Islands,061,CountryOrTerritory,CK,COK,false,false,true
+Country,258,French Polynesia,061,CountryOrTerritory,PF,PYF,false,false,true
+Country,570,Niue,061,CountryOrTerritory,NU,NIU,false,false,true
+Country,612,Pitcairn,061,CountryOrTerritory,PN,PCN,false,false,false
+Country,882,Samoa,061,CountryOrTerritory,WS,WSM,false,false,true
+Country,772,Tokelau,061,CountryOrTerritory,TK,TKL,false,false,false
+Country,776,Tonga,061,CountryOrTerritory,TO,TON,false,false,true
+Country,798,Tuvalu,061,CountryOrTerritory,TV,TUV,true,false,true
+Country,876,Wallis and Futuna Islands,061,CountryOrTerritory,WF,WLF,false,false,false
diff --git a/src/Cuemon.Extensions.Core/Globalization/StatisticalRegionExtensions.cs b/src/Cuemon.Extensions.Core/Globalization/StatisticalRegionExtensions.cs
new file mode 100644
index 000000000..55ab2a0a4
--- /dev/null
+++ b/src/Cuemon.Extensions.Core/Globalization/StatisticalRegionExtensions.cs
@@ -0,0 +1,109 @@
+using System;
+using Cuemon.Globalization;
+
+namespace Cuemon.Extensions.Globalization
+{
+ ///
+ /// Provides extension methods for .
+ ///
+ public static class StatisticalRegionExtensions
+ {
+ ///
+ /// Determines whether the specified region is the World region.
+ ///
+ /// The region to check.
+ /// true if the region is the World region; otherwise, false.
+ /// is null.
+ public static bool IsWorld(this StatisticalRegionInfo region)
+ {
+ Validator.ThrowIfNull(region);
+ return region.Kind == StatisticalRegionKind.World;
+ }
+
+ ///
+ /// Determines whether the specified region is a geographic region (continent or major area).
+ ///
+ /// The region to check.
+ /// true if the region is a Region; otherwise, false.
+ /// is null.
+ public static bool IsRegion(this StatisticalRegionInfo region)
+ {
+ Validator.ThrowIfNull(region);
+ return region.Kind == StatisticalRegionKind.Region;
+ }
+
+ ///
+ /// Determines whether the specified region is a subregion.
+ ///
+ /// The region to check.
+ /// true if the region is a Subregion; otherwise, false.
+ /// is null.
+ public static bool IsSubregion(this StatisticalRegionInfo region)
+ {
+ Validator.ThrowIfNull(region);
+ return region.Kind == StatisticalRegionKind.Subregion;
+ }
+
+ ///
+ /// Determines whether the specified region is an intermediate region.
+ ///
+ /// The region to check.
+ /// true if the region is an IntermediateRegion; otherwise, false.
+ /// is null.
+ public static bool IsIntermediateRegion(this StatisticalRegionInfo region)
+ {
+ Validator.ThrowIfNull(region);
+ return region.Kind == StatisticalRegionKind.IntermediateRegion;
+ }
+
+ ///
+ /// Determines whether the specified region is a country or territory.
+ ///
+ /// The region to check.
+ /// true if the region is a CountryOrTerritory; otherwise, false.
+ /// is null.
+ public static bool IsCountryOrTerritory(this StatisticalRegionInfo region)
+ {
+ Validator.ThrowIfNull(region);
+ return region.Kind == StatisticalRegionKind.CountryOrTerritory;
+ }
+
+ ///
+ /// Determines whether the specified region is a geographic area (not a country).
+ ///
+ /// The region to check.
+ /// true if the region is not a CountryOrTerritory; otherwise, false.
+ /// is null.
+ public static bool IsArea(this StatisticalRegionInfo region)
+ {
+ Validator.ThrowIfNull(region);
+ return region.Kind != StatisticalRegionKind.CountryOrTerritory;
+ }
+
+ ///
+ /// Determines whether the specified country has ISO code information available.
+ ///
+ /// The region to check.
+ /// true if the region is a country and has ISO codes; otherwise, false.
+ /// is null.
+ public static bool HasIsoCodes(this StatisticalRegionInfo region)
+ {
+ Validator.ThrowIfNull(region);
+ return region.Kind == StatisticalRegionKind.CountryOrTerritory &&
+ !string.IsNullOrEmpty(region.IsoAlpha2) &&
+ !string.IsNullOrEmpty(region.IsoAlpha3);
+ }
+
+ ///
+ /// Determines whether the specified country has a .NET available.
+ ///
+ /// The region to check.
+ /// true if the region is a country and has OS-level RegionInfo support; otherwise, false.
+ /// is null.
+ public static bool HasRegionInfo(this StatisticalRegionInfo region)
+ {
+ Validator.ThrowIfNull(region);
+ return region.Kind == StatisticalRegionKind.CountryOrTerritory && region.Region != null;
+ }
+ }
+}
diff --git a/test/Cuemon.Core.Tests/Globalization/StatisticalRegionInfoTest.cs b/test/Cuemon.Core.Tests/Globalization/StatisticalRegionInfoTest.cs
new file mode 100644
index 000000000..cbd5c8dde
--- /dev/null
+++ b/test/Cuemon.Core.Tests/Globalization/StatisticalRegionInfoTest.cs
@@ -0,0 +1,437 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using Codebelt.Extensions.Xunit;
+using Xunit;
+
+namespace Cuemon.Globalization
+{
+ public class StatisticalRegionInfoTest : Test
+ {
+ public StatisticalRegionInfoTest(ITestOutputHelper output) : base(output)
+ {
+ }
+
+ [Fact]
+ public void StatisticalRegions_ShouldContainWorld()
+ {
+ var world = World.StatisticalRegions.FirstOrDefault(r => r.Code == "001");
+
+ Assert.NotNull(world);
+ Assert.Equal("World", world.Name);
+ Assert.Null(world.Parent);
+ Assert.Equal(StatisticalRegionKind.World, world.Kind);
+ TestOutput.WriteLine(world.ToString());
+ }
+
+ [Fact]
+ public void StatisticalRegions_ShouldContainAllContinents()
+ {
+ var expectedContinents = new[] { "002", "009", "019", "142", "150" }; // Africa, Oceania, Americas, Asia, Europe
+
+ foreach (var code in expectedContinents)
+ {
+ var continent = World.GetStatisticalRegion(code);
+ Assert.NotNull(continent);
+ Assert.Equal("001", continent.Parent?.Code);
+ Assert.Equal(StatisticalRegionKind.Region, continent.Kind);
+ TestOutput.WriteLine(continent.ToString());
+ }
+ }
+
+ [Fact]
+ public void GetStatisticalRegion_ShouldReturnCorrectRegion()
+ {
+ var europe = World.GetStatisticalRegion("150");
+
+ Assert.NotNull(europe);
+ Assert.Equal("150", europe.Code);
+ Assert.Equal("Europe", europe.Name);
+ Assert.Equal("001", europe.Parent?.Code);
+ Assert.Equal(StatisticalRegionKind.Region, europe.Kind);
+ }
+
+ [Fact]
+ public void GetStatisticalRegion_InvalidCode_ShouldReturnNull()
+ {
+ var result = World.GetStatisticalRegion("99999");
+
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public void GetCountry_ByM49Code_US_ShouldReturn840()
+ {
+ var usa = World.GetCountry("840");
+
+ Assert.NotNull(usa);
+ Assert.Equal("840", usa.Code);
+ Assert.Equal("United States of America", usa.Name);
+ Assert.Equal("US", usa.IsoAlpha2);
+ Assert.Equal("USA", usa.IsoAlpha3);
+ Assert.Equal(StatisticalRegionKind.CountryOrTerritory, usa.Kind);
+
+ TestOutput.WriteLine(usa.ToString());
+ }
+
+ [Fact]
+ public void GetCountry_ByM49Code_DE_ShouldReturn276()
+ {
+ var germany = World.GetCountry("276");
+
+ Assert.NotNull(germany);
+ Assert.Equal("276", germany.Code);
+ Assert.Equal("Germany", germany.Name);
+ Assert.Equal("DE", germany.IsoAlpha2);
+ Assert.Equal("DEU", germany.IsoAlpha3);
+ Assert.Equal(StatisticalRegionKind.CountryOrTerritory, germany.Kind);
+
+ TestOutput.WriteLine(germany.ToString());
+ }
+
+ [Fact]
+ public void GetCountry_ByRegionInfo_US_ShouldReturnUnitedStates()
+ {
+ var regionInfo = new RegionInfo("US");
+ var usa = World.GetCountry(regionInfo);
+
+ Assert.NotNull(usa);
+ Assert.Equal("840", usa.Code);
+ Assert.Equal("United States of America", usa.Name);
+ }
+
+ [Fact]
+ public void GetCountry_ByRegionInfo_DE_ShouldReturnGermany()
+ {
+ var regionInfo = new RegionInfo("DE");
+ var germany = World.GetCountry(regionInfo);
+
+ Assert.NotNull(germany);
+ Assert.Equal("276", germany.Code);
+ Assert.Equal("Germany", germany.Name);
+ }
+
+ [Fact]
+ public void GetCountry_ByRegionInfo_Null_ShouldThrowArgumentNullException()
+ {
+ Assert.Throws(() => World.GetCountry((RegionInfo)null));
+ }
+
+ [Fact]
+ public void GetCountry_InvalidCode_ShouldReturnNull()
+ {
+ var result = World.GetCountry("99999");
+
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public void GetAncestors_FromCountry_ShouldReturnCompleteChain()
+ {
+ var usa = World.GetCountry("840");
+
+ Assert.NotNull(usa);
+
+ var ancestors = usa.GetAncestors().ToList();
+
+ Assert.True(ancestors.Count >= 2);
+ Assert.Contains(ancestors, r => r.Code == "021"); // Northern America
+ Assert.Contains(ancestors, r => r.Code == "019"); // Americas
+ Assert.Contains(ancestors, r => r.Code == "001"); // World
+
+ TestOutput.WriteLine($"Geographic ancestors of {usa.Name}:");
+ foreach (var ancestor in ancestors)
+ {
+ TestOutput.WriteLine($" - {ancestor} ({ancestor.Kind})");
+ }
+ }
+
+ [Fact]
+ public void GetAncestors_FromRegion_ShouldReturnCompleteChain()
+ {
+ var westernEurope = World.GetStatisticalRegion("155");
+
+ Assert.NotNull(westernEurope);
+ Assert.Equal(StatisticalRegionKind.Subregion, westernEurope.Kind);
+
+ var ancestors = westernEurope.GetAncestors().ToList();
+
+ Assert.Equal(2, ancestors.Count);
+ Assert.Equal("150", ancestors[0].Code); // Europe
+ Assert.Equal("001", ancestors[1].Code); // World
+
+ TestOutput.WriteLine($"Ancestors of {westernEurope.Name}:");
+ foreach (var ancestor in ancestors)
+ {
+ TestOutput.WriteLine($" - {ancestor}");
+ }
+ }
+
+ [Fact]
+ public void Children_ShouldBePopulated()
+ {
+ var world = World.GetStatisticalRegion("001");
+
+ Assert.NotNull(world);
+ Assert.True(world.Children.Count() >= 5, "World should have at least 5 continent children");
+
+ TestOutput.WriteLine($"Children of {world.Name}:");
+ foreach (var child in world.Children)
+ {
+ TestOutput.WriteLine($" - {child} ({child.Kind})");
+ }
+ }
+
+ [Fact]
+ public void GetAllCountries_ShouldReturn250PlusCountries()
+ {
+ var world = World.GetStatisticalRegion("001");
+
+ Assert.NotNull(world);
+ Assert.True(world.Countries.Count() >= 200, $"Expected at least 200 countries, got {world.Countries.Count()}");
+
+ TestOutput.WriteLine($"Total countries: {world.Countries.Count()}");
+ }
+
+ [Fact]
+ public void Countries_ShouldBeAssignedToCorrectRegions()
+ {
+ var europe = World.GetStatisticalRegion("150");
+ var germany = World.GetCountry("276");
+
+ Assert.Contains(germany, europe.Countries);
+ }
+
+ [Fact]
+ public void LDC_Flag_ShouldBeSetForLeastDevelopedCountries()
+ {
+ var afghanistan = World.GetCountry("004");
+
+ Assert.NotNull(afghanistan);
+ Assert.True(afghanistan.IsLeastDevelopedCountry);
+ Assert.True(afghanistan.IsLandLockedDevelopingCountry);
+ }
+
+ [Fact]
+ public void SIDS_Flag_ShouldBeSetForSmallIslandDevelopingStates()
+ {
+ var fiji = World.GetCountry("242");
+
+ Assert.NotNull(fiji);
+ Assert.True(fiji.IsSmallIslandDevelopingState);
+ }
+
+ [Fact]
+ public void DevelopedCountry_ShouldHaveNoFlags()
+ {
+ var usa = World.GetCountry("840");
+
+ Assert.NotNull(usa);
+ Assert.False(usa.IsLeastDevelopedCountry);
+ Assert.False(usa.IsLandLockedDevelopingCountry);
+ Assert.False(usa.IsSmallIslandDevelopingState);
+ }
+
+ [Fact]
+ public void AllCountries_ShouldHaveValidParent()
+ {
+ var world = World.GetStatisticalRegion("001");
+
+ foreach (var country in world.Countries)
+ {
+ Assert.NotNull(country.Parent);
+ // All countries should have a parent region code different from "001" (World)
+ Assert.NotEqual("001", country.Parent.Code);
+ }
+ }
+
+ [Fact]
+ public void IsoCodes_ShouldBeUppercase()
+ {
+ var world = World.GetStatisticalRegion("001");
+
+ foreach (var country in world.Countries)
+ {
+ Assert.True(country.IsoAlpha2.All(char.IsLetter),
+ $"Country {country.Name} should have valid ISO Alpha-2 code");
+ Assert.True(country.IsoAlpha3.All(char.IsLetter),
+ $"Country {country.Name} should have valid ISO Alpha-3 code");
+ Assert.Equal(2, country.IsoAlpha2.Length);
+ Assert.Equal(3, country.IsoAlpha3.Length);
+ }
+ }
+
+ [Fact]
+ public void RegionInfoLookup_ShouldWorkForMajorCountries()
+ {
+ var majorCountries = new[] { "US", "CA", "GB", "DE", "FR", "IT", "JP", "CN", "AU", "BR" };
+
+ foreach (var isoCode in majorCountries)
+ {
+ try
+ {
+ var regionInfo = new RegionInfo(isoCode);
+ var country = World.GetCountry(regionInfo);
+
+ Assert.NotNull(country);
+ Assert.Equal(isoCode, country.IsoAlpha2, ignoreCase: true);
+ TestOutput.WriteLine($"{isoCode} -> {country.Name}");
+ }
+ catch (ArgumentException)
+ {
+ TestOutput.WriteLine($"{isoCode} not supported on this OS");
+ }
+ }
+ }
+
+ [Fact]
+ public void WesternAfricanCountries_ShouldBeUnderWesternAfricaRegion()
+ {
+ var westernAfrica = World.GetStatisticalRegion("011");
+ Assert.NotNull(westernAfrica);
+ Assert.Equal(StatisticalRegionKind.Subregion, westernAfrica.Kind);
+
+ // Verify some Western African countries
+ var nigeria = World.GetCountry("566");
+ var ghana = World.GetCountry("288");
+ var senegal = World.GetCountry("686");
+
+ Assert.NotNull(nigeria);
+ Assert.NotNull(ghana);
+ Assert.NotNull(senegal);
+
+ Assert.Equal("011", nigeria.Parent.Code);
+ Assert.Equal("011", ghana.Parent.Code);
+ Assert.Equal("011", senegal.Parent.Code);
+
+ TestOutput.WriteLine($"Western Africa has {westernAfrica.Countries.Count()} countries");
+ }
+
+ [Fact]
+ public void AmericasHierarchy_ShouldBeConsistent()
+ {
+ // Test South American country under 005 -> 419 -> 019 -> 001
+ var brazil = World.GetCountry("076");
+ Assert.NotNull(brazil);
+ Assert.Equal("005", brazil.Parent.Code); // South America
+
+ var brazilAncestors = brazil.GetAncestors().ToList();
+ Assert.Contains(brazilAncestors, r => r.Code == "419"); // Latin America and the Caribbean
+ Assert.Contains(brazilAncestors, r => r.Code == "019"); // Americas
+ Assert.Contains(brazilAncestors, r => r.Code == "001"); // World
+
+ // Test Central American country
+ var mexico = World.GetCountry("484");
+ Assert.NotNull(mexico);
+ Assert.Equal("013", mexico.Parent.Code); // Central America
+
+ var mexicoAncestors = mexico.GetAncestors().ToList();
+ Assert.Contains(mexicoAncestors, r => r.Code == "419");
+ Assert.Contains(mexicoAncestors, r => r.Code == "019");
+
+ TestOutput.WriteLine("Americas hierarchy verified for Brazil and Mexico");
+ }
+
+ [Fact]
+ public void IntermediateRegions_ShouldExist()
+ {
+ var subSaharanAfrica = World.GetStatisticalRegion("202");
+ var latinAmerica = World.GetStatisticalRegion("419");
+
+ Assert.NotNull(subSaharanAfrica);
+ Assert.NotNull(latinAmerica);
+
+ Assert.Equal(StatisticalRegionKind.IntermediateRegion, subSaharanAfrica.Kind);
+ Assert.Equal(StatisticalRegionKind.IntermediateRegion, latinAmerica.Kind);
+
+ TestOutput.WriteLine($"{subSaharanAfrica.Name} is an intermediate region");
+ TestOutput.WriteLine($"{latinAmerica.Name} is an intermediate region");
+ }
+
+ [Fact]
+ public void Antarctica_ShouldBeRegionNotCountry()
+ {
+ var antarctica = World.GetStatisticalRegion("010");
+
+ Assert.NotNull(antarctica);
+ Assert.Equal("Antarctica", antarctica.Name);
+ Assert.Equal("001", antarctica.Parent?.Code);
+ Assert.Equal(StatisticalRegionKind.Region, antarctica.Kind);
+
+ // Antarctica should have no children
+ Assert.Empty(antarctica.Children);
+
+ // Antarctica should not be in countries list
+ Assert.DoesNotContain(antarctica, World.GetStatisticalRegion("001").Countries);
+
+ TestOutput.WriteLine($"Antarctica region: {antarctica}");
+ }
+
+ [Fact]
+ public void HierarchyDepth_ShouldNotExceed4()
+ {
+ var maxDepth = 0;
+
+ foreach (var region in World.StatisticalRegions)
+ {
+ var depth = GetDepth(region);
+ if (depth > maxDepth)
+ {
+ maxDepth = depth;
+ }
+ }
+
+ TestOutput.WriteLine($"Maximum hierarchy depth: {maxDepth}");
+ Assert.True(maxDepth <= 4, $"Hierarchy depth should not exceed 4, but was {maxDepth}");
+ }
+
+ private int GetDepth(StatisticalRegionInfo region)
+ {
+ int depth = 0;
+ var current = region;
+ while (current.Parent != null)
+ {
+ depth++;
+ current = current.Parent;
+ }
+ return depth;
+ }
+
+ [Fact]
+ public void GetAllDescendants_ShouldReturnAllChildrenRecursively()
+ {
+ var world = World.GetStatisticalRegion("001");
+ var allDescendants = world.GetAllDescendants().ToList();
+
+ // Should include regions and countries
+ Assert.True(allDescendants.Count > 200, "Should have many descendants");
+
+ TestOutput.WriteLine($"World has {allDescendants.Count} total descendants");
+ }
+
+ [Fact]
+ public void PrintFullHierarchy_ShouldOutputAllRegionsAndCountries()
+ {
+ var world = World.GetStatisticalRegion("001");
+
+ Assert.NotNull(world);
+
+ PrintHierarchy(world, 0);
+ }
+
+ private void PrintHierarchy(StatisticalRegionInfo region, int depth)
+ {
+ var indent = new string(' ', depth * 2);
+ var flags = region.Kind == StatisticalRegionKind.CountryOrTerritory
+ ? $" [{region.IsoAlpha2}/{region.IsoAlpha3}]"
+ : string.Empty;
+
+ TestOutput.WriteLine($"{indent}{region.Code} - {region.Name} ({region.Kind}){flags}");
+
+ foreach (var child in region.Children)
+ {
+ PrintHierarchy(child, depth + 1);
+ }
+ }
+ }
+}
diff --git a/test/Cuemon.Extensions.Core.Tests/Globalization/StatisticalRegionExtensionsTest.cs b/test/Cuemon.Extensions.Core.Tests/Globalization/StatisticalRegionExtensionsTest.cs
new file mode 100644
index 000000000..6c1d46b14
--- /dev/null
+++ b/test/Cuemon.Extensions.Core.Tests/Globalization/StatisticalRegionExtensionsTest.cs
@@ -0,0 +1,197 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using Codebelt.Extensions.Xunit;
+using Cuemon.Globalization;
+using Xunit;
+
+namespace Cuemon.Extensions.Globalization
+{
+ public class StatisticalRegionExtensions : Test
+ {
+ public StatisticalRegionExtensions(ITestOutputHelper output) : base(output)
+ {
+ }
+
+ [Fact]
+ public void StatisticalRegions_ShouldContainWorld()
+ {
+ var world = World.StatisticalRegions.FirstOrDefault(r => r.Code == "001");
+ Assert.True(world.IsWorld());
+ }
+
+ [Fact]
+ public void StatisticalRegions_ShouldContainAllContinents()
+ {
+ var expectedContinents = new[] { "002", "009", "019", "142", "150" }; // Africa, Oceania, Americas, Asia, Europe
+
+ foreach (var code in expectedContinents)
+ {
+ var continent = World.GetStatisticalRegion(code);
+ Assert.True(continent.IsRegion());
+ }
+ }
+
+ [Fact]
+ public void GetCountry_ByM49Code_US_ShouldReturn840()
+ {
+ var usa = World.GetCountry("840");
+
+ Assert.True(usa.IsCountryOrTerritory());
+ Assert.True(usa.HasIsoCodes());
+ }
+
+ [Fact]
+ public void GetCountry_ByRegionInfo_US_ShouldReturnUnitedStates()
+ {
+ var regionInfo = new RegionInfo("US");
+ var usa = World.GetCountry(regionInfo);
+ Assert.True(usa.IsCountryOrTerritory());
+ }
+
+ [Fact]
+ public void GetAncestors_FromRegion_ShouldReturnCompleteChain()
+ {
+ var westernEurope = World.GetStatisticalRegion("155");
+ Assert.True(westernEurope.IsSubregion());
+ }
+
+ [Fact]
+ public void Children_ShouldBePopulated()
+ {
+ var world = World.GetStatisticalRegion("001");
+ Assert.True(world.IsWorld());
+ }
+
+ [Fact]
+ public void AllCountries_ShouldHaveValidParent()
+ {
+ var world = World.GetStatisticalRegion("001");
+
+ foreach (var country in world.Countries)
+ {
+ Assert.NotNull(country.Parent);
+ Assert.True(country.IsCountryOrTerritory());
+ }
+ }
+
+ [Fact]
+ public void AmericasHierarchy_ShouldBeConsistent()
+ {
+ // Test South American country under 005 -> 419 -> 019 -> 001
+ var brazil = World.GetCountry("076");
+ Assert.NotNull(brazil);
+ Assert.True(brazil.Parent.IsSubregion());
+ }
+
+ [Fact]
+ public void IntermediateRegions_ShouldExist()
+ {
+ var subSaharanAfrica = World.GetStatisticalRegion("202");
+ var latinAmerica = World.GetStatisticalRegion("419");
+
+ Assert.NotNull(subSaharanAfrica);
+ Assert.NotNull(latinAmerica);
+
+ Assert.True(subSaharanAfrica.IsIntermediateRegion());
+ Assert.True(latinAmerica.IsIntermediateRegion());
+ }
+
+ [Fact]
+ public void Antarctica_ShouldBeRegionNotCountry()
+ {
+ var antarctica = World.GetStatisticalRegion("010");
+
+ Assert.NotNull(antarctica);
+ Assert.True(antarctica.IsRegion());
+
+ // Antarctica should have no children
+ Assert.Empty(antarctica.Children);
+
+ // Antarctica should not be in countries list
+ Assert.DoesNotContain(antarctica, World.GetStatisticalRegion("001").Countries);
+
+ TestOutput.WriteLine($"Antarctica region: {antarctica}");
+ }
+
+ [Fact]
+ public void GetAllDescendants_ShouldReturnAllChildrenRecursively()
+ {
+ var world = World.GetStatisticalRegion("001");
+ var allDescendants = world.GetAllDescendants().ToList();
+
+
+ // Should include both regions and countries
+ Assert.Contains(allDescendants, r => r.IsRegion());
+ Assert.Contains(allDescendants, r => r.IsCountryOrTerritory());
+ }
+
+ [Fact]
+ public void ExtensionMethods_ShouldWorkCorrectly()
+ {
+ var world = World.GetStatisticalRegion("001");
+ var europe = World.GetStatisticalRegion("150");
+ var westernEurope = World.GetStatisticalRegion("155");
+ var usa = World.GetCountry("840");
+
+ Assert.True(world.IsWorld());
+ Assert.False(world.IsRegion());
+ Assert.False(world.IsCountryOrTerritory());
+
+ Assert.True(europe.IsRegion());
+ Assert.False(europe.IsWorld());
+ Assert.False(europe.IsCountryOrTerritory());
+ Assert.True(europe.IsArea());
+
+ Assert.True(westernEurope.IsSubregion());
+ Assert.False(westernEurope.IsRegion());
+ Assert.True(westernEurope.IsArea());
+
+ Assert.True(usa.IsCountryOrTerritory());
+ Assert.False(usa.IsArea());
+ Assert.True(usa.HasIsoCodes());
+ }
+
+ [Fact]
+ public void HasRegionInfo_ShouldReturnTrue_WhenCountryHasRegionInfo()
+ {
+ var usa = World.GetCountry("840");
+
+ Assert.NotNull(usa);
+ Assert.True(usa.HasRegionInfo());
+ }
+
+ [Fact]
+ public void HasRegionInfo_ShouldReturnFalse_WhenRegionIsNotCountry()
+ {
+ var world = World.GetStatisticalRegion("001");
+ var europe = World.GetStatisticalRegion("150");
+
+ Assert.False(world.HasRegionInfo());
+ Assert.False(europe.HasRegionInfo());
+ }
+
+ [Fact]
+ public void HasRegionInfo_ShouldReturnFalse_WhenCountryHasNoRegionInfo()
+ {
+ var countriesWithoutRegionInfo = World.GetStatisticalRegion("001").Countries
+ .Where(c => c.Region == null);
+
+ foreach (var countryWithoutRegionInfo in countriesWithoutRegionInfo)
+ {
+ Assert.True(countryWithoutRegionInfo.IsCountryOrTerritory());
+ Assert.False(countryWithoutRegionInfo.HasRegionInfo());
+
+ TestOutput.WriteLine($"Country without RegionInfo: {countryWithoutRegionInfo}");
+ }
+ }
+
+ [Fact]
+ public void HasRegionInfo_ShouldThrowArgumentNullException_WhenRegionIsNull()
+ {
+ StatisticalRegionInfo region = null;
+
+ Assert.Throws(() => region.HasRegionInfo());
+ }
+ }
+}