commit 618e152ed12b7f1d10505318ca0a7b77b915fc27 Author: Tony Bark Date: Fri Mar 21 19:06:46 2025 -0400 Initial commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b4e4ee7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,128 @@ +# editorconfig.org + +# top-most EditorConfig file +root = true + +# Default settings: +# A newline ending every file +# Use 4 spaces as indentation +[*] +charset = utf-8 +end_of_line = crlf +indent_style = tab +indent_size = 4 +insert_final_newline = false +trim_trailing_whitespace = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 + +# C# files +[*.cs] +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = one_less_than_current + +# avoid this. unless absolutely necessary +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion + +# only use var when it's obvious what the variable type is +csharp_style_var_for_built_in_types = true:none +csharp_style_var_when_type_is_apparent = true:none +csharp_style_var_elsewhere = true:suggestion + +# use language keywords instead of BCL types +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Use UPPER_CASE for private or internal constant fields +dotnet_naming_rule.constants_should_be_upper_case.severity = suggestion +dotnet_naming_rule.constants_should_be_upper_case.symbols = constants +dotnet_naming_rule.constants_should_be_upper_case.style = constant_style + +dotnet_naming_symbols.constants.applicable_kinds = field, local +dotnet_naming_symbols.constants.required_modifiers = const + +dotnet_naming_style.constant_style.capitalization = all_upper + +# Comment this group and uncomment out the next group if you don't want _ prefixed fields. + +# internal and private fields should be _camel_case +dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion +dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields +dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style + +dotnet_naming_symbols.private_internal_fields.applicable_kinds = field +dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal + +dotnet_naming_style.camel_case_underscore_style.required_prefix = _ +dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case + +# Code style defaults +dotnet_sort_system_directives_first = true +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = false + +# Expression-level preferences +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion + +# Expression-bodied members +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Pattern matching +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion + +# Null checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = when_multiline:silent \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e20fc69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,548 @@ +# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig +# Created by https://www.toptal.com/developers/gitignore/api/rider,visualbasic,visualstudio +# Edit at https://www.toptal.com/developers/gitignore?templates=rider,visualbasic,visualstudio + +### Rider ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### VisualBasic ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +.DS_Store +.Trashes +*.vbw +*.csi +*.exp +*.lib +*.lvw +*.dca +*.scc +*.tmp +*.exe +*.bat +*.bak +*.zip +*.old +*.enc +*.key +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### VisualStudio ### +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.msix + +# JetBrains Rider +*.sln.iml + +### VisualStudio Patch ### +# Additional files built by Visual Studio + +# End of https://www.toptal.com/developers/gitignore/api/rider,visualbasic,visualstudio + +# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) + +.idea/** +*.txt +*.toml \ No newline at end of file diff --git a/CC0 b/CC0 new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/CC0 @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/GlobalUsing.cs b/GlobalUsing.cs new file mode 100644 index 0000000..b21675f --- /dev/null +++ b/GlobalUsing.cs @@ -0,0 +1,4 @@ +global using System.Diagnostics; +global using System.Text.Json; +global using System.Text.Json.Serialization; +global using Mirabelian; diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/Language.cs b/Language.cs new file mode 100644 index 0000000..41a3d99 --- /dev/null +++ b/Language.cs @@ -0,0 +1,55 @@ +namespace Mirabelian; + +internal class Language +{ + [JsonPropertyName("version")] + public string Version { get; set; } = string.Empty; + + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("words")] + public Dictionary Words { get; set; } + + void LanguageVersion(string name, string version) => + Tracer.LogLine($"{name} language v{version}"); + + Dictionary Defaults = new() + { + { "hello", "walin" }, + { "friend", "suhar" }, + { "water", "utol" }, + { "fire", "kotan" }, + { "mountain", "hukar" }, + { "fast", "sulat" }, + { "happy", "halun" }, + { "speak", "ratul" }, + { "walk", "saren" }, + { "know", "hiren" }, + { "exit", "etris" }, + }; + + public Language(string file) + { + var filePath = Path.Combine(Tracer.AppDirectory, file); + + if (!File.Exists(filePath)) + { + Name = "Simplified Mirabelian"; + Version = "0.1"; + Words = Defaults; + + Tracer.LogLine("Failed to locate language file. Switching to defaults."); + LanguageVersion(Name, Version); + } + else + { + Tracer.LogLine($"Language file found at {filePath}"); + var jsonFile = File.ReadAllText(filePath); + var json = JsonSerializer.Deserialize(jsonFile); + + LanguageVersion(json.Name, json.Version); + Words = json.Words; + } + } +} diff --git a/Mirabelian.csproj b/Mirabelian.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/Mirabelian.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..4bdd651 --- /dev/null +++ b/Program.cs @@ -0,0 +1,48 @@ +// I hereby waive this project under the public domain - see UNLICENSE for details. + +// Function to read user input +string ReadInput(string prompt) +{ + Console.Write(prompt); + return Console.ReadLine(); +} + +// Function to translate a complete sentence +string TranslateSentence(string sentence, Dictionary dictionary) +{ + if (string.IsNullOrWhiteSpace(sentence)) + return sentence; // Return the original sentence if it's empty or whitespace + + // Split the sentence into words, considering punctuation + var words = sentence.Split( + new char[] { ' ', ',', '.', '!', '?' }, + StringSplitOptions.RemoveEmptyEntries + ); + var translatedWords = words.Select(word => TranslateWord(word, dictionary)); + + // Reassemble the translated words into a sentence + return string.Join(" ", translatedWords); +} + +// Function to translate a single word +string TranslateWord(string word, Dictionary dictionary) +{ + if (dictionary.TryGetValue(word.ToLower(), out string? translatedWord)) + return translatedWord; + else + return word; // Return the original word if not found in the dictionary +} + +// Small dictionary for English to Mirabelian translation +// Mirabelian Language dictionary +var translationDict = new Language("mirabelian.json"); + +// Main method to read input and translate +string inputSentence = ReadInput("Enter an English sentence to translate (or 'exit' to quit): "); +var input = inputSentence.ToLower(); +while (input != "exit") +{ + string translatedSentence = TranslateSentence(inputSentence, translationDict.Words); + Console.WriteLine($"Translation: {translatedSentence}"); + inputSentence = ReadInput("Enter another sentence: "); +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..b340498 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Mirabelian + +Mirabelian is a constructed language for my fictional world, specifically the island of Mirabel, and this is a (romanized) translator made for it. + +## Language + +It uses a reduced runic alphabet consisting of 16 distinct letters: ᛟ (a), ᚦ (e), ᛏ (i), ᚢ (u), ᛡ (o), ᛒ (k), ᛇ (s), ᚾ (h), ᛅ (l), ᛗ (m), ᚻ (n), ᚱ (r), ᛊ (s), ᛏ (t), and ᛉ (w). The script can be written either horizontally or vertically, with a romanized form available. + +Mirabelian follows a phonemic vowel system and places importance on consonant length similar to Japanese. It features a reduced consonant inventory, making it distinct yet easy to learn. Words typically follow VCV, CV, or CVVC structures, maintaining a balance between simplicity and flexibility. + +The language avoids gender distinctions and lacks grammatical articles. Sentence structure follows either Subject-Verb-Object (SVO) or Subject-Object-Verb (SOV) orders, allowing for some syntactical flexibility. Punctuation includes commas for separating sentence elements, an ellipsis (… or ‥) for pauses or unfinished thoughts, and a full stop (。) to end of runic sentences. + +## License + +I hereby waive this project under the public domain - see [UNLICENSE](UNLICENSE) for details. diff --git a/Tracer.cs b/Tracer.cs new file mode 100644 index 0000000..41f88ac --- /dev/null +++ b/Tracer.cs @@ -0,0 +1,64 @@ +// I hereby waive this project under the public domain - see UNLICENSE for details. +namespace Mirabelian; + +/// +/// Provides debug-only console output methods. +/// These methods are only executed when the application is compiled in DEBUG mode. +/// +internal static class Tracer +{ + /// + /// Writes a line of text to the console, but only when in DEBUG mode. + /// + /// The text to write to the console. + [Conditional("DEBUG")] + internal static void LogLine(string content) => Console.WriteLine(content); + + /// + /// Writes text to the console without a newline, but only when in DEBUG mode. + /// + /// The text to write to the console. + [Conditional("DEBUG")] + internal static void Log(string content) => Console.Write(content); + + /// + /// Writes multiple lines of text to the console, but only when in DEBUG mode. + /// + /// A collection of text lines to write to the console. + [Conditional("DEBUG")] + internal static void LogLine(IEnumerable contents) + { + foreach (var content in contents) + { + Console.WriteLine(content); + } + } + + /// + /// Writes multiple text entries to the console without newlines, but only when in DEBUG mode. + /// + /// A collection of text entries to write to the console. + [Conditional("DEBUG")] + internal static void Log(IEnumerable contents) + { + foreach (var content in contents) + { + Console.Write(content); + } + } + + /// + /// Gets the current working directory in DEBUG mode or the application's base directory in release mode. + /// + internal static string AppDirectory + { + get + { +#if DEBUG + return Directory.GetCurrentDirectory(); +#else + return AppDomain.CurrentDomain.BaseDirectory; +#endif + } + } +} diff --git a/assets/Terra geopolitical map.png b/assets/Terra geopolitical map.png new file mode 100644 index 0000000..168055c Binary files /dev/null and b/assets/Terra geopolitical map.png differ diff --git a/assets/Terra geopolitical map.svg b/assets/Terra geopolitical map.svg new file mode 100644 index 0000000..93ed8e4 --- /dev/null +++ b/assets/Terra geopolitical map.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Port + + + HuisBoulongerSontiginoViraporizThoulisisVincumRogenJarnsdaElosOndreCorquileNewbokeStanstonManchLaneGatfordDarmingBarlinLelahlidAtriaAltfordChateauzyPrestogentSuleauliPrincipality of NvelinTarcelniaPrincipality of MilheiriaDuchy of Oster Peninsular CommonwealthDiocese of LokeriaKinmosian Commonwealth Juktosian FederationAtriaGrand Duchy of BomeileniaAltonlandPontasalean TheocracyHierarchy of AenonRepublic of OrciliaKarkmah RepublicRepublic of WarmingBoesiaLelahlidiaAlmeirian UnionMirabel RepublicDuchy of PoileauvilPontasalean Theocracy + + + 080160240320400 mi + + + + \ No newline at end of file diff --git a/mirabelian.json b/mirabelian.json new file mode 100644 index 0000000..798c4a6 --- /dev/null +++ b/mirabelian.json @@ -0,0 +1,130 @@ +{ + "version": "0.1", + "name": "Mirabelian", + "words": { + "the": "", + "a": "", + "an": "", + "he": "", + "she": "", + ",": ",", + "hello": "walin", + "goodbye": "tuhen", + "yes": "sai", + "no": "nel", + "please": "kato", + "thanks": "melka", + "sorry": "hunan", + "friend": "suhar", + "water": "utol", + "food": "matsi", + "house": "hlen", + "fire": "kotan", + "earth": "moten", + "sky": "watil", + "sun": "sola", + "moon": "kuma", + "star": "hasin", + "road": "woten", + "train": "rolen", + "boat": "sutal", + "mountain": "hukar", + "river": "sanul", + "ocean": "utalen", + "wind": "walur", + "strong": "morin", + "weak": "netan", + "fast": "sulat", + "slow": "loken", + "big": "hatur", + "small": "nelis", + "hot": "kutis", + "cold": "sunan", + "happy": "halun", + "sad": "nurak", + "angry": "teman", + "fear": "huran", + "love": "melur", + "speak": "ratul", + "listen": "kalur", + "see": "tanul", + "walk": "saren", + "run": "kutren", + "jump": "hatal", + "sleep": "luhen", + "wake": "motul", + "work": "marun", + "play": "sutan", + "read": "tatun", + "write": "miren", + "know": "hiren", + "think": "norun", + "give": "latul", + "take": "sokal", + "open": "kuten", + "close": "neken", + "light": "walin", + "dark": "sunen", + "left": "kalen", + "right": "ritan", + "up": "hulen", + "down": "netul", + "here": "telan", + "there": "ralen", + "who": "hirun", + "what": "lisen", + "where": "sulun", + "when": "kuren", + "why": "hoten", + "how": "metan", + "exit": "etris", + "morning": "sunet", + "night": "nokar", + "storm": "hulat", + "cloud": "mirun", + "forest": "tulen", + "stone": "rukal", + "path": "soten", + "bridge": "motar", + "city": "halis", + "village": "luhar", + "door": "katan", + "window": "selun", + "chair": "hotis", + "table": "muren", + "clothes": "takul", + "hat": "sunik", + "shoe": "lutan", + "metal": "kilun", + "wood": "turen", + "paper": "hirul", + "bag": "notan", + "key": "sarin", + "box": "kunel", + "animal": "morat", + "bird": "wetar", + "fish": "satan", + "horse": "hukel", + "cat": "mirat", + "dog": "tunar", + "insect": "suren", + "body": "hokan", + "hand": "liten", + "foot": "sotal", + "head": "rutis", + "eye": "makul", + "ear": "selat", + "mouth": "norin", + "heart": "melis", + "blood": "tuken", + "bone": "hulis", + "soft": "netul", + "hard": "rukar", + "new": "talin", + "old": "nokun", + "deep": "sutul", + "shallow": "litun", + "clean": "tisel", + "dirty": "muran" + } +}